@substrat-run/control-plane-api 0.162.0 → 0.164.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { ConnectionScopeBinding, ConnectionScopeBindingInput } from '@substrat-run/control-plane-client';
2
2
  import { Hono } from 'hono';
3
3
  import { type ConnectionCertificate, z, type ScopeStoreNeed, type StoreDriverRegistration } from '@substrat-run/contracts';
4
- import type { Connection, ConnectionActivity, ConnectionActivitySource, ConnectionCredential, ConnectionProbe, PlatformActorId } from '@substrat-run/contracts';
4
+ import type { Connection, ConnectionActivity, ConnectionActivitySource, ConnectionCredential, ConnectionProbe, PlatformActorId, ScopeId, TenantId } from '@substrat-run/contracts';
5
5
  import type { CrossVerticalOptions, HostAdmin, OpsFailureInput, ScopeHost } from '@substrat-run/kernel';
6
6
  import type { PlatformActorAuth, BuilderAuth, Principal, TenantServiceAuth } from './auth.js';
7
7
  import { type VerticalClient } from './vertical-client.js';
@@ -9,7 +9,7 @@ import { type CopyJobs } from './copy-job.js';
9
9
  import type { PlatformScopeStores } from './platform-scope-stores.js';
10
10
  import type { ScopeStoreEnsurerOptions, StoreCanaryTarget } from './store-script.js';
11
11
  import { type CanaryCall, type StoreReleaseBytes } from './store-releases.js';
12
- import { type ConnectionCandidatePrepare } from './connection-relay.js';
12
+ import { type ConnectionCandidatePrepare, type VerticalConnectorDeclarationOf } from './connection-relay.js';
13
13
  import type { DeployVerticalFn, FetchVerticalAssetFn, FetchVerticalModulesFn } from './deploy.js';
14
14
  import type { PatchScriptBindingsFn } from './wfp.js';
15
15
  import { type ObservabilityReader } from './observability.js';
