# @epilot/feature-flags 中文文档

规范地址：https://npmcn.com/package/%40epilot/feature-flags/

版本：0\.7\.0
npm 元数据更新时间：2026-11-10T09:28:46.387Z
中文译文更新时间：2026-11-13T19:43:50.687Z
软件包许可：UNLICENSED

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

原始 npm 页面：https://www.npmjs.com/package/%40epilot/feature-flags
原文对照：https://npmcn.com/package/%40epilot/feature-flags/?lang=original
项目主页：https://gitlab.com/e-pilot/product/feature-flags/epilot-feature-flags#readme
源码仓库：https://gitlab.com/e-pilot/product/feature-flags/epilot-feature-flags

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

- 包体积（解压后）：135 kB，34 个文件
- 模块格式：CommonJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=18
- 运行依赖：1 个
- peer 依赖：posthog-node ^4\.0\.0
- 首次发布：2026-05-01T15:53:59.427Z
- 最新版本发布：2026-09-23T08:54:15.278Z
- 近 30 天下载量：9154（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：13（近 12 个月 13 个）

## 中文简介

后端功能旗+产品分析客户端用于epilot Node服务. 后霍格被盖下,表面为OpenFeature.

## 安装

```sh
npm install @epilot/feature-flags
```

也可以使用：`pnpm add @epilot/feature-flags`、`yarn add @epilot/feature-flags`、`bun add @epilot/feature-flags`

## README

# @ epilot/ feature- flags

后端功能旗+epilot Node服务的产品分析. 后霍格被盖下,表面为OpenFeature.

## 为什么

-   所有电子驾驶服务的共同特性旗界面
-   OpenFeature抽象表示,如果我们互换供应商,呼叫站点就不会改变
-   方便Lambda的默认`flushAt: 1`, (中文(简体) ), `flushInterval: 0`,请求超时)

## 安装

```bash
npm install @epilot/feature-flags posthog-node
```

