# @atlaskit/feature-gate-js-client 中文文档

规范地址：https://npmcn.com/package/%40atlaskit/feature-gate-js-client/

版本：8\.0\.0
npm 元数据更新时间：2026-11-02T05:44:01.343Z
中文译文更新时间：2026-11-07T02:37:13.548Z
软件包许可：Apache-2\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40atlaskit/feature-gate-js-client
原文对照：https://npmcn.com/package/%40atlaskit/feature-gate-js-client/?lang=original
项目主页：https://bitbucket.org/atlassian/atlassian-frontend-monorepo#readme
源码仓库：https://bitbucket.org/atlassian/atlassian-frontend-monorepo

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：655 kB，150 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：6 个
- 首次发布：2024-03-01T03:15:02.526Z
- 最新版本发布：2026-11-02T05:44:01.131Z
- 近 30 天下载量：5681460（2026-10-07 至 2026-11-05，npm 官方下载统计）
- 已发布版本数：65（近 12 个月 16 个）

## 中文简介

Statsig js-lite客户端的地图集包.

## 安装

```sh
npm install @atlaskit/feature-gate-js-client
```

也可以使用：`pnpm add @atlaskit/feature-gate-js-client`、`yarn add @atlaskit/feature-gate-js-client`、`bun add @atlaskit/feature-gate-js-client`

## README

# 特性GateJs 客户端

Statsig js-lite客户端的地图集包.

## 使用量

`import FeatureGateJsClient from '@atlaskit/feature-gate-js-client';`

## 这个仓库是干什么的?

Js客户端覆盖前端功能门使用大小写. 这个客户端是模拟靴子陷阱 特性门值来自后端,不接收活更新.

## 客户用户

### 安装

客户可以从国家防范机制档案库中调取.

```shell
yarn add @atlaskit/feature-gate-js-client
```

### 初始化

客户端在尝试使用前必须初始化,否则会出错.

初始化客户有三种方式:

#### 1\. 默认初始化机制

这将通过调用特性旗服务来初始化客户端 (单位:千美元)[fx3 请检查url=值 (帮助)](https://go.atlassian.com/fx3)),并用返回的值将客户端拖入。 如果 客户端以任何理由未能初始化, 包括获取时间超过2秒 值,将使用默认值.

```typescript
import FeatureGates, {
    FeatureGateEnvironment,
    FeatureGateProducts,
    PerimeterType,
} from '@atlaskit/feature-gate-js-client';

try {
    await FeatureGates.initialize(
        {
            // This is an fx3 api key used to fetch the feature flag values.
            // Supported keys found at go/fx3/resources/api-keys
            apiKey: 'client-test',
            // This is the environment that you are operating in, targeting rules can target specific environments
            environment: FeatureGateEnvironment.Production,
            // This will be used to filter data from Statsig to only one target app.
            // View [doc](https://hello.atlassian.net/wiki/spaces/MEASURE/pages/2955970231/How-to+Use+TargetApps+in+Statsig)
            // for details on using targetApp.
            targetApp: 'jira_web',
            // [Optional] Default is 2000ms
            // This is the fetch timeout used for requests to feature-flag-service to get values to bootstrap the client.
            // The higher this value the longer your application will need to wait to render if you block on client initialization
            // Too low and your application will be more likely to fallback on default values
            fetchTimeoutMs: 1000,
            // [Optional] Default is false
            // This is a boolean to indicate whether to use the `gateway/api` url for the request to feature flag service.
            // Note that this option takes precendence over the environment and perimeter options in building the url.
            // To be used for applications with strict cross-origin policies, as it will keep all requests to the same origin.
            useGatewayUrl: true,
            // [Optional] Default is false
            // Whether to include flags served by the Feature Flag Platform (FFP). When true, values are fetched from the
            // feature-flag-service `/api/v1/evalFlags` endpoint instead of `/api/v2/frontend/experimentValues`.
            // Each flag is then served by the platform the service assigns it to. When false, FFP is treated as disabled.
            includeFfpFlags: false,
            // [Optional] Must be one of the strings from the exported enum PerimeterType.
            // If provided, will build base url for the `feature-flag-service` based on environment and perimeter type, and
            // will disable all logging to Statsig in perimeters where it is prohibited..
            perimeter: PerimeterType.FEDRAMP_MODERATE,
        },
        {
            // These are expected identifiers, you must provide them if they are relevant to your product and will be added to exposures events
            analyticsAnonymousId: '<analyticsAnonymousId>',
            atlassianAccountId: '<aaid>',
            atlassianOrgId: '<orgid>',
            tenantId: '<tenantid>',
            transactionAccountId: '<transactionAccountId>',
            trelloUserId: '<trelloUserId>',
            trelloWorkspaceId: '<trelloWorkspaceId>',
        },
        {
            // These are additional custom attributes that can be used for targeting and will be added to exposure events
            exampleCustomAttribute: '<attributeValue>',
        },
    );
} catch (err) {
    console.error('Failed to initialize FeatureGates client.', err);
}
```

如果您的应用程序有登录流程或其他机制,使用户能够 在会话中更改,然后可以使用 `updateUser` 方法应用此更改。 这个 此方法的签名几乎与 `initialize`,但仅需要选项 用于获取新的一组值.

**重要性**:调用这种方法将完全重新启用客户端并使用一对新的旗帜. 完成后,您需要重新发送整个页面,以确保所有东西都能接上 新旗帜值 。 您应该避免频繁使用它,因为它对用户有影响 经历.

```typescript
import FeatureGates, {
    FeatureGateEnvironment,
    FeatureGateProducts,
    PerimeterType,
} from '@atlaskit/feature-gate-js-client';

try {
    await FeatureGates.updateUser(
        {
            // This is an fx3 api key used to fetch the feature flag values.
            // Supported keys found at go/fx3/resources/api-keys
            apiKey: 'client-test',
            // This is the environment that you are operating in, targeting rules can target specific environments
            environment: FeatureGateEnvironment.Production,
            // [Optional] Default is 2000ms
            // This is the fetch timeout used for requests to feature-flag-service to get values to bootstrap the client.
            fetchTimeoutMs: 1000,
            // [Optional] Default is false
            // This is a boolean to indicate whether to use the `gateway/api` url for the request to feature flag service.
            // Note that this option takes precendence over the environment and perimeter options in building the url.
            // To be used for applications with strict cross-origin policies, as it will keep all requests to the same origin.
            useGatewayUrl: true,
            // [Optional] Default is false
            // Whether to include flags served by the Feature Flag Platform (FFP). When true, values are fetched from the
            // feature-flag-service `/api/v1/evalFlags` endpoint instead of `/api/v2/frontend/experimentValues`.
            // Each flag is then served by the platform the service assigns it to. When false, FFP is treated as disabled.
            includeFfpFlags: false,
            // [Optional] Default is COMMERCIAL. Must be one of the values from the exported enum PerimeterType.
            // If provided, will build base url for the `feature-flag-service` based on environment and perimeter type, and
            // will disable all logging to Statsig in perimeters where it is prohibited.
            perimeter: PerimeterType.FEDRAMP_MODERATE,
        },
        {
            // These are expected identifiers, you must provide them if they are relevant to your product and will be added to exposures events
            analyticsAnonymousId: '<analyticsAnonymousId>',
            atlassianAccountId: '<aaid>',
            atlassianOrgId: '<orgid>',
            tenantId: '<tenantid>',
            transactionAccountId: '<transactionAccountId>',
            trelloUserId: '<trelloUserId>',
            trelloWorkspaceId: '<trelloWorkspaceId>',
        },
        {
            // These are additional custom attributes that can be used for targeting and will be added to exposure events
            exampleCustomAttribute: '<attributeValue>',
        },
    );
} catch (err) {
    console.error('Failed to update the FeatureGates user.', err);
}
```

#### 2\. 从价值入手

您必须使用我们一个包装后端客户端获取自己的值( 也可以在此找到 ) repo)并提供给此前端客户端

