@cat-factory/gatekeeper-bindings

中文文档
0.46.0发布于 2026/11/04MITTypeScriptES Module构建来源已验证近 30 天下载 2959

Policy-annotated operation table for the cat-factory public API (/api/v1): per-operation scope floors, mutation and transport metadata, and invoke thunks over @cat-factory/sdk, generated from the same OpenAPI spec the SDKs are. Built for credential-holdin

原始使用文档
文档目录8 节
  1. What it is
  2. Purpose and goal
  3. What each binding carries
  4. The helpers
  5. How to use it
  6. What is generated
  7. Configuration and customization
  8. References

@cat-factory/gatekeeper-bindings

What it is

A policy-annotated table of every cat-factory public API (/api/v1) operation, plus the scope-ladder helpers a policy layer ranks keys and classifies calls with. Like sdk/mcp, this is not a fifth client: it is the same operations the four SDKs expose, projected as a table and generated from the same OpenAPI spec (pnpm gen:sdk), so it cannot drift from the surface it meters. The thunks call @cat-factory/sdk and re-implement none of its behaviour.

It is the data half of the cat-factory Gatekeeper family, three pieces taken two different ways:

PieceWhat it isHow you take it
@cat-factory/gatekeeper-bindings (this package)the generated operation table and the scope helpersinstall, to build your own policy layer
@cat-factory/gatekeeper-workerthe full Gatekeeper Worker machinery: Cap'n Web capability surface, key broker, webhook receiver, approvalsinstall, and write only a policy
deploy/gatekeeperthe deployment template: a policy file, wrangler bindings, three lines of wiringcopy, and edit src/policy.config.ts

Purpose and goal

For building credential-holding front-ends: services that hold the cat-factory API key themselves and meter what their own callers may do. The motivating consumer is a Cloudflare OS Gatekeeper Worker (design record: the design record), but nothing here is Cloudflare-specific: any proxy, bot or governance layer that fronts a cat-factory key can use it.

The goal is that such a layer enforces policy against the operations the deployment actually serves, at the scope floors it actually enforces, never against a hand-curated list that drifts. The floors come from the spec's x-min-scope, which the server generates from the same contract field its controllers enforce, so the declared scope and the enforced scope are one value.

What each binding carries

One GatekeeperBinding per /api/v1 operation:

  • name (tasks_create): the policy spelling, identical to the MCP facade's tool name.
  • minScope: the key-scope floor the deployment enforces for the route (read / write / decide / admin), read off the spec's x-min-scope. This is the STATIC floor: a run-starting operation can still be refused pipeline_requires_decide_scope at request time when the named pipeline can park on a human.
  • readOnly, consequence: what a front-end needs to decide which calls get waved through, which get logged, and which need a human. consequence is present only where the stakes are real money or a merged pull request, exactly as in the MCP tool table, so read it through resolveConsequence(binding) rather than directly: an unannotated mutation is cautiously destructive, and binding.consequence?.destructive would answer false for it.
  • result: how invoke's answer comes back (value, SSE stream, or binary bytes), so a JSON-relay front-end can route or withhold the non-value operations, stating which.
  • pathParams / queryParams / hasBody and invoke(client, args): enough to expose the whole surface dynamically without hand-writing a wrapper per operation. The argument convention is the MCP facade's (path params and query keys at the top level, body under body; unknown keys are dropped, never forwarded).

The helpers

Hand-written beside the table (src/index.ts), because every consumer needs them and deriving them independently is how one gets them backwards:

  • scopeSatisfies(have, need): whether a key of scope have clears a floor of need. The ladder is inclusive: every rung can do everything below it.
  • bindingsWithinScope(scope): every operation a key of that scope can call.
  • bindingByName(name): one operation by its policy spelling; undefined for a name the surface does not have, so a misspelled or retired name is a condition the caller reports rather than a thrown surprise.
  • resolveConsequence(binding): the consequence annotation with the cautious default applied (an unannotated mutation counts as destructive and non-idempotent).
  • PUBLIC_API_SCOPE_LADDER: the scope ranking itself, emitted from the spec's x-public-api-scopes.
  • renderSessionTypes(request): the .d.ts an object-capability session serves as its TypeScript types, composed from the generated SESSION_METHOD_SIGNATURES for exactly the operations a policy granted. Per-grant rather than shipped whole, because a file naming the full surface would promise methods the object does not have. It THROWS on a name it has no signature for: a silently dropped method reads to an agent exactly like an operation the deployment does not serve, and the two need opposite fixes.