`posthog-node` 是同级依赖。 检查 [扩展到其他提供者](https://npmcn.com/package/%40epilot/feature-flags/#readme-extending-to-other-providers) 关于如何推广到其他提供者的更多信息.

需要18号节点.

## 快开始

```ts
import { capture, init, isFeatureEnabled, shutdown } from '@epilot/feature-flags';

export const handler = async (event) => {
  await init({
    posthog: {
      apiKey: process.env.POSTHOG_API_KEY,
      host: process.env.POSTHOG_HOST,
    },
    // env defaults to process.env.STAGE — pass an explicit value only to override
    // <provider>: {
    //   apiKey: process.env.<PROVIDER>_API_KEY,
    //   host: process.env.<PROVIDER>_HOST,
    // },
    logger: powertoolsLogger,
  });

  const ctx = { orgId: event.org, userId: event.user };

  if (await isFeatureEnabled('ai-spam-detection', ctx, false)) {
    capture({ event: 'spam_check_started', context: ctx, properties: { messageId: event.id } });
    // ...
  }

  await shutdown(); // flush analytics before Lambda freezes
};
```

`init()` 可以安全地同时拨打——第一次拨打电线给供应商,随后的拨打共享同样的飞行中的承诺.

## API 密码

### `init(options)`

```ts
type InitOptions = {
  posthog?: {
    apiKey: string;
    host?: string;
    flushAt?: number;                     // default: 1
    flushInterval?: number;               // default: 0
    requestTimeout?: number;              // default: 5000ms
    featureFlagsPollingInterval?: number; // default: 30s
    personalApiKey?: string;
  };
  env?: string;          // deployment stage — see "Environment scoping" below
  logger?: Logger;       // any object with debug/info/warn/error
  cacheTtlMs?: number;   // evaluation cache TTL — default: 60s, 0 disables
  bulkOrgEval?: boolean; // isOrgFeatureEnabled resolves via the org map — default: true
};
```

回返 `true` 当所配置的提供者注册并准备就绪时, `false` 如果未提供配置或初始化失败( 在这种情况下, 所有旗下 evals 都会回到默认状态 ) `capture()` 是一个不开放。 失败的输入可以清除缓存的许诺, 以便下一个呼叫者可以重试 .

### 旗帜评价

```ts
const ctx = { orgId, userId };

await isFeatureEnabled('flag-name', ctx, false);          // boolean
await getStringFlag('flag-name', ctx, 'default');         // multivariate variant
await getNumberFlag('flag-name', ctx, 0);                 // numeric payload
await getObjectFlag('flag-name', ctx, { tier: 'free' });  // object payload
```

| 打开元件的方法 | 邮电 |
| --- | --- |
| `getBooleanValue` | `isFeatureEnabled` |
| `getStringValue` | `getFeatureFlag` (多变量变体) |
| `getNumberValue` | `getFeatureFlagPayload` |
| `getObjectValue` | `getFeatureFlagPayload` |

大批对应人员坐在他们旁边——见 [一个圆形的多面旗](https://npmcn.com/package/%40epilot/feature-flags/#readme-several-flags-for-one-org)。 。 。 .

### 镜像标记

多数 epilot 后端旗帜瞄准 `organization` 仅分组 : `env` 组合属性,或 Org 百分比推出。 对于这些旗帜,用户不能 更改结果, 所以使用 org 范围检查 :

```ts
await isOrgFeatureEnabled('o365-outlook-connect', orgId, false);
```

这事关成本, 不只是人造工程学。 评价缓存按键 `(kind, flagKey, orgId, distinctId)` 财务报告和审定财务报表 `distinctId` 嵌入用户——如此传入 `{ orgId, userId }` 创建一个缓存项(和一个可计费的) 后霍格请求) **每个用户** 尽管答案对所有人来说都是一样的 他们。 在高流量的路径上,它将缓存分解到~0%的命中率. 由 Org 键入 单靠一个热容器,每个缓存窗口最多可提出一个请求.

继续使用 `isFeatureEnabled` 满分 `{ orgId, userId }` 当旗帜有时 人员级别条件或用户推开的百分比.

`isOrgFeatureEnabled` 解决整个在线地图:每个请求一个答案 org-scoped key for that org, 之后在同一缓存窗口中读取从中出. Batching是普通人的行为,不是每个呼叫者必须达到的 为. 无法解决的地图是 _无答复_没有 _无启用_所以钥匙掉下来了 应自己要求而不是采取 `defaultValue` - 每一面旗帜都是真的 在其默认适用前进行评审。 过 `bulkOrgEval: false` 改为 `init` 改为 总是抓取每个密钥; 这只值得对一个服务读取一个 org 范围 需要较小反应的旗帜.

### 一个圆形的多面旗

Org-scoped的读取已经共享了一个完整的项目地图,所以一个扇出 `isOrgFeatureEnabled` 电话不要求每个电话。 当呼叫者想要地图时 联系这两个人 本身——已知的密钥集,或每个旗帜:

```ts
// Known keys — always a full map, never null:
const flags = await areOrgFeaturesEnabled(['portals-engagement-center', 'portals-mcp'], orgId);
if (flags['portals-mcp']) { /* ... */ }

// Or the whole project's flags, when the set isn't known up front:
const all = await getOrgFeatureFlags(orgId);
if (all?.['portals-engagement-center']) { /* ... */ }
```

两个都花费了一个请求。 偏爱 `areOrgFeaturesEnabled`: 它充满 `defaultValue` 用于任何旗帜 无法解决的项目,所以没有 `null` 守卫 使用 `getOrgFeatureFlags` 当呼叫者需要每一面旗帜, 或者需要告诉 _未解决_ 除 _已禁用_ (登入,说.

两种份额 **一个** 缓存条目 per org —— 全项目映射. 缩小请求范围 请求的密钥会按请求的一组键键取缓存,将它分解到每个呼叫站点并计算成本 a 请求每个。 因为他们分享它, 任何后期的角镜 `isOrgFeatureEnabled` 在同一个进程中 免费读取该条目的答案,包括在不相关请求路径上的旗帜.

霍格邮局收费 `/flags` 电话和 [项目中活动旗帜的数量不影响每项请求的成本](https://posthog.com/docs/feature-flags/cutting-costs), (中文(简体) ), 这就是为什么一个地图比N键便宜 和为什么Org-scoped getter把它。 (本节) 当地评价的定义民意测验(一个终点)适用10项要求的逐名乘数 此软件包不使用。 ) 大通电话的确要花费更多的响应大小和缓存 内存,因为一个条目持有每个项目旗而不是一个布尔.

回返 `null` 当没有PostHog供应商注册或请求无法使用时 映射 – 然后应用您自己的每面旗默认值, 并注意一个密钥从一个 无`null` 地图是工程没有的旗帜 。 多变量旗帜倒塌到 `true` 当变量匹配; 读取变量和有效载荷 `getStringFlag` 编号 : `getObjectFlag`。 。 。 .

### 分析

```ts
capture({
  event: 'message_sent',
  context: { orgId, userId },
  properties: { channel: 'email', size: 1024 },
});

await shutdown(); // flushes pending events
```

`capture()` 通过 OpenFeature 的路由 `track()` 和活动的提供者,所以在没有提供者配置时,它是不开放的.

### 直接 OpenFeature 客户端

```ts
import { getFeatureFlagsClient } from '@epilot/feature-flags';

const client = getFeatureFlagsClient();
const details = await client.getBooleanDetails('flag', false, { targetingKey: 'org_user' });

logger.debug(details.reason); // 'TARGETING_MATCH' | 'DEFAULT' | 'ERROR' | ...
```

### 背景形状

```ts
type EpilotFlagContext = {
  orgId?: string;
  userId?: string;
};
```

翻译为:

-   `distinctId = ${orgId}_${userId}`
-   `groups = { organization: orgId }` 用于 org 升起旗帜

您也可以通过一个原始的 OpenFeature `EvaluationContext` 直接进行控制.

### 环境范围界定

软件包读取 `process.env.STAGE` 自动发送 `groupProperties: { organization: { env } }` 在每一旗的评价。 每一个电子驾驶Lambda服务 `STAGE` 设置,所以你不需要通过手动连接.

这符合现有的 epilot PostHog 旗使用的常规——多个放出组,每个放出组由 `env` 组属性——因此向dev推出的旗帜不会意外地与prod相匹配,反之亦然.

```ts
// default behavior — STAGE picked up from env
await init({ posthog: { ... } });

// override only when you need to (e.g. tests, multi-tenant service)
await init({ posthog: { ... }, env: 'preview-42' });
```

`capture()` 事件得到 `env` 也作为常规事件财产.

## 评价缓存

每一个未标记的旗帜评价都是可收费的 PostHog 请求——postHog-node 没有自己的结果缓存(没有) `personalApiKey` 每个电话都是网络 `/decide`编号 :`/flags` 请求,而其唯一的内部缓存 `$feature_flag_called` 分析事件,而不是请求). 因此,供应商对每个评价结果进行缓存 `(kind, flagKey, orgId, distinctId)` 默认为60个,以每个进程1,000个条目为限.

-   缓存漏掉的费用恰恰是本来会提出的一个请求;冷的容器从未比没有缓存更糟糕.
-   在TTL内用热容器传播旗帜变化;冷容器立即看到它们.
-   失败的评价缓存了 TTL 的倒置默认值, 当 PostHog 无法到达时, TTL 作为后压值加倍 .
-   通过电路或禁用 `init({ cacheTtlMs })` (单位:千美元)`0` / 禁用).
-   散装分辨率在每条条目下缓存整个地图 `(orgId, distinctId)`,而当同一上下文被缓存时,单旗布尔检查会读取该条目。 块状扫描结果从不回答人状扫描:块状键嵌入相同的 `distinctId`上下文改变。 地图所持有的密钥不归结于请求,而不是解决 `false`与每个旗手不同 **没有** 缓存失败, 因为一个缓存失败会让 TTL 的默认标记 .

包裹从不调用 `posthog.groupIdentify()`。旗帜瞄准仅需要 `groups` + 键 `groupProperties` 每一个容器都是新鲜的,所以用容器来识别体积表 `$groupidentify` 活动)。 坚持下去 `env` 在 org 组配置文件上——所以 org 可以通过 `env` 在PostHog UI中——被处理出带外(例如一次性回填脚本或在org创建时间),而不是从请求路径.