```typescript
import FeatureGates, {
    FeatureGateEnvironment,
    FeatureGateProducts,
} from '@atlaskit/feature-gate-js-client';

try {
    await FeatureGates.initializeFromValues(
        {
            // [Optional] This should come directly from a backend or service from the Statsig.getClientInitializeResponse(user) call
            // Or supplied from the statsig UI
            // Should be provided if it is available. It is optional so initialisation can still occur if the request to fetch the key fails
            // If not provided, a default string will be used but exposure event data will not be sent back to Statsig
            sdkKey: 'client-test',
            // This is the environment that you are operating in, targeting rules can target specific environments
            environment: FeatureGateEnvironment.Production,
            // This will be used to filter config data relevant to the listed products
            products: [FeatureGateProducts.Jira],
        },
        {
            // These are expected identifiers, you must provide them if they are relevant to your product and will be added to exposures events
            analyticsAnonymousId: '<analyticsAnonymousId>',
            atlassianAccountId: '<aaid>',
            atlassianOrgId: '<orgid>',
            tenantId: '<tenantid>',
            transactionAccountId: '<transactionAccountId>',
            trelloUserId: '<trelloUserId>',
            trelloWorkspaceId: '<trelloWorkspaceId>',
        },
        {
            // These are additional custom attributes that will be added to exposure events
            exampleCustomAttribute: '<attributeValue>',
        },
        // This should come directly from a backend or service from the Statsig.getClientInitializeResponse(user) call
        initializeValues,
    );
} catch (err) {
    console.error('Failed to initialize FeatureGates client.', err);
}
```

如果您的应用程序有登录流程或其他机制,使用户能够 在会话中更改,然后可以使用 `updateUserWithValues` 方法应用此更改. 这种方法的签名几乎与 `initializeFromValues`,但是它没有 需要任何选项.

**重要性**:调用这种方法将完全重新启用客户端并使用一对新的旗帜. 完成后,您需要重新发送整个页面,以确保所有东西都能接上 新旗帜值 。 您应该避免频繁使用它,因为它对用户有影响 经历.