The ladder helpers throw on a scope they do not carry rather than ranking it below read: a deployment one release ahead of this package must read as version skew, never as a key with no permissions.

How to use it

import { CatFactoryClient } from '@cat-factory/sdk'
import {
  bindingByName,
  bindingsWithinScope,
  resolveConsequence,
  scopeSatisfies,
} from '@cat-factory/gatekeeper-bindings'

const client = new CatFactoryClient({ baseUrl: process.env.BASE_URL!, apiKey: process.env.KEY! })

// Expose to this caller only what a `write` key can do, minus anything destructive. Read the
// consequence through the helper: most mutations carry no annotation, and the unannotated ones
// are the cautious case, not the safe one.
const exposed = bindingsWithinScope('write').filter((b) => !resolveConsequence(b).destructive)

// Forward a metered call.
const binding = bindingByName('tasks_create')!
if (!scopeSatisfies('write', binding.minScope)) throw new Error('caller tier too low')
const result = await binding.invoke(client, {
  serviceId: 'svc_123',
  body: { title: 'Fix the flaky login test', description: '...' },
})

Two routes are deliberately absent from the table because they have no honest operation shape: GET /api/v1/openapi.json (spec discovery) and ALL /api/v1/mcp (the hosted MCP endpoint). Both gate at read on the server.

What is generated

Two files, both by pnpm gen:sdk and both guarded against drift by pnpm check:sdk:

FileWhat it carries
src/bindings.generated.tsThe operation table: scope floors, mutation and transport metadata, consequence hints, invoke thunks.
src/session-types.generated.tsOne TypeScript method signature per operation, for composing a granted session's .d.ts.

The signatures carry fully typed ARGUMENTS (path parameters, query keys with their requiredness, a body where the operation takes one) and an unknown result. That is deliberate rather than a gap: a session relays the deployment's own decoded JSON, and the authority for those shapes is the OpenAPI document at GET /api/v1/openapi.json, which every deployment serves. Inlining the model tree would put a second copy of it inside every consumer's bundle, free to disagree with the first.

Configuration and customization

Nothing in this package is configured or customized: it is generated data plus pure helpers, and the policy built on top of it belongs to the consumer (see @cat-factory/gatekeeper-worker for a ready-made one). src/bindings.generated.ts is GENERATED (pnpm gen:sdk); change the route contracts, never the file.

References

版本与发布记录

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

版本发布日期距今
0.46.0latest2026/11/045 天前
0.45.02026/11/045 天前
0.44.02026/11/045 天前
0.43.02026/11/045 天前
0.42.02026/11/045 天前
0.41.12026/10/1722 天前

关于 @cat-factory/gatekeeper-bindings 的常见问题

@cat-factory/gatekeeper-bindings 是什么?

Policy-annotated operation table for the cat-factory public API (/api/v1): per-operation scope floors, mutation and transport metadata, and invoke thunks over @cat-factory/sdk, generated from the same OpenAPI spec the SDKs are. Built for credential-holdin

如何安装 @cat-factory/gatekeeper-bindings?

在项目目录运行 npm install @cat-factory/gatekeeper-bindings,或使用 pnpm add / yarn add / bun add。

@cat-factory/gatekeeper-bindings 支持 TypeScript 吗?

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

@cat-factory/gatekeeper-bindings 支持 ESM 还是 CommonJS?

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

@cat-factory/gatekeeper-bindings 需要什么版本的 Node.js?

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

@cat-factory/gatekeeper-bindings 可以商用吗?

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

@cat-factory/gatekeeper-bindings 的下载量有多少?

根据 npm 官方下载统计,@cat-factory/gatekeeper-bindings 在 2026/10/09 – 2026/11/07 这 30 天内被下载 2,959 次,日均约 99 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cat-factory/gatekeeper-bindings 还在维护吗?

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