@@ -349,6 +349,22 @@ export interface ControlPlaneApiOptions {
349
349
  * verify a Fortnox key yet" is a true statement; "your Fortnox key is fine" is not.
350
350
  */
351
351
  connectionInspectors?: Record<string, ConnectionInspector>;
352
+ /**
353
+ * The inspector for a vertical-defined provider (`<namespace>.<name>`, vertical-connectors.md
354
+ * §6.4), which `connectionInspectors` never names: built per (tenant, vertical), since its code
355
+ * runs in that vertical's deployment. Asked only for a dotted provider the record lacks. Absent,
356
+ * such a provider answers as an unregistered one does.
357
+ */
358
+ verticalConnectorInspector?: (provider: string, context: {
359
+ tenantId: TenantId;
360
+ vertical: string;
361
+ scopeId: ScopeId | null;
362
+ }) => ConnectionInspector | undefined;
363
+ /**
364
+ * A vertical-defined provider's serving declaration, which the tenant connection route grants
365
+ * from (`VerticalConnectorDeclarationOf`). Absent, that route refuses a dotted provider.
366
+ */
367
+ verticalConnectorDeclaration?: VerticalConnectorDeclarationOf;
352
368
  /**
353
369
  * Where this platform's compute actually runs — the coordinates a staff surface needs
354
370
  * to hand an operator a link INTO the provider's own console (the right script, the
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/api.js CHANGED
@@ -2,12 +2,13 @@ import { PREVIEW_CONNECTIONS_REFUSAL } from './connection-relay.js';
2
2
  import { connectionBindingOptions } from './connection-binding-options.js';
3
3
  import { resolveObservabilityWindow } from './observability-window.js';
4
4
  import { Hono } from 'hono';
5
- import { permissionKey, parseHostname, withLabel, RESERVED_LABEL_SEPARATOR, adminAction, lakeEventsInput, ownerTransferInput, memberInviteInput, memberRoleInput, ASSET_PART_PREFIX, assetHash, STORE_DRIVERS, STORE_RELEASE_MAX_BYTES, channelName, connectLinkId, connectionActivity, connectionActivitySource, connectionCredential, connectionCertificate, connectionFilter, connectionHealthState, connectionProvider, connectorDispatchKind, PROVISION_SIBLING_KIND, ARCHIVE_SCOPE_KIND, PROVISION_TENANT_KIND, SET_ENTITLEMENTS_KIND, MODEL_USAGE_KIND, SWEEP_RUNS_KIND, toConnectionHealthEntry, CONNECTION_EXPIRY_WARNING_DAYS, CONNECTION_STALE_DAYS, connectionProbe, createTenantInput, entitlementGrantInput, hostname as hostnameSchema, hostnameRegion, hostnameStatus, identityLink, errorCode, issueStatus, issueStatusInput, FINDINGS_LIMIT_DEFAULT, FINDINGS_LIMIT_MAX, findingCursorOf, findingKind, findingRuleInput, findingStatus, findingStatusInput, listPageQuery, matchesOutboundHost, pageOf, platformRequestFilter, principalId as principalIdSchema, impersonationStamp, promotionAcknowledgement, bindAcknowledgement, rebindAcknowledgement, provisionableJurisdiction, publishVersionInput, queryScopeInput, readScopeTableInput, entityHistoryInput, eventFacetInput, eventCauseInput, eventEffectsInput, invocationEventsInput, deadLettersInput, lifecycleFlowInput, operationSeriesCount, operationSeriesInput, delegatedReadParams, createOrgInput, roleKey as roleKeySchema, peerSwitch, verticalSlug, scopeText, systemSwitch, DEFAULT_DENIAL_LIMIT, DENIAL_LIMIT_MAX, denialGroupBy, registerVerticalInput, platformScriptCollision, platformScriptRefusal, PLATFORM_SCRIPT_NAMES, serviceDimensions, sweepRunKind, sweepRunOutcome, scopeDump, dataSubjectId as dataSubjectIdSchema, scopeId as scopeIdSchema, scopeStatus, requestRollupReading, meterDaysReading, verticalOwnersReading, utcDay, storageShape, surfaceName, tenantId as tenantIdSchema, tenantStatus, versionOrigin, z, PROBLEM_CONTENT_TYPE, toProblem, validationIssuesFrom, redrainEventsInput, importCursorMove, importCursorAcknowledgementMissing, REDRAIN_BATCH, migrationsOnTop, substratError, errorCodeOf, capabilityFilterQuery, capabilityId as capabilityIdSchema, PLATFORM_FEATURES_HEADER, PLATFORM_FEATURE_SCOPE_SWEEPER, SOCIAL_RELAY_VERTICALS, } from '@substrat-run/contracts';
5
+ import { permissionKey, parseHostname, withLabel, RESERVED_LABEL_SEPARATOR, adminAction, lakeEventsInput, ownerTransferInput, memberInviteInput, memberRoleInput, ASSET_PART_PREFIX, assetHash, STORE_DRIVERS, STORE_RELEASE_MAX_BYTES, channelName, connectLinkId, connectionActivity, connectionActivitySource, connectionCredential, connectionCertificate, connectionFilter, connectionHealthState, connectionProvider, connectorDispatchKind, PROVISION_SIBLING_KIND, ARCHIVE_SCOPE_KIND, PROVISION_TENANT_KIND, SET_ENTITLEMENTS_KIND, MODEL_USAGE_KIND, SWEEP_RUNS_KIND, toConnectionHealthEntry, CONNECTION_EXPIRY_WARNING_DAYS, CONNECTION_STALE_DAYS, connectionProbe, createTenantInput, entitlementGrantInput, hostname as hostnameSchema, hostnameRegion, hostnameStatus, identityLink, errorCode, issueStatus, issueStatusInput, FINDINGS_LIMIT_DEFAULT, FINDINGS_LIMIT_MAX, findingCursorOf, findingKind, findingRuleInput, findingStatus, findingStatusInput, listPageQuery, matchesOutboundHost, pageOf, platformRequestFilter, principalId as principalIdSchema, impersonationStamp, promotionAcknowledgement, bindAcknowledgement, rebindAcknowledgement, provisionableJurisdiction, publishVersionInput, queryScopeInput, readScopeTableInput, entityHistoryInput, eventFacetInput, eventCauseInput, eventEffectsInput, invocationEventsInput, deadLettersInput, lifecycleFlowInput, operationSeriesCount, operationSeriesInput, delegatedReadParams, createOrgInput, roleKey as roleKeySchema, peerSwitch, verticalSlug, scopeText, systemSwitch, DEFAULT_DENIAL_LIMIT, DENIAL_LIMIT_MAX, denialGroupBy, registerVerticalInput, platformScriptCollision, platformScriptRefusal, PLATFORM_SCRIPT_NAMES, serviceDimensions, sweepRunKind, sweepRunOutcome, scopeDump, dataSubjectId as dataSubjectIdSchema, scopeId as scopeIdSchema, scopeStatus, requestRollupReading, meterDaysReading, verticalOwnersReading, utcDay, storageShape, surfaceName, tenantId as tenantIdSchema, tenantStatus, versionOrigin, z, PROBLEM_CONTENT_TYPE, toProblem, validationIssuesFrom, redrainEventsInput, importCursorMove, importCursorAcknowledgementMissing, REDRAIN_BATCH, migrationsOnTop, substratError, errorCodeOf, capabilityFilterQuery, capabilityId as capabilityIdSchema, PLATFORM_FEATURES_HEADER, PLATFORM_FEATURE_SCOPE_SWEEPER, SOCIAL_RELAY_VERTICALS, isVerticalConnectorProvider, } from '@substrat-run/contracts';
6
6
  import { upstreamHandleIn, upstreamReferenceOf, withUpstreamReference } from '@substrat-run/contracts';
7
+ import { ENGINE_ENTITLEMENT_KEYS, bareSlug, declarableEntitlementKey, entitlementNamespaceRefusal, grantableEntitlements } from '@substrat-run/contracts';
7
8
  import { SCOPE_COPY_LEASE_MS, copyRestoreFence, publishedMigrationDigest, replayStoreErasures } from '@substrat-run/kernel';
8
9
  import { attributeFailure } from './failure-attribution.js';
9
10
  import { auditedChange, withAuditedOutcomes } from './audited-change.js';
10
- import { BIND_EXPORT_BREAK_REFUSAL, CARRIED_AWAY_KEY, bindExportBreakRefusal, carriedAwayDump, dumpMetaValue, metaValueIn, crossVerticalHealth, exportBreakRefusal, isBindExportBreakRefusal, isExportBreakRefusal, isExportBreakUnjudged, isPrimaryScope, promoteReviewDigest, rebindReviewDigest, assertRebindReviewCurrent, migrationProgress, ulid, auditWarningOf, REQUEST_ROLLUP_LIMIT_DEFAULT, REQUEST_ROLLUP_LIMIT_MAX, METER_DAYS_LIMIT_DEFAULT, METER_DAYS_LIMIT_MAX, releaseRolesAskScopes, releaseRoleSetRefusal, withheldOpsFailure, } from '@substrat-run/kernel';
11
+ import { BIND_EXPORT_BREAK_REFUSAL, CARRIED_AWAY_KEY, bindExportBreakRefusal, carriedAwayDump, dumpMetaValue, metaValueIn, crossVerticalHealth, exportBreakRefusal, isBindExportBreakRefusal, isExportBreakRefusal, listedPromoteRefusal, isExportBreakUnjudged, isPrimaryScope, promoteReviewDigest, rebindReviewDigest, assertRebindReviewCurrent, migrationProgress, ulid, auditWarningOf, REQUEST_ROLLUP_LIMIT_DEFAULT, REQUEST_ROLLUP_LIMIT_MAX, METER_DAYS_LIMIT_DEFAULT, METER_DAYS_LIMIT_MAX, releaseRolesAskScopes, releaseRoleSetRefusal, withheldOpsFailure, } from '@substrat-run/kernel';
11
12
  import { TENANT_HEADER, confinedTenant } from './auth.js';
12
13
  import { mintTenantToken } from './tenant-token.js';
13
14
  import { beginTransfer, connectionGrantsForScope, transferScope, isScopeNotHeld, notHeldIsBenign } from './vertical-client.js';
@@ -28,7 +29,7 @@ import { NON_PROBLEM_REFUSAL, coded, mapError, relayed } from './errors.js';
28
29
  import { maskDump, maskRecords } from './mask.js';
29
30
  import { createPseudonymizer } from './pseudonymize.js';
30
31
  import { openDump, sealDump } from './seal.js';
31
- import { assertSandboxContract, verticalUploadBindings, migrationsDigestBindings, deployManifest, storedDeployManifest, pushedOwnerGrantProblems, pushedModuleRegistryProblems, pushedPermissionRegistry, deploymentRefFor, stableDeploymentRefFor, nextMigrationTag, upstreamStatusOf, } from './deploy.js';
32
+ import { assertSandboxContract, verticalUploadBindings, migrationsDigestBindings, deployManifest, storedDeployManifest, pushedOwnerGrantProblems, pushedConnectorProblems, pushedModuleRegistryProblems, pushedPermissionRegistry, deploymentRefFor, stableDeploymentRefFor, nextMigrationTag, upstreamStatusOf, } from './deploy.js';
32
33
  /**
33
34
  * Answer with a problem document (#113 phase 4).
34
35
  *
@@ -113,6 +114,18 @@ class ExportBreakRefused extends ControlPlaneError {
113
114
  this.breaks = breaks;
114
115
  }
115
116
  }
117
+ /**
118
+ * #2577: a serve whose upload carried a DO-class migration, refused its record because another serve
119
+ * changed the serving row's class set or tag during the upload. The runtime's migration tag is now
120
+ * past the record's, so a re-serve diffed from the record names an `old_tag` the runtime refuses:
121
+ * promoting again cannot land, and the record needs repair.
122
+ */
123
+ class ServeRecordBehindScript extends ControlPlaneError {
124
+ constructor(slug) {
125
+ super(409, `the serving record of '${slug}' changed while this serve's upload added a Durable Object class, so the ` +
126
+ "record's migration tag is behind the serving script's (#2577)");
127
+ }
128
+ }
116
129
  /**
117
130
  * A carry whose source store kept changing between its export and its bind (#1722, Codex #2008
118
131
  * r12): every re-carry from a fresh export found the source changed again before it could bind.
@@ -2161,7 +2174,11 @@ export function createControlPlaneApi(options) {
2161
2174
  return refuse(c, 'validation_failed', 'body tenantId disagrees with the route tenant');
2162
2175
  }
2163
2176
  try {
2164
- return c.json(await relayConnectionUpsert(c.var.host, c.get('actor'), { ...body, tenantId }, { probeCandidate, prepareCandidate }));
2177
+ return c.json(await relayConnectionUpsert(c.var.host, c.get('actor'), { ...body, tenantId }, {
2178
+ probeCandidate,
2179
+ prepareCandidate,
2180
+ ...(options.verticalConnectorDeclaration ? { declarationOf: options.verticalConnectorDeclaration } : {}),
2181
+ }));
2165
2182
  }
2166
2183
  catch (err) {
2167
2184
  if (err instanceof ConnectionRelayError && err.status < 500) {
@@ -2271,12 +2288,20 @@ export function createControlPlaneApi(options) {
2271
2288
  * exactly like an absent one — and revoked rows are excluded: a withdrawn credential
2272
2289
  * has no secret left to probe with, so "revoked" is a 404 for these reads too.
2273
2290
  */
2291
+ /**
2292
+ * The inspector for `provider`: the record's entry, else, for a vertical-defined provider, the one
2293
+ * built for the vertical the connection belongs to (vertical-connectors.md §6.4).
2294
+ */
2295
+ const inspectorFor = (provider, context) => options.connectionInspectors?.[provider] ??
2296
+ (isVerticalConnectorProvider(provider) ? options.verticalConnectorInspector?.(provider, context) : undefined);
2297
+ /** {@link inspectorFor} for a connection row, which names its own tenant and vertical. */
2298
+ const inspectorOf = (row) => inspectorFor(row.provider, { tenantId: row.tenantId, vertical: row.vertical, scopeId: null });
2274
2299
  /**
2275
2300
  * The connect-time gate (#605), as the relay consumes it: ask the provider about a
2276
2301
  * candidate credential, or answer `undefined` when this platform has no probe for it —
2277
2302
  * in which case the upsert behaves exactly as it always did, storing unverified.
2278
2303
  */
2279
- const probeCandidate = async (provider, secret) => options.connectionInspectors?.[provider]?.probeCandidate?.(secret);
2304
+ const probeCandidate = async (provider, secret, context) => inspectorFor(provider, context)?.probeCandidate?.(secret);
2280
2305
  /** #2100: the provider's own half of a credential, made before the probe sees it. */
2281
2306
  const prepareCandidate = (provider) => options.connectionInspectors?.[provider]?.prepareCandidate;
2282
2307
  const inspectableConnection = async (c) => {
@@ -2292,7 +2317,7 @@ export function createControlPlaneApi(options) {
2292
2317
  const row = await inspectableConnection(c);
2293
2318
  if (!row)
2294
2319
  return refuse(c, 'not_found', 'unknown connection');
2295
- const read = options.connectionInspectors?.[row.provider]?.bindings;
2320
+ const read = inspectorOf(row)?.bindings;
2296
2321
  if (!read)
2297
2322
  return refuseStatus(c, 501, `no scope binding registered for provider '${row.provider}'`);
2298
2323
  const bindings = await read(c.var.host, row);
@@ -2313,7 +2338,7 @@ export function createControlPlaneApi(options) {
2313
2338
  const row = await inspectableConnection(c);
2314
2339
  if (!row)
2315
2340
  return refuse(c, 'not_found', 'unknown connection');
2316
- const bind = options.connectionInspectors?.[row.provider]?.bindScope;
2341
+ const bind = inspectorOf(row)?.bindScope;
2317
2342
  if (!bind)
2318
2343
  return refuseStatus(c, 501, `no scope binding registered for provider '${row.provider}'`);
2319
2344
  const scopeId = scopeIdSchema.parse(c.req.param('scopeId'));
@@ -2367,7 +2392,7 @@ export function createControlPlaneApi(options) {
2367
2392
  const row = await inspectableConnection(c);
2368
2393
  if (!row)
2369
2394
  return refuse(c, 'not_found', 'unknown connection');
2370
- const probe = options.connectionInspectors?.[row.provider]?.probe;
2395
+ const probe = inspectorOf(row)?.probe;
2371
2396
  if (!probe) {
2372
2397
  return refuseStatus(c, 501, `no probe registered for provider '${row.provider}'`);
2373
2398
  }
@@ -2389,7 +2414,7 @@ export function createControlPlaneApi(options) {
2389
2414
  const row = await inspectableConnection(c);
2390
2415
  if (!row)
2391
2416
  return refuse(c, 'not_found', 'unknown connection');
2392
- const activity = options.connectionInspectors?.[row.provider]?.activity;
2417
+ const activity = inspectorOf(row)?.activity;
2393
2418
  if (!activity) {
2394
2419
  return refuseStatus(c, 501, `no activity view registered for provider '${row.provider}'`);
2395
2420
  }
@@ -2410,7 +2435,7 @@ export function createControlPlaneApi(options) {
2410
2435
  const row = await inspectableConnection(c);
2411
2436
  if (!row)
2412
2437
  return refuse(c, 'not_found', 'unknown connection');
2413
- const credential = options.connectionInspectors?.[row.provider]?.credential;
2438
+ const credential = inspectorOf(row)?.credential;
2414
2439
  if (!credential) {
2415
2440
  return refuseStatus(c, 501, `no credential view registered for provider '${row.provider}'`);
2416
2441
  }
@@ -2425,7 +2450,7 @@ export function createControlPlaneApi(options) {
2425
2450
  const row = await inspectableConnection(c);
2426
2451
  if (!row)
2427
2452
  return refuse(c, 'not_found', 'unknown connection');
2428
- const certificate = await options.connectionInspectors?.[row.provider]?.certificate?.(c.var.host, row);
2453
+ const certificate = await inspectorOf(row)?.certificate?.(c.var.host, row);
2429
2454
  if (!certificate)
2430
2455
  return refuse(c, 'not_found', 'this connection signs in with no certificate');
2431
2456
  return c.json(connectionCertificate.parse(certificate));
@@ -5883,7 +5908,10 @@ export function createControlPlaneApi(options) {
5883
5908
  });
5884
5909
  // The write half of the governed pull (§8) — load a dump INTO an existing scope:
5885
5910
  // restore a backup, back out to a snapshot, or land a locally-built world on a
5886
- // hosted app. Staff-only like the export (not in BUILDER_ROUTES). No jurisdiction
5911
+ // hosted app. Staff, and a tenant's own credential (TENANT_ROUTES, path-pinned): the
5912
+ // dashboard's Import sends a file a team owner or admin uploaded (#2573), the dashboard
5913
+ // asking that role, since this plane sees the credential, not the person. Builders are
5914
+ // refused (not in BUILDER_ROUTES). The dump is input, judged on load. No jurisdiction
5887
5915
  // gate: this is ingress — the data ENTERS the scope's pinned region, it never
5888
5916
  // leaves one. Mirrors the export's delegation shape: the canonical `restoreScope`
5889
5917
  // writes the audit row (and the co-located bytes); when the scope's data lives in
@@ -5988,7 +6016,7 @@ export function createControlPlaneApi(options) {
5988
6016
  // A restore throw is driven by the caller-supplied dump (a shape the target cannot
5989
6017
  // load, a DDL the engine rejects), so DISCLOSE it as an actionable 422 rather than
5990
6018
  // collapsing to the generic 500 `internal error` mapError would produce (#321,
5991
- // secondary obs #2). The route is staff/owner-gated and the detail is about the
6019
+ // secondary obs #2). The route is staff- or own-tenant-gated and the detail is about the
5992
6020
  // dump the caller sent, not another tenant's state.
5993
6021
  const detail = e instanceof Error ? e.message : String(e);
5994
6022
  return refuseStatus(c, 422, 'restore failed — the backup could not be loaded', { detail });
@@ -6743,6 +6771,8 @@ export function createControlPlaneApi(options) {
6743
6771
  * vertical stays owner-only, and so do the reads narrowed on purpose (migration SQL,
6744
6772
  * the prod history).
6745
6773
  */
6774
+ /** The bare slug of every registered vertical: what a manager's SKU may not be (#2388). */
6775
+ const verticalSlugsOf = async (actor) => (await host.admin.listVerticals(actor)).map((v) => bareSlug(v.slug));
6746
6776
  /**
6747
6777
  * Whether a CONFINED principal may grant its own tenant `key` (#977): some vertical it
6748
6778
  * can read — its own, or a listed one — declares the key, or is the vertical whose
@@ -6750,14 +6780,40 @@ export function createControlPlaneApi(options) {
6750
6780
  * (`installEntitlements`), checked here so a credential cannot grant what no install
6751
6781
  * would. Read through the configured host: a check audits nothing.
6752
6782
  */
6783
+ /**
6784
+ * The refusal for REGISTERING a vertical whose bare slug is a plan SKU a manager declares (#2388),
6785
+ * so the manager's key does not change meaning under a later registration. A manager is a row that
6786
+ * holds the tenant-provisioner capability or declares `provisions` (the capability is granted after
6787
+ * the first push). Its own slug and the engine keys are always declarable, so they reserve nothing.
6788
+ * Only a new slug is judged; the sentence names no other vertical.
6789
+ */
6790
+ const slugClaimsSku = async (actor, slug) => {
6791
+ const all = await host.admin.listVerticals(actor);
6792
+ if (all.some((v) => v.slug === slug))
6793
+ return undefined;
6794
+ const name = bareSlug(slug);
6795
+ return all.some((v) => (v.tenantProvisioner || v.provisions?.length) &&
6796
+ bareSlug(v.slug) !== name &&
6797
+ !ENGINE_ENTITLEMENT_KEYS.includes(name) &&
6798
+ v.entitlements?.includes(name))
6799
+ ? `'${bareSlug(slug)}' is not available as a vertical name`
6800
+ : undefined;
6801
+ };
6802
+ /** The declared keys of a registry row that an install may grant: a manager's include plan SKUs. */
6803
+ const grantableOf = (v, slugs) => grantableEntitlements(v.slug, v.entitlements ?? [], v.tenantProvisioner ? slugs : undefined);
6753
6804
  const tenantGrantable = async (p, key) => {
6754
6805
  const pin = confinedTenant(p);
6755
6806
  if (pin === null)
6756
6807
  return true;
6757
- const visible = (await host.admin.listVerticals(p.actor)).filter((v) => v.ownerTenant === pin || v.listed);
6758
- return visible.some((v) => v.entitlements && v.entitlements.length > 0
6759
- ? v.entitlements.includes(key)
6760
- : (v.slug.split('/').pop() || v.slug) === key);
6808
+ const all = await host.admin.listVerticals(p.actor);
6809
+ const slugs = all.map((v) => bareSlug(v.slug));
6810
+ const visible = all.filter((v) => v.ownerTenant === pin || v.listed);
6811
+ return visible.some((v) => {
6812
+ // The install's own derivation (`installEntitlements`): the declared keys the vertical may
6813
+ // declare, else its bare slug.
6814
+ const grantable = grantableOf(v, slugs);
6815
+ return (grantable.length > 0 ? grantable : declarableEntitlementKey(v.slug, bareSlug(v.slug), v.tenantProvisioner ? slugs : undefined) ? [bareSlug(v.slug)] : []).includes(key);
6816
+ });
6761
6817
  };
6762
6818
  const notReadable = async (p, slug) => {
6763
6819
  const pin = confinedTenant(p);
@@ -6834,7 +6890,13 @@ export function createControlPlaneApi(options) {
6834
6890
  ? all.filter((v) => v.ownerTenant === p.tenantId)
6835
6891
  : all.filter((v) => (ownerTenant === undefined || v.ownerTenant === ownerTenant) &&
6836
6892
  (visibleTo === undefined || v.listed || v.ownerTenant === visibleTo));
6837
- return c.json(pageSlice(visible, page, (v) => v.slug));
6893
+ // The install catalog (`visibleTo`) carries what an install may grant, not what a row declared
6894
+ // before the namespace rule (#2388), so the dashboard's install and the grant paths agree.
6895
+ const slugs = visibleTo === undefined || p.kind === 'builder' ? [] : all.map((v) => bareSlug(v.slug));
6896
+ const rows = visibleTo === undefined || p.kind === 'builder'
6897
+ ? visible
6898
+ : visible.map((v) => (v.entitlements ? { ...v, entitlements: grantableOf(v, slugs) } : v));
6899
+ return c.json(pageSlice(rows, page, (v) => v.slug));
6838
6900
  });
6839
6901
  // -- the service→dimensions resolver (#1231's last item) -----------------------
6840
6902
  // What a Cloudflare service ref MEANS: each owned vertical's serving script and
@@ -6939,6 +7001,15 @@ export function createControlPlaneApi(options) {
6939
7001
  return refuse(c, 'forbidden', 'forbidden');
6940
7002
  input.ownerTenant = p.tenantId;
6941
7003
  }
7004
+ const claimed = await slugClaimsSku(c.get('actor'), input.slug);
7005
+ if (claimed)
7006
+ return refuseStatus(c, 422, claimed);
7007
+ // #2388: the same declaration rule as a push, for any principal that is not staff.
7008
+ if (p.kind !== 'staff') {
7009
+ const foreignKey = entitlementNamespaceRefusal(input.slug, input.entitlements ?? [], input.provisions?.length ? await verticalSlugsOf(c.get('actor')) : undefined);
7010
+ if (foreignKey)
7011
+ return refuseStatus(c, 422, foreignKey);
7012
+ }
6942
7013
  await c.var.admin.registerVertical(c.get('actor'), input);
6943
7014
  // Idempotent on the slug (a conflicting re-register throws below the seam), so
6944
7015
  // read back rather than echo the request.
@@ -7009,6 +7080,9 @@ export function createControlPlaneApi(options) {
7009
7080
  const ownerGrants = pushedOwnerGrantProblems(checked.data);
7010
7081
  if (ownerGrants.length > 0)
7011
7082
  return refuseManifest({ path: ['ownerGrants'], message: ownerGrants.join('; ') });
7083
+ const connectorProblems = pushedConnectorProblems(checked.data);
7084
+ if (connectorProblems.length > 0)
7085
+ return refuseManifest({ path: ['connectors'], message: connectorProblems.join('; ') });
7012
7086
  }
7013
7087
  await c.var.admin.publishVersion(c.get('actor'), input);
7014
7088
  const version = await c.var.admin.getVersion(c.get('actor'), input.id, slug);
@@ -7488,6 +7562,11 @@ export function createControlPlaneApi(options) {
7488
7562
  : undefined);
7489
7563
  await recordWireUpload(admin, actor, versionId, wire);
7490
7564
  const addedClasses = serving ? doClasses.some((cls) => !serving.doClasses.includes(cls)) : false;
7565
+ // #2577: `serving`'s class set and tag are what the upload's migration was diffed from, so the
7566
+ // record lands only while the row still holds them; a serve that moved only the ref and version
7567
+ // meanwhile is recorded over, as before. A refusal is not retried: the script already runs this
7568
+ // upload. When a migration rode it, the runtime's tag is past the record's and a retry cannot land.
7569
+ const migrated = !serving || addedClasses;
7491
7570
  await admin.setVerticalServing(actor, slug, {
7492
7571
  ref,
7493
7572
  versionId,
@@ -7500,6 +7579,8 @@ export function createControlPlaneApi(options) {
7500
7579
  ? nextMigrationTag(serving.migrationTag)
7501
7580
  : serving.migrationTag
7502
7581
  : 'v1',
7582
+ }, serving).catch((e) => {
7583
+ throw migrated && errorCodeOf(e) === 'precondition_failed' ? new ServeRecordBehindScript(slug) : e;
7503
7584
  });
7504
7585
  };
7505
7586
  /**
@@ -7719,8 +7800,11 @@ export function createControlPlaneApi(options) {
7719
7800
  // service token, and this issue narrows WHOSE data a credential reaches, not what
7720
7801
  // a tenant may do inside its own. Taking the gate away from them here would be a
7721
7802
  // capability change hidden in a security fix.
7803
+ //
7804
+ // Answered here, before any other gate or read, and judged again by the host (`unlistedOnly`,
7805
+ // below) in the unit that moves the channel, so a listing that lands meanwhile is seen (#2565).
7722
7806
  if (p.kind === 'builder' && channel === 'prod' && v.listed) {
7723
- return refuse(c, 'forbidden', 'promotion to prod is staff-only for a listed vertical');
7807
+ return refuse(c, 'forbidden', listedPromoteRefusal().message);
7724
7808
  }
7725
7809
  }
7726
7810
  const { versionId, acknowledge } = promoteVersionBody.parse(await c.req.json());
@@ -7764,7 +7848,7 @@ export function createControlPlaneApi(options) {
7764
7848
  // and refuses a non-admitted version. Both are enforced below the seam and
7765
7849
  // surface as a 4xx through mapError, not a 500.
7766
7850
  try {
7767
- await c.var.admin.promoteVersion(c.get('actor'), slug, channel, versionId, acknowledge);
7851
+ await c.var.admin.promoteVersion(c.get('actor'), slug, channel, versionId, acknowledge, { unlistedOnly: p.kind === 'builder' });
7768
7852
  }
7769
7853
  catch (err) {
7770
7854
  if (!isExportBreakRefusal(err))
@@ -7808,7 +7892,11 @@ export function createControlPlaneApi(options) {
7808
7892
  // The serve, the adopt and the backfill reach every install of the vertical, whoever's, so
7809
7893
  // what failed is withheld from a confined caller (#2540), and the tenant the backstop would
7810
7894
  // have filed it under reads only the sentence.
7811
- const sentence = (reference) => `promoted, but the in-place serve failed — scopes still run the previous code; promote again to retry (reference ${reference})`;
7895
+ // #2577: a serve refused after its upload already runs the new code, so neither says which code runs.
7896
+ const sentence = (reference) => e instanceof ServeRecordBehindScript
7897
+ ? `promoted, but the in-place serve failed — another serve changed the serving record while this one ` +
7898
+ `added a Durable Object class, so promoting again cannot land until the record is repaired (reference ${reference})`
7899
+ : `promoted, but the in-place serve failed — promote again to retry (reference ${reference})`;
7812
7900
  const withheld = withheldFailure(c, {
7813
7901
  operation: 'promote.serve',
7814
7902
  stage: 'serve-in-place',
@@ -7903,6 +7991,10 @@ export function createControlPlaneApi(options) {
7903
7991
  const ownerGrants = pushedOwnerGrantProblems(manifest);
7904
7992
  if (ownerGrants.length > 0)
7905
7993
  return refuse(c, 'validation_failed', `manifest ownerGrants: ${ownerGrants.join('; ')}`);
7994
+ // vertical-connectors.md §7.1: a connector's standing grant is a declared, person-held key.
7995
+ const connectorProblems = pushedConnectorProblems(manifest);
7996
+ if (connectorProblems.length > 0)
7997
+ return refuse(c, 'validation_failed', `manifest connectors: ${connectorProblems.join('; ')}`);
7906
7998
  // §4 sandbox contract, before anything reaches the namespace.
7907
7999
  assertSandboxContract(manifest, options.storeDrivers);
7908
8000
  // #2339: a push whose migration digest is not the one its migrations give is refused here,
@@ -8047,6 +8139,17 @@ export function createControlPlaneApi(options) {
8047
8139
  if (!modules.some((m) => m.name === manifest.entry)) {
8048
8140
  return refuse(c, 'validation_failed', `entry module '${manifest.entry}' is not among the uploaded files`);
8049
8141
  }
8142
+ // #2388: a new version declares only keys its vertical may (its own, the engines', and those of
8143
+ // the verticals it provisions). The capability is granted after a first push, so the declaration
8144
+ // is judged here and honoured by the grant paths only for a tenant-provisioner. Earlier versions
8145
+ // are not re-judged.
8146
+ // Declaring `provisions` marks a manager: the capability itself is granted after a first push.
8147
+ const foreignKey = entitlementNamespaceRefusal(slug, manifest.entitlements ?? [], manifest.provisions?.length ? await verticalSlugsOf(c.get('actor')) : undefined);
8148
+ if (foreignKey)
8149
+ return refuseStatus(c, 422, foreignKey);
8150
+ const claimed = await slugClaimsSku(c.get('actor'), slug);
8151
+ if (claimed)
8152
+ return refuseStatus(c, 422, claimed);
8050
8153
  // The static-asset half of the §4 sandbox contract (self-serve-deploy.md §4.1). The
8051
8154
  // bytes are inert — no code, no authority — so they are ACCEPTED; the content-address
8052
8155
  // is not, so it is VERIFIED. The runtime's asset store dedups by hash across the whole
@@ -8176,6 +8279,9 @@ export function createControlPlaneApi(options) {
8176
8279
  ...(manifest.entitlements ? { entitlements: manifest.entitlements } : {}),
8177
8280
  ...(manifest.provides ? { provides: manifest.provides } : {}),
8178
8281
  ...(manifest.requires ? { requires: manifest.requires } : {}),
8282
+ // The declared vertical-defined connectors (vertical-connectors.md §7.2): what the dashboard's
8283
+ // door renders. The proxy never reads this copy; it reads the running version's manifest.
8284
+ ...(manifest.connectors ? { connectors: manifest.connectors } : {}),
8179
8285
  // The declared provisioner intent (#455) — a REQUEST the console reviews; the
8180
8286
  // tenant-provisioner grant itself is never touched by a push. Refreshes on every
8181
8287
  // re-push like the rest of the install spec, exactly because it grants nothing.