UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

1 lines • 51.2 kB
{"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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"}