```typescript
import FeatureGates, {
    FeatureGateEnvironment,
    FeatureGateProducts,
} from '@atlaskit/feature-gate-js-client';

try {
    await FeatureGates.updateWithValues(
        {
            // These are expected identifiers, you must provide them if they are relevant to your product and will be added to exposures events
            analyticsAnonymousId: '<analyticsAnonymousId>',
            atlassianAccountId: '<aaid>',
            atlassianOrgId: '<orgid>',
            tenantId: '<tenantid>',
            transactionAccountId: '<transactionAccountId>',
            trelloUserId: '<trelloUserId>',
            trelloWorkspaceId: '<trelloWorkspaceId>',
        },
        {
            // These are additional custom attributes that will be added to exposure events
            exampleCustomAttribute: '<attributeValue>',
        },
        // This should come directly from a backend or service from the Statsig.getClientInitializeResponse(user) call
        initializeValues,
    );
} catch (err) {
    console.error('Failed to update FeatureGates user.', err);
}
```

* * *

如果在初始化过程中有任何问题,那么客户端将会被置于一种总是模式中 返回默认值,并返回被拒绝的许诺。 你就能抓住这个被拒的承诺 如果您希望记录自己的日志和参数,或者您希望停止申请 装入默认值.

FeatureGates 客户端只有一次实例,所以只有第一个初始化的呼叫才会开始 初始化 。 任何后续的呼唤,都会还原现有的第一个承诺 初始化, 参数值将被忽略 。 为了确认客户是否 已经开始初始化,你可以打电话 `FeatureGates.initializeCalled()`。 。 。 .

#### 3\. 使用提供者初始化

此初始化使用提供方的操作来获取客户端 sdk 关键值和实验值.

支助提供者有:

-   `@atlaskit/feature-gate-single-fetch-provider`
-   `@atlaskit/feature-gate-polling-provider`

```typescript
import FeatureGates, {
    FeatureGateEnvironment,
    FeatureGateProducts,
    PerimeterType,
} from '@atlaskit/feature-gate-js-client';

try {
    await FeatureGates.initializeWithProvider(
        {
            // This is an fx3 api key used to fetch the feature flag values.
            // Supported keys found at go/fx3/resources/api-keys
            apiKey: 'client-test',
            // This is the environment that you are operating in, targeting rules can target specific environments
            environment: FeatureGateEnvironment.Production,
            // This will be used to filter data from Statsig to only one target app.
            // View [doc](https://hello.atlassian.net/wiki/spaces/MEASURE/pages/2955970231/How-to+Use+TargetApps+in+Statsig)
            // for details on using targetApp.
            targetApp: 'jira_web',
            // [Optional] Must be one of the strings from the exported enum PerimeterType.
            // If provided, will build base url for the `feature-flag-service` based on environment and perimeter type, and
            // will disable all logging to Statsig in perimeters where it is prohibited..
            perimeter: PerimeterType.FEDRAMP_MODERATE,
        },
        new Provider(/* ... */),
        {
            // These are expected identifiers, you must provide them if they are relevant to your product and will be added to exposures events
            analyticsAnonymousId: '<analyticsAnonymousId>',
            atlassianAccountId: '<aaid>',
            atlassianOrgId: '<orgid>',
            tenantId: '<tenantid>',
            transactionAccountId: '<transactionAccountId>',
            trelloUserId: '<trelloUserId>',
            trelloWorkspaceId: '<trelloWorkspaceId>',
        },
        {
            // These are additional custom attributes that can be used for targeting and will be added to exposure events
            exampleCustomAttribute: '<attributeValue>',
        },
    );
} catch (err) {
    console.error('Failed to initialize FeatureGates client.', err);
}
```

如果您的应用程序有登录流程或其他机制,使用户能够 在会话中更改,然后可以使用 `updateUserWithProvider` 方法应用此更改. 这种方法将使用相同的提供者和选项 `initializeWithProvider`这需要 新用户的标识符和自定义属性。 与网络有关,它会 用于获取新的一组值.

**重要性**:调用这种方法将完全重新启用客户端并使用一对新的旗帜. 完成后,您需要重新发送整个页面,以确保所有东西都能接上 新旗帜值 。 您应该避免频繁使用它,因为它对用户有影响 经历.

```typescript
import FeatureGates, {
    FeatureGateEnvironment,
    FeatureGateProducts,
} from '@atlaskit/feature-gate-js-client';

try {
    await FeatureGates.updateUserWithProvider(
        {
            // These are expected identifiers, you must provide them if they are relevant to your product and will be added to exposures events
            analyticsAnonymousId: '<analyticsAnonymousId>',
            atlassianAccountId: '<aaid>',
            atlassianOrgId: '<orgid>',
            tenantId: '<tenantid>',
            transactionAccountId: '<transactionAccountId>',
            trelloUserId: '<trelloUserId>',
            trelloWorkspaceId: '<trelloWorkspaceId>',
        },
        {
            // These are additional custom attributes that can be used for targeting and will be added to exposure events
            exampleCustomAttribute: '<attributeValue>',
        },
    );
} catch (err) {
    console.error('Failed to update the FeatureGates user.', err);
}
```

