everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
1 lines • 51.2 kB
Source Map (JSON)
{"version":3,"file":"train.cjs","names":["run","fetchBosConfigFromFastKv","process","preflightPublish","PublishTrainError","pinsFromPublishedConfig","pinsFromDeployState","findConfigPath","isAppDescriptorPath","openResolution","resolveWorkspaceTarget","uploadWorkspaceBundle","join","sourceLegDirs","platformUrlDeployEntries","hasFolderFormUi","resolveUiRuntimeName","existsSync","colors","icons","padRight","pluginUiUrlDeployEntries","generateCodeArtifacts","mergeAuthoredOverPublished","applyDeployResults","verifyRollbackSnapshot","pointerFingerprint","slotPins","fetchRegistryKey","composePlatformManifestPublishEntry","platformTruthViolations","formatNearError","buildWorkspaceTargets","realStorageLegDeps","fetchConfigHistory","dispatchSubmit","Context","Layer","Effect","BundleStorage","RegistryStore","SignerService","BuildTrainService","DeployTrainRenderService","Option"],"sources":["../../../src/services/deploy/train.ts"],"sourcesContent":["import { existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport process from \"node:process\";\nimport { Context, Effect, Layer, Option } from \"effect\";\nimport { hasFolderFormUi } from \"every-plugin/build/ui\";\nimport { findConfigPath, isAppDescriptorPath, resolveUiRuntimeName } from \"../../config\";\nimport type { WorkspaceDeployResult } from \"../../contract\";\nimport { openResolution } from \"../../services/resolution/session\";\nimport type { BosConfig, BosConfigInput, RuntimeConfig } from \"../../types\";\nimport { run } from \"../../utils/run\";\nimport { padRight } from \"../../utils/string\";\nimport { colors, icons } from \"../../utils/theme\";\nimport { ensureCustodyBalance, submitRegistryWriteCustody } from \"../auth/custody-signer\";\nimport { ensureDelegateKey, submitRegistryWriteDelegated } from \"../auth/delegate-signer\";\nimport { submitRegistryWrite } from \"../auth/near-signer\";\nimport { dispatchSubmit, SignerService, type SignerServiceShape } from \"../auth/signer\";\nimport { generateCodeArtifacts } from \"../codegen/artifacts\";\nimport { fetchBosConfigFromFastKv, fetchConfigHistory, fetchRegistryKey } from \"../registry/fastkv\";\nimport { pointerFingerprint, slotPins } from \"../registry/fingerprint\";\nimport { mergeAuthoredOverPublished } from \"../resolution/merge\";\nimport {\n type BuildTargetsDeps,\n type BuildTargetsInput,\n type BuildTargetsResult,\n BuildTrainService,\n buildWorkspaceTargets,\n resolveWorkspaceTarget,\n} from \"../workspace/build-train\";\nimport { BundleStorage, RegistryStore, type RegistryStoreShape } from \"./deps\";\nimport {\n type PreviousPin,\n pinsFromDeployState,\n pinsFromPublishedConfig,\n upsertDeployStatePins,\n} from \"./diff\";\nimport { PublishTrainError, type PublishTrainFailureResult, type PublishTrainOk } from \"./errors\";\nimport { formatNearError } from \"./format\";\nimport { applyDeployResults, type DeployResultEntry } from \"./integrity\";\nimport { platformUrlDeployEntries, pluginUiUrlDeployEntries } from \"./platform\";\nimport {\n composePlatformManifestPublishEntry,\n type PlatformManifestPublishEntry,\n platformTruthViolations,\n} from \"./platform-manifest\";\nimport { type PublishPreflightPlan, preflightPublish } from \"./preflight\";\nimport { type DeployTrainRender, DeployTrainRenderService } from \"./render\";\nimport { verifyRollbackSnapshot } from \"./rollback\";\nimport {\n realStorageLegDeps,\n type StorageLegDeps,\n sourceLegDirs,\n uploadWorkspaceBundle,\n} from \"./upload-leg\";\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Best-effort repo HEAD for the version manifest (`gitSha`): non-git\n * contexts (child bundles built outside a repo) omit the field silently —\n * it never fails the deploy. */\nasync function resolveGitSha(cwd: string): Promise<string | undefined> {\n try {\n const result = await run(\"git\", [\"rev-parse\", \"HEAD\"], { cwd, capture: true });\n const sha = result?.stdout.trim();\n return result && result.exitCode === 0 && sha ? sha : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport async function waitForPublishedConfig(opts: {\n account: string;\n gateway: string;\n publishConfig: BosConfigInput;\n registry?: string;\n timeoutMs?: number;\n intervalMs?: number;\n fetchConfig?: typeof fetchBosConfigFromFastKv;\n /** The submit's tx hash (#430): once the registry history shows this tx,\n * the write has landed on-chain — one authoritative read-back decides\n * instead of repeated deep-equality polling. */\n txHash?: string;\n fetchHistory?: typeof fetchConfigHistory;\n}): Promise<void> {\n const fetchConfig = opts.fetchConfig ?? fetchBosConfigFromFastKv;\n const envTimeoutMs = Number(process.env.BOS_PUBLISH_CONFIRMATION_TIMEOUT_MS);\n const envIntervalMs = Number(process.env.BOS_PUBLISH_CONFIRMATION_INTERVAL_MS);\n const timeoutMs =\n opts.timeoutMs ?? (Number.isFinite(envTimeoutMs) ? envTimeoutMs : undefined) ?? 120_000;\n const intervalMs =\n opts.intervalMs ?? (Number.isFinite(envIntervalMs) ? envIntervalMs : undefined) ?? 3_000;\n const startedAt = Date.now();\n let lastError: unknown;\n\n // The tx probe is the cheap poll (#430): while it is informative (returns\n // entries, tx not yet visible), the config equality read-back waits. After\n // a bounded run of informative-but-absent probes — or any probe failure —\n // the wait falls back permanently to plain equality polling, so a registry\n // whose history never carries the tx still confirms.\n let txProbeSkips = 0;\n const TX_PROBE_SKIP_LIMIT = 2;\n\n while (Date.now() - startedAt < timeoutMs) {\n try {\n let trackByTx = opts.txHash !== undefined && opts.fetchHistory !== undefined;\n if (trackByTx && txProbeSkips >= TX_PROBE_SKIP_LIMIT) {\n trackByTx = false;\n }\n\n if (trackByTx) {\n try {\n const history = await opts.fetchHistory!({\n accountId: opts.account,\n gatewayId: opts.gateway,\n registry: opts.registry,\n limit: 5,\n });\n const txLanded = history.some((entry) => entry.txHash === opts.txHash);\n if (txLanded) {\n // The write landed on-chain — the read-back is the authoritative\n // content check (ADR 0001). A mismatch keeps polling:\n // replication may lag the tx.\n txProbeSkips = 0;\n } else {\n txProbeSkips += 1;\n await sleep(intervalMs);\n continue;\n }\n } catch (historyError) {\n // A history probe failure must not starve the wait — fall back to\n // the plain equality poll.\n lastError = historyError;\n }\n }\n\n const verifiedConfig = await fetchConfig<BosConfigInput>(\n `bos://${opts.account}/${opts.gateway}`,\n opts.registry,\n );\n if (JSON.stringify(verifiedConfig) === JSON.stringify(opts.publishConfig)) {\n return;\n }\n } catch (error) {\n lastError = error;\n }\n\n await sleep(intervalMs);\n }\n\n const reason = lastError instanceof Error ? ` Last error: ${lastError.message}` : \"\";\n throw new Error(\n `Timed out waiting for publish confirmation at bos://${opts.account}/${opts.gateway}.${reason}`,\n );\n}\n\nexport async function isConfigAlreadyPublished(opts: {\n account: string;\n gateway: string;\n publishConfig: BosConfigInput;\n registry?: string;\n fetchConfig?: typeof fetchBosConfigFromFastKv;\n}): Promise<boolean> {\n const fetchConfig = opts.fetchConfig ?? fetchBosConfigFromFastKv;\n try {\n const current = await fetchConfig<BosConfigInput>(\n `bos://${opts.account}/${opts.gateway}`,\n opts.registry,\n );\n return JSON.stringify(current) === JSON.stringify(opts.publishConfig);\n } catch {\n return false;\n }\n}\n\n/** Per-workspace upload facts the renderer needs (#431) — the leg reports,\n * the renderer shows. */\nexport interface UploadUnitDetail {\n base: string;\n uploaded: number;\n skipped: number;\n durationMs: number;\n notes: string[];\n}\n\nexport interface TrainDeps {\n storage: StorageLegDeps;\n registry: RegistryStoreShape;\n signer: SignerServiceShape;\n /** presentation seam (#431) — sections render; the train never prints */\n render?: DeployTrainRender;\n buildTrain: {\n buildTargets: (\n input: BuildTargetsInput,\n deps?: BuildTargetsDeps,\n ) => Promise<BuildTargetsResult>;\n };\n}\n\nexport interface DeployTrainInput {\n bosConfig: BosConfig;\n runtimeConfig: RuntimeConfig | null;\n configDir: string;\n env: \"production\" | \"staging\";\n build: boolean;\n dryRun: boolean;\n verbose: boolean;\n packages: string;\n network?: \"mainnet\" | \"testnet\";\n privateKey?: string;\n wallet?: boolean;\n registry?: string;\n /** Skip the diff upload and re-upload every dist file (escape hatch). */\n fullUpload?: boolean;\n /** Force every prerequisite rebuild even when the content-hash oracle judges\n * them fresh (the pre-#430 behavior; escape hatch for the oracle). */\n forceBuild?: boolean;\n /** Publish `bosConfig` verbatim — no authored/published merge, no ts-form\n * config-only guard. Rollbacks use this: the payload is the previous\n * snapshot, already assembled. */\n exactPayload?: boolean;\n}\n\n/**\n * The deploy-train publish core (ADR 0020, as amended): preflight\n * (storage/CDN creds + signing) fails fast before the build, then build →\n * upload → version-manifest pin → config write-back → FastKV publish +\n * read-back. Scoped to one plugin via `packages`, a single-plugin redeploy\n * ships real bytes to the storage origin — same as the full train, nothing\n * image-native left.\n *\n * Terminal failures throw `PublishTrainError` (the typed channel, ticket\n * #422); callers behind the service map it to wire shapes mechanically.\n */\nexport async function runPublishTrain(\n input: DeployTrainInput,\n deps: TrainDeps,\n): Promise<PublishTrainOk> {\n const preflight = await preflightPublish(input);\n if (preflight.kind === \"error\") {\n throw new PublishTrainError({\n kind: \"preflight\",\n registryUrl: preflight.registryUrl,\n error: preflight.error,\n });\n }\n if (preflight.kind === \"dry-run\") {\n return { status: \"dry-run\", registryUrl: preflight.registryUrl };\n }\n const plan: PublishPreflightPlan = preflight.plan;\n const {\n isStaging,\n account,\n gateway,\n network,\n registryUrl,\n registryNamespace,\n targets,\n useWallet,\n useCustody,\n strategy,\n } = plan;\n const storageOrigin = plan.storageOrigin;\n const storageApiKey = plan.storageApiKey;\n\n const { configDir } = input;\n const render = deps.render;\n let bosConfig = input.bosConfig;\n const runtimeConfig = input.runtimeConfig;\n let built: string[] | undefined;\n let skipped: string[] | undefined;\n let deployResults: WorkspaceDeployResult[] | undefined;\n const urlOrigin = plan.cdnOrigin ?? `https://${gateway}`;\n const platformEntries: DeployResultEntry[] = [];\n const fullUpload = input.fullUpload === true || process.env.BOS_FULL_UPLOAD === \"1\";\n const sourcePublish = bosConfig.publish?.sourcePublish === true;\n const gitSha = await resolveGitSha(configDir);\n const memoryBackendAbort = () =>\n new PublishTrainError({\n kind: \"memory-backend\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error:\n \"The receiving instance is serving bundle storage from memory (BOS_STORAGE_* R2 credentials are not configured there) — uploaded bytes would be lost on restart. Aborting before publish.\",\n });\n\n // Previous per-workspace pins for the diff upload: the local pointer wins\n // (written after every confirmed publish), the published config is the\n // fallback. Neither → full upload. Hoisted above the build so pipelined\n // uploads can read it the moment a build completes.\n const prevPins: Record<string, PreviousPin> = fullUpload\n ? {}\n : {\n ...pinsFromPublishedConfig(\n (plan.publishedConfig ?? {}) as BosConfigInput,\n account,\n gateway,\n ),\n ...pinsFromDeployState(configDir, account, gateway),\n };\n\n const authoredPath = findConfigPath(configDir);\n const tsForm = authoredPath !== null && isAppDescriptorPath(authoredPath);\n // Resolved before the build phase: pipelined uploads (#430) start the moment\n // a workspace build completes and the folder-form plugin-ui leg reads the\n // authored config — the binding must be live by then, never first\n // initialized after the train. The post-build refresh reassigns\n // publishRawConfig for the publish payload.\n const openedRaw = await openResolution({ cwd: configDir });\n if (!openedRaw?.rawConfig) {\n throw new PublishTrainError({\n kind: \"reload\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error: \"Failed to load the authored config for publish\",\n });\n }\n const authoredRawConfig = openedRaw.rawConfig;\n let publishRawConfig: BosConfigInput = authoredRawConfig;\n\n render?.cdnBanner?.(storageOrigin);\n\n // One workspace = one upload unit: the workspace bundle, then (for\n // folder-form plugin workspaces) its <plugin>/ui/dist as its own bundle\n // key. Workspace paths resolve from the authored config — identical before\n // and after the post-build config refresh — so pipelined uploads (#430) can\n // start the moment a build completes.\n const uploadOneWorkspace = async (\n key: string,\n rawConfig: BosConfigInput,\n ): Promise<{\n entries: DeployResultEntry[];\n detail: UploadUnitDetail;\n shared: Record<string, Record<string, string>>;\n }> => {\n const startedAt = Date.now();\n const ws = resolveWorkspaceTarget(key, bosConfig, runtimeConfig, configDir);\n if (!ws)\n return {\n entries: [],\n detail: { base: \"\", uploaded: 0, skipped: 0, durationMs: 0, notes: [] },\n shared: {},\n };\n\n const outcome = await uploadWorkspaceBundle({\n account,\n gateway,\n workspaceKey: key,\n distDir: join(ws.path, \"dist\"),\n storageOrigin,\n storageApiKey,\n urlOrigin,\n previousPin: prevPins[key],\n ...(sourcePublish ? { source: sourceLegDirs(ws.path) } : {}),\n ...(gitSha ? { gitSha } : {}),\n deps: deps.storage,\n });\n if (outcome.kind === \"error\") {\n throw new PublishTrainError({\n kind: \"upload\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error: outcome.message,\n });\n }\n if (outcome.kind === \"memory\") throw memoryBackendAbort();\n if (outcome.kind === \"missing-manifest\") {\n throw new PublishTrainError({\n kind: \"missing-manifest\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error: `bundle upload for ${key}: version manifest missing — the dist predates hashed entry names (rebuild required; atomic-deploys hard break)`,\n });\n }\n\n if (sourcePublish && outcome.storage === \"memory\") throw memoryBackendAbort();\n\n const entries = platformUrlDeployEntries({\n origin: urlOrigin,\n account,\n gateway,\n key,\n kind: ws.kind,\n integrity: outcome.entryIntegrity,\n ssrIntegrity: outcome.ssrEntryIntegrity,\n pin: outcome.pin,\n });\n\n // Folder-form plugin ui: the workspace build also produces <plugin>/ui/dist\n // (web remoteEntry + ssr container) — upload it as its own bundle key and\n // pin <slot>.<key>.ui.* so the host can compose the ui surface in production.\n let uiOutcomeShared: Record<string, string> | undefined;\n if (hasFolderFormUi(ws.path)) {\n const uiDistDir = join(ws.path, \"ui\", \"dist\");\n const uiSlot = ws.kind === \"app\" ? \"app\" : \"plugins\";\n const rawSlot = (uiSlot === \"app\" ? rawConfig.app : rawConfig.plugins) as\n | Record<string, Record<string, unknown> | undefined>\n | undefined;\n const rawUi = rawSlot?.[key]?.ui as Record<string, unknown> | undefined;\n const uiName = resolveUiRuntimeName(rawUi, join(ws.path, \"ui\"), key);\n let uiIntegrity: string | undefined;\n let uiSsrIntegrity: string | undefined;\n let uiPin: (typeof outcome)[\"pin\"] | undefined;\n if (existsSync(uiDistDir)) {\n const uiOutcome = await uploadWorkspaceBundle({\n account,\n gateway,\n workspaceKey: `${key}-ui`,\n distDir: uiDistDir,\n storageOrigin,\n storageApiKey,\n urlOrigin,\n previousPin: prevPins[`${key}-ui`],\n deps: deps.storage,\n });\n if (uiOutcome.kind === \"error\") {\n throw new PublishTrainError({\n kind: \"upload\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error: uiOutcome.message,\n });\n }\n if (uiOutcome.kind === \"memory\") throw memoryBackendAbort();\n if (uiOutcome.kind === \"missing-manifest\") {\n throw new PublishTrainError({\n kind: \"missing-manifest\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error: `bundle upload for ${key}-ui: version manifest missing — the dist predates hashed entry names (rebuild required; atomic-deploys hard break)`,\n });\n }\n uiIntegrity = uiOutcome.entryIntegrity;\n uiSsrIntegrity = uiOutcome.ssrEntryIntegrity;\n uiPin = uiOutcome.pin;\n uiOutcomeShared = uiOutcome.shared;\n } else {\n console.log(\n ` ${colors.green(icons.ok)} ${padRight(`${key}-ui`, 28)} → ${urlOrigin}/bundles/${account}/${gateway}/${key}-ui/`,\n );\n }\n\n entries.push(\n ...pluginUiUrlDeployEntries({\n origin: urlOrigin,\n account,\n gateway,\n key,\n kind: ws.kind,\n integrity: uiIntegrity,\n ssrIntegrity: uiSsrIntegrity,\n name: uiName,\n pin: uiPin,\n }),\n );\n }\n\n return {\n entries,\n detail: {\n base: outcome.detail.base,\n uploaded: outcome.uploaded,\n skipped: outcome.skipped,\n durationMs: Date.now() - startedAt,\n notes: outcome.detail.notes,\n },\n shared: {\n ...(outcome.shared ? { [key]: outcome.shared } : {}),\n ...(uiOutcomeShared ? { [`${key}-ui`]: uiOutcomeShared } : {}),\n },\n };\n };\n\n // Uploads are independent bundle keys (#430): bounded concurrency, and —\n // when building — each workspace's upload pipelines as its build completes\n // instead of waiting for the whole train. The merged config assembles in\n // target order (byte-identical to the serial train); the first failure in\n // that order is the one thrown.\n const uploadConcurrency = Math.max(1, Number(process.env.BOS_UPLOAD_CONCURRENCY) || 4);\n interface UploadUnitResult {\n entries: DeployResultEntry[];\n detail: UploadUnitDetail;\n /** Shared-singleton versions per uploaded bundle key (#546) — the truth\n * gate cross-checks these against the platform release manifest. */\n shared: Record<string, Record<string, string>>;\n }\n const uploaded = new Map<string, Promise<UploadUnitResult>>();\n // Rejections stay in the map until the drain's allSettled — deleting would\n // both swallow the failure (the drain substitutes an empty result) and let\n // the fallback loop silently re-attempt the upload. The immediate no-op\n // catch keeps the pipelined rejection handled while the build continues.\n const trackUpload = (key: string, pending: Promise<UploadUnitResult>) => {\n uploaded.set(key, pending);\n pending.catch(() => {});\n };\n let inFlight = 0;\n const waiters: Array<() => void> = [];\n const acquireUploadSlot = () => {\n if (inFlight < uploadConcurrency) {\n inFlight++;\n return Promise.resolve();\n }\n return new Promise<void>((resolve) => waiters.push(resolve));\n };\n const releaseUploadSlot = () => {\n inFlight--;\n waiters.shift()?.();\n };\n const startUpload = (key: string) => {\n if (uploaded.has(key)) return;\n trackUpload(\n key,\n (async () => {\n await acquireUploadSlot();\n try {\n return await uploadOneWorkspace(key, authoredRawConfig);\n } finally {\n releaseUploadSlot();\n }\n })(),\n );\n };\n\n if (input.build) {\n await generateCodeArtifacts(configDir, bosConfig, {\n env: \"production\",\n runtimeConfig: runtimeConfig ?? undefined,\n });\n\n const result = await deps.buildTrain.buildTargets(\n {\n configDir,\n bosConfig,\n runtimeConfig,\n targets,\n deploy: true,\n verbose: input.verbose,\n ...(input.forceBuild ? { forceBuild: true } : {}),\n },\n {\n onWorkspaceBuilt: (key) => {\n if (targets.includes(key)) startUpload(key);\n },\n },\n );\n built = result.built;\n skipped = result.skipped;\n deployResults = result.deployResults;\n\n if (deployResults) {\n const failures = deployResults.filter((r) => !r.success);\n if (failures.length > 0) {\n const total = deployResults.length;\n console.log();\n console.log(\n colors.error(\n ` ${icons.err} Deploy failed — ${failures.length} of ${total} workspace${total > 1 ? \"s\" : \"\"} failed`,\n ),\n );\n console.log();\n for (const f of failures) {\n const errorLine = (f.error ?? \"Failed\").split(\"\\n\")[0];\n console.log(` ${colors.error(icons.err)} ${padRight(f.key, 28)} ${errorLine}`);\n }\n console.log();\n if (!input.verbose) {\n console.log(colors.dim(\" Run with --verbose for full build output.\"));\n console.log();\n }\n throw new PublishTrainError({\n kind: \"build\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error: `${failures.length} of ${total} workspaces failed to deploy`,\n });\n }\n }\n\n const refreshed = await openResolution({ cwd: configDir });\n if (!refreshed?.config) {\n throw new PublishTrainError({\n kind: \"reload\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error: \"Failed to reload the config after build\",\n });\n }\n\n bosConfig = refreshed.config;\n if (refreshed.rawConfig) publishRawConfig = refreshed.rawConfig;\n }\n\n if (\n tsForm &&\n !input.build &&\n input.exactPayload !== true &&\n plan.publishedConfigState === \"unreachable\"\n ) {\n // A config-only TS-form publish derives its pipeline state from the live\n // published config — publishing without it would wipe bundle URLs.\n throw new PublishTrainError({\n kind: \"config-state\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error:\n \"Cannot read the currently published config from the registry — a config-only publish would overwrite live bundle URLs. Retry when the registry is reachable, or run a full deploy.\",\n });\n }\n let publishPayload: BosConfigInput =\n input.exactPayload === true\n ? // The rollback payload is a previous snapshot: Zod-parsed form, already\n // assembled — the hand-written input shape and the parsed shape agree\n // at runtime; the declared types don't (pre-existing publish.ts:779).\n (input.bosConfig as unknown as BosConfigInput)\n : tsForm && !input.build\n ? // Config-only publish on a TS-form project: the authored config owns\n // composition (hand-edits win) while live pipeline state (bundle\n // URLs, integrity) carries over from the published config.\n mergeAuthoredOverPublished(\n (plan.publishedConfig ?? {}) as BosConfigInput,\n publishRawConfig,\n )\n : publishRawConfig;\n\n // Everything the pipeline has not already started uploads now — same\n // bounded pool. With build:false there is nothing to upload (config-only).\n for (const key of built ?? []) {\n if (targets.includes(key)) startUpload(key);\n }\n\n const deployTargets = (built ?? []).filter((key) => targets.includes(key));\n const settled = await Promise.allSettled(\n deployTargets.map(\n (key) =>\n uploaded.get(key) ??\n Promise.resolve({\n entries: [],\n detail: { base: \"\", uploaded: 0, skipped: 0, durationMs: 0, notes: [] },\n shared: {},\n }),\n ),\n );\n // Shared-singleton versions per uploaded bundle key (#546) — the truth gate\n // consumes this before the platform manifest rides the atomic publish.\n const sharedByWorkspace = new Map<string, Record<string, string>>();\n\n const uploadFailures = settled\n .map((result, index) =>\n result.status === \"rejected\"\n ? { key: deployTargets[index], error: result.reason as unknown }\n : null,\n )\n .filter((entry): entry is { key: string; error: unknown } => entry !== null);\n\n for (let index = 0; index < deployTargets.length; index++) {\n const result = settled[index];\n const key = deployTargets[index];\n if (result.status === \"fulfilled\") {\n platformEntries.push(...result.value.entries);\n for (const [bundleKey, shared] of Object.entries(result.value.shared)) {\n sharedByWorkspace.set(bundleKey, shared);\n }\n render?.uploadOutcome?.({\n key,\n ok: true,\n ...(input.verbose ? { detailNotes: result.value.detail.notes } : {}),\n ...result.value.detail,\n });\n } else {\n render?.uploadOutcome?.({ key, ok: false });\n }\n }\n\n if (uploadFailures.length > 0) {\n const thrown = uploadFailures[0].error;\n if (thrown instanceof PublishTrainError) throw thrown;\n throw new PublishTrainError({\n kind: \"upload\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error: thrown instanceof Error ? thrown.message : String(thrown),\n });\n }\n\n if (platformEntries.length > 0) {\n const merged = applyDeployResults(publishRawConfig as Record<string, unknown>, platformEntries);\n if (!tsForm) {\n // Legacy JSON-form children keep their local write-back; TS-form keeps\n // pipeline state in FastKV only — a write-back would shadow the\n // authored bos.app.ts descriptor.\n try {\n writeFileSync(join(configDir, \"bos.config.json\"), `${JSON.stringify(merged, null, 2)}\\n`);\n } catch (error) {\n throw new PublishTrainError({\n kind: \"config-write\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error: `Failed to write bundle URLs to bos.config.json: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n }\n publishPayload = merged as BosConfigInput;\n }\n if (isStaging) {\n publishPayload = { ...publishPayload, domain: gateway };\n }\n\n const pinVerification = await verifyRollbackSnapshot(publishPayload);\n if (pinVerification.verifiable && !pinVerification.ok) {\n const failures = pinVerification.slots\n .filter((check) => !check.ok)\n .map((check) => ` ${check.slot}: ${check.reason}`)\n .join(\"\\n\");\n console.error(\n ` ${colors.error(icons.err)} Publish blocked — a pinned slot's bytes do not serve at its production URL:\\n${failures}`,\n );\n throw new PublishTrainError({\n kind: \"pin-verification\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error: `Publish blocked — pinned slot bytes missing or SRI mismatched:\\n${failures}`,\n });\n }\n\n const registryKey = `apps/${account}/${gateway}/bos.config.json`;\n const publishedAt = new Date().toISOString();\n // version identity printed + returned for every deploy (atomic-deploys 12)\n const fingerprint = pointerFingerprint(publishPayload as never);\n const publishSlotPins = slotPins(publishPayload as never);\n const registryEntries: Record<string, string> = {\n [registryKey]: JSON.stringify(publishPayload),\n };\n const manifestKey = `apps/${account}/${gateway}/manifests/${publishedAt.replace(/[:.]/g, \"-\")}.json`;\n // ADR 0034: the platform release manifest rides the same atomic write —\n // framework-rooted production build trains only (children and config-only\n // publishes publish nothing). The compat floor is the previous release; a\n // registry *failure* (vs an absent slot) skips this deploy's manifest —\n // a silently-widened or silently-tightened floor would publish a wrong\n // compat window — and the next deploy lands it.\n let platformManifest: PlatformManifestPublishEntry | null = null;\n if (!isStaging && input.build) {\n try {\n const previous = await fetchRegistryKey<{ frameworkVersion?: string }>(\n account,\n gateway,\n \"platform.json\",\n );\n platformManifest = composePlatformManifestPublishEntry({\n configDir,\n account,\n gateway,\n previousFrameworkVersion: previous?.frameworkVersion,\n gitSha,\n });\n } catch (error) {\n console.warn(\n ` platform manifest skipped this deploy — the previous release could not be read: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n // The truth gate (#546): the manifest is composed from the release\n // catalog; a workspace whose installed shared versions drifted from the\n // catalog (stale install, misaligned bump) would publish a manifest that\n // lies about the uploaded bytes — the exact republish that breaks\n // pinned children. Refuses loudly instead.\n if (platformManifest) {\n const violations = platformTruthViolations(platformManifest.manifest, sharedByWorkspace);\n if (violations.length > 0) {\n throw new PublishTrainError({\n kind: \"platform-truth\",\n registryUrl,\n built,\n skipped,\n deployResults,\n error:\n `platform manifest does not match the uploaded bundles:\\n` +\n violations.map((line) => ` ${line}`).join(\"\\n\"),\n });\n }\n }\n }\n registryEntries[manifestKey] = JSON.stringify({\n account,\n gateway,\n network,\n publishedAt,\n registryUrl,\n ...(platformManifest\n ? {\n platformManifest: {\n file: platformManifest.key,\n integrity: platformManifest.integrity,\n },\n }\n : {}),\n });\n if (platformManifest) {\n registryEntries[platformManifest.key] = platformManifest.value;\n }\n\n render?.publish?.({\n registryUrl,\n fingerprint,\n slotPins: Object.entries(publishSlotPins),\n auditManifestFile: manifestKey.split(\"/\").pop() ?? manifestKey,\n });\n\n // Record the live pins for the next deploy's diff upload — only after the\n // config is confirmed published, so the pointer never claims undeployed state.\n const persistDeployState = () => {\n try {\n const pins = pinsFromPublishedConfig(publishPayload as BosConfigInput, account, gateway);\n if (Object.keys(pins).length > 0) {\n upsertDeployStatePins(configDir, account, gateway, pins);\n }\n } catch (error) {\n console.log(\n colors.dim(\n ` Note: could not update .bos/deploy-state.json — ${error instanceof Error ? error.message : String(error)}`,\n ),\n );\n }\n };\n\n try {\n // NOT deduped with the preflight's published-config read (#430): that\n // fetch returns the raw stored JSON, while the idempotency comparison is\n // normalization-sensitive (the registry reader Zod-parses — defaults and\n // key order differ) — comparing across the two readers misdetects drift\n // and would republish every run. The equality fetch stays.\n const alreadyPublished = await isConfigAlreadyPublished({\n account,\n gateway,\n publishConfig: publishPayload,\n registry: input.registry,\n fetchConfig: deps.registry.fetchConfig,\n });\n if (alreadyPublished) {\n console.log(\" Already up to date — skipping transaction\");\n persistDeployState();\n return {\n status: \"published\",\n registryUrl,\n built,\n skipped,\n deployResults,\n publishConfig: publishPayload,\n };\n }\n\n console.log(` Submitting transaction on ${network}...`);\n\n // Auth handles were validated once in preflight (guards once per run,\n // ticket #422) — the dispatch consumes the plan's handles.\n const result = await (async (): Promise<{ success: boolean; txHash?: string }> => {\n if (useCustody) {\n if (!plan.custodyWallet) {\n throw new PublishTrainError({\n kind: \"submit\",\n registryUrl,\n error: \"custody publish requires the preflight custody wallet\",\n });\n }\n return deps.signer.submit({\n mode: \"custody\",\n account,\n contract: registryNamespace,\n args: registryEntries,\n custodyWallet: plan.custodyWallet,\n idempotencyKey: `bos-publish-${fingerprint}`,\n });\n }\n if (useWallet) {\n const credential = plan.credential;\n if (!credential || credential.accountId !== account) {\n throw new PublishTrainError({\n kind: \"submit\",\n registryUrl,\n error: `--wallet requires a CLI session under ${account}. Run bos login first.`,\n });\n }\n return deps.signer.submit({\n mode: \"wallet\",\n account,\n contract: registryNamespace,\n network,\n args: registryEntries,\n credential,\n configDir,\n });\n }\n if (!strategy) {\n throw new PublishTrainError({\n kind: \"submit\",\n registryUrl,\n error: \"non-wallet publish requires a resolved signing strategy\",\n });\n }\n return deps.signer.submit({\n mode: \"key\",\n account,\n contract: registryNamespace,\n network,\n args: registryEntries,\n privateKey: input.privateKey,\n strategy,\n });\n })();\n\n if (result.txHash) {\n console.log(` Transaction submitted: ${colors.dim(result.txHash)}`);\n }\n\n console.log(\" Waiting for publish confirmation...\");\n try {\n await waitForPublishedConfig({\n account,\n gateway,\n publishConfig: publishPayload,\n registry: input.registry,\n fetchConfig: deps.registry.fetchConfig,\n ...(result.txHash\n ? { txHash: result.txHash, fetchHistory: deps.registry.fetchHistory }\n : {}),\n });\n } catch (error) {\n throw new PublishTrainError({\n kind: \"confirm\",\n registryUrl,\n error: formatNearError(error),\n built,\n skipped,\n deployResults,\n });\n }\n persistDeployState();\n\n return {\n status: \"published\",\n registryUrl,\n txHash: result.txHash,\n fingerprint,\n slotPins: publishSlotPins,\n built,\n skipped,\n deployResults,\n publishConfig: publishPayload,\n };\n } catch (error) {\n if (error instanceof PublishTrainError) throw error;\n throw new PublishTrainError({\n kind: \"sign\",\n registryUrl,\n error: formatNearError(error),\n built,\n skipped,\n deployResults,\n });\n }\n}\n\n/** Procedural entry point: the train behind a plain promise — legacy callers\n * and tests see the string-error result shape, the Effect service maps the\n * typed channel. */\nexport async function publishToFastKv(input: DeployTrainInput): Promise<PublishToFastKvResult> {\n try {\n const ok = await runPublishTrain(input, realTrainDeps);\n return ok;\n } catch (error) {\n if (error instanceof PublishTrainError) return error.toResult();\n throw error;\n }\n}\n\nconst defaultBuildTrain = {\n buildTargets: (input: BuildTargetsInput, deps?: BuildTargetsDeps) =>\n buildWorkspaceTargets(input, deps),\n};\n\nexport const realTrainDeps: TrainDeps = {\n buildTrain: defaultBuildTrain,\n storage: realStorageLegDeps,\n registry: { fetchConfig: fetchBosConfigFromFastKv, fetchHistory: fetchConfigHistory },\n signer: {\n submitRegistryWrite,\n submitRegistryWriteDelegated,\n submitRegistryWriteCustody,\n ensureDelegateKey,\n ensureCustodyBalance,\n submit: dispatchSubmit,\n },\n};\n\nexport type PublishToFastKvResult = PublishTrainOk | PublishTrainFailureResult;\n\n/**\n * The train as a Context.Service (ticket #422): `publish` fails with the\n * typed `PublishTrainError`; handlers yield the service and map failures\n * mechanically.\n */\nexport class DeployTrainService extends Context.Service<\n DeployTrainService,\n {\n publish: (input: DeployTrainInput) => Effect.Effect<PublishTrainOk, PublishTrainError>;\n }\n>()(\"everything-dev/deploy/train\") {\n static readonly Live = Layer.effect(\n this,\n Effect.gen(function* () {\n const storage = yield* BundleStorage;\n const registry = yield* RegistryStore;\n const signer = yield* SignerService;\n const buildTrainOption = yield* Effect.serviceOption(BuildTrainService);\n const renderOption = yield* Effect.serviceOption(DeployTrainRenderService);\n return DeployTrainService.of({\n publish: (input: DeployTrainInput) =>\n Effect.tryPromise({\n try: () =>\n runPublishTrain(input, {\n storage,\n registry,\n signer,\n buildTrain: Option.getOrUndefined(buildTrainOption) ?? defaultBuildTrain,\n render: Option.getOrUndefined(renderOption),\n }),\n catch: (error) =>\n error instanceof PublishTrainError\n ? error\n : new PublishTrainError({ kind: \"submit\", registryUrl: \"\", error: String(error) }),\n }),\n });\n }),\n );\n}\n"],"mappings":"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"}