@substrat-run/control-plane-api 0.153.0 → 0.155.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
@@ -17,6 +17,7 @@ import { type DoNamespaceReader } from './do-namespaces.js';
17
17
  import type { DirectoryBackupStore, ScopeBackupStore } from './backups.js';
18
18
  import { type LakeQueryEngine } from './lake-gateway.js';
19
19
  import { type CustomHostnameProvisioner } from './custom-hostnames.js';
20
+ import { type SocialRelayOptions } from './social-relay.js';
20
21
  /**
21
22
  * What one provider can answer about a live connection (#605) — the seam behind
22
23
  * `POST /tenants/:t/connections/:id/verify` and `GET …/activity`.
@@ -372,6 +373,13 @@ export interface ControlPlaneApiOptions {
372
373
  * self-host / dev shape, where there is no CF-for-SaaS zone).
373
374
  */
374
375
  provisionHostname?: CustomHostnameProvisioner;
376
+ /**
377
+ * The platform's social relay (#1544, `social-relay.ts`): how an Auth Server install is given
378
+ * its own client there. When present, a hostname of such an install becoming active
379
+ * reconciles that install, and the two staff routes under `social-relay` can reconcile one
380
+ * install or all of them. Absent ⇒ nothing here ever calls the relay.
381
+ */
382
+ socialRelay?: SocialRelayOptions;
375
383
  /**
376
384
  * The platform's base domains — the wildcard-covered zones a PLATFORM hostname is
377
385
  * minted under (`substrat.run`, `global.substrat.run`, …). A bind AT or UNDER one of
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
@@ -1,14 +1,15 @@
1
1
  import { PREVIEW_CONNECTIONS_REFUSAL } from './connection-relay.js';
2
+ import { connectionBindingOptions } from './connection-binding-options.js';
2
3
  import { resolveObservabilityWindow } from './observability-window.js';
3
4
  import { Hono } from 'hono';
4
- 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, 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, 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, } 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, 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, 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
6
  import { SCOPE_COPY_LEASE_MS, copyRestoreFence, publishedMigrationDigest, replayStoreErasures } from '@substrat-run/kernel';
6
7
  import { attributeFailure } from './failure-attribution.js';
7
8
  import { auditedChange, withAuditedOutcomes } from './audited-change.js';
8
9
  import { BIND_EXPORT_BREAK_REFUSAL, CARRIED_AWAY_KEY, bindExportBreakRefusal, carriedAwayDump, dumpMetaValue, metaValueIn, crossVerticalHealth, exportBreakRefusal, isBindExportBreakRefusal, isExportBreakRefusal, isPrimaryScope, promoteReviewDigest, rebindReviewDigest, assertRebindReviewCurrent, migrationProgress, ulid, auditWarningOf, } from '@substrat-run/kernel';
9
10
  import { TENANT_HEADER, confinedTenant } from './auth.js';
10
11
  import { mintTenantToken } from './tenant-token.js';
11
- import { connectionGrantsForScope } from './vertical-client.js';
12
+ import { connectionGrantsForScope, transferScope } from './vertical-client.js';
12
13
  import { runningVersionOf, runningVersionStoresOf, scopeStoreReachOf, scopeStoresOf, unrouteScope } from './platform-scope-stores.js';
13
14
  import { STORE_REBUILD_REQUEST_SUBREQUESTS, runStoreFleetRebuild, storeRebuildBudget, storeRebuildStatus } from './store-rebuild.js';
14
15
  import { PUSH_HOLD_TTL_MS, runStoreDriverRollout, storeDriverRelease, storedReleaseLoader } from './store-releases.js';
@@ -25,7 +26,7 @@ import { NON_PROBLEM_REFUSAL, coded, mapError, relayed } from './errors.js';
25
26
  import { maskDump, maskRecords } from './mask.js';
26
27
  import { createPseudonymizer } from './pseudonymize.js';
27
28
  import { openDump, sealDump } from './seal.js';
28
- import { assertSandboxContract, verticalUploadBindings, migrationsDigestBindings, deployManifest, storedDeployManifest, pushedPermissionRegistry, deploymentRefFor, stableDeploymentRefFor, nextMigrationTag, upstreamStatusOf, } from './deploy.js';
29
+ import { assertSandboxContract, verticalUploadBindings, migrationsDigestBindings, deployManifest, storedDeployManifest, pushedOwnerGrantProblems, pushedPermissionRegistry, deploymentRefFor, stableDeploymentRefFor, nextMigrationTag, upstreamStatusOf, } from './deploy.js';
29
30
  /**
30
31
  * Answer with a problem document (#113 phase 4).
31
32
  *
@@ -68,6 +69,7 @@ import { STORAGE_PAGE_DEFAULT, STORAGE_PAGE_MAX, readStoragePage } from './stora
68
69
  import { queryLakeEvents } from './lake-gateway.js';
69
70
  import { LakeQueryError } from './r2-sql-engine.js';
70
71
  import { isCustomHostname, validateBindableHostname, } from './custom-hostnames.js';
72
+ import { isSocialRelayVertical, reconcileScopeSocialRelay, relayHostnames, } from './social-relay.js';
71
73
  /**
72
74
  * Response headers carrying the CLI version advisory (`ControlPlaneApiOptions.cliAdvisory`).
73
75
  * The CLI reads these by the same spelling (`packages/cli/src/version.ts`); exported so a
@@ -2038,23 +2040,10 @@ export function createControlPlaneApi(options) {
2038
2040
  if (target.status !== 'active' || !target.vertical || target.vertical !== row.vertical) {
2039
2041
  return refuseStatus(c, 409, 'connection and target must share an active vertical scope');
2040
2042
  }
2041
- const fields = {
2043
+ const schema = connectionBindingOptions(row.provider).extend({
2042
2044
  operation: z.string().regex(/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+$/),
2043
2045
  permission: permissionKey,
2044
- };
2045
- const schema = row.provider === 'planima'
2046
- ? z.object({ ...fields,
2047
- organizationId: z.number().int().positive().nullable().optional(),
2048
- currency: z.string().regex(/^[A-Z]{3}$/).optional(),
2049
- window: z.object({ fromYear: z.number().int(), toYear: z.number().int() })
2050
- .refine((w) => w.toYear >= w.fromYear, 'window ends before it starts').nullable().optional(),
2051
- horizonYears: z.number().int().min(0).optional(),
2052
- }).strict()
2053
- : row.provider === 'microsoft365'
2054
- // #2101: the channel folder, by its drive path. The connector resolves it and holds the
2055
- // fence to it; this only bounds the input.
2056
- ? z.object({ ...fields, folder: z.string().trim().min(1).max(400) }).strict()
2057
- : z.object(fields).strict();
2046
+ });
2058
2047
  const input = schema.parse(await c.req.json());
2059
2048
  const grants = await c.var.host.connectionGrantsInScope(row.tenantId, scopeId);
2060
2049
  if (!grants.some((g) => g.connectionId === row.id && g.permission === input.permission)) {
@@ -2276,6 +2265,48 @@ export function createControlPlaneApi(options) {
2276
2265
  open: (items) => c.var.admin.openSubjectPayloads(c.get('actor'), tenantId, scopeId, items),
2277
2266
  });
2278
2267
  const verticalForScope = async (c, scope) => (await deploymentForScope(c, scope))?.client;
2268
+ /**
2269
+ * Reconcile one install's client at the social relay (#1544). Skips — never throws for — an
2270
+ * install the relay is not for: not configured here, not an Auth Server, or no deployment to
2271
+ * deliver to. A relay or delivery failure DOES throw, so a staff route can report it.
2272
+ */
2273
+ const reconcileRelayFor = async (c, tenantId, scopeId) => {
2274
+ if (!options.socialRelay)
2275
+ return { status: 'skipped', reason: 'no social relay is configured on this control plane' };
2276
+ const actor = c.get('actor');
2277
+ return reconcileScopeSocialRelay({
2278
+ relay: options.socialRelay,
2279
+ getScope: (t, s) => c.var.admin.getScopeRecord(actor, tenantIdSchema.parse(t), scopeIdSchema.parse(s)),
2280
+ activeHostnames: async (s) => relayHostnames(await c.var.admin.listHostnames(actor, { scopeId: scopeIdSchema.parse(s), status: 'active' }), {
2281
+ isCustom: custom,
2282
+ provisioner: options.provisionHostname,
2283
+ }),
2284
+ deploymentOf: (scope) => verticalForScope(c, scope),
2285
+ }, tenantId, scopeId);
2286
+ };
2287
+ /**
2288
+ * After a hostname of an Auth Server install became active: register it at the relay. Best
2289
+ * effort, and awaited rather than deferred — the route that activated the hostname has done its
2290
+ * job either way, and a failure here is logged and repaired by the next trigger or a staff run.
2291
+ * Awaited so two activations of one install never reconcile concurrently.
2292
+ */
2293
+ const relayAfterActivation = async (c, before, after) => {
2294
+ if (!options.socialRelay || !after || after.status !== 'active' || before?.status === 'active')
2295
+ return;
2296
+ if (!isSocialRelayVertical(after.verticalSlug))
2297
+ return;
2298
+ try {
2299
+ const outcome = await reconcileRelayFor(c, after.tenantId, after.scopeId);
2300
+ console.log('social-relay.reconciled', { scopeId: after.scopeId, trigger: 'hostname-active', ...outcome });
2301
+ }
2302
+ catch (e) {
2303
+ console.error('social-relay.reconcile.failed', {
2304
+ scopeId: after.scopeId,
2305
+ trigger: 'hostname-active',
2306
+ detail: e instanceof Error ? e.message : String(e),
2307
+ });
2308
+ }
2309
+ };
2279
2310
  /**
2280
2311
  * `verticalForScope`, saying WHICH rung of the ladder chose the client (#1653).
2281
2312
  *
@@ -2664,7 +2695,8 @@ export function createControlPlaneApi(options) {
2664
2695
  await c.var.admin.recordScopeScriptCopy(actor, tenantId, scopeId, servingRef, moveId, { role: 'destination', loadStamp: restoredStamp, leaseMs: copyLeaseMs });
2665
2696
  }
2666
2697
  const erasureEpoch = await c.var.admin.scopeErasureEpoch(actor, tenantId, scopeId);
2667
- const { tables: dump, loadStamp: sourceStamp, revision: sourceRevision } = await retryTransient(() => source.exportScopeStamped(scopeId));
2698
+ // #2450: a page at a time into the destination's stage, so a scope of any size moves.
2699
+ const { dump, loadStamp: sourceStamp, revision: sourceRevision } = await transferScope(source, dest, { from: scopeId }, { retry: retryTransient });
2668
2700
  const restored = await restoreCarryingSwitches(actor, dest, tenantId, scopeId, dump, {
2669
2701
  scopeId, exact: true, loadStamp: restoredStamp,
2670
2702
  ...(moveId ? { fence: copyRestoreFence(moveId, recordedAt, copyLeaseMs, erasureEpoch) } : {}),
@@ -2801,7 +2833,10 @@ export function createControlPlaneApi(options) {
2801
2833
  // cleanup. Name it before any bytes are restored so reap and erasure can find it.
2802
2834
  await c.var.admin.recordScopeScriptCopy(actor, scope.tenantId, scope.id, to, moveId, { role: 'destination', loadStamp: restoredStamp, leaseMs: copyLeaseMs });
2803
2835
  const erasureEpoch = await c.var.admin.scopeErasureEpoch(actor, scope.tenantId, scope.id);
2804
- const { tables: dump, loadStamp: sourceStamp, revision: sourceRevision } = await retryTransient(() => source.exportScopeStamped(scope.id));
2836
+ // #2450: a page at a time into the destination's stage, so a scope of any size moves. The
2837
+ // stage moves neither the destination's load stamp nor its write revision, so the marker read
2838
+ // next still describes the store the restore below commits into.
2839
+ const { dump, loadStamp: sourceStamp, revision: sourceRevision, meta } = await transferScope(source, dest, { from: scope.id }, { retry: retryTransient });
2805
2840
  // What the destination holds now, read before the binding is checked again. The restore
2806
2841
  // sends it back and is refused if the store moved since: another carry into the same script
2807
2842
  // loaded it, or it went live under another carry's bind and took a write. That is a CI retry
@@ -2814,7 +2849,7 @@ export function createControlPlaneApi(options) {
2814
2849
  throw new ControlPlaneError(412, `scope ${scope.id} was re-pointed while its data was being copied out of '${from}', so nothing was ` +
2815
2850
  `moved or bound (#1722). Reload the scope and retry.`);
2816
2851
  }
2817
- if (dumpMetaValue(dump, CARRIED_AWAY_KEY) !== null) {
2852
+ if (dumpMetaValue(meta, CARRIED_AWAY_KEY) !== null) {
2818
2853
  throw new ControlPlaneError(412, `the copy of scope ${scope.id} in '${from}' was already carried to another script and wiped, so nothing ` +
2819
2854
  `was moved or bound (#1722). Reload the scope and retry.`);
2820
2855
  }
@@ -3186,8 +3221,8 @@ export function createControlPlaneApi(options) {
3186
3221
  await releaseIfLive(c, scope, versionId, carried, carried.dest, carried.to);
3187
3222
  let sourceMarker = { loadStamp: carried.sourceStamp, revision: carried.sourceRevision };
3188
3223
  if (await isCarriedAway(carried.dest, scope)) {
3189
- const { tables: dump, loadStamp: stamp, revision } = await retryTransient(() => carried.source.exportScopeStamped(scope.id));
3190
- if (dumpMetaValue(dump, CARRIED_AWAY_KEY) !== null) {
3224
+ const { dump, loadStamp: stamp, revision, meta } = await transferScope(carried.source, carried.dest, { from: scope.id }, { retry: retryTransient });
3225
+ if (dumpMetaValue(meta, CARRIED_AWAY_KEY) !== null) {
3191
3226
  throw new ControlPlaneError(500, `both copies of scope ${scope.id} hold the carried_away tombstone; nothing was wiped`);
3192
3227
  }
3193
3228
  // The re-carry is a copy move of its own (#1722): in the ledger and leased before it
@@ -6364,6 +6399,10 @@ export function createControlPlaneApi(options) {
6364
6399
  if (!registry.success)
6365
6400
  return refuseManifest(registry.error.issues[0], ['registry']);
6366
6401
  }
6402
+ // #2430: an owner grant is a person's, so it holds no key the registry reserves.
6403
+ const ownerGrants = pushedOwnerGrantProblems(checked.data);
6404
+ if (ownerGrants.length > 0)
6405
+ return refuseManifest({ path: ['ownerGrants'], message: ownerGrants.join('; ') });
6367
6406
  }
6368
6407
  await c.var.admin.publishVersion(c.get('actor'), input);
6369
6408
  const version = await c.var.admin.getVersion(c.get('actor'), input.id, slug);
@@ -7066,6 +7105,10 @@ export function createControlPlaneApi(options) {
7066
7105
  if (typeof raw !== 'string')
7067
7106
  return refuse(c, 'validation_failed', 'missing manifest part');
7068
7107
  const manifest = deployManifest.parse(JSON.parse(raw));
7108
+ // #2430: an owner grant is a person's, so it holds no key the registry reserves.
7109
+ const ownerGrants = pushedOwnerGrantProblems(manifest);
7110
+ if (ownerGrants.length > 0)
7111
+ return refuse(c, 'validation_failed', `manifest ownerGrants: ${ownerGrants.join('; ')}`);
7069
7112
  // §4 sandbox contract, before anything reaches the namespace.
7070
7113
  assertSandboxContract(manifest, options.storeDrivers);
7071
7114
  // #2339: a push whose migration digest is not the one its migrations give is refused here,
@@ -8042,8 +8085,52 @@ export function createControlPlaneApi(options) {
8042
8085
  // Re-read so the response carries the post-issuance status + DNS records the caller
8043
8086
  // (dashboard / CLI) renders — a custom bind comes back `verifying` with records.
8044
8087
  const out = (await c.var.admin.listHostnames(c.get('actor'), { scopeId: input.scopeId })).find((h) => h.hostname === input.hostname);
8088
+ // An install's platform hostname binds active here, which is what makes this the
8089
+ // install-time trigger for an Auth Server's relay client (#1544).
8090
+ await relayAfterActivation(c, undefined, out);
8045
8091
  return c.json(out ?? bound, 201);
8046
8092
  });
8093
+ // -- platform-provided social sign-in (#1544) --------------------------------
8094
+ // Staff only: on neither BUILDER_ROUTES nor TENANT_ROUTES, so both default-deny them. The
8095
+ // automatic trigger is a hostname becoming active (`relayAfterActivation`); these are the
8096
+ // levers for everything else — one install, or every Auth Server install after the relay
8097
+ // gained or lost a provider.
8098
+ app.post('/tenants/:tenantId/scopes/:scopeId/social-relay', async (c) => {
8099
+ if (!options.socialRelay)
8100
+ return refuseStatus(c, 501, 'no social relay is configured on this control plane');
8101
+ const tenantId = tenantIdSchema.parse(c.req.param('tenantId'));
8102
+ const scopeId = scopeIdSchema.parse(c.req.param('scopeId'));
8103
+ return c.json(await reconcileRelayFor(c, tenantId, scopeId));
8104
+ });
8105
+ app.post('/social-relay/reconcile', async (c) => {
8106
+ if (!options.socialRelay)
8107
+ return refuseStatus(c, 501, 'no social relay is configured on this control plane');
8108
+ const results = [];
8109
+ for (const vertical of SOCIAL_RELAY_VERTICALS) {
8110
+ const scopes = await c.var.admin.listScopes(c.get('actor'), { vertical, status: ['active'] });
8111
+ // One install at a time: each is a relay call and a delivery, and a fleet in parallel
8112
+ // would be a burst at the relay's single Durable Object for no gain.
8113
+ for (const scope of scopes) {
8114
+ try {
8115
+ results.push({ tenantId: scope.tenantId, scopeId: scope.id, ...(await reconcileRelayFor(c, scope.tenantId, scope.id)) });
8116
+ }
8117
+ catch (e) {
8118
+ results.push({
8119
+ tenantId: scope.tenantId,
8120
+ scopeId: scope.id,
8121
+ status: 'failed',
8122
+ reason: e instanceof Error ? e.message : String(e),
8123
+ });
8124
+ }
8125
+ }
8126
+ }
8127
+ return c.json({
8128
+ delivered: results.filter((r) => r.status === 'delivered').length,
8129
+ skipped: results.filter((r) => r.status === 'skipped').length,
8130
+ failed: results.filter((r) => r.status === 'failed').length,
8131
+ results,
8132
+ });
8133
+ });
8047
8134
  // Re-poll a custom hostname's issuance ("check again" in the dashboard). Tenant-narrowed
8048
8135
  // like the other hostname routes; a platform mint or an already-active row is a no-op
8049
8136
  // re-affirm. Idempotent and safe to hammer — it just reflects Cloudflare's current state.
@@ -8056,7 +8143,9 @@ export function createControlPlaneApi(options) {
8056
8143
  if (!row)
8057
8144
  return refuse(c, 'not_found', `unknown hostname: ${name.toLowerCase()}`);
8058
8145
  await runIssuance(c.var.admin, c.get('actor'), row);
8059
- return c.json(await hostnameRow(c, name));
8146
+ const after = await hostnameRow(c, name);
8147
+ await relayAfterActivation(c, row, after);
8148
+ return c.json(after);
8060
8149
  });
8061
8150
  app.patch('/hostnames/:hostname/status', async (c) => {
8062
8151
  const { status, note } = setHostnameStatusBody.parse(await c.req.json());
@@ -8066,8 +8155,10 @@ export function createControlPlaneApi(options) {
8066
8155
  if (confinedTenant(c.get('principal')) !== null && !(await tenantHostname(c, name))) {
8067
8156
  return refuse(c, 'not_found', `unknown hostname: ${name.toLowerCase()}`);
8068
8157
  }
8158
+ const before = await hostnameRow(c, name);
8069
8159
  await c.var.admin.setHostnameStatus(c.get('actor'), name, status, note);
8070
8160
  const row = (await c.var.admin.listHostnames(c.get('actor'), {})).find((h) => h.hostname === name.toLowerCase());
8161
+ await relayAfterActivation(c, before, row);
8071
8162
  return c.json(row);
8072
8163
  });
8073
8164
  // Unbind (hard-delete) a hostname row — what the orphan cleanup uses on rows
@@ -8458,6 +8549,8 @@ export function createControlPlaneApi(options) {
8458
8549
  let row;
8459
8550
  /** `fenced`: the ledger stamp and lease of this fork's restore (#1722), when it has one. */