#### 特性旗子平台值

在从Statsig向地标旗平台迁移的过程中,旗帜由一个平台服务 或别. 与 `includeFfpFlags: true`, (中文(简体) ), `initialize` 财务报告和审定财务报表 `updateUser` 获取特性旗 服务 `/api/v1/evalFlags` 结束点, 将它们分割并返回 `{ statsig, ffp }`因此,每个 旗帜键出现在一个平台下。 没有它,只获取 Statsig 值和 FFP 被视为残疾。 客户端读取 FFP 的密钥(通过 `@atlaskit/flag-client`) 当最新的FFFP 值包含它,而 Statsig 则不包含; 评估 API 不改变 :

-   `checkGate` 读取 FFP 布尔旗.
-   `getExperiment` 编号 : `getExperimentValue` 将 FFP JSON 对象旗读作实验参数。 任意 其他FFP旗是一面平整的 Statsig 动态配置,所以用 `value` 参数,用于 实例 `getExperimentValue('example.flag', 'value', 'default')`。 。 。 .
-   局部的覆被仍然优先,地层总是由Statsig服务.
-   FFP 曝光遥测在联邦RAMP中以及何时停止使用 `disableAllLogging` 已经设定.

从数值初始化或更新时,通过 `ffp` 作为服务响应的成员 可选最后一个参数 `initializeFromValues` 编号 : `updateUserWithValues`,或作为 `ffp` 在一个 `Provider`是因为 `getExperimentValues` 结果。 在省略后,Statsig为每一面旗帜服务. 过 不变: `requestContext` 需要,没有它,FFP对用户没有任何好处.

答复还有: `status` 每个平台: `OK`, (中文(简体) ), `DISABLED` (故意不使用)或 `UNAVAILABLE` (无法评价). 客户端只使用平台的值 `OK`, (中文(简体) ), 所以只使用不健康平台的旗帜 返回他们的代码默认值; 当没有FFP时, 该服务为仍在从Statsig迁移的旗帜服务. `initialize` 财务报告和审定财务报表 `updateUser` 获取一次。 虽然至少有一个平台 `OK`,或者两者都不使用,它们就会解决;当一个平台 无法使用(或既不使用),客户端登录外部生产警告并发送 `degraded featureGatesClientValues` 操作活动 `statsigStatus`, (中文(简体) ), `ffpStatus` 财务报告和审定财务报表 `trigger` 属性。 当没有平台时 `OK` 一个是 `UNAVAILABLE` (例如,Statsig为 无法使用,且 FFP 已禁用),没有值可使用,因此拒绝任何失败 获取 : `initialize` 仍然启动 Statsig 没有值,所以评价返回默认值,以及 `updateUser` 保存上一个用户的值。 供应商可以报告其价值的状况 返回通过 `status` 区域。 投票服务商再次打来 当平台是 `UNAVAILABLE` (大约30秒后,退到它的投票间隔), 但不是为了 `DISABLED`,并保留最后一个 `OK` 无法打开的平台的值 恢复状态 它用它通常的回放来重复一个没有可用平台的响应,就像5xx一样. 这个 除非用户更改,否则不重试408和429以外的4xx响应.

### 评价

为了评估一个大门:

```typescript
import FeatureGates from '@atlaskit/feature-gate-js-client';

// Note: this checkGate call will automatically fire an exposure event
if (FeatureGates.checkGate('gateName')) {
    // do something here
}
```

为了评估一项实验:

```typescript
import FeatureGates from '@atlaskit/feature-gate-js-client';

// Note: this call will automatically fire an exposure event
if (FeatureGates.getExperimentValue('myExperiment', 'myBooleanParameter', false)) {
    // do something here
}
```

为了使用更复杂的实验配置:

```typescript
import FeatureGates from '@atlaskit/feature-gate-js-client';

// You can provide an optional function like this to reject any incoming values that don't meet your expectations.
// If this function does not pass, the default value will be returned instead.
const isHexCode = (value: unknown) =>
    typeof value === 'string' && value.startsWith('#') && value.length === 7;

// Note: this call will automatically fire an exposure event. You can provide "fireExposureEvent: false" in the options if you wish to suppress it.
const buttonColor: string = FeatureGates.getExperimentValue(
    'myExperiment',
    'myButtonColorStringParameter',
    '#000000',
    {
        typeGuard: isHexCode,
    },
);
```

#### 新建只使用FFP的旗帜与迁移的旗帜

旗帜分为两组,而产品则从Statsig移动到地物旗平台(FFP):

| 旗帜 | 读出来 | 为什么 |
| --- | --- | --- |
| 新旗帜,只在FFP中创建 | `FeatureGates.ffpClient` | 它在斯达西格不存在. |
| 原已存在的Statsig旗,其中一面被迁移到FFP | `checkGate`, (中文(简体) ), `getExperiment`, (中文(简体) ), `getExperimentValue` | 它们从Feature Flag Service分配给它的任何平台提供每个密钥. |

