@kapable/ops-sdk (0.1.1)
Installation
@kapable:registry=npm install @kapable/ops-sdk@0.1.1"@kapable/ops-sdk": "0.1.1"About this package
@kapable/ops-sdk
Operator-tier TypeScript SDK for the Kapable v2 platform — the trust-perimeter
twin of @kapable/sdk.
New here? Start at the SDK suite front door:
../docs/sdk.md— which package, which token, the module catalog, and coverage at a glance.
Version 0.1.0 — 10 operator modules, 122 TS methods (TS↔Rust parity: 122 Rust methods), operator coverage 57.6% (98/170 ops-eligible endpoints; the denominator includes Berth's full 85-endpoint operator surface — see Coverage). See CHANGELOG.md. Not published to any registry.
It wraps the operator / admin / service-token endpoints the customer SDK
deliberately excludes — Berth, Foreman, kapable-host, kapable-gateway,
harbor-admin, the kapable-data query proxy, Burrow tunnels, kapable-auth admin,
and the billing/comms internal routes — mirroring the kapable (customer) vs
kapable-ops (operator) CLI trust split.
The operator vs customer perimeter (the load-bearing invariant)
The OpsClient constructor classifies the supplied token by prefix and throws
an OperatorPerimeterError if it is a customer API key
(sk_live_/sk_test_/sk_org_). The operator/customer boundary is therefore a
physical, fail-fast fact: an operator wrapper cannot even be instantiated
with a customer credential, so a customer dependency tree literally cannot drive
operator endpoints with its own key.
| Token prefixes | |
|---|---|
| Accepted | kses_ (platform_staff session), sk_admin_ (platform superkey), st_/st_ci_/st_deploy_/st_wh_/st_svc_ (service tokens), unrecognized/JWT-shaped (server gates) |
| Rejected | sk_live_ / sk_test_ / sk_org_ (customer API keys) |
The SDK never enforces authorization — the server (require_permission +
per-service scope checks) is the sole authority. This perimeter only ensures the
right class of credential reaches the operator surface. Some modules layer an
additional per-call header credential (Berth deploy-sync's Ed25519
X-Signature; the billing/comms X-Internal-Token; the auth admin x-api-key).
Quick start
bun add @kapable/ops-sdk # not published — use the file: workspace dependency
import { OpsClient } from '@kapable/ops-sdk';
const ops = new OpsClient({
baseUrl: 'https://data.kapable.ai',
token: 'st_ci_...', // or sk_admin_..., or a platform_staff kses_...
});
// data query proxy — POST /v1/query/{database} (PlatformAdmin + db:read/db:write)
const r = await ops.data.query(
'kapable_platform',
'SELECT id FROM orgs WHERE slug = $1',
{ params: ['acme'] },
);
console.log(r.row_count, r.rows);
// Berth deploy control-plane — GET /api/v1/binaries
const berth = new OpsClient({ baseUrl: 'http://localhost:3100', token: 'st_svc_...' });
const binaries = await berth.berth.listBinaries();
// A customer key throws at construction:
new OpsClient({ baseUrl: '...', token: 'sk_live_...' }); // OperatorPerimeterError
Modules
Driven from coverage-manifest.json (regenerate with
bun run generate-manifest). Each module is reachable as ops.<module>.<method>()
and is verified at TS↔Rust parity (see Tooling).
| Module | Methods | Service | Operator surface |
|---|---|---|---|
auth |
14 | kapable-auth |
ADMIN surface (org/app provision, SSO-callback registration, beta gate, request metrics, launchpad admin) |
berth |
36 | berth |
Deploy control-plane (binaries, deploy-sync, slots, reconcile, freeze, rollback, restart, canary/rollout) + observability reads (audit, versions, deploy/config diff, config, health-history, rollback-history, processes, dependency-graph) |
billing |
1 | kapable-billing |
Internal billing-portal mint (X-Internal-Token) |
burrow |
4 | burrow |
Tunnel REGISTRY (list/get/register/remove tunnels) |
comms |
2 | kapable-comms |
Service-to-service internal routes (intercept, send; X-Internal-Token) |
data |
1 | kapable-data |
DB query proxy (replaces ssh … psql) |
foreman |
15 | foreman |
CI job queue + recipe runner (recipes, recipe-runs, tasks, runners, pipeline metrics) |
gateway |
6 | kapable-gateway |
gateway_services CRUD + reconcile (owns Caddy routing) |
harbor |
23 | harbor |
ADMIN/mutation surface (products, features, tiers, licenses, releases, org keypairs) |
host |
20 | kapable-host |
Containers + blue-green deploy, snapshots, images, volumes |
| Total | 122 | 10 services | operator coverage 57.6% (98/170 ops-eligible endpoints) |
⚠
harborhas no server-side RBAC and incomplete org-scoping (IDOR, IMP-1366); the customer SDK deferred it. It is safe here only because this client rejects customer keys at construction — operator-only by the SDK perimeter until IMP-1366 lands server RBAC.
Coverage
The denominator is every ops-eligible endpoint in the verified surface
inventory (../docs/sdk-surface-inventory.json):
an API route that is either (a) on an operator-tier service (Berth, Foreman,
kapable-gateway, kapable-host, Burrow) and not public, or (b) gated to an
explicitly operator-only auth tier (admin / platform_staff / service_token
/ internal_token) on a customer-tier service — i.e. exactly the routes the
customer SDK rejects at its perimeter.
Berth alone contributes 85 ops-eligible endpoints (82 service_token), of which
the SDK now wraps the 35 that cover the day-to-day deploy/inspect/observe loop
(iter-34 added the audit / versions / deploy-diff / config(+diff) / health-history
/ rollback-history / processes / dependency-graph reads) — so the aggregate
57.6% is an honest figure against the full operator surface, not just the
wrapped slice. Per-service: host/gateway/data 100%, foreman 83%, burrow 80%,
auth 64%, billing/comms internal 50–67%, berth 41%. Remaining Berth gaps are the
deliberately-deferred mutation/niche routes — see the next paragraph.
Berth — still deferred (lower-value or dangerous mutations, NOT wrapped):
notifications email/slack (get/put/delete/test), key import/export/rotate,
secrets PUT/DELETE (write side), secrets-canonical PUT/DELETE, retention-run,
maintenance get/set, webhooks register/list/remove, caddy route add,
admin reap-stale, POST .../config (config write), DELETE .../binaries/{name}
(deregister), POST .../binaries/{name}/stop, proxy-health reset, queue delete,
deploy submit/dry-run/cancel/approve, scheduled, openapi, retention get. The
SSE-only GET /api/v1/events(+/{name}) are skipped here — they are a streaming
surface, not a JSON read, and want an SSE-aware client method. All tracked by
bun run check-drift.
Token tiering — st_* / sk_admin_ / session
The Permission / TokenType / Scope enums and the tier-aware
AuthRequirement are re-exported from @kapable/sdk/security (a file:
dependency), so the customer and operator packages share a single source of truth
and cannot drift. This package adds the operator-perimeter helpers on top:
isOperatorToken, classifyToken, OPS_ACCEPTED_TOKEN_TYPES,
OPS_REJECTED_TOKEN_TYPES. Use them to validate a token's class before handing
it to an OpsClient (the constructor enforces the same rule):
import { isOperatorToken, classifyToken } from '@kapable/ops-sdk';
isOperatorToken('st_ci_...'); // true — service token
isOperatorToken('sk_admin_...'); // true — platform superkey
isOperatorToken('kses_...'); // true — platform_staff session
isOperatorToken('sk_live_...'); // false — customer key (rejected at construction)
Tooling
Mirrors the customer SDK's coverage + quality tooling (CONTRIBUTING.md):
| Command | What it does |
|---|---|
bun run typecheck |
tsc --noEmit over src/. |
bun test |
Unit tests + the cross-language parity test (test/parity.test.ts). |
bun run build |
tsc declarations + per-module ESM bundles into dist/. |
bun run generate-manifest |
Rebuilds coverage-manifest.json from live source — never hand-edit the manifest. |
bun run check-drift |
Reports operator coverage + un-wrapped gaps, and fails (exit 1) on any phantom (a method claiming a route the server does not expose). |
The introspector (scripts/ops-introspect.ts) parses the real TS client.ts
methods and Rust mod.rs pub fns — it never hardcodes a method list — so the
manifest, parity test, and drift report always reflect the code as it is now.
Related
../kapable-sdk/CONTRIBUTING.md— the SDK contribution + coverage-tooling guide (shared conventions).../docs/sdk-surface-matrix.md— the full per-service surface + RBAC token-tiering matrix.../kapable-ops-sdk-rs— the Rust twin (method parity enforced bytest/parity.test.ts).
Dependencies
Dependencies
| ID | Version |
|---|---|
| @kapable/sdk | file:../kapable-sdk |
Development dependencies
| ID | Version |
|---|---|
| @types/bun | ^1.2.0 |
| typescript | ^5.7.0 |