@substrat-run/control-plane-api 0.114.0 → 0.117.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/api.d.ts +31 -1
  2. package/dist/api.d.ts.map +1 -1
  3. package/dist/api.js +594 -106
  4. package/dist/api.js.map +1 -1
  5. package/dist/auth.d.ts +35 -3
  6. package/dist/auth.d.ts.map +1 -1
  7. package/dist/auth.js +11 -0
  8. package/dist/auth.js.map +1 -1
  9. package/dist/cf-observability.d.ts.map +1 -1
  10. package/dist/cf-observability.js +26 -2
  11. package/dist/cf-observability.js.map +1 -1
  12. package/dist/client.d.ts +35 -2
  13. package/dist/client.d.ts.map +1 -1
  14. package/dist/client.js +47 -3
  15. package/dist/client.js.map +1 -1
  16. package/dist/deploy.d.ts +3 -2
  17. package/dist/deploy.d.ts.map +1 -1
  18. package/dist/deploy.js +5 -4
  19. package/dist/deploy.js.map +1 -1
  20. package/dist/errors.d.ts.map +1 -1
  21. package/dist/errors.js +32 -11
  22. package/dist/errors.js.map +1 -1
  23. package/dist/identity-tenants.d.ts +30 -0
  24. package/dist/identity-tenants.d.ts.map +1 -0
  25. package/dist/identity-tenants.js +23 -0
  26. package/dist/identity-tenants.js.map +1 -0
  27. package/dist/index.d.ts +10 -3
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +6 -2
  30. package/dist/index.js.map +1 -1
  31. package/dist/observability.d.ts +6 -0
  32. package/dist/observability.d.ts.map +1 -1
  33. package/dist/platform-drain.d.ts +6 -3
  34. package/dist/platform-drain.d.ts.map +1 -1
  35. package/dist/platform-drain.js +22 -4
  36. package/dist/platform-drain.js.map +1 -1
  37. package/dist/push-token.d.ts.map +1 -1
  38. package/dist/push-token.js +9 -23
  39. package/dist/push-token.js.map +1 -1
  40. package/dist/scope-deployment.d.ts +34 -0
  41. package/dist/scope-deployment.d.ts.map +1 -0
  42. package/dist/scope-deployment.js +19 -0
  43. package/dist/scope-deployment.js.map +1 -0
  44. package/dist/storage-meter.d.ts +32 -0
  45. package/dist/storage-meter.d.ts.map +1 -0
  46. package/dist/storage-meter.js +69 -0
  47. package/dist/storage-meter.js.map +1 -0
  48. package/dist/tenant-token.d.ts +41 -0
  49. package/dist/tenant-token.d.ts.map +1 -0
  50. package/dist/tenant-token.js +108 -0
  51. package/dist/tenant-token.js.map +1 -0
  52. package/dist/token-codec.d.ts +30 -0
  53. package/dist/token-codec.d.ts.map +1 -0
  54. package/dist/token-codec.js +63 -0
  55. package/dist/token-codec.js.map +1 -0
  56. package/dist/vertical-client.d.ts +42 -4
  57. package/dist/vertical-client.d.ts.map +1 -1
  58. package/dist/vertical-client.js +83 -4
  59. package/dist/vertical-client.js.map +1 -1
  60. package/package.json +6 -6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-deployment.d.ts","sourceRoot":"","sources":["../src/scope-deployment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,gBAAgB,GAAG,eAAe,GAAG,MAAM,CAAC;AAE7E,wDAAwD;AACxD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,CAAC;IACvB,GAAG,EAAE,kBAAkB,CAAC;CACzB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,kBAAkB,EACvB,KAAK,EAAE;IAAE,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACvE,OAAO,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,GACzC,MAAM,GAAG,IAAI,CAEf"}