读取新的只使用 FFP 的旗帜, 其输入方法为 `FeatureGates.ffpClient`,这是 `FlagClient` 联 合 国 `@atlaskit/flag-client` 此软件包管理 :

```typescript
import FeatureGates from '@atlaskit/feature-gate-js-client';
import type { EvaluationDetails } from '@atlaskit/flag-client/types';

const enabled = FeatureGates.ffpClient?.getBooleanValue('my-new-flag', false) ?? false;
const limit = FeatureGates.ffpClient?.getNumberValue('my-new-limit', 10) ?? 10;
const theme = FeatureGates.ffpClient?.getObjectValue('my-new-theme', { color: 'blue' }) ?? {
    color: 'blue',
};

// To log the exposure later, for example when the user sees the feature:
const details: EvaluationDetails<boolean> | undefined = FeatureGates.ffpClient?.getBooleanDetails(
    'my-new-flag',
    false,
    { disableExposureLogging: true },
);
if (details) {
    FeatureGates.ffpClient?.logExposure(details);
}
```

-   `ffpClient` 实值 `undefined` 直到一个初始化方法被调用。 之后就一样了 包括横跨 `updateUser` 打电话.
-   在FFP值到达之前,当服务不为用户使用FFP时,请读回 默认你通过.
-   本地覆盖( O)`overrideGate`, (中文(简体) ), `overrideConfig`, (中文(简体) ), `setOverrides`)不适用.
-   FFP 曝光遥测在联邦RAMP中以及何时停止使用 `disableAllLogging` 已经设定.
-   `FfpEvaluationClient`,类型 `ffpClient`,从 `@atlaskit/feature-gate-js-client/ffp/types`使用的方法类型(`EvaluationDetails`, (中文(简体) ), `EvaluationOptions` 和其余的)来自 `@atlaskit/flag-client/types`,所以添加 `@atlaskit/flag-client` 作为导入它们的依赖.