若为 `process.env.STAGE` 没有设定,也没有明确 `env` 通过, 包跳过 `groupProperties` 完全没有.

## 地方发展

```bash
npm install
npm run lint    # tsc --noEmit
npm test        # vitest
npm run build   # emit dist/
```

## 释放

标记承诺 :

```bash
npm version patch   # or minor / major
git push --follow-tags
```

CI 在任何标签匹配上发布到 npm `v*`。 。 。 .

## 扩展到其他提供者

要将这个软件包扩展至与其他提供者合作,您可以创建一个自定义提供者,执行OpenFeature提供者接口. 提供者应能够处理国旗评价和分析捕获.

所以,如果你最后使用一个特定于你的使用大小写 PostHog 的内存或内部FF 替代品,这个软件包只是给你一个接口来配合它. 你唯一要做的就是执行提供者接口,然后传给 `init` 函数.

## 常见问题

### @epilot/feature-flags 是什么？

后端功能旗\+产品分析客户端用于epilot Node服务\. 后霍格被盖下,表面为OpenFeature\.

### 如何安装 @epilot/feature-flags？

在项目目录运行 npm install @epilot/feature-flags，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：posthog-node（^4\.0\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @epilot/feature-flags 支持 TypeScript 吗？

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

### @epilot/feature-flags 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @epilot/feature-flags 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=18。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @epilot/feature-flags 可以商用吗？

@epilot/feature-flags 使用 UNLICENSED 许可。作者声明为 UNLICENSED，即不授予公开使用许可（与公共领域的 Unlicense 不同）。使用前需获得作者授权。以上为概括，不构成法律意见，请以许可原文为准。

### @epilot/feature-flags 的下载量有多少？

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

### @epilot/feature-flags 还在维护吗？

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

