@substrat-run/control-plane-api 0.118.0 → 0.120.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 +2 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +533 -18
- package/dist/api.js.map +1 -1
- package/dist/cf-observability.d.ts +8 -0
- package/dist/cf-observability.d.ts.map +1 -1
- package/dist/cf-observability.js +135 -6
- package/dist/cf-observability.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/observability-window.d.ts +13 -0
- package/dist/observability-window.d.ts.map +1 -0
- package/dist/observability-window.js +20 -0
- package/dist/observability-window.js.map +1 -0
- package/dist/observability.d.ts +63 -0
- package/dist/observability.d.ts.map +1 -1
- package/dist/observability.js.map +1 -1
- package/dist/platform-drain.d.ts +35 -0
- package/dist/platform-drain.d.ts.map +1 -1
- package/dist/platform-drain.js +109 -2
- package/dist/platform-drain.js.map +1 -1
- package/dist/preview-auth.d.ts +51 -0
- package/dist/preview-auth.d.ts.map +1 -0
- package/dist/preview-auth.js +273 -0
- package/dist/preview-auth.js.map +1 -0
- package/dist/vertical-client.d.ts +81 -1
- package/dist/vertical-client.d.ts.map +1 -1
- package/dist/vertical-client.js +185 -1
- package/dist/vertical-client.js.map +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { SHARED_ISSUER_CONFIG_KEY, oidcCallbackUrl, } from '@substrat-run/contracts';
|
|
2
|
+
import { ControlPlaneError } from './client.js';
|
|
3
|
+
/**
|
|
4
|
+
* A preview's login (#1704) — the control plane's half. The issuer's half, and why the
|
|
5
|
+
* protocol has the shape it has, are in `@substrat-run/contracts`' `preview-client.ts`.
|
|
6
|
+
*
|
|
7
|
+
* A fork arrives with the parent's DATA and none of its delivered config: the PR's version
|
|
8
|
+
* is its own script with its own, empty, config store — at create and again after every push,
|
|
9
|
+
* which binds yet another script. The parent's `substrat:auth` carries a client secret the
|
|
10
|
+
* platform neither stores nor reads back, so it cannot be copied either. What CAN be done,
|
|
11
|
+
* when the parent signs in at one of the team's own auth-servers, is to give the preview a
|
|
12
|
+
* client of its own there and deliver THAT. Prod's client is never read, written, or taught a
|
|
13
|
+
* preview's callback.
|
|
14
|
+
*
|
|
15
|
+
* ## Which issuer
|
|
16
|
+
*
|
|
17
|
+
* Nothing the control plane holds says which issuer an app chose — only the dashboard knows,
|
|
18
|
+
* and it tells the ISSUER (#1619's resource rows, #1670's places), never the plane. So every
|
|
19
|
+
* active auth-server of the preview's OWN tenant is asked whether it signs the parent in; a
|
|
20
|
+
* fork or preview of an auth-server is never asked (it holds copies of prod's clients, not
|
|
21
|
+
* the parent's binding). One claim is wired. None is `unregistered` — an external issuer, a
|
|
22
|
+
* builtin login, or an install the dashboard has not registered yet — and more than one is
|
|
23
|
+
* `ambiguous`, which wires nothing rather than guess.
|
|
24
|
+
*
|
|
25
|
+
* ## Concurrent pushes
|
|
26
|
+
*
|
|
27
|
+
* Two pushes to one preview each bind their own version, and each version is its own config
|
|
28
|
+
* store; only the version the preview is bound to NOW is served. So a push:
|
|
29
|
+
*
|
|
30
|
+
* 1. re-reads the binding before it mints, and stops if its version is no longer bound;
|
|
31
|
+
* 2. delivers into ITS OWN version's deployment — never "whatever the scope is bound to",
|
|
32
|
+
* which would let an older push overwrite a newer push's store;
|
|
33
|
+
* 3. re-reads the binding before it retires anything, and if its version has moved on,
|
|
34
|
+
* deletes only the client it minted (which lives in its own, unserved, store) and stops;
|
|
35
|
+
* 4. otherwise retires the preview's clients OLDER than its own. `superseded` (a newer one
|
|
36
|
+
* exists) means stop: the push that minted it owns what happens next. Only `kept: false`
|
|
37
|
+
* — its own client vanished while its version is still bound — is retried, three
|
|
38
|
+
* attempts in all; running out is a failure, never a success.
|
|
39
|
+
*/
|
|
40
|
+
/** The capability a vertical declares to be a team issuer (manifest `provides`, #427). */
|
|
41
|
+
const OIDC_ISSUER = 'oidc-issuer';
|
|
42
|
+
/** Rows pushed before `provides` existed — the same legacy slug the dashboard counts. */
|
|
43
|
+
const LEGACY_ISSUER_SLUG = 'auth-server';
|
|
44
|
+
/** The most callbacks a parent's hostnames yield in one check (the wire bound). */
|
|
45
|
+
const MAX_PARENT_CALLBACKS = 32;
|
|
46
|
+
const MAX_ATTEMPTS = 3;
|
|
47
|
+
/** The team's own auth-servers: active, not a fork, not a preview, of a vertical that provides `oidc-issuer`. */
|
|
48
|
+
export async function tenantIssuers(deps, tenantId) {
|
|
49
|
+
const verticals = await deps.admin.listVerticals(deps.actor);
|
|
50
|
+
const issuerSlugs = new Set([LEGACY_ISSUER_SLUG, ...verticals.filter((v) => v.provides?.includes(OIDC_ISSUER)).map((v) => v.slug)]);
|
|
51
|
+
const scopes = await deps.admin.listScopes(deps.actor, { tenantId, status: ['active'] });
|
|
52
|
+
return scopes.filter((s) => s.tenantId === tenantId && s.vertical !== null && issuerSlugs.has(s.vertical) && !s.forkedFrom && s.kind !== 'preview');
|
|
53
|
+
}
|
|
54
|
+
/** The hostname an issuer is addressed by: its canonical app hostname, else any live one. */
|
|
55
|
+
function issuerHostname(bound) {
|
|
56
|
+
const live = bound.filter((h) => h.status !== 'failed');
|
|
57
|
+
const active = live.filter((h) => h.status === 'active');
|
|
58
|
+
const pick = (hs) => hs.find((h) => h.surface === 'app' && h.canonical) ?? hs.find((h) => h.canonical) ?? hs[0];
|
|
59
|
+
return (pick(active) ?? pick(live))?.hostname;
|
|
60
|
+
}
|
|
61
|
+
const reasonOf = (e) => (e instanceof Error ? e.message : String(e));
|
|
62
|
+
/** Re-exported for the preview routes, which name a preview's callback on every row. */
|
|
63
|
+
export { oidcCallbackUrl };
|
|
64
|
+
/** Why a push left the login alone, as `preview create` reports it. */
|
|
65
|
+
function superseded(callbackUrl, why) {
|
|
66
|
+
return {
|
|
67
|
+
status: 'superseded',
|
|
68
|
+
callbackUrl,
|
|
69
|
+
note: `Sign-in: ${why} — a newer push owns this preview's login, so this push delivered none.`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Give a freshly bound preview its own client at the team auth-server its parent signs in
|
|
74
|
+
* with. Answers what it did; THROWS only when it minted a client and could not leave the
|
|
75
|
+
* preview with a working login — that is a failure, and `preview create` must not report it
|
|
76
|
+
* as success. The secret travels from the mint's answer into `deliver` and nowhere else.
|
|
77
|
+
*/
|
|
78
|
+
export async function wirePreviewAuth(deps, input) {
|
|
79
|
+
const callbackUrl = oidcCallbackUrl(input.previewHostname);
|
|
80
|
+
if (!input.parent) {
|
|
81
|
+
return {
|
|
82
|
+
status: 'not-applicable',
|
|
83
|
+
callbackUrl,
|
|
84
|
+
note: 'Sign-in: a clean-room preview forks no app, so it has no login to take after and none was delivered.',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const parent = input.parent;
|
|
88
|
+
const parentRedirectUris = [
|
|
89
|
+
...new Set((await deps.admin.listHostnames(deps.actor, { scopeId: parent.id }))
|
|
90
|
+
.filter((h) => h.status !== 'failed')
|
|
91
|
+
.map((h) => oidcCallbackUrl(h.hostname))),
|
|
92
|
+
].slice(0, MAX_PARENT_CALLBACKS);
|
|
93
|
+
const unregistered = (extra) => ({
|
|
94
|
+
status: 'unregistered',
|
|
95
|
+
callbackUrl,
|
|
96
|
+
note: `Sign-in: no team auth server of this team signs in the app this preview forks, so no client was minted ` +
|
|
97
|
+
`for it and no login config was delivered.${extra ? ` ${extra}` : ''} If the app signs in at an EXTERNAL ` +
|
|
98
|
+
`issuer, that issuer needs ${callbackUrl} registered as a redirect URI — and the preview still has no ` +
|
|
99
|
+
`login config, because an external client's credentials are never copied to a preview. If the app signs ` +
|
|
100
|
+
`in at one of your auth servers, open the dashboard's Apps list once (it registers existing installs ` +
|
|
101
|
+
`there) and re-run.`,
|
|
102
|
+
});
|
|
103
|
+
if (parentRedirectUris.length === 0)
|
|
104
|
+
return unregistered('The app it forks has no hostname to sign in at.');
|
|
105
|
+
// Ask every issuer of the tenant; mint only where exactly one claims.
|
|
106
|
+
const claims = [];
|
|
107
|
+
const problems = [];
|
|
108
|
+
for (const scope of await tenantIssuers(deps, input.tenantId)) {
|
|
109
|
+
const client = await deps.issuerClient(scope);
|
|
110
|
+
if (!client) {
|
|
111
|
+
problems.push({ issuerScopeId: scope.id, problem: 'its deployment could not be resolved' });
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const { claimed } = await client.checkPreviewClient({
|
|
116
|
+
tenantId: input.tenantId,
|
|
117
|
+
scopeId: scope.id,
|
|
118
|
+
parentScopeId: parent.id,
|
|
119
|
+
parentRedirectUris,
|
|
120
|
+
});
|
|
121
|
+
if (!claimed)
|
|
122
|
+
continue;
|
|
123
|
+
const hostname = issuerHostname(await deps.admin.listHostnames(deps.actor, { scopeId: scope.id }));
|
|
124
|
+
if (!hostname) {
|
|
125
|
+
problems.push({ issuerScopeId: scope.id, problem: 'it claims the app but has no hostname to be an issuer at' });
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
claims.push({ scope, client, hostname });
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
problems.push({ issuerScopeId: scope.id, problem: reasonOf(e) });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (claims.length > 1) {
|
|
135
|
+
return {
|
|
136
|
+
status: 'ambiguous',
|
|
137
|
+
callbackUrl,
|
|
138
|
+
issuers: claims.map((c) => ({ issuerScopeId: c.scope.id })),
|
|
139
|
+
note: `Sign-in: more than one of your auth servers claims the app this preview forks ` +
|
|
140
|
+
`(${claims.map((c) => c.scope.id).join(', ')}), so the platform wired none rather than guess. ` +
|
|
141
|
+
`Open the dashboard's Apps list once so each auth server learns which apps are its own, then re-run.`,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const claim = claims[0];
|
|
145
|
+
if (!claim) {
|
|
146
|
+
if (problems.length === 0)
|
|
147
|
+
return unregistered();
|
|
148
|
+
return {
|
|
149
|
+
status: 'unknown',
|
|
150
|
+
callbackUrl,
|
|
151
|
+
issuers: problems,
|
|
152
|
+
note: `Sign-in: not set up — ${problems.length === 1 ? 'an auth server' : 'some auth servers'} of this team ` +
|
|
153
|
+
`could not be asked: ${problems.map((p) => `${p.issuerScopeId}: ${p.problem}`).join('; ')}. None that could ` +
|
|
154
|
+
`be asked signs the app in. Fix that and re-run to give this preview its login.`,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const issuer = `https://${claim.hostname}`;
|
|
158
|
+
const address = { tenantId: input.tenantId, scopeId: claim.scope.id, previewScopeId: input.previewId };
|
|
159
|
+
const retireOwn = (minted) => claim.client.retirePreviewClients({ ...address, only: minted.clientId }).then(() => null, (e) => reasonOf(e));
|
|
160
|
+
const bound = async () => {
|
|
161
|
+
const rec = await deps.admin.getScopeRecord(deps.actor, input.tenantId, input.previewId);
|
|
162
|
+
if (!rec || rec.status !== 'active')
|
|
163
|
+
return 'gone';
|
|
164
|
+
return rec.verticalVersionId === input.versionId ? 'ours' : 'moved';
|
|
165
|
+
};
|
|
166
|
+
const reapedMeanwhile = async () => {
|
|
167
|
+
// The preview was reaped while this push ran: nothing may outlive it at the issuer.
|
|
168
|
+
await claim.client.retirePreviewClients(address).catch(() => undefined);
|
|
169
|
+
return superseded(callbackUrl, 'the preview was reaped while this push ran');
|
|
170
|
+
};
|
|
171
|
+
const noLogin = (why) => new ControlPlaneError(502, `preview '${input.tag}' was created but has NO working login: ${why}. Re-run \`preview create\` to retry.`);
|
|
172
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
173
|
+
const before = await bound();
|
|
174
|
+
if (before === 'gone')
|
|
175
|
+
return reapedMeanwhile();
|
|
176
|
+
if (before === 'moved')
|
|
177
|
+
return superseded(callbackUrl, 'another push re-bound the preview');
|
|
178
|
+
let minted;
|
|
179
|
+
try {
|
|
180
|
+
minted = await claim.client.mintPreviewClient({
|
|
181
|
+
...address,
|
|
182
|
+
parentScopeId: parent.id,
|
|
183
|
+
parentRedirectUris,
|
|
184
|
+
redirectUri: callbackUrl,
|
|
185
|
+
postLogoutRedirectUri: `https://${input.previewHostname}/`,
|
|
186
|
+
clientName: `${input.appName} (preview ${input.tag})`,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
catch (e) {
|
|
190
|
+
throw noLogin(`the auth server ${claim.scope.id} did not mint its client (${reasonOf(e)})`);
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
await input.deliver([
|
|
194
|
+
{
|
|
195
|
+
key: 'substrat:auth',
|
|
196
|
+
value: JSON.stringify({ mode: 'oidc', issuer, clientId: minted.clientId, clientSecret: minted.clientSecret }),
|
|
197
|
+
},
|
|
198
|
+
// A team auth-server is shared by construction (#1683): the preview accepts its OWN tokens only.
|
|
199
|
+
{ key: SHARED_ISSUER_CONFIG_KEY, value: 'true' },
|
|
200
|
+
]);
|
|
201
|
+
}
|
|
202
|
+
catch (e) {
|
|
203
|
+
const cleanup = await retireOwn(minted);
|
|
204
|
+
throw noLogin(`delivering its client failed (${reasonOf(e)})` +
|
|
205
|
+
(cleanup ? `, and removing that client failed too (${cleanup}) — the preview's reap removes it` : ''));
|
|
206
|
+
}
|
|
207
|
+
const after = await bound();
|
|
208
|
+
if (after !== 'ours') {
|
|
209
|
+
// Our client sits only in our own version's store, which is no longer served.
|
|
210
|
+
await retireOwn(minted);
|
|
211
|
+
return after === 'gone' ? reapedMeanwhile() : superseded(callbackUrl, 'another push re-bound the preview');
|
|
212
|
+
}
|
|
213
|
+
let retired;
|
|
214
|
+
try {
|
|
215
|
+
retired = await claim.client.retirePreviewClients({ ...address, keep: minted.clientId });
|
|
216
|
+
}
|
|
217
|
+
catch (e) {
|
|
218
|
+
// Delivered and bound: the login works. What is left is older clients, which the next
|
|
219
|
+
// push or the reap removes — said, not hidden.
|
|
220
|
+
return wired(claim.scope.id, issuer, minted.clientId, callbackUrl, ` Older clients of this preview could not be removed yet (${reasonOf(e)}); the next push or the reap removes them.`);
|
|
221
|
+
}
|
|
222
|
+
if (retired.kept === false)
|
|
223
|
+
continue; // our own client vanished while our version is bound
|
|
224
|
+
if ((await bound()) === 'gone')
|
|
225
|
+
return reapedMeanwhile();
|
|
226
|
+
return wired(claim.scope.id, issuer, minted.clientId, callbackUrl);
|
|
227
|
+
}
|
|
228
|
+
throw noLogin(`its client kept disappearing at the auth server ${claim.scope.id} (${MAX_ATTEMPTS} attempts)`);
|
|
229
|
+
}
|
|
230
|
+
function wired(issuerScopeId, issuer, clientId, callbackUrl, extra = '') {
|
|
231
|
+
return {
|
|
232
|
+
status: 'wired',
|
|
233
|
+
callbackUrl,
|
|
234
|
+
issuer,
|
|
235
|
+
issuerScopeId,
|
|
236
|
+
clientId,
|
|
237
|
+
note: `Sign-in: this preview has its own client at your auth server ${issuer} (client ${clientId}); it is deleted when the preview is reaped.${extra}`,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Delete every client minted for a preview, at every auth-server of its tenant — the reap's
|
|
242
|
+
* half, run BEFORE the preview's storage and row go, so a failure leaves a preview a retry can
|
|
243
|
+
* still find. An auth-server that predates preview clients cannot have minted one and is
|
|
244
|
+
* skipped; any other failure throws.
|
|
245
|
+
*/
|
|
246
|
+
export async function retireAllPreviewClients(deps, tenantId, previewScopeId) {
|
|
247
|
+
const deleted = [];
|
|
248
|
+
for (const scope of await tenantIssuers(deps, tenantId)) {
|
|
249
|
+
const client = await deps.issuerClient(scope);
|
|
250
|
+
if (!client)
|
|
251
|
+
throw new ControlPlaneError(502, `the auth server ${scope.id} could not be reached to delete preview ${previewScopeId}'s clients`);
|
|
252
|
+
try {
|
|
253
|
+
deleted.push(...(await client.retirePreviewClients({ tenantId, scopeId: scope.id, previewScopeId })).deleted);
|
|
254
|
+
}
|
|
255
|
+
catch (e) {
|
|
256
|
+
if (e instanceof ControlPlaneError && e.status === 501)
|
|
257
|
+
continue;
|
|
258
|
+
throw e;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return deleted;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* The reap's half for ANY scope about to go, as the platform sweep's expiry GC sees it: a
|
|
265
|
+
* preview fork's clients are retired, and anything else — a snapshot, a clean room — has none
|
|
266
|
+
* and is left alone. One predicate for the interactive reap and the sweep, so they agree.
|
|
267
|
+
*/
|
|
268
|
+
export async function retireClientsOfReapedScope(deps, scope) {
|
|
269
|
+
if (!scope || scope.kind !== 'preview' || !scope.forkedFrom)
|
|
270
|
+
return [];
|
|
271
|
+
return retireAllPreviewClients(deps, scope.tenantId, scope.id);
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=preview-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-auth.js","sourceRoot":"","sources":["../src/preview-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
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';
|
|
1
|
+
import type { AttachmentRecord, ConnectionId, EntityRef, EntitlementGrant, ModuleId, PermissionKey, PlatformRequest, PlatformRequestFilter, PlatformRequestId, PlatformRequestStatus, PlatformRequestFailure, MintedPreviewClient, PreviewClientCheck, PreviewClientClaim, PreviewClientMint, PreviewClientRetire, PrincipalId, RetiredPreviewClients, PeerGrantsEntry, PeerSwitchOutcome, SystemSwitchOutcome, SystemScheduleEntry, 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
2
|
import type { OpenedAttachment, UndrainedEvents } from '@substrat-run/kernel';
|
|
3
3
|
/**
|
|
4
4
|
* The platform's client for calling a VERTICAL (K-31).
|
|
@@ -355,6 +355,69 @@ export declare class VerticalClient {
|
|
|
355
355
|
moduleId: ModuleId;
|
|
356
356
|
to: 'on' | 'off';
|
|
357
357
|
}): Promise<SystemSwitchOutcome>;
|
|
358
|
+
/**
|
|
359
|
+
* The read half of the schedule kill switch's status (#1674): every module the
|
|
360
|
+
* deployment serving this scope holds or has held system authority for, and where each
|
|
361
|
+
* stands. Mirrors `systemSwitch`'s seam and its skew rule exactly (#1666's "only the
|
|
362
|
+
* explicit legacy signal reads as redeploy"): a 404 (the route does not exist) or an SPA
|
|
363
|
+
* shell (a 200 that is not JSON) are the deployment's own proof it predates this read,
|
|
364
|
+
* and become a 501 that says so. A 200 of the wrong-shaped JSON is NOT that proof — it
|
|
365
|
+
* is a failure this client cannot explain, so it surfaces as the 502 it is rather than a
|
|
366
|
+
* guess at "redeploy". The far end's own 501 (the route exists, the method doesn't)
|
|
367
|
+
* passes through `refusal` verbatim, unchanged either way.
|
|
368
|
+
*/
|
|
369
|
+
systemGrantsStatus(input: {
|
|
370
|
+
scopeId: ScopeId;
|
|
371
|
+
}): Promise<SystemScheduleEntry[]>;
|
|
372
|
+
/**
|
|
373
|
+
* The read half of the peer kill switch's status (#1706): every peer the deployment
|
|
374
|
+
* serving this scope holds or has held grants for, and where each stands. Mirrors
|
|
375
|
+
* `peerSwitch`'s seam and `systemGrantsStatus`'s skew rule exactly — a 404 or an SPA
|
|
376
|
+
* shell are the deployment's own proof it predates this read and become a 501 that says
|
|
377
|
+
* to redeploy; a wrong-shaped 200 is not that proof and surfaces as the 502 it is.
|
|
378
|
+
*/
|
|
379
|
+
peerGrantsStatus(input: {
|
|
380
|
+
scopeId: ScopeId;
|
|
381
|
+
}): Promise<PeerGrantsEntry[]>;
|
|
382
|
+
/**
|
|
383
|
+
* Move one PEER's kill switch in the deployment serving the scope (#1706) — the far end
|
|
384
|
+
* of `revokeFromPeer` / `restoreToPeer` for a hosted scope, whose `vertical:<slug>` grants
|
|
385
|
+
* live there and nowhere the shared control plane can reach.
|
|
386
|
+
*
|
|
387
|
+
* The seam, the skew rule and the honesty rule are `systemSwitch`'s, for the same reasons:
|
|
388
|
+
* a **404** (no such route) or an **SPA shell** (a 200 that is not JSON) are the
|
|
389
|
+
* deployment's own proof that it predates this route and therefore cannot have switched
|
|
390
|
+
* anything — the route itself answers a peer the scope holds nothing for with a 200
|
|
391
|
+
* `held: false`, never a 404. Everything else surfaces as the failure it is, because the
|
|
392
|
+
* request may have landed and the switch may have moved before the answer was lost.
|
|
393
|
+
*/
|
|
394
|
+
peerSwitch(input: {
|
|
395
|
+
scopeId: ScopeId;
|
|
396
|
+
vertical: string;
|
|
397
|
+
to: 'on' | 'off';
|
|
398
|
+
}): Promise<PeerSwitchOutcome>;
|
|
399
|
+
/**
|
|
400
|
+
* A preview's own client at a team auth-server (#1704, `@substrat-run/contracts`'
|
|
401
|
+
* `preview-client.ts`): does the parent sign in at THIS issuer, mint the preview a client
|
|
402
|
+
* here, delete the preview's clients. Addressed to the ISSUER's deployment (this client),
|
|
403
|
+
* never the preview's.
|
|
404
|
+
*
|
|
405
|
+
* The skew rule is `systemSwitch`'s, widened by one status: a deployment built before these
|
|
406
|
+
* routes answers its `/internal/*` fallback — a JSON **501** on the auth-server — or a
|
|
407
|
+
* **404**, or an SPA shell (a 200 that is not JSON). All three are the deployment's own
|
|
408
|
+
* proof it cannot have acted, and become a 501 that says to redeploy the auth server. The
|
|
409
|
+
* caller must never read that as "the parent does not sign in here". A 200 of the wrong
|
|
410
|
+
* shape is not that proof and surfaces as a 502; a refusal (403 another tenant's issuer,
|
|
411
|
+
* 409 a parent it does not claim) passes through verbatim.
|
|
412
|
+
*
|
|
413
|
+
* The mint's answer carries a client SECRET. It is returned to the caller and nothing here
|
|
414
|
+
* keeps, logs or quotes it: no error message on this path includes a response body that
|
|
415
|
+
* could hold one.
|
|
416
|
+
*/
|
|
417
|
+
checkPreviewClient(input: PreviewClientCheck): Promise<PreviewClientClaim>;
|
|
418
|
+
mintPreviewClient(input: PreviewClientMint): Promise<MintedPreviewClient>;
|
|
419
|
+
retirePreviewClients(input: PreviewClientRetire): Promise<RetiredPreviewClients>;
|
|
420
|
+
private previewClientCall;
|
|
358
421
|
/** Journal a platform-request outcome back in the vertical after the platform ran it. */
|
|
359
422
|
settlePlatformRequest(tenantId: TenantId, scopeId: ScopeId, id: PlatformRequestId, outcome: {
|
|
360
423
|
status: PlatformRequestStatus;
|
|
@@ -509,6 +572,23 @@ export declare class VerticalClient {
|
|
|
509
572
|
*/
|
|
510
573
|
private parseInternal;
|
|
511
574
|
/** A platform-authenticated POST to the vertical's `/internal/*` surface. */
|
|
575
|
+
/**
|
|
576
|
+
* Invoke ONE operation on this deployment as a PEER vertical (#1706) — the far end of an
|
|
577
|
+
* asynchronous peer call, whose caller the platform took from the scope it drained the
|
|
578
|
+
* intent from. The door at the other end admits it (declared peer, switch on, operation
|
|
579
|
+
* allowlisted) and every check inside runs as `{ vertical, scope }`.
|
|
580
|
+
*/
|
|
581
|
+
verticalInvoke(input: {
|
|
582
|
+
caller: {
|
|
583
|
+
vertical: string;
|
|
584
|
+
scope: ScopeId;
|
|
585
|
+
};
|
|
586
|
+
tenantId: TenantId;
|
|
587
|
+
scopeId: ScopeId;
|
|
588
|
+
operation: string;
|
|
589
|
+
input?: unknown;
|
|
590
|
+
idempotencyKey?: string;
|
|
591
|
+
}): Promise<unknown>;
|
|
512
592
|
private postInternal;
|
|
513
593
|
/** A platform-authenticated GET to the vertical's `/internal/*` surface. */
|
|
514
594
|
private getInternal;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vertical-client.d.ts","sourceRoot":"","sources":["../src/vertical-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EAEZ,SAAS,EACT,gBAAgB,EAChB,QAAQ,EACR,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,WAAW,EACX,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,SAAS,EACT,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,IAAI,EACJ,cAAc,EACd,OAAO,EACP,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,QAAQ,EACR,iBAAiB,EACjB,UAAU,EACX,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"vertical-client.d.ts","sourceRoot":"","sources":["../src/vertical-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EAEZ,SAAS,EACT,gBAAgB,EAChB,QAAQ,EACR,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,WAAW,EACX,qBAAqB,EACrB,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,SAAS,EACT,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,IAAI,EACJ,cAAc,EACd,OAAO,EACP,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,QAAQ,EACR,iBAAiB,EACjB,UAAU,EACX,MAAM,yBAAyB,CAAC;AAejC,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAiB,MAAM,sBAAsB,CAAC;AAiB7F;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,wDAAwD;IACxD,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAClC;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACxC;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC9C;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAC1C;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,sBAAsB;IACrC;8FAC0F;IAC1F,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,6EAA6E;IAC7E,OAAO,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAgCD,MAAM,WAAW,sBAAsB;IACrC;iGAC6F;IAC7F,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB;;uEAEmE;IACnE,YAAY,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAClC;;2DAEuD;IACvD,aAAa,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACxC;;;gEAG4D;IAC5D,gBAAgB,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC9C;;;wEAGoE;IACpE,cAAc,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAC1C;;;;8EAI0E;IAC1E,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACpC;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,qBAAqB,EAAE,EAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,OAAO,EAAE,OAAO,GACf,wBAAwB,EAAE,CAS5B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,gGAAgG;IAChG,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,OAAO;IAApC,YAA6B,OAAO,EAAE,qBAAqB,EAAI;IAE/D;;;;;;OAMG;IACG,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAwBnF;IAED;;;;;;;OAOG;IACG,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpE;IAED;;;;;;;;OAQG;IACG,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAElF;IAED;;;;;;;OAOG;IACG,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAE7D;IAED,mDAAmD;IAC7C,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,CAAC,CAS1F;IAED;;;;;;OAMG;IACG,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEpF;IAED;;;;;;OAMG;IACG,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAEtF;IAED,wFAAwF;IAClF,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAItF;IAED;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAGxE;IAED;;;;;;OAMG;IACG,cAAc,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAE7G;IAED;;;;;OAKG;IACG,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAG3F;IAED;;;;;OAKG;IACG,0BAA0B,CAC9B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,eAAe,EAAE,CAAC,CAM5B;IAED;;;;;;OAMG;IACG,eAAe,CAAC,KAAK,EAAE;QAC3B,YAAY,EAAE,YAAY,CAAC;QAC3B,QAAQ,EAAE,QAAQ,CAAC;QACnB,OAAO,EAAE,OAAO,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnB;IAED;;;;OAIG;IACG,yBAAyB,CAAC,KAAK,EAAE;QACrC,YAAY,EAAE,YAAY,CAAC;QAC3B,QAAQ,EAAE,QAAQ,CAAC;QACnB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,SAAS,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,UAAU,CAAC;QACvB,IAAI,EAAE,UAAU,CAAC;KAClB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgB5B;IAED;;;;;;;;;;OAUG;IACG,uBAAuB,CAAC,KAAK,EAAE;QACnC,YAAY,EAAE,YAAY,CAAC;QAC3B,QAAQ,EAAE,QAAQ,CAAC;QACnB,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB;;;;WAIG;QACH,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAiCnC;IAED;;;;OAIG;IACG,cAAc,CAAC,KAAK,EAAE;QAC1B,YAAY,EAAE,YAAY,CAAC;QAC3B,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,EAAE,aAAa,CAAC;QAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhB;IAED;;;;;;;;;;;;;;;OAeG;IACG,YAAY,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,QAAQ,CAAC;QAAC,EAAE,EAAE,IAAI,GAAG,KAAK,CAAA;KAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAkClH;IAED;;;;;;;;;;OAUG;IACG,kBAAkB,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAgCpF;IAED;;;;;;OAMG;IACG,gBAAgB,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CA6B9E;IAED;;;;;;;;;;;OAWG;IACG,UAAU,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,IAAI,GAAG,KAAK,CAAA;KAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAkC5G;IAED;;;;;;;;;;;;;;;;;OAiBG;IACG,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAE/E;IAEK,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAE9E;IAEK,oBAAoB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAErF;YAEa,iBAAiB;IAsC/B,yFAAyF;IACnF,qBAAqB,CACzB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,iBAAiB,EACrB,OAAO,EAAE;QACP,MAAM,EAAE,qBAAqB,CAAC;QAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,OAAO,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;KACzC,GACA,OAAO,CAAC,IAAI,CAAC,CAMf;IAED;;;;;OAKG;IACG,aAAa,CAAC,KAAK,EAAE;QACzB,aAAa,EAAE,OAAO,CAAC;QACvB,UAAU,EAAE,OAAO,CAAC;KACrB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAE9B;IAED;;;;;OAKG;IACG,WAAW,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5D;IAED;;;;;OAKG;IACG,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAI7D;IAED;;;;;;;;;OASG;IACG,YAAY,CAChB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,cAAc,EAAE,GACvB,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAE7B;IAED,yFAAyF;IACnF,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CASrF;IAED,6FAA6F;IACvF,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAI9E;IAED,iFAAiF;IAC3E,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAInF;IAED,sFAAsF;IAChF,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAIhG;IAED,sFAAsF;IAChF,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAKtF;IAED,6GAA6G;IACvG,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAS5F;IAED;;;;;;;;OAQG;IACG,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAM/E;IAED;;;;OAIG;IACG,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOzG;IAED;;;;;;;;;;OAUG;IACG,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBjG;IAED;;;OAGG;IACG,iBAAiB,CACrB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC,CAI5E;IAED;;;;OAIG;IACG,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAQpD;IAED;;;;OAIG;IACG,kBAAkB,CACtB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC,CAIrE;IAED;;;;;OAKG;IACG,WAAW,CACf,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GACzB,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAMlC;IAED;;;;;;;OAOG;YACW,KAAK;IASnB;;;;;;;;;;OAUG;YACW,OAAO;IAmBrB;;;;;;OAMG;YACW,aAAa;IAa3B,6EAA6E;IAC7E;;;;;OAKG;IACG,cAAc,CAAC,KAAK,EAAE;QAC1B,MAAM,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,OAAO,CAAA;SAAE,CAAC;QAC7C,QAAQ,EAAE,QAAQ,CAAC;QACnB,OAAO,EAAE,OAAO,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,GAAG,OAAO,CAAC,OAAO,CAAC,CAcnB;YAEa,YAAY;IAgB1B,4EAA4E;YAC9D,WAAW;CAU1B"}
|
package/dist/vertical-client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { attachmentRecord, denialFilterParams, ownerSeat, ownerClaimLink, systemSwitchOutcome, } from '@substrat-run/contracts';
|
|
1
|
+
import { PREVIEW_CLIENT_PATH, attachmentRecord, denialFilterParams, mintedPreviewClient, ownerSeat, ownerClaimLink, previewClientClaim, retiredPreviewClients, peerGrantsEntry, peerSwitchOutcome, systemSwitchOutcome, systemScheduleEntry, } from '@substrat-run/contracts';
|
|
2
2
|
import { CONNECTOR_ATTACHMENT_RECORD_HEADER, PLATFORM_SECRET_HEADER, undrainedEventsOf } from '@substrat-run/kernel';
|
|
3
3
|
import { ControlPlaneError } from './client.js';
|
|
4
4
|
/**
|
|
@@ -338,6 +338,173 @@ export class VerticalClient {
|
|
|
338
338
|
}
|
|
339
339
|
return parsed.data;
|
|
340
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* The read half of the schedule kill switch's status (#1674): every module the
|
|
343
|
+
* deployment serving this scope holds or has held system authority for, and where each
|
|
344
|
+
* stands. Mirrors `systemSwitch`'s seam and its skew rule exactly (#1666's "only the
|
|
345
|
+
* explicit legacy signal reads as redeploy"): a 404 (the route does not exist) or an SPA
|
|
346
|
+
* shell (a 200 that is not JSON) are the deployment's own proof it predates this read,
|
|
347
|
+
* and become a 501 that says so. A 200 of the wrong-shaped JSON is NOT that proof — it
|
|
348
|
+
* is a failure this client cannot explain, so it surfaces as the 502 it is rather than a
|
|
349
|
+
* guess at "redeploy". The far end's own 501 (the route exists, the method doesn't)
|
|
350
|
+
* passes through `refusal` verbatim, unchanged either way.
|
|
351
|
+
*/
|
|
352
|
+
async systemGrantsStatus(input) {
|
|
353
|
+
const verb = 'system-grants';
|
|
354
|
+
const predates = () => new ControlPlaneError(501, `the deployment serving scope ${input.scopeId} predates the schedule switch's status read (#1674) — ` +
|
|
355
|
+
`redeploy the vertical, then retry.`);
|
|
356
|
+
const base = this.options.baseUrl ?? 'https://vertical.invalid';
|
|
357
|
+
const res = await this.reach(verb, () => this.options.fetch(`${base}/internal/system-grants?scopeId=${encodeURIComponent(input.scopeId)}`, {
|
|
358
|
+
method: 'GET',
|
|
359
|
+
headers: { [PLATFORM_SECRET_HEADER]: this.options.platformSecret },
|
|
360
|
+
}));
|
|
361
|
+
if (res.status === 404)
|
|
362
|
+
throw predates();
|
|
363
|
+
if (!res.ok)
|
|
364
|
+
throw await this.refusal(verb, res);
|
|
365
|
+
const text = await res.text();
|
|
366
|
+
let raw;
|
|
367
|
+
try {
|
|
368
|
+
raw = JSON.parse(text);
|
|
369
|
+
}
|
|
370
|
+
catch {
|
|
371
|
+
throw predates();
|
|
372
|
+
}
|
|
373
|
+
const parsed = systemScheduleEntry.array().safeParse(raw);
|
|
374
|
+
if (!parsed.success) {
|
|
375
|
+
throw new ControlPlaneError(502, `vertical answered ${verb} with an unexpected shape for scope ${input.scopeId}.`);
|
|
376
|
+
}
|
|
377
|
+
return parsed.data;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* The read half of the peer kill switch's status (#1706): every peer the deployment
|
|
381
|
+
* serving this scope holds or has held grants for, and where each stands. Mirrors
|
|
382
|
+
* `peerSwitch`'s seam and `systemGrantsStatus`'s skew rule exactly — a 404 or an SPA
|
|
383
|
+
* shell are the deployment's own proof it predates this read and become a 501 that says
|
|
384
|
+
* to redeploy; a wrong-shaped 200 is not that proof and surfaces as the 502 it is.
|
|
385
|
+
*/
|
|
386
|
+
async peerGrantsStatus(input) {
|
|
387
|
+
const verb = 'peer-grants';
|
|
388
|
+
const predates = () => new ControlPlaneError(501, `the deployment serving scope ${input.scopeId} predates the peer switch's status read (#1706) — ` +
|
|
389
|
+
`redeploy the vertical, then retry.`);
|
|
390
|
+
const base = this.options.baseUrl ?? 'https://vertical.invalid';
|
|
391
|
+
const res = await this.reach(verb, () => this.options.fetch(`${base}/internal/peer-grants?scopeId=${encodeURIComponent(input.scopeId)}`, {
|
|
392
|
+
method: 'GET',
|
|
393
|
+
headers: { [PLATFORM_SECRET_HEADER]: this.options.platformSecret },
|
|
394
|
+
}));
|
|
395
|
+
if (res.status === 404)
|
|
396
|
+
throw predates();
|
|
397
|
+
if (!res.ok)
|
|
398
|
+
throw await this.refusal(verb, res);
|
|
399
|
+
const text = await res.text();
|
|
400
|
+
let raw;
|
|
401
|
+
try {
|
|
402
|
+
raw = JSON.parse(text);
|
|
403
|
+
}
|
|
404
|
+
catch {
|
|
405
|
+
throw predates();
|
|
406
|
+
}
|
|
407
|
+
const parsed = peerGrantsEntry.array().safeParse(raw);
|
|
408
|
+
if (!parsed.success) {
|
|
409
|
+
throw new ControlPlaneError(502, `vertical answered ${verb} with an unexpected shape for scope ${input.scopeId}.`);
|
|
410
|
+
}
|
|
411
|
+
return parsed.data;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Move one PEER's kill switch in the deployment serving the scope (#1706) — the far end
|
|
415
|
+
* of `revokeFromPeer` / `restoreToPeer` for a hosted scope, whose `vertical:<slug>` grants
|
|
416
|
+
* live there and nowhere the shared control plane can reach.
|
|
417
|
+
*
|
|
418
|
+
* The seam, the skew rule and the honesty rule are `systemSwitch`'s, for the same reasons:
|
|
419
|
+
* a **404** (no such route) or an **SPA shell** (a 200 that is not JSON) are the
|
|
420
|
+
* deployment's own proof that it predates this route and therefore cannot have switched
|
|
421
|
+
* anything — the route itself answers a peer the scope holds nothing for with a 200
|
|
422
|
+
* `held: false`, never a 404. Everything else surfaces as the failure it is, because the
|
|
423
|
+
* request may have landed and the switch may have moved before the answer was lost.
|
|
424
|
+
*/
|
|
425
|
+
async peerSwitch(input) {
|
|
426
|
+
const verb = 'peer-switch';
|
|
427
|
+
const predates = () => new ControlPlaneError(501, `the deployment serving scope ${input.scopeId} predates the peer kill switch (#1706) — ` +
|
|
428
|
+
`redeploy the vertical, then retry. Nothing was switched.`);
|
|
429
|
+
const base = this.options.baseUrl ?? 'https://vertical.invalid';
|
|
430
|
+
const res = await this.reach(verb, () => this.options.fetch(`${base}/internal/peer-switch`, {
|
|
431
|
+
method: 'POST',
|
|
432
|
+
headers: { 'content-type': 'application/json', [PLATFORM_SECRET_HEADER]: this.options.platformSecret },
|
|
433
|
+
body: JSON.stringify(input),
|
|
434
|
+
}));
|
|
435
|
+
if (res.status === 404)
|
|
436
|
+
throw predates();
|
|
437
|
+
if (!res.ok)
|
|
438
|
+
throw await this.refusal(verb, res);
|
|
439
|
+
const text = await res.text();
|
|
440
|
+
let raw;
|
|
441
|
+
try {
|
|
442
|
+
raw = JSON.parse(text);
|
|
443
|
+
}
|
|
444
|
+
catch {
|
|
445
|
+
throw predates();
|
|
446
|
+
}
|
|
447
|
+
const parsed = peerSwitchOutcome.safeParse(raw);
|
|
448
|
+
if (!parsed.success) {
|
|
449
|
+
throw new ControlPlaneError(502, `vertical answered ${verb} with an unexpected shape — the switch for peer '${input.vertical}' on ` +
|
|
450
|
+
`scope ${input.scopeId} may or may not have moved. Confirm its position before retrying.`);
|
|
451
|
+
}
|
|
452
|
+
return parsed.data;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* A preview's own client at a team auth-server (#1704, `@substrat-run/contracts`'
|
|
456
|
+
* `preview-client.ts`): does the parent sign in at THIS issuer, mint the preview a client
|
|
457
|
+
* here, delete the preview's clients. Addressed to the ISSUER's deployment (this client),
|
|
458
|
+
* never the preview's.
|
|
459
|
+
*
|
|
460
|
+
* The skew rule is `systemSwitch`'s, widened by one status: a deployment built before these
|
|
461
|
+
* routes answers its `/internal/*` fallback — a JSON **501** on the auth-server — or a
|
|
462
|
+
* **404**, or an SPA shell (a 200 that is not JSON). All three are the deployment's own
|
|
463
|
+
* proof it cannot have acted, and become a 501 that says to redeploy the auth server. The
|
|
464
|
+
* caller must never read that as "the parent does not sign in here". A 200 of the wrong
|
|
465
|
+
* shape is not that proof and surfaces as a 502; a refusal (403 another tenant's issuer,
|
|
466
|
+
* 409 a parent it does not claim) passes through verbatim.
|
|
467
|
+
*
|
|
468
|
+
* The mint's answer carries a client SECRET. It is returned to the caller and nothing here
|
|
469
|
+
* keeps, logs or quotes it: no error message on this path includes a response body that
|
|
470
|
+
* could hold one.
|
|
471
|
+
*/
|
|
472
|
+
async checkPreviewClient(input) {
|
|
473
|
+
return this.previewClientCall('POST', `${PREVIEW_CLIENT_PATH}/check`, input, previewClientClaim, 'preview-client check', input.scopeId);
|
|
474
|
+
}
|
|
475
|
+
async mintPreviewClient(input) {
|
|
476
|
+
return this.previewClientCall('POST', PREVIEW_CLIENT_PATH, input, mintedPreviewClient, 'preview-client mint', input.scopeId);
|
|
477
|
+
}
|
|
478
|
+
async retirePreviewClients(input) {
|
|
479
|
+
return this.previewClientCall('DELETE', PREVIEW_CLIENT_PATH, input, retiredPreviewClients, 'preview-client retire', input.scopeId);
|
|
480
|
+
}
|
|
481
|
+
async previewClientCall(method, path, body, schema, verb, issuerScopeId) {
|
|
482
|
+
const predates = () => new ControlPlaneError(501, `the auth server serving scope ${issuerScopeId} predates preview clients (#1704) — redeploy it, ` +
|
|
483
|
+
`then re-run. Nothing was minted or deleted there.`);
|
|
484
|
+
const base = this.options.baseUrl ?? 'https://vertical.invalid';
|
|
485
|
+
const res = await this.reach(verb, () => this.options.fetch(`${base}${path}`, {
|
|
486
|
+
method,
|
|
487
|
+
headers: { 'content-type': 'application/json', [PLATFORM_SECRET_HEADER]: this.options.platformSecret },
|
|
488
|
+
body: JSON.stringify(body),
|
|
489
|
+
}));
|
|
490
|
+
if (res.status === 404 || res.status === 501)
|
|
491
|
+
throw predates();
|
|
492
|
+
if (!res.ok)
|
|
493
|
+
throw await this.refusal(verb, res);
|
|
494
|
+
const text = await res.text();
|
|
495
|
+
let raw;
|
|
496
|
+
try {
|
|
497
|
+
raw = JSON.parse(text);
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
throw predates();
|
|
501
|
+
}
|
|
502
|
+
const parsed = schema.safeParse(raw);
|
|
503
|
+
if (!parsed.success) {
|
|
504
|
+
throw new ControlPlaneError(502, `auth server answered ${verb} with an unexpected shape for scope ${issuerScopeId}.`);
|
|
505
|
+
}
|
|
506
|
+
return parsed.data;
|
|
507
|
+
}
|
|
341
508
|
/** Journal a platform-request outcome back in the vertical after the platform ran it. */
|
|
342
509
|
async settlePlatformRequest(tenantId, scopeId, id, outcome) {
|
|
343
510
|
await this.postInternal('/internal/platform-requests/settle', { tenantId, scopeId, id, ...outcome }, 'settle-platform-request');
|
|
@@ -587,6 +754,23 @@ export class VerticalClient {
|
|
|
587
754
|
}
|
|
588
755
|
}
|
|
589
756
|
/** A platform-authenticated POST to the vertical's `/internal/*` surface. */
|
|
757
|
+
/**
|
|
758
|
+
* Invoke ONE operation on this deployment as a PEER vertical (#1706) — the far end of an
|
|
759
|
+
* asynchronous peer call, whose caller the platform took from the scope it drained the
|
|
760
|
+
* intent from. The door at the other end admits it (declared peer, switch on, operation
|
|
761
|
+
* allowlisted) and every check inside runs as `{ vertical, scope }`.
|
|
762
|
+
*/
|
|
763
|
+
async verticalInvoke(input) {
|
|
764
|
+
const { result } = await this.postInternal('/internal/vertical-invoke', {
|
|
765
|
+
caller: input.caller,
|
|
766
|
+
tenantId: input.tenantId,
|
|
767
|
+
scopeId: input.scopeId,
|
|
768
|
+
operation: input.operation,
|
|
769
|
+
...(input.input === undefined ? {} : { input: input.input }),
|
|
770
|
+
...(input.idempotencyKey === undefined ? {} : { idempotencyKey: input.idempotencyKey }),
|
|
771
|
+
}, 'peer call');
|
|
772
|
+
return result;
|
|
773
|
+
}
|
|
590
774
|
async postInternal(path, body, verb) {
|
|
591
775
|
const base = this.options.baseUrl ?? 'https://vertical.invalid';
|
|
592
776
|
const res = await this.reach(verb, () => this.options.fetch(`${base}${path}`, {
|