@substrat-run/control-plane-api 0.133.0 → 0.135.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.
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +22 -2
- package/dist/api.js.map +1 -1
- package/dist/auth.d.ts +2 -13
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +4 -13
- package/dist/auth.js.map +1 -1
- package/dist/browser.d.ts +12 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +13 -0
- package/dist/browser.js.map +1 -0
- package/dist/cf-observability.js +1 -1
- package/dist/cf-observability.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +13 -18
- package/dist/errors.js.map +1 -1
- package/dist/failure-attribution.js +1 -1
- package/dist/failure-attribution.js.map +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/platform-drain.d.ts.map +1 -1
- package/dist/platform-drain.js +4 -4
- package/dist/platform-drain.js.map +1 -1
- package/dist/preview-auth.js +1 -1
- package/dist/preview-auth.js.map +1 -1
- package/dist/staff-client.d.ts +399 -0
- package/dist/staff-client.d.ts.map +1 -0
- package/dist/staff-client.js +302 -0
- package/dist/staff-client.js.map +1 -0
- package/dist/vertical-client.d.ts +3 -1
- package/dist/vertical-client.d.ts.map +1 -1
- package/dist/vertical-client.js +8 -2
- package/dist/vertical-client.js.map +1 -1
- package/package.json +10 -5
- package/dist/client.d.ts +0 -137
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -194
- package/dist/client.js.map +0 -1
- package/dist/identity-tenants.d.ts +0 -30
- package/dist/identity-tenants.d.ts.map +0 -1
- package/dist/identity-tenants.js +0 -23
- package/dist/identity-tenants.js.map +0 -1
package/dist/client.d.ts
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import type { ConnectionProbe, EntitlementGrant, EntitlementGrantInput, QueryScopeInput, ReadScopeTableInput, Scope, ScopeId, ScopeQueryResult, DenialFilter, DenialSummary, PermissionDenial, ScopeTable, ScopeTablePage, Tenant, TenantId } from '@substrat-run/contracts';
|
|
2
|
-
import { type IdentityTenant } from './identity-tenants.js';
|
|
3
|
-
/**
|
|
4
|
-
* A typed HTTP client for the control-plane API — the vertical side of the
|
|
5
|
-
* connect seam (first-flow.md slice 4).
|
|
6
|
-
*
|
|
7
|
-
* A vertical that runs against a *separately deployed* shared control plane uses
|
|
8
|
-
* this to (a) register its tenant, entitlements, and scope on boot, and (b) gate
|
|
9
|
-
* each request on the directory's authoritative lifecycle — `assertScopeActive`
|
|
10
|
-
* fails closed exactly as the kernel's own `getScope` does, so a suspend in the
|
|
11
|
-
* console bites the vertical's next operation even across process and deployment
|
|
12
|
-
* boundaries.
|
|
13
|
-
*
|
|
14
|
-
* What it deliberately does NOT do: write roles or grants. Those are not on the
|
|
15
|
-
* control-plane HTTP surface (api.ts §4.5 — permission writes are the human
|
|
16
|
-
* checkpoint, D-22/D-29), so a connected vertical keeps its permission model
|
|
17
|
-
* local and treats the shared plane as the authority for tenant/scope lifecycle
|
|
18
|
-
* and entitlements only.
|
|
19
|
-
*
|
|
20
|
-
* `fetch` is injectable: pass a Worker service-binding's fetch, or the router's
|
|
21
|
-
* own `app.fetch` for an in-process test, instead of the global.
|
|
22
|
-
*/
|
|
23
|
-
export interface ControlPlaneClientOptions {
|
|
24
|
-
/** Base URL of the control-plane API, e.g. `https://cp.example.com` or `http://127.0.0.1:8788`. */
|
|
25
|
-
baseUrl: string;
|
|
26
|
-
/**
|
|
27
|
-
* The platform actor id stamped as the audit subject on every write — sent as the
|
|
28
|
-
* dev-only `x-platform-actor` header, and ONLY when no `serviceToken` is set. With a
|
|
29
|
-
* token the control plane resolves the subject from the token (its fixed service
|
|
30
|
-
* actor), so the header is never consulted there and is not sent (#980).
|
|
31
|
-
*/
|
|
32
|
-
actor: string;
|
|
33
|
-
/**
|
|
34
|
-
* A service credential (`x-service-token`) proving the caller is an authorized
|
|
35
|
-
* vertical, not just anyone with an actor id. Required when the control plane
|
|
36
|
-
* has real auth — the dev-actor header alone does not authenticate there. When
|
|
37
|
-
* set, it is the request's only credential: `actor` is not sent.
|
|
38
|
-
*/
|
|
39
|
-
serviceToken?: string;
|
|
40
|
-
/** Defaults to the global `fetch`. */
|
|
41
|
-
fetch?: typeof globalThis.fetch;
|
|
42
|
-
}
|
|
43
|
-
export interface ClientProvisionScopeInput {
|
|
44
|
-
tenantId: TenantId;
|
|
45
|
-
scopeId: ScopeId;
|
|
46
|
-
slug?: string;
|
|
47
|
-
kind?: string;
|
|
48
|
-
name?: string;
|
|
49
|
-
vertical?: string | null;
|
|
50
|
-
jurisdiction?: 'eu' | 'us' | 'global';
|
|
51
|
-
}
|
|
52
|
-
/** A non-2xx (or unreachable) control-plane response. `status` is 0 on a transport error. */
|
|
53
|
-
export declare class ControlPlaneError extends Error {
|
|
54
|
-
readonly status: number;
|
|
55
|
-
/**
|
|
56
|
-
* The provider's own answer, when the plane refused a connect because the credential
|
|
57
|
-
* was rejected upstream (#605, 422). Carried so a console can show WHY — "Scrive:
|
|
58
|
-
* No valid access credentials were provided" — instead of a generic save failure.
|
|
59
|
-
*/
|
|
60
|
-
readonly probe?: ConnectionProbe | undefined;
|
|
61
|
-
constructor(status: number, message: string,
|
|
62
|
-
/**
|
|
63
|
-
* The provider's own answer, when the plane refused a connect because the credential
|
|
64
|
-
* was rejected upstream (#605, 422). Carried so a console can show WHY — "Scrive:
|
|
65
|
-
* No valid access credentials were provided" — instead of a generic save failure.
|
|
66
|
-
*/
|
|
67
|
-
probe?: ConnectionProbe | undefined);
|
|
68
|
-
}
|
|
69
|
-
export declare class ControlPlaneClient {
|
|
70
|
-
private readonly baseUrl;
|
|
71
|
-
private readonly actor;
|
|
72
|
-
private readonly serviceToken?;
|
|
73
|
-
private readonly fetchImpl;
|
|
74
|
-
constructor(options: ControlPlaneClientOptions);
|
|
75
|
-
/**
|
|
76
|
-
* One request, and the one place a failure is read: a transport error or a non-2xx answer
|
|
77
|
-
* throws `ControlPlaneError`, so what comes back is always a successful `Response`. A 404
|
|
78
|
-
* is handed back as-is when the caller allows it.
|
|
79
|
-
*/
|
|
80
|
-
private send;
|
|
81
|
-
private call;
|
|
82
|
-
createTenant(input: {
|
|
83
|
-
id: TenantId;
|
|
84
|
-
slug: string;
|
|
85
|
-
name: string;
|
|
86
|
-
}): Promise<Tenant>;
|
|
87
|
-
grantEntitlement(tenantId: TenantId, key: string, plan?: EntitlementGrantInput): Promise<EntitlementGrant[]>;
|
|
88
|
-
provisionScope(input: ClientProvisionScopeInput): Promise<Scope>;
|
|
89
|
-
/**
|
|
90
|
-
* Confirm the scope exists here, moving the directory row provisioning → active.
|
|
91
|
-
*
|
|
92
|
-
* In this (push) direction the vertical has already built the scope locally, so
|
|
93
|
-
* registering and confirming are the same moment — but they stay two calls so
|
|
94
|
-
* `provisionScope` means one thing everywhere, and so the directory is never the
|
|
95
|
-
* one deciding a scope is ready (K-31).
|
|
96
|
-
*/
|
|
97
|
-
activateScope(tenantId: TenantId, scopeId: ScopeId): Promise<Scope>;
|
|
98
|
-
getTenant(tenantId: TenantId): Promise<Tenant | undefined>;
|
|
99
|
-
getScopeRecord(tenantId: TenantId, scopeId: ScopeId): Promise<Scope | undefined>;
|
|
100
|
-
listEntitlements(tenantId: TenantId): Promise<EntitlementGrant[]>;
|
|
101
|
-
/**
|
|
102
|
-
* The tenants a login builds for, each flagged with whether it holds the `builder`
|
|
103
|
-
* entitlement — the builder studio's membership read (builder-plane.md §4). `externalId`
|
|
104
|
-
* is the login's OIDC subject. Service-token gated: an unset token is refused by the
|
|
105
|
-
* plane, never bypassed.
|
|
106
|
-
*
|
|
107
|
-
* The answer is PARSED, not asserted: a plane that renamed `entitled`, or answered an
|
|
108
|
-
* `{ error }` body with a 200, would hand a cast `entitled: undefined` — falsy, so the
|
|
109
|
-
* studio would lock the tenant out with the ordinary "not enabled" page and nothing
|
|
110
|
-
* anywhere would say the directory had changed shape. A refused parse throws instead.
|
|
111
|
-
* The message names the shape that was wrong, never the body — the body is directory
|
|
112
|
-
* facts about a person's tenants.
|
|
113
|
-
*/
|
|
114
|
-
identityTenants(externalId: string): Promise<IdentityTenant[]>;
|
|
115
|
-
/** Every table in the scope's own database, with row counts (Data view). */
|
|
116
|
-
listScopeTables(tenantId: TenantId, scopeId: ScopeId): Promise<ScopeTable[]>;
|
|
117
|
-
/** A bounded page of one table of the scope's database. */
|
|
118
|
-
readScopeTable(tenantId: TenantId, scopeId: ScopeId, input: ReadScopeTableInput): Promise<ScopeTablePage>;
|
|
119
|
-
/** One read-only SQL statement against the scope's database — the console (#219). */
|
|
120
|
-
queryScope(tenantId: TenantId, scopeId: ScopeId, input: QueryScopeInput): Promise<ScopeQueryResult>;
|
|
121
|
-
/**
|
|
122
|
-
* The scope's recorded permission refusals, bucketed per (actor, permission) with the
|
|
123
|
-
* window's own facts beside them — the view to open first, because the raw log's
|
|
124
|
-
* volume is attacker-influenceable and a prober can flood a newest-first page.
|
|
125
|
-
*/
|
|
126
|
-
summarizeDenials(tenantId: TenantId, scopeId: ScopeId, filter?: DenialFilter): Promise<DenialSummary>;
|
|
127
|
-
/** The raw rows behind a bucket, newest first. */
|
|
128
|
-
listDenials(tenantId: TenantId, scopeId: ScopeId, filter?: DenialFilter): Promise<PermissionDenial[]>;
|
|
129
|
-
/**
|
|
130
|
-
* The gate. Throws unless the tenant is active AND the scope exists and is
|
|
131
|
-
* active — the same fail-closed logic the kernel's `validateScopeAccess`
|
|
132
|
-
* applies locally, so a tenant-level cascade suspend bites too, not just a
|
|
133
|
-
* per-scope one. Call it before handing a request to the local scope host.
|
|
134
|
-
*/
|
|
135
|
-
assertScopeActive(tenantId: TenantId, scopeId: ScopeId): Promise<void>;
|
|
136
|
-
}
|
|
137
|
-
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import { denialQuery, problemDetail } from '@substrat-run/contracts';
|
|
2
|
-
import { DEV_ACTOR_HEADER, SERVICE_TOKEN_HEADER } from './auth.js';
|
|
3
|
-
import { identityTenantsResponse } from './identity-tenants.js';
|
|
4
|
-
/** A non-2xx (or unreachable) control-plane response. `status` is 0 on a transport error. */
|
|
5
|
-
export class ControlPlaneError extends Error {
|
|
6
|
-
status;
|
|
7
|
-
probe;
|
|
8
|
-
constructor(status, message,
|
|
9
|
-
/**
|
|
10
|
-
* The provider's own answer, when the plane refused a connect because the credential
|
|
11
|
-
* was rejected upstream (#605, 422). Carried so a console can show WHY — "Scrive:
|
|
12
|
-
* No valid access credentials were provided" — instead of a generic save failure.
|
|
13
|
-
*/
|
|
14
|
-
probe) {
|
|
15
|
-
super(message);
|
|
16
|
-
this.status = status;
|
|
17
|
-
this.probe = probe;
|
|
18
|
-
this.name = 'ControlPlaneError';
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
export class ControlPlaneClient {
|
|
22
|
-
baseUrl;
|
|
23
|
-
actor;
|
|
24
|
-
serviceToken;
|
|
25
|
-
fetchImpl;
|
|
26
|
-
constructor(options) {
|
|
27
|
-
this.baseUrl = options.baseUrl.replace(/\/$/, '');
|
|
28
|
-
this.actor = options.actor;
|
|
29
|
-
this.serviceToken = options.serviceToken;
|
|
30
|
-
// Bind to globalThis: workerd throws "Illegal invocation" if `fetch` is called
|
|
31
|
-
// with a `this` other than the global scope (which `this.fetchImpl(...)` would
|
|
32
|
-
// otherwise set to this instance). An injected fetch is used as-is.
|
|
33
|
-
this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* One request, and the one place a failure is read: a transport error or a non-2xx answer
|
|
37
|
-
* throws `ControlPlaneError`, so what comes back is always a successful `Response`. A 404
|
|
38
|
-
* is handed back as-is when the caller allows it.
|
|
39
|
-
*/
|
|
40
|
-
async send(path, init, allow404 = false) {
|
|
41
|
-
let res;
|
|
42
|
-
try {
|
|
43
|
-
res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
44
|
-
...init,
|
|
45
|
-
headers: {
|
|
46
|
-
// One credential per request (#980): a service token identifies the caller as
|
|
47
|
-
// the plane's service actor and is checked BEFORE the dev-actor stub, so the
|
|
48
|
-
// actor header would be ignored there — and a dev-only header has no business
|
|
49
|
-
// leaving a production caller at all. Without a token, the actor header IS the
|
|
50
|
-
// (local, UNSAFE) credential.
|
|
51
|
-
...(this.serviceToken
|
|
52
|
-
? { [SERVICE_TOKEN_HEADER]: this.serviceToken }
|
|
53
|
-
: { [DEV_ACTOR_HEADER]: this.actor }),
|
|
54
|
-
'content-type': 'application/json',
|
|
55
|
-
...init?.headers,
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
catch (e) {
|
|
60
|
-
// A transport failure (control plane down) must fail closed, not silently
|
|
61
|
-
// pass — a vertical that cannot reach the authority does not get to run.
|
|
62
|
-
throw new ControlPlaneError(0, `control plane unreachable: ${e.message}`);
|
|
63
|
-
}
|
|
64
|
-
if (res.status === 404 && allow404)
|
|
65
|
-
return res;
|
|
66
|
-
if (!res.ok) {
|
|
67
|
-
// `problemDetail` is the one reading of a failed body (#971): the RFC 9457
|
|
68
|
-
// `detail` first, the deprecated `error` duplicate second, both against the
|
|
69
|
-
// published schema — so this works either way, and keeps working the day the
|
|
70
|
-
// duplicate is deleted. The status line is the fallback only when the body
|
|
71
|
-
// said nothing readable.
|
|
72
|
-
const body = await res.json().catch(() => null);
|
|
73
|
-
throw new ControlPlaneError(res.status, problemDetail(body) ?? `${res.status} ${res.statusText}`);
|
|
74
|
-
}
|
|
75
|
-
return res;
|
|
76
|
-
}
|
|
77
|
-
async call(path, init, allow404 = false) {
|
|
78
|
-
const res = await this.send(path, init, allow404);
|
|
79
|
-
if (res.status === 404 && allow404)
|
|
80
|
-
return undefined;
|
|
81
|
-
return res.status === 204 ? undefined : (await res.json());
|
|
82
|
-
}
|
|
83
|
-
// -- registration (idempotent, mirrors HostAdmin) --------------------------
|
|
84
|
-
createTenant(input) {
|
|
85
|
-
return this.call('/tenants', { method: 'POST', body: JSON.stringify(input) });
|
|
86
|
-
}
|
|
87
|
-
grantEntitlement(tenantId, key, plan) {
|
|
88
|
-
return this.call(`/tenants/${tenantId}/entitlements/${key}`, {
|
|
89
|
-
method: 'PUT',
|
|
90
|
-
body: plan === undefined ? undefined : JSON.stringify(plan),
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
provisionScope(input) {
|
|
94
|
-
return this.call('/scopes', { method: 'POST', body: JSON.stringify(input) });
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Confirm the scope exists here, moving the directory row provisioning → active.
|
|
98
|
-
*
|
|
99
|
-
* In this (push) direction the vertical has already built the scope locally, so
|
|
100
|
-
* registering and confirming are the same moment — but they stay two calls so
|
|
101
|
-
* `provisionScope` means one thing everywhere, and so the directory is never the
|
|
102
|
-
* one deciding a scope is ready (K-31).
|
|
103
|
-
*/
|
|
104
|
-
activateScope(tenantId, scopeId) {
|
|
105
|
-
return this.call(`/tenants/${tenantId}/scopes/${scopeId}/activate`, { method: 'POST' });
|
|
106
|
-
}
|
|
107
|
-
// -- reads used for gating -------------------------------------------------
|
|
108
|
-
getTenant(tenantId) {
|
|
109
|
-
return this.call(`/tenants/${tenantId}`, undefined, true);
|
|
110
|
-
}
|
|
111
|
-
getScopeRecord(tenantId, scopeId) {
|
|
112
|
-
return this.call(`/tenants/${tenantId}/scopes/${scopeId}`, undefined, true);
|
|
113
|
-
}
|
|
114
|
-
listEntitlements(tenantId) {
|
|
115
|
-
return this.call(`/tenants/${tenantId}/entitlements`);
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* The tenants a login builds for, each flagged with whether it holds the `builder`
|
|
119
|
-
* entitlement — the builder studio's membership read (builder-plane.md §4). `externalId`
|
|
120
|
-
* is the login's OIDC subject. Service-token gated: an unset token is refused by the
|
|
121
|
-
* plane, never bypassed.
|
|
122
|
-
*
|
|
123
|
-
* The answer is PARSED, not asserted: a plane that renamed `entitled`, or answered an
|
|
124
|
-
* `{ error }` body with a 200, would hand a cast `entitled: undefined` — falsy, so the
|
|
125
|
-
* studio would lock the tenant out with the ordinary "not enabled" page and nothing
|
|
126
|
-
* anywhere would say the directory had changed shape. A refused parse throws instead.
|
|
127
|
-
* The message names the shape that was wrong, never the body — the body is directory
|
|
128
|
-
* facts about a person's tenants.
|
|
129
|
-
*/
|
|
130
|
-
async identityTenants(externalId) {
|
|
131
|
-
const res = await this.send('/internal/builder/identity-tenants', {
|
|
132
|
-
method: 'POST',
|
|
133
|
-
body: JSON.stringify({ externalId }),
|
|
134
|
-
});
|
|
135
|
-
const parsed = identityTenantsResponse.safeParse(await res.json().catch(() => null));
|
|
136
|
-
if (!parsed.success) {
|
|
137
|
-
throw new ControlPlaneError(res.status, `identity-tenants returned an unexpected shape: ${parsed.error.message}`);
|
|
138
|
-
}
|
|
139
|
-
return parsed.data.tenants;
|
|
140
|
-
}
|
|
141
|
-
// -- read-only scope-DB introspection (§5.4 admin-query RPC) ----------------
|
|
142
|
-
/** Every table in the scope's own database, with row counts (Data view). */
|
|
143
|
-
listScopeTables(tenantId, scopeId) {
|
|
144
|
-
return this.call(`/tenants/${tenantId}/scopes/${scopeId}/tables`);
|
|
145
|
-
}
|
|
146
|
-
/** A bounded page of one table of the scope's database. */
|
|
147
|
-
readScopeTable(tenantId, scopeId, input) {
|
|
148
|
-
const q = new URLSearchParams({ limit: String(input.limit), offset: String(input.offset) });
|
|
149
|
-
return this.call(`/tenants/${tenantId}/scopes/${scopeId}/tables/${encodeURIComponent(input.table)}?${q}`);
|
|
150
|
-
}
|
|
151
|
-
/** One read-only SQL statement against the scope's database — the console (#219). */
|
|
152
|
-
queryScope(tenantId, scopeId, input) {
|
|
153
|
-
return this.call(`/tenants/${tenantId}/scopes/${scopeId}/query`, {
|
|
154
|
-
method: 'POST',
|
|
155
|
-
body: JSON.stringify(input),
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
// -- the denial log (K-35, #867) --------------------------------------------
|
|
159
|
-
/**
|
|
160
|
-
* The scope's recorded permission refusals, bucketed per (actor, permission) with the
|
|
161
|
-
* window's own facts beside them — the view to open first, because the raw log's
|
|
162
|
-
* volume is attacker-influenceable and a prober can flood a newest-first page.
|
|
163
|
-
*/
|
|
164
|
-
summarizeDenials(tenantId, scopeId, filter) {
|
|
165
|
-
return this.call(`/tenants/${tenantId}/scopes/${scopeId}/denials/summary${denialQuery(filter)}`);
|
|
166
|
-
}
|
|
167
|
-
/** The raw rows behind a bucket, newest first. */
|
|
168
|
-
listDenials(tenantId, scopeId, filter) {
|
|
169
|
-
return this.call(`/tenants/${tenantId}/scopes/${scopeId}/denials${denialQuery(filter)}`);
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* The gate. Throws unless the tenant is active AND the scope exists and is
|
|
173
|
-
* active — the same fail-closed logic the kernel's `validateScopeAccess`
|
|
174
|
-
* applies locally, so a tenant-level cascade suspend bites too, not just a
|
|
175
|
-
* per-scope one. Call it before handing a request to the local scope host.
|
|
176
|
-
*/
|
|
177
|
-
async assertScopeActive(tenantId, scopeId) {
|
|
178
|
-
const [tenant, scope] = await Promise.all([
|
|
179
|
-
this.getTenant(tenantId),
|
|
180
|
-
this.getScopeRecord(tenantId, scopeId),
|
|
181
|
-
]);
|
|
182
|
-
if (!tenant)
|
|
183
|
-
throw new ControlPlaneError(403, `unknown tenant: ${tenantId}`);
|
|
184
|
-
if (tenant.status !== 'active') {
|
|
185
|
-
throw new ControlPlaneError(403, `tenant not active (status: ${tenant.status}): ${tenantId}`);
|
|
186
|
-
}
|
|
187
|
-
if (!scope)
|
|
188
|
-
throw new ControlPlaneError(403, `unknown scope for tenant: (${tenantId}, ${scopeId})`);
|
|
189
|
-
if (scope.status !== 'active') {
|
|
190
|
-
throw new ControlPlaneError(403, `scope not active (status: ${scope.status}): ${scopeId}`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAmBrE,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAuB,MAAM,uBAAuB,CAAC;AAsDrF,6FAA6F;AAC7F,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAE/B,MAAM;IAON,KAAK;IARhB,YACW,MAAc,EACvB,OAAe;IACf;;;;OAIG;IACM,KAAuB;QAEhC,KAAK,CAAC,OAAO,CAAC,CAAC;sBATN,MAAM;qBAON,KAAK;QAGd,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,MAAM,OAAO,kBAAkB;IACZ,OAAO,CAAS;IAChB,KAAK,CAAS;IACd,YAAY,CAAU;IACtB,SAAS,CAA0B;IAEpD,YAAY,OAAkC;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;QACzC,+EAA+E;QAC/E,+EAA+E;QAC/E,oEAAoE;QACpE,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACtE,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,IAAkB,EAAE,QAAQ,GAAG,KAAK;QACnE,IAAI,GAAa,CAAC;QAClB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;gBACnD,GAAG,IAAI;gBACP,OAAO,EAAE;oBACP,8EAA8E;oBAC9E,6EAA6E;oBAC7E,8EAA8E;oBAC9E,+EAA+E;oBAC/E,8BAA8B;oBAC9B,GAAG,CAAC,IAAI,CAAC,YAAY;wBACnB,CAAC,CAAC,EAAE,CAAC,oBAAoB,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE;wBAC/C,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;oBACvC,cAAc,EAAE,kBAAkB;oBAClC,GAAG,IAAI,EAAE,OAAO;iBACjB;aACF,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,0EAA0E;YAC1E,yEAAyE;YACzE,MAAM,IAAI,iBAAiB,CAAC,CAAC,EAAE,8BAA+B,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QACvF,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ;YAAE,OAAO,GAAG,CAAC;QAC/C,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,2EAA2E;YAC3E,4EAA4E;YAC5E,6EAA6E;YAC7E,2EAA2E;YAC3E,yBAAyB;YACzB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YAChD,MAAM,IAAI,iBAAiB,CACzB,GAAG,CAAC,MAAM,EACV,aAAa,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CACzD,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAEO,KAAK,CAAC,IAAI,CAAI,IAAY,EAAE,IAAkB,EAAE,QAAQ,GAAG,KAAK;QACtE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QAClD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ;YAAE,OAAO,SAAc,CAAC;QAC1D,OAAO,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAE,SAAe,CAAC,CAAC,CAAE,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAO,CAAC;IAC3E,CAAC;IAED,6EAA6E;IAE7E,YAAY,CAAC,KAAmD;QAC9D,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAChF,CAAC;IAED,gBAAgB,CACd,QAAkB,EAClB,GAAW,EACX,IAA4B;QAE5B,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,QAAQ,iBAAiB,GAAG,EAAE,EAAE;YAC3D,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC5D,CAAC,CAAC;IACL,CAAC;IAED,cAAc,CAAC,KAAgC;QAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED;;;;;;;OAOG;IACH,aAAa,CAAC,QAAkB,EAAE,OAAgB;QAChD,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,QAAQ,WAAW,OAAO,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1F,CAAC;IAED,6EAA6E;IAE7E,SAAS,CAAC,QAAkB;QAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAC5D,CAAC;IAED,cAAc,CAAC,QAAkB,EAAE,OAAgB;QACjD,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,QAAQ,WAAW,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAC9E,CAAC;IAED,gBAAgB,CAAC,QAAkB;QACjC,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,QAAQ,eAAe,CAAC,CAAC;IACxD,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,eAAe,CAAC,UAAkB;QACtC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,oCAAoC,EAAE;YAChE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,CAAC;SACrC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,uBAAuB,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QACrF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,iBAAiB,CACzB,GAAG,CAAC,MAAM,EACV,kDAAkD,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CACzE,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;IAC7B,CAAC;IAED,8EAA8E;IAE9E,4EAA4E;IAC5E,eAAe,CAAC,QAAkB,EAAE,OAAgB;QAClD,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,QAAQ,WAAW,OAAO,SAAS,CAAC,CAAC;IACpE,CAAC;IAED,2DAA2D;IAC3D,cAAc,CACZ,QAAkB,EAClB,OAAgB,EAChB,KAA0B;QAE1B,MAAM,CAAC,GAAG,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC5F,OAAO,IAAI,CAAC,IAAI,CACd,YAAY,QAAQ,WAAW,OAAO,WAAW,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CACxF,CAAC;IACJ,CAAC;IAED,qFAAqF;IACrF,UAAU,CACR,QAAkB,EAClB,OAAgB,EAChB,KAAsB;QAEtB,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,QAAQ,WAAW,OAAO,QAAQ,EAAE;YAC/D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,8EAA8E;IAE9E;;;;OAIG;IACH,gBAAgB,CACd,QAAkB,EAClB,OAAgB,EAChB,MAAqB;QAErB,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,QAAQ,WAAW,OAAO,mBAAmB,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnG,CAAC;IAED,kDAAkD;IAClD,WAAW,CACT,QAAkB,EAClB,OAAgB,EAChB,MAAqB;QAErB,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,QAAQ,WAAW,OAAO,WAAW,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3F,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,iBAAiB,CAAC,QAAkB,EAAE,OAAgB;QAC1D,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACxC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;YACxB,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC;SACvC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,iBAAiB,CAAC,GAAG,EAAE,mBAAmB,QAAQ,EAAE,CAAC,CAAC;QAC7E,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,MAAM,IAAI,iBAAiB,CAAC,GAAG,EAAE,8BAA8B,MAAM,CAAC,MAAM,MAAM,QAAQ,EAAE,CAAC,CAAC;QAChG,CAAC;QACD,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,iBAAiB,CAAC,GAAG,EAAE,8BAA8B,QAAQ,KAAK,OAAO,GAAG,CAAC,CAAC;QACpG,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC9B,MAAM,IAAI,iBAAiB,CAAC,GAAG,EAAE,6BAA6B,KAAK,CAAC,MAAM,MAAM,OAAO,EAAE,CAAC,CAAC;QAC7F,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { z } from '@substrat-run/contracts';
|
|
2
|
-
/**
|
|
3
|
-
* A tenant a login builds for, as the control plane's studio membership read states it
|
|
4
|
-
* (`POST /internal/builder/identity-tenants`, builder-plane.md §4).
|
|
5
|
-
*
|
|
6
|
-
* The three directory fields are parsed with the SAME schemas the `tenant` record
|
|
7
|
-
* publishes (`contracts/src/tenancy.ts`), not with generic strings: the id is a ULID, the
|
|
8
|
-
* slug is the constrained slug, the name is non-empty. That costs nothing in lockout risk
|
|
9
|
-
* — `createTenantInput` picks those same three, so a tenant that exists satisfied them at
|
|
10
|
-
* creation — and it buys the half a loose parse would miss. A non-empty but malformed id
|
|
11
|
-
* passes `z.string()` and then becomes a Durable Object key and a team route, which is the
|
|
12
|
-
* downstream use this parse exists to protect.
|
|
13
|
-
*/
|
|
14
|
-
export declare const identityTenant: z.ZodObject<{
|
|
15
|
-
id: z.core.$ZodBranded<z.ZodString, "TenantId", "out">;
|
|
16
|
-
slug: z.ZodString;
|
|
17
|
-
name: z.ZodString;
|
|
18
|
-
entitled: z.ZodBoolean;
|
|
19
|
-
}, z.core.$strip>;
|
|
20
|
-
/** The `/internal/builder/identity-tenants` response body. */
|
|
21
|
-
export declare const identityTenantsResponse: z.ZodObject<{
|
|
22
|
-
tenants: z.ZodArray<z.ZodObject<{
|
|
23
|
-
id: z.core.$ZodBranded<z.ZodString, "TenantId", "out">;
|
|
24
|
-
slug: z.ZodString;
|
|
25
|
-
name: z.ZodString;
|
|
26
|
-
entitled: z.ZodBoolean;
|
|
27
|
-
}, z.core.$strip>>;
|
|
28
|
-
}, z.core.$strip>;
|
|
29
|
-
export type IdentityTenant = z.infer<typeof identityTenant>;
|
|
30
|
-
//# sourceMappingURL=identity-tenants.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"identity-tenants.d.ts","sourceRoot":"","sources":["../src/identity-tenants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,CAAC,EAAE,MAAM,yBAAyB,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc;;;;;iBAMzB,CAAC;AAEH,8DAA8D;AAC9D,eAAO,MAAM,uBAAuB;;;;;;;iBAAiD,CAAC;AAEtF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC"}
|
package/dist/identity-tenants.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { slug, tenantId, z } from '@substrat-run/contracts';
|
|
2
|
-
/**
|
|
3
|
-
* A tenant a login builds for, as the control plane's studio membership read states it
|
|
4
|
-
* (`POST /internal/builder/identity-tenants`, builder-plane.md §4).
|
|
5
|
-
*
|
|
6
|
-
* The three directory fields are parsed with the SAME schemas the `tenant` record
|
|
7
|
-
* publishes (`contracts/src/tenancy.ts`), not with generic strings: the id is a ULID, the
|
|
8
|
-
* slug is the constrained slug, the name is non-empty. That costs nothing in lockout risk
|
|
9
|
-
* — `createTenantInput` picks those same three, so a tenant that exists satisfied them at
|
|
10
|
-
* creation — and it buys the half a loose parse would miss. A non-empty but malformed id
|
|
11
|
-
* passes `z.string()` and then becomes a Durable Object key and a team route, which is the
|
|
12
|
-
* downstream use this parse exists to protect.
|
|
13
|
-
*/
|
|
14
|
-
export const identityTenant = z.object({
|
|
15
|
-
id: tenantId,
|
|
16
|
-
slug,
|
|
17
|
-
name: z.string().min(1),
|
|
18
|
-
/** Whether the tenant holds the `builder` entitlement (the control plane applies expiry at read). */
|
|
19
|
-
entitled: z.boolean(),
|
|
20
|
-
});
|
|
21
|
-
/** The `/internal/builder/identity-tenants` response body. */
|
|
22
|
-
export const identityTenantsResponse = z.object({ tenants: z.array(identityTenant) });
|
|
23
|
-
//# sourceMappingURL=identity-tenants.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"identity-tenants.js","sourceRoot":"","sources":["../src/identity-tenants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,yBAAyB,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,EAAE,EAAE,QAAQ;IACZ,IAAI;IACJ,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,qGAAqG;IACrG,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;CACtB,CAAC,CAAC;AAEH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC"}
|