@@ -0,0 +1,19 @@
1
+ import { runningVersionOf } from '@substrat-run/kernel';
2
+ /**
3
+ * The version the deployment chosen for `scope` runs — the one a provision receipt may
4
+ * name after a reconcile through it (#1653).
5
+ *
6
+ * - `serving-script`: what the vertical's serving script serves (`runningVersionOf`), or
7
+ * the bound version when the pointer names another script or could not be read.
8
+ * - `bound-version`: the bound version — that deployment IS it. This is where a serving
9
+ * ref that does not resolve falls to, and why the answer has to come from here: the
10
+ * hook that ran is the bound version's, and a receipt naming the served one would mark
11
+ * the scope repaired while the served version's hook never ran.
12
+ * - `slug`: the bound version. A static binding or a slug's deployment runs whatever it
13
+ * runs, and the platform cannot name it; this is the answer every receipt gave before
14
+ * #1653, kept so a scope reached only this way is not asked again on every pass.
15
+ */
16
+ export function versionReachedAt(via, scope, serving) {
17
+ return via === 'serving-script' ? runningVersionOf(scope, serving) : scope.verticalVersionId;
18
+ }
19
+ //# sourceMappingURL=scope-deployment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-deployment.js","sourceRoot":"","sources":["../src/scope-deployment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAuB,MAAM,sBAAsB,CAAC;AAkB7E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAuB,EACvB,KAAuE,EACvE,OAA0C;IAE1C,OAAO,GAAG,KAAK,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;AAC/F,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { type ScopeId, type ScopeStatus, type StorageMeterReading, type TenantId } from '@substrat-run/contracts';
2
+ /**
3
+ * The on-demand storage reading (#1524), without any HTTP around it.
4
+ *
5
+ * Every scope it reads is a Durable Object it wakes, so every limit here is a cost
6
+ * limit. The directory listing that supplies `scopes` is a cheap read and is taken
7
+ * whole, which keeps `total` honest. Only the wakes are bounded:
8
+ * - **per page**: at most `limit` scopes, capped at `STORAGE_PAGE_MAX`. A tenant with
9
+ * thousands of scopes is read a page at a time, and each page is asked for by a person.
10
+ * - **in flight**: at most `STORAGE_READ_CONCURRENCY` reads run at once within a page.
11
+ */
12
+ export declare const STORAGE_PAGE_DEFAULT = 50;
13
+ export declare const STORAGE_PAGE_MAX = 200;
14
+ export declare const STORAGE_READ_CONCURRENCY = 8;
15
+ export interface StorageScope {
16
+ scopeId: ScopeId;
17
+ status: ScopeStatus;
18
+ }
19
+ export interface StoragePageInput<S extends StorageScope> {
20
+ tenantId: TenantId;
21
+ readAt: string;
22
+ /** Every scope row the tenant has, in any order. Reaped rows are counted, never read. */
23
+ scopes: readonly S[];
24
+ /** Resume after this scope id, the previous page's `nextCursor`. */
25
+ cursor?: ScopeId;
26
+ limit?: number;
27
+ concurrency?: number;
28
+ /** One scope's database size. A throw is recorded against that scope, never the page. */
29
+ read: (scope: S) => Promise<number>;
30
+ }
31
+ export declare function readStoragePage<S extends StorageScope>(input: StoragePageInput<S>): Promise<StorageMeterReading>;
32
+ //# sourceMappingURL=storage-meter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-meter.d.ts","sourceRoot":"","sources":["../src/storage-meter.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,OAAO,EACZ,KAAK,WAAW,EAEhB,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EACd,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,YAAY;IACtD,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;IACrB,oEAAoE;IACpE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yFAAyF;IACzF,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACrC;AAED,wBAAsB,eAAe,CAAC,CAAC,SAAS,YAAY,EAC1D,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,mBAAmB,CAAC,CAoD9B"}
@@ -0,0 +1,69 @@
1
+ import { STORAGE_EXCLUSIONS, storageMeterReading, } from '@substrat-run/contracts';
2
+ /**
3
+ * The on-demand storage reading (#1524), without any HTTP around it.
4
+ *
5
+ * Every scope it reads is a Durable Object it wakes, so every limit here is a cost
6
+ * limit. The directory listing that supplies `scopes` is a cheap read and is taken
7
+ * whole, which keeps `total` honest. Only the wakes are bounded:
8
+ * - **per page**: at most `limit` scopes, capped at `STORAGE_PAGE_MAX`. A tenant with
9
+ * thousands of scopes is read a page at a time, and each page is asked for by a person.
10
+ * - **in flight**: at most `STORAGE_READ_CONCURRENCY` reads run at once within a page.
11
+ */
12
+ export const STORAGE_PAGE_DEFAULT = 50;
13
+ export const STORAGE_PAGE_MAX = 200;
14
+ export const STORAGE_READ_CONCURRENCY = 8;
15
+ export async function readStoragePage(input) {
16
+ const limit = Math.max(1, Math.min(Math.floor(input.limit ?? STORAGE_PAGE_DEFAULT), STORAGE_PAGE_MAX));
17
+ const concurrency = Math.max(1, Math.min(Math.floor(input.concurrency ?? STORAGE_READ_CONCURRENCY), STORAGE_READ_CONCURRENCY));
18
+ const readable = input.scopes
19
+ .filter((s) => s.status !== 'reaped')
20
+ .sort((a, b) => (a.scopeId < b.scopeId ? -1 : a.scopeId > b.scopeId ? 1 : 0));
21
+ const reaped = input.scopes.length - readable.length;
22
+ const after = input.cursor;
23
+ const remaining = after === undefined ? readable : readable.filter((s) => s.scopeId > after);
24
+ const page = remaining.slice(0, limit);
25
+ const nextCursor = remaining.length > page.length ? page[page.length - 1].scopeId : null;
26
+ const results = new Array(page.length);
27
+ let next = 0;
28
+ const worker = async () => {
29
+ for (let i = next++; i < page.length; i = next++) {
30
+ const scope = page[i];
31
+ try {
32
+ const bytes = await input.read(scope);
33
+ if (!Number.isInteger(bytes) || bytes < 0)
34
+ throw new Error(`not a size: ${String(bytes)}`);
35
+ results[i] = { scopeId: scope.scopeId, status: scope.status, bytes };
36
+ }
37
+ catch (e) {
38
+ const message = e instanceof Error ? e.message : String(e);
39
+ results[i] = { scopeId: scope.scopeId, status: scope.status, bytes: null, error: message || 'read failed' };
40
+ }
41
+ }
42
+ };
43
+ await Promise.all(Array.from({ length: Math.min(concurrency, page.length) }, worker));
44
+ let bytes = 0;
45
+ let failed = 0;
46
+ for (const r of results) {
47
+ if (r.bytes === null)
48
+ failed += 1;
49
+ else
50
+ bytes += r.bytes;
51
+ }
52
+ return storageMeterReading.parse({
53
+ tenantId: input.tenantId,
54
+ readAt: input.readAt,
55
+ basis: 'scope-databases',
56
+ excluded: [...STORAGE_EXCLUSIONS],
57
+ bytes,
58
+ scopes: results,
59
+ read: results.length - failed,
60
+ failed,
61
+ total: readable.length,
62
+ reaped,
63
+ nextCursor,
64
+ // The one field that licenses the word "total": this page is the whole tenant, and
65
+ // every read in it answered.
66
+ complete: after === undefined && nextCursor === null && failed === 0,
67
+ });
68
+ }
69
+ //# sourceMappingURL=storage-meter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-meter.js","sourceRoot":"","sources":["../src/storage-meter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { type PlatformActorId, type TenantId } from '@substrat-run/contracts';
2
+ import { type TenantServiceAuth } from './auth.js';
3
+ interface TenantTokenClaim {
4
+ v: 1;
5
+ tenantId: string;
6
+ /** Informational — no expiry in v1, exactly as push tokens have none. */
7
+ iat: number;
8
+ }
9
+ /**
10
+ * Mint a tenant token.
11
+ *
12
+ * The tenant NEED NOT EXIST in the directory yet, and the claim deliberately carries
13
+ * no slug. Both follow from the same fact: a tenant token narrows WHOSE rows a caller
14
+ * may touch, and a tenant with no rows is narrowed to nothing. What such a credential
15
+ * can do is create the directory row for its own id — `POST /tenants` is body-pinned
16
+ * to the same tenant — which is precisely the sign-up bootstrap dashboard.md §4 names
17
+ * as the one act that cannot be tenant-narrowed, because there is no tenant yet.
18
+ * Requiring the row here would break it: the dashboard's first call for a new team IS
19
+ * `ensureTenant`, and a mint that 404s first makes that unreachable.
20
+ *
21
+ * A slug would also be a staleness hazard rather than a saving: the only thing that
22
+ * reads one is the builder's bare-slug prefixing (#417), and a tenant principal
23
+ * resolves a slug through the `x-substrat-tenant` header the plane already pins.
24
+ */
25
+ export declare function mintTenantToken(secret: string, identity: {
26
+ tenantId: TenantId;
27
+ }): Promise<string>;
28
+ /** Verify a tenant token string → its claim, or null (bad prefix/shape/signature). */
29
+ export declare function verifyTenantToken(secret: string, token: string): Promise<TenantTokenClaim | null>;
30
+ /**
31
+ * A `TenantServiceAuth` over tenant tokens: reads `x-service-token`, handles only
32
+ * `stt1.…` values (anything else → null, so every other reader is untouched), verifies,
33
+ * and returns the tenant the token is pinned to.
34
+ *
35
+ * `actor` is the audited subject the HOST supplies — the same fixed service actor a
36
+ * platform service token already resolves to. It is NOT read from the token, for the
37
+ * reason the module docblock gives.
38
+ */
39
+ export declare function tenantTokenAuth(secret: string, actor: PlatformActorId): TenantServiceAuth;
40
+ export {};
41
+ //# sourceMappingURL=tenant-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-token.d.ts","sourceRoot":"","sources":["../src/tenant-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAC1G,OAAO,EAAwB,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAmDzE,UAAU,gBAAgB;IACxB,CAAC,EAAE,CAAC,CAAC;IACL,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAGvG;AAED,sFAAsF;AACtF,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAavG;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,iBAAiB,CAQzF"}
@@ -0,0 +1,108 @@
1
+ import { tenantId as tenantIdSchema } from '@substrat-run/contracts';
2
+ import { SERVICE_TOKEN_HEADER } from './auth.js';
3
+ import { hasTokenPrefix, openToken, signToken } from './token-codec.js';
4
+ /**
5
+ * Tenant tokens — the dashboard's tenant-scoped service credential (#977).
6
+ *
7
+ * The dashboard reached the shared control plane over the platform `SERVICE_TOKEN`,
8
+ * which authenticates as `{ kind: 'staff' }` and has FLEET-WIDE reach. Its narrowing to
9
+ * one tenant was a constructor argument in the dashboard's own worker
10
+ * (`TenantNarrowedControlPlane`) plus a caller-asserted `x-substrat-tenant` header the
11
+ * plane read only for slug resolution. So the narrowing was the dashboard's promise
12
+ * about itself, not a property of the credential: one wrong tenant id at any of its
13
+ * ~90 call sites reached another customer's data with a staff-level token and nothing
14
+ * server-side to refuse it. That is the vulnerability this closes.
15
+ *
16
+ * A tenant token is the same stateless shape push tokens already establish
17
+ * (`push-token.ts`), with a different claim and a different meaning:
18
+ *
19
+ * `stt1.<b64url payload>.<b64url HMAC-SHA256 sig>`
20
+ *
21
+ * It authenticates as `{ kind: 'tenant' }` — staff-equivalent CAPABILITY, confined to
22
+ * ONE tenant, which is what a dashboard actually needs. The confinement is enforced by
23
+ * the control plane (`createControlPlaneApi`'s allowlist + pin middleware), so a
24
+ * dashboard bug cannot spend it outside its tenant however it asks.
25
+ *
26
+ * **The claim carries no actor, deliberately.** Who a row is audited as stays the
27
+ * host's decision (`tenantTokenAuth(secret, actor)`, exactly as `serviceTokenAuth`
28
+ * takes it), so a minted token can never name its own audit subject — and the audit
29
+ * row keeps naming what it named before this existed. Making the audit row carry the
30
+ * customer's own `PrincipalId` is the SECOND half of #977 and is deliberately not
31
+ * here: it makes `PlatformActorId` stop being the type of an audit actor, which is
32
+ * kernel-facing and gets its own diff and its own review.
33
+ *
34
+ * **A dedicated secret**, never `pushTokenSecret` and never `PLATFORM_SECRET`. A
35
+ * shared signing key would make a compromised CI push token and a compromised
36
+ * dashboard credential the same incident: whoever holds the key mints either class,
37
+ * and rotating to contain one revokes the other. `PLATFORM_SECRET` is worse still —
38
+ * it is injected into every pushed vertical, so any customer's code could mint a
39
+ * credential for any tenant. Rotating the dedicated secret invalidates every issued
40
+ * tenant token at once (the dashboard re-mints on its next request, so that is a blip
41
+ * rather than an outage) — which is the whole revocation story in v1.
42
+ *
43
+ * Presented in the SAME `x-service-token` header, discriminated by the `stt1.` prefix.
44
+ * A collision is not a risk to reason about: the platform service token is random hex
45
+ * and a push token starts `spt1.`, so no other credential this plane accepts can begin
46
+ * `stt1.`, and the prefix is inside the signed input (`token-codec.ts`) so a push
47
+ * token's payload cannot be replayed as a tenant token even under an equal secret.
48
+ */
49
+ const PREFIX = 'stt1';
50
+ /**
51
+ * Mint a tenant token.
52
+ *
53
+ * The tenant NEED NOT EXIST in the directory yet, and the claim deliberately carries
54
+ * no slug. Both follow from the same fact: a tenant token narrows WHOSE rows a caller
55
+ * may touch, and a tenant with no rows is narrowed to nothing. What such a credential
56
+ * can do is create the directory row for its own id — `POST /tenants` is body-pinned
57
+ * to the same tenant — which is precisely the sign-up bootstrap dashboard.md §4 names
58
+ * as the one act that cannot be tenant-narrowed, because there is no tenant yet.
59
+ * Requiring the row here would break it: the dashboard's first call for a new team IS
60
+ * `ensureTenant`, and a mint that 404s first makes that unreachable.
61
+ *
62
+ * A slug would also be a staleness hazard rather than a saving: the only thing that
63
+ * reads one is the builder's bare-slug prefixing (#417), and a tenant principal
64
+ * resolves a slug through the `x-substrat-tenant` header the plane already pins.
65
+ */
66
+ export async function mintTenantToken(secret, identity) {
67
+ const claim = { v: 1, tenantId: identity.tenantId, iat: Date.now() };
68
+ return signToken(PREFIX, secret, claim);
69
+ }
70
+ /** Verify a tenant token string → its claim, or null (bad prefix/shape/signature). */
71
+ export async function verifyTenantToken(secret, token) {
72
+ const opened = await openToken(PREFIX, secret, token);
73
+ if (opened === null)
74
+ return null;
75
+ try {
76
+ const claim = opened;
77
+ if (claim.v !== 1)
78
+ return null;
79
+ // Parse, don't trust: the signature proves WE minted it, the parse proves the
80
+ // fields are still the ones a pin is made of (a format bump fails closed).
81
+ tenantIdSchema.parse(claim.tenantId);
82
+ return claim;
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ }
88
+ /**
89
+ * A `TenantServiceAuth` over tenant tokens: reads `x-service-token`, handles only
90
+ * `stt1.…` values (anything else → null, so every other reader is untouched), verifies,
91
+ * and returns the tenant the token is pinned to.
92
+ *
93
+ * `actor` is the audited subject the HOST supplies — the same fixed service actor a
94
+ * platform service token already resolves to. It is NOT read from the token, for the
95
+ * reason the module docblock gives.
96
+ */
97
+ export function tenantTokenAuth(secret, actor) {
98
+ return async (request) => {
99
+ const presented = request.headers.get(SERVICE_TOKEN_HEADER);
100
+ if (!presented || !hasTokenPrefix(PREFIX, presented))
101
+ return null;
102
+ const claim = await verifyTenantToken(secret, presented);
103
+ if (!claim)
104
+ return null;
105
+ return { actor, tenantId: tenantIdSchema.parse(claim.tenantId) };
106
+ };
107
+ }
108
+ //# sourceMappingURL=tenant-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-token.js","sourceRoot":"","sources":["../src/tenant-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,cAAc,EAAuC,MAAM,yBAAyB,CAAC;AAC1G,OAAO,EAAE,oBAAoB,EAA0B,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,MAAM,MAAM,GAAG,MAAM,CAAC;AAStB;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAc,EAAE,QAAgC;IACpF,MAAM,KAAK,GAAqB,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACvF,OAAO,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AAC1C,CAAC;AAED,sFAAsF;AACtF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAc,EAAE,KAAa;IACnE,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IACtD,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAA0B,CAAC;QACzC,IAAI,KAAK,CAAC,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC/B,8EAA8E;QAC9E,2EAA2E;QAC3E,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACrC,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,KAAsB;IACpE,OAAO,KAAK,EAAE,OAAO,EAAE,EAAE;QACvB,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAC5D,IAAI,CAAC,SAAS,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC;YAAE,OAAO,IAAI,CAAC;QAClE,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACzD,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;IACnE,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The wire codec the platform's stateless HMAC credentials share — push tokens
3
+ * (`push-token.ts`) and tenant tokens (`tenant-token.ts`).
4
+ *
5
+ * Shape: `<prefix>.<b64url payload>.<b64url HMAC-SHA256 sig>`, verified against a
6
+ * secret the holder never sees. One implementation rather than one per credential,
7
+ * because the two must not drift: a verification that differs between them is a
8
+ * difference neither credential's own suite would notice, and the whole point of the
9
+ * prefix is that a reader discriminates WITHOUT trying every secret it holds.
10
+ *
11
+ * The prefix is inside the signed input, never only in front of it. So a payload
12
+ * minted under one prefix cannot be replayed under another even where two deployments
13
+ * happen to configure the same secret for both — the signature is over the pair.
14
+ *
15
+ * Web Crypto only (`globalThis.crypto`): the same API in Node, workerd and a browser,
16
+ * which is what lets this live in a package both a Worker and a Node host import.
17
+ */
18
+ /** Does this presented value claim to be a `<prefix>.…` token at all? */
19
+ export declare function hasTokenPrefix(prefix: string, presented: string): boolean;
20
+ /** Sign a claim into a `<prefix>.<payload>.<sig>` token. */
21
+ export declare function signToken(prefix: string, secret: string, claim: unknown): Promise<string>;
22
+ /**
23
+ * Verify a token's prefix, shape and signature → its decoded payload, or null.
24
+ *
25
+ * The payload comes back as `unknown` deliberately: the signature proves WE minted it,
26
+ * and nothing more. Whether the fields are still the ones the caller needs is the
27
+ * caller's own parse — a format bump must fail closed, not arrive half-typed.
28
+ */
29
+ export declare function openToken(prefix: string, secret: string, token: string): Promise<unknown | null>;
30
+ //# sourceMappingURL=token-codec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-codec.d.ts","sourceRoot":"","sources":["../src/token-codec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAcH,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAEzE;AAED,4DAA4D;AAC5D,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAO/F;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAqBtG"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The wire codec the platform's stateless HMAC credentials share — push tokens
3
+ * (`push-token.ts`) and tenant tokens (`tenant-token.ts`).
4
+ *
5
+ * Shape: `<prefix>.<b64url payload>.<b64url HMAC-SHA256 sig>`, verified against a
6
+ * secret the holder never sees. One implementation rather than one per credential,
7
+ * because the two must not drift: a verification that differs between them is a
8
+ * difference neither credential's own suite would notice, and the whole point of the
9
+ * prefix is that a reader discriminates WITHOUT trying every secret it holds.
10
+ *
11
+ * The prefix is inside the signed input, never only in front of it. So a payload
12
+ * minted under one prefix cannot be replayed under another even where two deployments
13
+ * happen to configure the same secret for both — the signature is over the pair.
14
+ *
15
+ * Web Crypto only (`globalThis.crypto`): the same API in Node, workerd and a browser,
16
+ * which is what lets this live in a package both a Worker and a Node host import.
17
+ */
18
+ const enc = new TextEncoder();
19
+ const b64url = (bytes) => btoa(String.fromCharCode(...bytes)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
20
+ const b64urlToBytes = (s) => Uint8Array.from(atob(s.replace(/-/g, '+').replace(/_/g, '/')), (c) => c.charCodeAt(0));
21
+ async function hmacKey(secret, usage) {
22
+ return crypto.subtle.importKey('raw', enc.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, [usage]);
23
+ }
24
+ /** Does this presented value claim to be a `<prefix>.…` token at all? */
25
+ export function hasTokenPrefix(prefix, presented) {
26
+ return presented.startsWith(`${prefix}.`);
27
+ }
28
+ /** Sign a claim into a `<prefix>.<payload>.<sig>` token. */
29
+ export async function signToken(prefix, secret, claim) {
30
+ const payload = b64url(enc.encode(JSON.stringify(claim)));
31
+ const signingInput = `${prefix}.${payload}`;
32
+ const sig = new Uint8Array(await crypto.subtle.sign('HMAC', await hmacKey(secret, 'sign'), enc.encode(signingInput)));
33
+ return `${signingInput}.${b64url(sig)}`;
34
+ }
35
+ /**
36
+ * Verify a token's prefix, shape and signature → its decoded payload, or null.
37
+ *
38
+ * The payload comes back as `unknown` deliberately: the signature proves WE minted it,
39
+ * and nothing more. Whether the fields are still the ones the caller needs is the
40
+ * caller's own parse — a format bump must fail closed, not arrive half-typed.
41
+ */
42
+ export async function openToken(prefix, secret, token) {
43
+ const parts = token.split('.');
44
+ if (parts.length !== 3 || parts[0] !== prefix)
45
+ return null;
46
+ const [, payload, sig] = parts;
47
+ let ok = false;
48
+ try {
49
+ ok = await crypto.subtle.verify('HMAC', await hmacKey(secret, 'verify'), b64urlToBytes(sig), enc.encode(`${prefix}.${payload}`));
50
+ }
51
+ catch {
52
+ return null;
53
+ }
54
+ if (!ok)
55
+ return null;
56
+ try {
57
+ return JSON.parse(new TextDecoder().decode(b64urlToBytes(payload)));
58
+ }
59
+ catch {
60
+ return null;
61
+ }
62
+ }
63
+ //# sourceMappingURL=token-codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-codec.js","sourceRoot":"","sources":["../src/token-codec.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import type { AttachmentRecord, ConnectionId, DrainedEvent, EntityRef, EntitlementGrant, PermissionKey, PlatformRequest, PlatformRequestFilter, PlatformRequestId, PlatformRequestStatus, PlatformRequestFailure, PrincipalId, ConnectionGrantRecord, ProjectedConnectionGrant, ProjectedConnectionKey, ProjectedIdentityLink, OwnerSeat, OwnerClaimLink, QueryScopeInput, ReadScopeTableInput, EntityHistoryInput, EventFacetInput, EventCauseInput, EventEffectsInput, EffectsTree, InvocationEventsInput, InvocationEvents, DeadLettersInput, DeadLetter, CauseChain, EventFacetResult, HistoryEntry, Page, ScopeDumpTable, ScopeId, ScopeQueryResult, DenialFilter, DenialSummary, PermissionDenial, ScopeTable, ScopeTablePage, TenantId, TenantStoreHandle, Visibility } from '@substrat-run/contracts';
2
- import type { OpenedAttachment } from '@substrat-run/kernel';
1
+ import type { AttachmentRecord, ConnectionId, EntityRef, EntitlementGrant, ModuleId, PermissionKey, PlatformRequest, PlatformRequestFilter, PlatformRequestId, PlatformRequestStatus, PlatformRequestFailure, PrincipalId, SystemSwitchOutcome, ConnectionGrantRecord, ProjectedConnectionGrant, ProjectedConnectionKey, ProjectedIdentityLink, OwnerSeat, OwnerClaimLink, QueryScopeInput, ReadScopeTableInput, EntityHistoryInput, EventFacetInput, EventCauseInput, EventEffectsInput, EffectsTree, InvocationEventsInput, InvocationEvents, DeadLettersInput, DeadLetter, CauseChain, EventFacetResult, HistoryEntry, Page, ScopeDumpTable, ScopeId, ScopeQueryResult, DenialFilter, DenialSummary, PermissionDenial, ScopeTable, ScopeTablePage, TenantId, TenantStoreHandle, Visibility } from '@substrat-run/contracts';
2
+ import type { OpenedAttachment, UndrainedEvents } from '@substrat-run/kernel';
3
3
  /**
4
4
  * The platform's client for calling a VERTICAL (K-31).
5
5
  *
@@ -334,6 +334,27 @@ export declare class VerticalClient {
334
334
  permission: PermissionKey;
335
335
  expiresAt?: string;
336
336
  }): Promise<void>;
337
+ /**
338
+ * Move one module's schedule kill switch in the deployment serving the scope (#1666) —
339
+ * the far end of `revokeFromSystem` / `restoreToSystem` for a hosted scope, whose
340
+ * `system:<module>` grants live there and nowhere the platform can reach.
341
+ *
342
+ * ONE shape is normalized to "redeploy the vertical", and only because it is the
343
+ * deployment's own proof that it cannot have acted: a script built before the route
344
+ * answers a **404** (the path does not exist — the route itself answers a module it holds
345
+ * nothing for with a 200 `held: false`, never a 404) or its **SPA shell** (a 200 that is
346
+ * not JSON). "Nothing was switched" is true of exactly those.
347
+ *
348
+ * Everything else surfaces as the failure it is, and never claims that: a transport
349
+ * failure (`reach` → 502 "unreachable"), a genuine 5xx from the far end, and a 200 JSON of
350
+ * the wrong shape. The request may have landed and the switch may have moved before the
351
+ * answer was lost, so the only honest instruction is to confirm the position first.
352
+ */
353
+ systemSwitch(input: {
354
+ scopeId: ScopeId;
355
+ moduleId: ModuleId;
356
+ to: 'on' | 'off';
357
+ }): Promise<SystemSwitchOutcome>;
337
358
  /** Journal a platform-request outcome back in the vertical after the platform ran it. */
338
359
  settlePlatformRequest(tenantId: TenantId, scopeId: ScopeId, id: PlatformRequestId, outcome: {
339
360
  status: PlatformRequestStatus;
@@ -398,8 +419,12 @@ export declare class VerticalClient {
398
419
  * The Tier-2 drain's read (#1334): the oldest not-yet-drained events of a scope this
399
420
  * deployment serves. Scope bytes cross, on their way to the lake; the control plane's
400
421
  * `readUndrainedEvents` is the audited door this stands behind.
422
+ *
423
+ * Asks for what the read stepped over too (#1636, `withSkipped=1`), and takes either
424
+ * answer: a vertical deployed before that parameter ignores it and sends the bare array,
425
+ * which reads as a read that said nothing about skips — never as one that skipped none.
401
426
  */
402
- undrainedEvents(scopeId: ScopeId, limit: number): Promise<DrainedEvent[]>;
427
+ undrainedEvents(scopeId: ScopeId, limit: number): Promise<UndrainedEvents>;
403
428
  /**
404
429
  * The Tier-2 drain's stamp (#1334), after the sink confirmed the batch. Answers how
405
430
  * many rows changed, which is what lets a retried pass record no egress it did not
@@ -409,8 +434,15 @@ export declare class VerticalClient {
409
434
  /**
410
435
  * Reopen rows stamped before `drainedBefore` so the drain ships them again (#1334).
411
436
  * Answers how many changed, which is what the platform's receipt is written from.
437
+ *
438
+ * `countOnly` (#1545) asks the same window for a number and changes nothing — and it
439
+ * takes a DIFFERENT path rather than riding as a field on this one. The deployment on
440
+ * the far end is the tenant's, deployed on its own clock, so it is routinely older than
441
+ * this client: an unknown field is stripped by the Zod boundary there, and the reopen
442
+ * would run and answer with a number that looks exactly like the count. A path that
443
+ * deployment does not serve answers 404, which throws here, before anything moves.
412
444
  */
413
- redrainEvents(scopeId: ScopeId, drainedBefore: string): Promise<number>;
445
+ redrainEvents(scopeId: ScopeId, drainedBefore: string, countOnly?: boolean): Promise<number>;
414
446
  /**
415
447
  * When one scope's migrations actually ran (#1236) — the schema-change
416
448
  * annotation release health reads. Metadata only; no scope bytes cross.
@@ -420,6 +452,12 @@ export declare class VerticalClient {
420
452
  version: string;
421
453
  appliedAt: string | null;
422
454
  }[]>;
455
+ /**
456
+ * One scope's database size in bytes (#1524), for the on-demand storage reading.
457
+ * Metadata only. A 200 without a number is a wire disagreement and throws, because a
458
+ * missing size read as 0 would sit inside a sum and look like a real, small scope.
459
+ */
460
+ databaseSize(scopeId: ScopeId): Promise<number>;
423
461
  /**
424
462
  * The PITR bookmarks one scope recorded before its migration passes (#286) —
425
463
  * the rewind points the deployments UI offers for a backout. Metadata only;
@@ -1 +1 @@
1
- {"version":3,"file":"vertical-client.d.ts","sourceRoot":"","sources":["../src/vertical-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vertical-client.d.ts","sourceRoot":"","sources":["../src/vertical-client.ts"],"names":[],"mappings":"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"}