继续读取已有的 Statsig 旗 `checkGate` 或者说 `getExperimentValue` 当它是 迁移。 不要切换到 `ffpClient`数字 : `ffpClient` 仅服务 FFP 值,因此返回 默认任何用户 Statsig 仍然为旗帜服务 。 相反,不要只读FFP的旗帜 与 `checkGate` 或者说 `getExperimentValue`: 它们将 FFP 值映射到 Statsig 形状( 见 [特性旗子平台值](https://npmcn.com/package/%40atlaskit/feature-gate-js-client/#readme-feature-flag-platform-ffp-values)和正在退休 斯达西格.

方法 `ffpClient` 符合 `FlagClient`,所以一旦迁移完成,代码: 读取 `ffpClient` 可以移动到一个 `FlagClient` 从 `@atlaskit/flag-client` 而不改变它的读数.

#### 曝光事件日志

曝光事件进行分批处理,并每10秒被送往Statsig. Statsig 的活动域名 looking API 被一些广告屏蔽器所屏蔽,所以默认情况下我们将通过这些请求代理 `xp.atlassian.com` 减少接触损失.

### 订阅

要订阅更改的大门。 当检查门值改变时, 调用会调用 .

```typescript
import FeatureGates from '@atlaskit/feature-gate-js-client';

const unsubscribe = FeatureGates.onGateUpdated('gateName', () => {});

// To unsubscribe
unsubscribe();
```

要订阅对实验值的修改。 当实验值值时, 回调将被调用 变化.

```typescript
import FeatureGates from '@atlaskit/feature-gate-js-client';

const unsubscribe = FeatureGates.onExperimentValueUpdated(
    'myExperiment',
    'myButtonColorStringParameter',
    '#000000',
    () => {},
    {
        typeGuard: isHexCode,
    },
);

// To unsubscribe
unsubscribe();
```

订阅客户端更新的新的一组值,无论其基础是什么 价值观已经改变.

```typescript
import FeatureGates from '@atlaskit/feature-gate-js-client';

// Note: The callback will be called whenever a new set of values is set even if none of the values in the set have changed.
const unsubscribe = FeatureGates.onAnyUpdated(() => {});

// To unsubscribe
unsubscribe();
```

### 基于文件的持久覆盖

对于没有浏览器本地Storage的 CLI 工具和本地开发环境,您可以使用 `FilePersistentOverrideAdapter`。这允许您对文件系统上的文件坚持特性标记覆盖.

**不要用这个包 在丛生的背景** - 那个 `FilePersistentOverrideAdapter` 设计对象仅为CLI工具和当地发展环境. 它不会在浏览器环境中正常工作,并可能造成出错.

```typescript
import { FilePersistentOverrideAdapter } from '@atlaskit/feature-gate-js-client/file-persistent-override-adapter';
import { FeatureGateClient } from '@atlaskit/feature-gate-js-client/client';

// Create the file override adapter with a path where overrides will be stored
const overrideAdapter = new FilePersistentOverrideAdapter('/path/to/overrides.json');

// Create a client instance with the adapter
const client = new FeatureGateClient({
  overrideAdapter: overrideAdapter
});


await client.initialize({
  // ... standard initialization options
});

```

与浏览器本地Storage适配器不同,文件适配器会创建任何存储文件的必要目录,并妥善处理文件系统错误.

### 单一页面上的多个客户端

通常我们不允许在单一页面上多处使用功能门客户端,因为 客户端会发出很多重的网络呼叫 可能会对运行产生巨大影响 如果许多客户在一页上存在的话。 但是,在有些情况下 将客户端隔离到产品上是绝对必要的. 我们揭发了一种方法 来抓新客户 而不是用静态方法处理此案.

由于所涉业绩问题 **请在使用前询问我们 独立客户端** 这样我们可以检查是否有其他的解决方案不会影响 并让我们知道需要分开客户的情况.

```typescript
import FeatureGateClient from '@atlaskit/feature-gate-js-client/client';

const featureGates = new FeatureGateClient();

// Usage is the same as the static API
await featureGates.initialize({
    // ...
});
featureGates.checkGate('my-gate');
```

### 孤立的云支持

客户端支持孤立的云环境,并能够 `init` 在IC环境中使用FFS. SDK 自动解决右边 stargate api url 基于用户提供的环境和窗口位置.

如果用户正在运行这个客户端作为服务器代码的一部分,并作为后端 SDK 并想要直接与 FFS 交谈,他们需要通过 `isolationContextId` 这是可选的 输入 `ClientOptions`。 。 。 . SDK将根据 `isolationContextId` sDK将从中进行初始化.

```typescript
import FeatureGates, {
    FeatureGateEnvironment,
    FeatureGateProducts,
    PerimeterType,
} from '@atlaskit/feature-gate-js-client';

try {
    await FeatureGates.initialize(
        {
            // This is an fx3 api key used to fetch the feature flag values.
            // Supported keys found at go/fx3/resources/api-keys
            apiKey: 'client-test',
            isolationContextId: 'ic-7bf',
        });
} catch (err) {
    console.error('Failed to initialize FeatureGates client.', err);
}
```

## 测试

### 欢乐

#### 测试初始化状态

您可以通过模拟返回值来测试各种初始化状态 `initialize` 财务报告和审定财务报表 `updateUser`。请注意,你还需要嘲笑 `initializeCalled`,因为这通常由 真实 `initialize` 函数.

```typescript
import FeatureGates from '@atlaskit/feature-gate-js-client';

jest.mock('@atlaskit/feature-gate-js-client', () => ({
    ...jest.requireActual('@atlaskit/feature-gate-js-client'),
    initializeCalled: jest.fn(),
    initialize: jest.fn(),
    updateUser: jest.fn(),
}));

const MockedFeatureGates = jest.mocked(FeatureGates);

describe('with successful initialization', () => {
    beforeEach(() => {
        MockedFeatureGates.initializeCalled.mockReturnValue(true);
        MockedFeatureGates.initialize.mockResolvedValue();
        MockedFeatureGates.updateUser.mockResolvedValue();
    });

    afterEach(() => jest.resetAllMocks());
});

describe('with failed initialization', () => {
    beforeEach(() => {
        MockedFeatureGates.initializeCalled.mockReturnValue(true);
        MockedFeatureGates.initialize.mockRejectedValue();
        MockedFeatureGates.updateUser.mockRejectedValue();
    });

    afterEach(() => jest.resetAllMocks());
});

describe('with pending initialization', () => {
    // These can be called within your tests transition from the pending
    // initialization state into a successful/failed state.
    let resolveInitPromise;
    let rejectInitPromise;
    beforeEach(() => {
        const initPromise = new Promise((resolve, reject) => {
            resolveInitPromise = resolve;
            rejectInitPromise = reject;
        });
        MockedFeatureGates.initializeCalled.mockReturnValue(true);
        MockedFeatureGates.initialize.mockReturnValue(initPromise);
        MockedFeatureGates.updateUser.mockReturnValue(initPromise);
    });

    afterEach(() => jest.resetAllMocks());
});
```

#### 超过数值

在 Jest 测试中,可以有两种方法可以覆盖值:

1.  使用模拟
2.  使用内置覆盖方法

#### 使用模拟

```typescript
import FeatureGates, { DynamicConfig, EvaluationReason } from '@atlaskit/feature-gate-js-client';

jest.mock('@atlaskit/feature-gate-js-client', () => ({
    ...jest.requireActual('@atlaskit/feature-gate-js-client'),
    getExperiment: jest.fn(),
    checkGate: jest.fn(),
}));

const MockedFeatureGates = jest.mocked(FeatureGates);

describe('with mocked experiments and gates', () => {
    beforeEach(() => {
        const overrides = {
            configs: {
                'example-experiment': {
                    cohort: 'variation',
                },
            },
            gates: {
                'example-gate': true,
            },
        };

        MockedFeatureGates.getExperiment.mockImplementation((experimentName) => {
            const values = overrides.configs[experimentName] || {};
            return new DynamicConfig(experimentName, values, 'rule-id', {
                time: Date.now(),
                reason: EvaluationReason.LocalOverride,
            });
        });

        MockedFeatureGates.checkGate.mockImplementation((gateName, defaultValue) => {
            return overrides.gates[gateName] || defaultValue;
        });
    });

    afterEach(() => jest.resetAllMocks());
});
```

#### 使用覆盖方法

```typescript
import FeatureGates, { FeatureGateEnvironment } from '@atlaskit/feature-gate-js-client';

describe('with overridden gates and experiments', () => {
    beforeAll(async () => {
        // setOverrides can only be called if the client is _actually_ initialized. You can't mock the initialization, you will have invoke it properly.
        await FeatureGates.initializeWithValues(
            {
                environment: FeatureGateEnvironment.Development,
                sdkKey: 'client-default-key',
                localMode: true,
            },
            {},
            {},
        );
    });

    beforeEach(() => {
        const overrides = {
            configs: {
                'example-experiment': {
                    cohort: 'variation',
                },
            },
            gates: {
                'example-gate': true,
            },
        };

        FeatureGates.setOverrides(overrides);
    });

    afterEach(() => FeatureGates.clearAllOverrides());
});
```

### 齐压

#### 超过数值

这个 `.visit` 命令在 Cypress 中创建了新窗口, 并使用它自己的特异功能Gates 实例, 所以您 将无法简单地导入模块并应用分贝.

```typescript
// ❌ This will not work!

import FeatureGates, { LocalOverrides } from '@atlaskit/feature-gate-js-client';

const overrides: LocalOverrides = {
    configs: {
        'example-experiment': {
            cohort: 'variation',
        },
    },
    gates: {
        'example-gate': true,
    },
};

// These interact with the FeatureGates instance that your test framework is running in
cy.stub(
    FeatureGates,
    'checkGate',
    (gateName, defaultValue) => overrides.gates[gateName] || defaultValue,
);

cy.stub(FeatureGates, 'getExperiment', (experimentName) => {
    const values = overrides.configs[experimentName] || {};
    return new DynamicConfig(experimentName, values, 'rule-id', {
        time: Date.now(),
        reason: EvaluationReason.LocalOverride,
    });
});

// This will creates a new window, with its own FeatureGates instance.
cy.visit('http://localhost:3000/');

// The test feature will not exist since the stubs don't exist on the visited window.
cy.get('#test-feature').dblclick();
```

相反,您需要获得存在于生成窗口上的客户端的引用,以及 应用您的功能代替.

我们暴露了一个 `window.__FEATUREGATES_JS__` 变量,将包含 窗户.

```typescript
// ✅ Do this instead!

import { LocalOverrides } from '@atlaskit/feature-gate-js-client';

const overrides: LocalOverrides = {
    configs: {
        'example-experiment': {
            cohort: 'variation',
        },
    },
    gates: {
        'example-gate': true,
    },
};

cy.visit('http://localhost:3001', {
    // onLoad provides a reference to the generated window, and it is also only invoked when all scripts have finished loading, so the __FEATUREGATES_JS__
    // variable will be available at this point.
    onLoad: (contentWindow) => {
        const FeatureGates = contentWindow.__FEATUREGATES_JS__;

        // Note that the client would not have been initialized by this point, so we can't use the override* or setOverrides methods.
        // We also don't want to wait until the initialization completes, because then the page may have already started to render without these overrides.
        cy.stub(
            FeatureGates,
            'checkGate',
            (gateName, defaultValue) => overrides.gates[gateName] || defaultValue,
        );

        cy.stub(FeatureGates, 'getExperiment', (experimentName) => {
            const values = overrides.configs[experimentName] || {};
            return new DynamicConfig(experimentName, values, {
                time: Date.now(),
                reason: EvaluationReason.LocalOverride,
            });
        });
    },
});
```

您也可以设置您自己的自定义命令, 它会听下一个 `window:load` 要完成的事件 在任何页面访问前都可以引用的同样内容:

```typescript
import { LocalOverrides } from '@atlaskit/feature-gate-js-client';

Cypress.Commands.add('featureGateOverrides', (overrides: LocalOverrides) => {
    // Use cy.once instead of cy.on so that this only affects the next visit.
    cy.once('window:load', (contentWindow) => {
        const FeatureGates = contentWindow.__FEATUREGATES_JS__;

        cy.stub(
            FeatureGates,
            'checkGate',
            (gateName, defaultValue) => overrides?.gates?.[gateName] || defaultValue,
        );

        cy.stub(FeatureGates, 'getExperiment', (experimentName) => {
            const values = overrides?.configs?.[experimentName] || {};

            return new DynamicConfig(experimentName, values, {
                time: Date.now(),
                reason: EvaluationReason.LocalOverride,
            });
        });
    });
});

// Once the command has been added, you can use it in any of your tests like this
cy.featureGateOverrides({
    configs: {
        'example-experiment': {
            cohort: 'variation',
        },
    },
    gates: {
        'example-gate': true,
    },
}).visit('http://localhost:3001');
```

### 剧作家

与 Cypress 类似, Playwright 要求您在页面加载后应用您的根. 我们可以利用 [页面。添加Init脚本](https://playwright.dev/docs/api/class-page#page-add-init-script) 钩入这个生命周期,以便支起 `window.__FEATUREGATES_JS__`。 。 。 .

#### 超过数值

```typescript
import {
  LocalOverrides,
  DynamicConfig,
  EvaluationReason,
} from '@atlaskit/feature-gate-js-client';
import { Page } from '@playwright/test';

export async function withFeatureGateOverrides(
  page: Page,
  overrides: LocalOverrides,
) {
  await page.addInitScript(
    ({ overridesSerialized, localOverrideReason }) => {
      const FeatureGates = {
        initialize: () => Promise.resolve(),
        checkGate: (gateName: string) => {
          return overridesSerialized.gates?.[gateName] ?? false;
        },

        getExperiment: (experimentName: string) => {
          const values = overridesSerialized.configs?.[experimentName] || {};
          return new DynamicConfig(experimentName, values, 'rule-id', {
            time: Date.now(),
            reason: localOverrideReason,
          });
        },
      };

      window.__FEATUREGATES_JS__ = {
        ...window.__FEATUREGATES_JS__,
        ...FeatureGates,
      };
    },
    {
      overridesSerialized: overrides,
      localOverrideReason: EvaluationReason.LocalOverride,
    },
  );
}
```

以下是消费这个的例子:

```typescript
import { expect, test } from '@playwright/test';
import { withFeatureGateOverrides } from './utils/statsig';

test.describe('Playwright test suite', () => {
  test.beforeEach(async ({ page }) => {
    await withFeatureGateOverrides(page, {
      configs: {},
      gates: {
        your_feature_gate: true,
      },
      layers: {},
    });
  });

  test('should pass', async ({ page }) => {
    await expect(1).toEqual(1);
  });
});
```

### 故事书

#### 超过数值

故事本上没有任何嘲弄或取笑API,但你可以使用 `override*` 财务报告和审定财务报表 `setOverrides` 用于替换此客户端的方法.

请注意,在调用这些方法之前,客户必须先初始化,而且 每本故事手册被卸载后,需要清除,因为这些内容将持续 (原始内容存档于2018-10-21). localStorage.

设置最简单的方法是使用 `FeatureGatesInitializationWithDefaults` 构成部分 我们的反应 SDK (`@atlassian/feature-gates-react`与 `overrides` 道具集,因为这个管理 初始化和清理给你。 请看 [组成部分文件](https://npmcn.com/package/docs/react-sdk/FEATURE_GATES_INITIALIZATION_WITH_DEFAULTS.md) 页:1 更多信息.

## 发展

### 我该怎么安排?

-   设立情况概述
    -   此 repo 软件包使用纱线
    -   运行 `yarn install` 在根目录中设置您 git 钩.
    -   为了开始运行 `yarn` 以安装依赖关系
-   如何运行测试
    -   为了运行所有测试 只需运行 `yarn test packages/measurement/feature-gate-js-client` 从平台目录
    -   为了在运行开发时在监视模式下运行滑稽测试 `yarn test:jest --watch`
    -   注:您可能需要运行 `yarn build @atlaskit/feature-gate-js-client` 创建版本.ts 一些测试所需的文件

### 捐款准则

-   所有新逻辑都必须测试
    -   无需直接通过 Statsig APIs
    -   参数转换算作新逻辑
-   代码审查
    -   更改必须经过拉动请求才能合并
-   其他准则

### 释放

这个包是AFP单列波的一部分. 使用 `yarn changeset` 承诺. [文档](https://hello.atlassian.net/wiki/spaces/AF/pages/2630205905/Releasing+Packages)

### 我和谁说话?

这回波是实验平台团队拥有的 伸手去 [{\\fn方正粗倩简体\\fs12\\an8\\1chffff00\\b0}帮助巫师](https://atlassian.enterprise.slack.com/archives/C04PR2YE4UC) 如果你需要的话 一只手。 一只手。 .

## 常见问题

### @atlaskit/feature-gate-js-client 是什么？

Statsig js-lite客户端的地图集包\.

### 如何安装 @atlaskit/feature-gate-js-client？

在项目目录运行 npm install @atlaskit/feature-gate-js-client，或使用 pnpm add / yarn add / bun add。

### @atlaskit/feature-gate-js-client 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @atlaskit/feature-gate-js-client 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @atlaskit/feature-gate-js-client 可以商用吗？

@atlaskit/feature-gate-js-client 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @atlaskit/feature-gate-js-client 的下载量有多少？

根据 npm 官方下载统计，@atlaskit/feature-gate-js-client 在 2026/10/07 – 2026/11/05 这 30 天内被下载 5,681,460 次，日均约 189,382 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @atlaskit/feature-gate-js-client 还在维护吗？

最新版本 8\.0\.0 发布于 2026/11/02（5 天前）；至今共发布 65 个版本，其中过去 12 个月发布了 16 个；首次发布于 2024/03/01。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

