@substrat-run/control-plane-api 0.62.0 → 0.64.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 +50 -3
- package/dist/api.js.map +1 -1
- package/dist/connection-relay.d.ts +15 -2
- package/dist/connection-relay.d.ts.map +1 -1
- package/dist/connection-relay.js +19 -1
- package/dist/connection-relay.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +20 -0
- package/dist/errors.js.map +1 -1
- package/dist/platform-drain.d.ts.map +1 -1
- package/dist/platform-drain.js +32 -2
- package/dist/platform-drain.js.map +1 -1
- package/dist/vertical-client.d.ts +8 -1
- package/dist/vertical-client.d.ts.map +1 -1
- package/dist/vertical-client.js +16 -0
- package/dist/vertical-client.js.map +1 -1
- package/package.json +6 -6
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
-
import { adminAction, ASSET_PART_PREFIX, assetHash, channelName, connectionActivity, connectionActivitySource, connectionCredential, connectionFilter, connectionProbe, createTenantInput, entitlementGrantInput, hostname as hostnameSchema, hostnameRegion, hostnameStatus, identityLink, listPageQuery, pageOf, principalId as principalIdSchema, promotionAcknowledgement, provisionableJurisdiction, publishVersionInput, queryScopeInput, readScopeTableInput, registerVerticalInput, scopeDump, dataSubjectId as dataSubjectIdSchema, scopeId as scopeIdSchema, scopeStatus, storageShape, surfaceName, tenantId as tenantIdSchema, tenantStatus, versionOrigin, z, } from '@substrat-run/contracts';
|
|
2
|
+
import { adminAction, ASSET_PART_PREFIX, assetHash, channelName, connectionActivity, connectionActivitySource, connectionCredential, connectionFilter, connectionProbe, createTenantInput, entitlementGrantInput, hostname as hostnameSchema, hostnameRegion, hostnameStatus, identityLink, listPageQuery, pageOf, platformRequestFilter, principalId as principalIdSchema, promotionAcknowledgement, provisionableJurisdiction, publishVersionInput, queryScopeInput, readScopeTableInput, registerVerticalInput, scopeDump, dataSubjectId as dataSubjectIdSchema, scopeId as scopeIdSchema, scopeStatus, storageShape, surfaceName, tenantId as tenantIdSchema, tenantStatus, versionOrigin, z, } from '@substrat-run/contracts';
|
|
3
3
|
import { migrationProgress, ulid } from '@substrat-run/kernel';
|
|
4
4
|
import { TENANT_HEADER } from './auth.js';
|
|
5
5
|
import { connectionGrantsForScope } from './vertical-client.js';
|
|
@@ -338,6 +338,9 @@ export function createControlPlaneApi(options) {
|
|
|
338
338
|
{ method: 'GET', re: /\/scopes$/ },
|
|
339
339
|
{ method: 'GET', re: /\/tenants\/[^/]+\/scopes\/[^/]+$/ },
|
|
340
340
|
{ method: 'GET', re: /\/tenants\/[^/]+\/scopes\/[^/]+\/health$/ },
|
|
341
|
+
// The scope's platform-intent journal (#618) — "why did my connector fail?", answered
|
|
342
|
+
// without the read-only SQL console. Tenant-narrowed in the handler like the health read.
|
|
343
|
+
{ method: 'GET', re: /\/tenants\/[^/]+\/scopes\/[^/]+\/intents$/ },
|
|
341
344
|
// Add a SIBLING scope (a new "site") to an app the builder's own tenant already runs
|
|
342
345
|
// (multi-scope self-serve, M1). Tenant-narrowed + parent-authorized in the handler; the
|
|
343
346
|
// allowlist alone is not authz.
|
|
@@ -430,7 +433,9 @@ export function createControlPlaneApi(options) {
|
|
|
430
433
|
// threw either. That left every unmapped failure (e.g. a raw SQLite constraint from a
|
|
431
434
|
// registry write, or a deploy that 500s with no detail) undiagnosable without reproducing
|
|
432
435
|
// it. Log the real error + the request that provoked it, server-side only, so the worker
|
|
433
|
-
// tail names the cause. Mapped 4xx are honest refusals — no log needed.
|
|
436
|
+
// tail names the cause. Mapped 4xx are honest refusals — no log needed. A MAPPED 5xx
|
|
437
|
+
// (the 503 for a plane with no seal key, #603) passes through here too: its body already
|
|
438
|
+
// says what is wrong, and the tail line is what ties it to the request that hit it.
|
|
434
439
|
if (status >= 500) {
|
|
435
440
|
console.error('control-plane.unhandled', {
|
|
436
441
|
method: c.req.method,
|
|
@@ -653,11 +658,15 @@ export function createControlPlaneApi(options) {
|
|
|
653
658
|
return c.json(await relayConnectionUpsert(host, c.get('actor'), { ...body, tenantId }, { probeCandidate }));
|
|
654
659
|
}
|
|
655
660
|
catch (err) {
|
|
656
|
-
if (err instanceof ConnectionRelayError) {
|
|
661
|
+
if (err instanceof ConnectionRelayError && err.status < 500) {
|
|
657
662
|
// A refusal carries the provider's own answer, so a console can show WHY rather
|
|
658
663
|
// than "save failed" — the whole point of checking before writing.
|
|
659
664
|
return c.json({ error: err.message, ...(err.probe ? { probe: err.probe } : {}) }, err.status);
|
|
660
665
|
}
|
|
666
|
+
// A 5xx relay refusal (#603: this deployment holds no seal key) is the PLATFORM
|
|
667
|
+
// failing, not the caller — rethrown so the shared boundary maps it (still a 503
|
|
668
|
+
// with this message) and records the ops-failure row a console can list. Answering
|
|
669
|
+
// it here would leave the operator's screen as the only place it was ever seen.
|
|
661
670
|
throw err;
|
|
662
671
|
}
|
|
663
672
|
});
|
|
@@ -1145,6 +1154,44 @@ export function createControlPlaneApi(options) {
|
|
|
1145
1154
|
roleProjectionEmpty,
|
|
1146
1155
|
});
|
|
1147
1156
|
});
|
|
1157
|
+
/**
|
|
1158
|
+
* **A scope's platform-intent journal** (#618) — what the vertical asked the platform to do,
|
|
1159
|
+
* and what came back.
|
|
1160
|
+
*
|
|
1161
|
+
* The gap this closes: a connector delivery routed as a `connector:<provider>` intent journals
|
|
1162
|
+
* the provider's full refusal in `last_error`, correctly and durably — inside the scope's own
|
|
1163
|
+
* DO, in the vertical's deployment, where the only readers were the read-only SQL console with
|
|
1164
|
+
* system tables toggled on and a break-glass `scope pull --full`. A connection card could say
|
|
1165
|
+
* "HTTP 409 from scrive" and nothing more, while the nine words that were the entire diagnosis
|
|
1166
|
+
* ("requires valid personal number field") sat one hop away.
|
|
1167
|
+
*
|
|
1168
|
+
* `payload` rides along deliberately: what was SENT next to what came back is the difference
|
|
1169
|
+
* between reading an error and fixing it. Nothing here is a credential — a connector's secret
|
|
1170
|
+
* lives in the sealed directory, never in an intent — and the rows are the tenant's own scope's,
|
|
1171
|
+
* behind the same K-3 addressing as every other scope read.
|
|
1172
|
+
*/
|
|
1173
|
+
app.get('/tenants/:tenantId/scopes/:scopeId/intents', async (c) => {
|
|
1174
|
+
const tenantId = tenantIdSchema.parse(c.req.param('tenantId'));
|
|
1175
|
+
const scopeId = scopeIdSchema.parse(c.req.param('scopeId'));
|
|
1176
|
+
const principal = c.get('principal');
|
|
1177
|
+
if (principal.kind === 'builder' && principal.tenantId !== tenantId) {
|
|
1178
|
+
return c.json({ error: `unknown scope for tenant: (${tenantId}, ${scopeId})` }, 404);
|
|
1179
|
+
}
|
|
1180
|
+
const filter = platformRequestFilter.parse({
|
|
1181
|
+
kind: c.req.query('kind'),
|
|
1182
|
+
status: c.req.query('status'),
|
|
1183
|
+
limit: c.req.query('limit') ? Number(c.req.query('limit')) : undefined,
|
|
1184
|
+
});
|
|
1185
|
+
const scope = await admin.getScopeRecord(c.get('actor'), tenantId, scopeId);
|
|
1186
|
+
if (!scope)
|
|
1187
|
+
return c.json({ error: `unknown scope for tenant: (${tenantId}, ${scopeId})` }, 404);
|
|
1188
|
+
// Same delegation ladder as the table reads: the intents live in the DO of the scope's BOUND
|
|
1189
|
+
// version, so a hosted scope is asked through its vertical and a co-located one locally.
|
|
1190
|
+
const vertical = await verticalForScope(c, scope);
|
|
1191
|
+
return c.json(vertical
|
|
1192
|
+
? await vertical.listPlatformRequestHistory(tenantId, scopeId, filter)
|
|
1193
|
+
: await host.listPlatformRequestHistory(tenantId, scopeId, filter));
|
|
1194
|
+
});
|
|
1148
1195
|
// #332: re-provision a scope stuck at "roles projected, zero tuples" — the enforcement flip
|
|
1149
1196
|
// switched on against an empty tuple table, so every login denies and the owner is locked out
|
|
1150
1197
|
// with no lever (the platform secret is the CP's, not the builder's). This is that lever: the
|