@12-apps/feature-flags

中文文档
2.4.1发布于 2026/08/25MITTypeScriptES Module零依赖构建来源已验证近 30 天下载 3.2万

User-level feature flags: per-user beta grants composed as a VEIL over the tenant axes — never a key past them. Core reader (.), framework-neutral superadmin management endpoints (./server), management screen (./react), wiring manifests (./manifest*), and

原始使用文档
文档目录5 节
  1. The one rule: a flag is a veil, never a key
  2. What lives where
  3. Surfaces
  4. Adoption sketch (server)
  5. Prisma

@12-apps/feature-flags

User-level feature flags: a superadmin grants a feature in beta to individual people — an owner and a couple of users — and only they see it.

The one rule: a flag is a veil, never a key

A flag composes by AND over every axis the host already has. It can only narrow visibility; it never turns on a feature that the tenant's plan, lifecycle status, own settings or RBAC turn off. Two consequences:

  • Grants are user-global and safe to be. The grant follows the person, and in a store whose tenant axes deny the feature, the grant lights nothing — which is exactly why no per-tenant grant column is needed.
  • The veil fails CLOSED. A flag that is absent, stale or failed-to-load hides the feature. This is the opposite of the entitlements degradation rule (absent ⇒ unlocked), and deliberately so: a stale client must never paywall an owned feature, and must never leak an unreleased one.

In the origin host the server-side order is 401 auth → 403 RBAC → flag veil → 402 entitlements — the veil sits before the entitlement stack so nobody is upsold a feature that is not purchasable yet.

What lives where

  • Grants live in the database: user_feature_grants, one row per (user, flag), no row = the flag's default (off), enabled: false = an explicit opt-out that survives a future default-on rollout. user_id is a by-value scalar — no FK into host tables (the payments-backend doctrine).
  • The catalog is HOST CODE, handed in as config. A flag with no code behind it does nothing — every flag ships with a deploy anyway. A grant whose key left the catalog is an orphan: reported by the management surface, invisible to the reader.
  • Every word is the host's. The screen's copy (FeatureFlagsCopy) and the routes' denial sentences (FeatureFlagsServerCopy) are REQUIRED config with no defaults — the package ships no silent language, and server assembly fails naming every missing key. pt-BR still ships, as NAMED packs (PT_BR_FEATURE_FLAGS_COPY from ./react, PT_BR_FEATURE_FLAGS_SERVER_COPY from ./server): a host imports one and passes it by hand, so choosing the language is a reviewable line. The machine error codes (unknown_flag, user_not_found, …) are the stable half a client may branch on; the sentences beside them are the host's.

Surfaces

subpathexportwhat it is
.createFlagReaderthe enforcement half — flagsFor(userId) for host gates
./servercreateApiFeatureFlagssix framework-neutral route descriptors (WireRoute-shaped) for the superadmin management surface
./reactcreateWebFeatureFlagsthe management screen, { page }
./manifest, ./manifest/server, ./manifest/webwiring manifestsadopt through @12-apps/wiring/consumer

Deliberate absences in the manifest: no mcp (the surface is browser-only — a superadmin bearer already inherits cross-tenant reach over shared tools) and no permissions (platform authority in the origin host is an env allowlist no permission id can express).

Adoption sketch (server)

import { createWiringHost } from '@12-apps/wiring/consumer';
import { featureFlagsManifest } from '@12-apps/feature-flags/manifest';
import { featureFlagsServerManifest } from '@12-apps/feature-flags/manifest/server';

const host = createWiringHost({ name: 'my-host', kind: 'server' });
host.adoptServer({
  manifest: featureFlagsManifest,
  server: featureFlagsServerManifest,
  bindings: {
    http: {
      mountPath: '/api/platform/feature-flags',
      // `copy` is every denial sentence — required; pass a named pack or
      // your own object.
      config: { db, catalog, directory, copy, audit },
    },
  },
});
const wired = host.assemble();

The host resolves the actor (its superadmin guard) before any handler runs; the actor is { email } — the audit identity, not an authorization input. Route order is load-bearing for an in-order dispatcher (/users/:userId before /:key/…), and assertCatalog refuses a flag named users so the static segment can never be swallowed.

Prisma

prisma/feature-flags.prisma is copied — never symlinked — into the host's schema folder by pnpm --filter @12-apps/feature-flags prisma:sync (--check gates drift). Migrations are discovered structurally by the host's plugin sync from prisma/migrations/.

版本与发布记录

@12-apps/feature-flags 共发布 11 个版本,首次发布于 2026/08/21;过去 12 个月发布了 11 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.4.1latest2026/08/252 个月前
2.4.02026/08/252 个月前
2.3.02026/08/252 个月前
2.2.02026/08/242 个月前
2.1.12026/08/212 个月前
2.1.02026/08/212 个月前

关于 @12-apps/feature-flags 的常见问题

@12-apps/feature-flags 是什么?

User-level feature flags: per-user beta grants composed as a VEIL over the tenant axes — never a key past them. Core reader (.), framework-neutral superadmin management endpoints (./server), management screen (./react), wiring manifests (./manifest*), and

如何安装 @12-apps/feature-flags?

在项目目录运行 npm install @12-apps/feature-flags,或使用 pnpm add / yarn add / bun add。

@12-apps/feature-flags 支持 TypeScript 吗?

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

@12-apps/feature-flags 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@12-apps/feature-flags 需要什么版本的 Node.js?

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

@12-apps/feature-flags 可以商用吗?

@12-apps/feature-flags 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@12-apps/feature-flags 的下载量有多少?

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

@12-apps/feature-flags 还在维护吗?

最新版本 2.4.1 发布于 2026/08/25(2 个月前);至今共发布 11 个版本,其中过去 12 个月发布了 11 个;首次发布于 2026/08/21。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。