8460
8551
  let restore;
8552
+ /** #2450: the fork's data, moved into the preview's copy once the ledger names it. */
8553
+ let forkData = null;
8461
8554
  /** #2009: the directory's classification of the row below, which every restore of it carries. */
8462
8555
  const markCopyOfRow = () => {
8463
8556
  const lineage = copyLineageOf({ kind: row.kind ?? '', forkedFrom: row.forkedFrom ?? null });
@@ -8472,7 +8565,14 @@ export function createControlPlaneApi(options) {
8472
8565
  throw new ControlPlaneError(501, 'preview needs dispatch resolution for the PR version');
8473
8566
  }
8474
8567
  const canonical = await c.var.admin.exportScope(actor, tenantId, source.id);
8475
- const tables = sourceClient ? await sourceClient.exportScope(source.id) : canonical.tables;
8568
+ // #2450: from a vertical, the fork's data moves a page at a time into the preview's own stage
8569
+ // there, so a scope of any size forks. Unstamped, as the whole export was: a fork writes
8570
+ // nothing into its source. Moved once, after the row and the ledger name the preview's copy
8571
+ // (K-31: no copied data without a record) and ahead of the restore's own retries, so a
8572
+ // restore blip reloads the same stage and an export fault is not recorded as a restore's.
8573
+ forkData = sourceClient
8574
+ ? async () => (await transferScope(sourceClient, target, { from: source.id, to: previewId }, { retry: retryTransient, stamp: false })).dump
8575
+ : async () => canonical.tables;
8476
8576
  // Directory row FIRST as `provisioning` (K-31 two-phase): a crash before the data
8477
8577
  // copy leaves an inert row that — carrying `forkedFrom` + `expiresAt` — the GC sweep
8478
8578
  // reaps, never copied data with no record.
@@ -8495,7 +8595,7 @@ export function createControlPlaneApi(options) {
8495
8595
  // pushes a fresh version per try) — #559 (2).
8496
8596
  // #2009: a load classifies nothing by itself, so the restore carries the directory's
8497
8597
  // classification of the row below, as every restore onto a non-primary scope does.
8498
- restore = (fenced) => target.restoreScope(tenantId, previewId, tables, { sourceScopeId: source.id, exact: true, ...markCopyOfRow(), ...fenced });
8598
+ restore = (fenced, dump) => target.restoreScope(tenantId, previewId, dump ?? [], { sourceScopeId: source.id, exact: true, ...markCopyOfRow(), ...fenced });
8499
8599
  }
8500
8600
  else {
8501
8601
  // A clean-room preview (#509 (b)): an EMPTY scope, no source to export. No `forkedFrom`
@@ -8541,7 +8641,8 @@ export function createControlPlaneApi(options) {
8541
8641
  fenced = { loadStamp: restoredStamp, fence: copyRestoreFence(moveId, recordedAt, copyLeaseMs, erasureEpoch) };
8542
8642
  }
8543
8643
  const load = restore;
8544
- await restoreOrRecord(() => load(fenced));
8644
+ const dump = forkData ? await forkData() : undefined;
8645
+ await restoreOrRecord(() => load(fenced, dump));
8545
8646
  }
8546
8647
  await c.var.admin.activateScope(actor, tenantId, previewId);
8547
8648
  // Bind the PR version. A private vertical's push self-admitted, so this is accepted; a