{"version":3,"file":"publish.mjs","names":[],"sources":["../src/publish.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport process from \"node:process\";\nimport { hasFolderFormUi } from \"every-plugin/build/ui\";\nimport { readSessionHandle } from \"./auth-session\";\nimport { buildWorkspaceTargets, resolveWorkspaceTarget, selectWorkspaceTargets } from \"./build\";\nimport { type CdnDeployInputs, probeStorageOrigin, resolveCdnDeployInputs } from \"./cdn-deploy\";\nimport { formatDuration } from \"./cli/timing\";\nimport { generateCodeArtifacts } from \"./code-artifacts\";\nimport { findConfigPath, isAppDescriptorPath, resolveUiRuntimeName } from \"./config\";\nimport type { WorkspaceDeployResult } from \"./contract\";\nimport { ensureDelegateKey, submitRegistryWriteDelegated } from \"./delegate-signer\";\nimport {\n  diffWorkspaceFiles,\n  localSriMap,\n  mergedFileIntegrity,\n  type PreviousPin,\n  pinsFromDeployState,\n  pinsFromPublishedConfig,\n  upsertDeployStatePins,\n} from \"./deploy-diff\";\nimport {\n  buildRegistryConfigUrlForNetwork,\n  fetchBosConfigFromFastKv,\n  getRegistryNamespaceForNetwork,\n  type NetworkId,\n} from \"./fastkv\";\nimport { pointerFingerprint, slotPins } from \"./fingerprint\";\nimport { fetchResponse } from \"./http-client\";\nimport { applyDeployResults, type DeployResultEntry } from \"./integrity\";\nimport { mergeAuthoredOverPublished } from \"./merge\";\nimport {\n  describeSigningStrategy,\n  resolveSigningStrategy,\n  type SigningStrategy,\n  submitRegistryWrite,\n} from \"./near-signer\";\nimport { getNetworkIdForAccount } from \"./network\";\nimport { platformUrlDeployEntries, pluginUiUrlDeployEntries } from \"./platform-deploy\";\nimport { openResolution } from \"./resolution/session\";\nimport { verifyRollbackSnapshot } from \"./rollback\";\nimport {\n  collectDistFiles,\n  type DistFile,\n  uploadBundle,\n  uploadWorkspaceDist,\n} from \"./storage-upload\";\nimport type { BosConfig, BosConfigInput, PublishConfig, RuntimeConfig } from \"./types\";\nimport { padRight } from \"./utils/string\";\nimport { colors, icons } from \"./utils/theme\";\nimport { composeWorkspaceVersionManifest, readBuildReport } from \"./version-manifest-deploy\";\nimport { resolveSlotVersion } from \"./version-manifest-resolve\";\n\nfunction sleep(ms: number): Promise<void> {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Compose + upload the workspace's version manifest (atomic-deploys 03): the\n * manifest is built from the dist build report + the **server-computed** SRI\n * map of the just-finished upload, uploaded additively at\n * `versions/<version>.json`, and returned as the slot's pointer. Returns\n * undefined when the dist predates hashed entry names (no report / no entry\n * SRI) — the caller aborts the train: uploaded workspaces must pin.\n */\n/**\n * The manifest's own storage backend — when every dist file was diff-skipped\n * it is the only upload of the leg, so it is the only signal for the\n * memory-backend abort below.\n */\nexport interface VersionManifestPin {\n  file: string;\n  integrity: string;\n  storage?: \"s3\" | \"memory\";\n}\n\nasync function pinWorkspaceVersionManifest(input: {\n  origin: string;\n  apiKey?: string;\n  account: string;\n  gateway: string;\n  workspace: string;\n  report: ReturnType<typeof readBuildReport>;\n  ssrReport: ReturnType<typeof readBuildReport>;\n  integrityMap: Record<string, string>;\n  /** full per-file SRI map of the dist — recorded for the next deploy's diff */\n  files?: Record<string, string>;\n}): Promise<VersionManifestPin | undefined> {\n  if (!input.report) return undefined;\n  const versionManifest = composeWorkspaceVersionManifest({\n    report: input.report,\n    ssrReport: input.ssrReport,\n    integrityMap: input.integrityMap,\n    ...(input.files ? { files: input.files } : {}),\n  });\n  if (!versionManifest) return undefined;\n\n  const manifestFile = `versions/${versionManifest.version}.json`;\n  const manifestUpload = await uploadBundle({\n    origin: input.origin,\n    apiKey: input.apiKey,\n    account: input.account,\n    gateway: input.gateway,\n    workspace: input.workspace,\n    files: [\n      {\n        path: manifestFile,\n        bytes: new TextEncoder().encode(`${JSON.stringify(versionManifest, null, 2)}\\n`),\n      },\n    ],\n  });\n  const manifestIntegrity = manifestUpload.integrity[manifestFile];\n  if (!manifestIntegrity) return undefined;\n  console.log(\n    `    ${colors.dim(`${padRight(\"\", 28)} version manifest ${manifestFile} (SRI pinned)`)}`,\n  );\n  return { file: manifestFile, integrity: manifestIntegrity, storage: manifestUpload.storage };\n}\n\ninterface DiffUploadOutcome {\n  result: {\n    stored: number;\n    totalBytes: number;\n    integrity: Record<string, string>;\n    storage?: \"s3\" | \"memory\";\n  };\n  /** per-file SRI map covering the whole dist (uploaded → server SRI, skipped → previous manifest SRI) */\n  fileIntegrity: Record<string, string>;\n  uploaded: number;\n  skipped: number;\n  total: number;\n}\n\n/**\n * One workspace's upload leg with skip-unchanged diffing: resolve the previous\n * manifest's `files` map, hash the local dist, upload only new/changed files,\n * and return the merged per-file SRI map for the version manifest. Any failure\n * to resolve the previous map degrades to a full upload.\n */\nasync function diffUploadWorkspace(input: {\n  origin: string;\n  apiKey?: string;\n  account: string;\n  gateway: string;\n  workspace: string;\n  files: DistFile[];\n  base: string;\n  previousPin: PreviousPin | undefined;\n}): Promise<DiffUploadOutcome> {\n  const localSri = localSriMap(input.files);\n  let uploadFiles = input.files;\n  let prevFiles: Record<string, string> | undefined;\n  if (input.previousPin) {\n    try {\n      const resolved = await resolveSlotVersion({ base: input.base, pin: input.previousPin });\n      if (resolved.files) {\n        const diff = diffWorkspaceFiles(input.files, localSri, resolved.files);\n        prevFiles = resolved.files;\n        uploadFiles = diff.upload;\n        if (diff.skipped > 0) {\n          console.log(\n            `    ${colors.dim(`${padRight(input.workspace, 28)} ${diff.skipped} unchanged file(s) — skipping (manifest diff)`)}`,\n          );\n        }\n      }\n    } catch {\n      console.log(\n        `    ${colors.dim(`${padRight(input.workspace, 28)} previous manifest unusable — uploading everything`)}`,\n      );\n    }\n  }\n\n  console.log(\n    `    ${padRight(input.workspace, 28)} uploading ${uploadFiles.length} of ${input.files.length} files (${formatBundleMb(uploadFiles)}) → ${input.base}`,\n  );\n  const result =\n    uploadFiles.length > 0\n      ? await uploadWorkspaceDist({\n          origin: input.origin,\n          apiKey: input.apiKey,\n          account: input.account,\n          gateway: input.gateway,\n          workspace: input.workspace,\n          files: uploadFiles,\n        })\n      : { stored: 0, totalBytes: 0, integrity: {}, storage: undefined };\n  return {\n    result,\n    fileIntegrity: mergedFileIntegrity(input.files, result.integrity, prevFiles),\n    uploaded: result.stored,\n    skipped: input.files.length - uploadFiles.length,\n    total: input.files.length,\n  };\n}\n\nfunction formatBundleMb(files: Array<{ bytes: Uint8Array }>): string {\n  const total = files.reduce((sum, file) => sum + file.bytes.byteLength, 0);\n  return `${(total / 1024 / 1024).toFixed(1)} MB`;\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}): Promise<void> {\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  while (Date.now() - startedAt < timeoutMs) {\n    try {\n      const verifiedConfig = await fetchBosConfigFromFastKv<BosConfigInput>(\n        `bos://${opts.account}/${opts.gateway}`,\n        opts.registry,\n      );\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}): Promise<boolean> {\n  try {\n    const current = await fetchBosConfigFromFastKv<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\ninterface PublishToFastKvInput {\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}\n\ninterface PublishToFastKvResult {\n  status: \"published\" | \"error\" | \"dry-run\";\n  registryUrl: string;\n  txHash?: string;\n  built?: string[];\n  skipped?: string[];\n  error?: string;\n  publishConfig?: BosConfigInput;\n  deployResults?: WorkspaceDeployResult[];\n  fingerprint?: string;\n  slotPins?: Record<string, string>;\n}\n\nexport type PublishedConfigState = \"fetched\" | \"missing\" | \"unreachable\";\n\nexport interface PublishPreflightPlan {\n  isStaging: boolean;\n  account: string;\n  gateway: string;\n  network: NetworkId;\n  registryUrl: string;\n  registryNamespace: string;\n  targets: string[];\n  useWallet: boolean;\n  strategy?: SigningStrategy;\n  cdnOrigin: string | undefined;\n  storageOrigin: string;\n  storageApiKey?: string;\n  /** The config currently published to FastKV (null when missing or unreachable). */\n  publishedConfig: Record<string, unknown> | null;\n  /** Whether the preflight FastKV read succeeded, found nothing, or failed. */\n  publishedConfigState: PublishedConfigState;\n}\n\nexport type PublishPreflight =\n  | { kind: \"dry-run\"; registryUrl: string }\n  | { kind: \"error\"; registryUrl: string; error: string }\n  | { kind: \"ready\"; plan: PublishPreflightPlan };\n\nconst FRAMEWORK_PACKAGE_NAMES = [\"better-near-auth\", \"every-plugin\", \"everything-dev\"] as const;\n\n/**\n * Whether npm serves `name@version` (true), definitively does not (404 —\n * false), or whether publishability could not be determined (network error,\n * unexpected status — null; callers must not block on that).\n */\nexport async function npmVersionPublished(name: string, version: string): Promise<boolean | null> {\n  try {\n    const res = await fetchResponse(`https://registry.npmjs.org/${name}/${version}`, {\n      headers: { Accept: \"application/json\" },\n    });\n    if (res.status === 200) return true;\n    if (res.status === 404) return false;\n    return null;\n  } catch {\n    return null;\n  }\n}\n\n/**\n * The npm-publish gate: a workspace that vendors the framework packages'\n * sources must not ship bundles ahead of npm — the update check, child\n * scaffolds (`bos init`), and template syncs all read those versions from\n * the registry. Reads only apply when the sources are workspace-local (the\n * parent repo); child projects install the framework from npm and are\n * inherently in sync.\n */\nexport async function findUnpublishedFrameworkPackages(\n  configDir: string,\n): Promise<Array<{ name: string; version: string }>> {\n  const unpublished: Array<{ name: string; version: string }> = [];\n  for (const name of FRAMEWORK_PACKAGE_NAMES) {\n    const manifestPath = join(configDir, \"packages\", name, \"package.json\");\n    if (!existsSync(manifestPath)) continue;\n    const version = (JSON.parse(readFileSync(manifestPath, \"utf-8\")) as { version?: string })\n      .version;\n    if (!version) continue;\n    const published = await npmVersionPublished(name, version);\n    if (published === false) {\n      unpublished.push({ name, version });\n    } else if (published === null) {\n      console.log(\n        colors.yellow(\n          `  ! Could not verify ${name}@${version} on npm (registry unreachable) — continuing`,\n        ),\n      );\n    }\n  }\n  return unpublished;\n}\n\n// Pure preflight (resolve, don't mutate) — every failure returns before the\n// build train runs (issue #287). Dry-run exits after the auth guards, before\n// any signing (keychain/TTY side effects).\nexport async function preflightPublish(input: PublishToFastKvInput): Promise<PublishPreflight> {\n  const { configDir } = input;\n  const bosConfig = input.bosConfig;\n\n  const isStaging = input.env === \"staging\";\n  const account = isStaging ? (bosConfig.staging?.account ?? bosConfig.account) : bosConfig.account;\n  const gateway = isStaging ? (bosConfig.staging?.domain ?? bosConfig.domain) : bosConfig.domain;\n  if (!gateway) {\n    return {\n      kind: \"error\",\n      registryUrl: \"\",\n      error: \"authored config must define domain to publish\",\n    };\n  }\n\n  const network: NetworkId = input.network ?? getNetworkIdForAccount(account);\n  const registryUrl = buildRegistryConfigUrlForNetwork(network, account, gateway, input.registry);\n  const fail = (error: string): PublishPreflight => ({ kind: \"error\", registryUrl, error });\n\n  const publishAuth: PublishConfig[\"auth\"] = bosConfig.publish?.auth;\n  const governsWalletPublish = (publishAuth === \"session\" || input.wallet) && !input.privateKey;\n  if (governsWalletPublish) {\n    const session = readSessionHandle(configDir);\n    if (!session?.credential) {\n      return fail(\n        (input.wallet\n          ? \"--wallet requires\"\n          : 'the authored config sets publish.auth = \"session\", but') +\n          \" no CLI session is stored in .bos/ for this project. Run bos login to create one.\",\n      );\n    }\n    if (session.credential.accountId && session.credential.accountId !== account) {\n      return fail(\n        `The CLI session was created for ${session.credential.accountId}, but the configured ` +\n          `account is ${account}. Gasless wallet publish relays the FastKV write under the session's ` +\n          \"NEAR account. Run bos login again under the matching account.\",\n      );\n    }\n  }\n  if (publishAuth && !input.privateKey) {\n    if (publishAuth === \"custody\") {\n      return fail(\n        'the authored config sets publish.auth = \"custody\", but custody publish is not implemented yet (see NEARBuilders/everything-dev#291).',\n      );\n    }\n  }\n\n  if (input.dryRun) {\n    return { kind: \"dry-run\", registryUrl };\n  }\n\n  const useWallet = input.wallet === true;\n  let strategy: SigningStrategy | undefined;\n  if (useWallet) {\n    console.log(\n      `  Signing via ${colors.cyan(\"gasless NEP-366 delegate action (relayed by the platform relayer)\")}`,\n    );\n  } else {\n    try {\n      strategy = await resolveSigningStrategy({ privateKey: input.privateKey, account, network });\n      console.log(`  Signing via ${colors.cyan(describeSigningStrategy(strategy))}`);\n    } catch (error) {\n      return fail(error instanceof Error ? error.message : \"Unknown error\");\n    }\n  }\n\n  // CDN deploy credentials (ADR 0020) — resolved before the build train so a\n  // missing bundle origin or BOS_STORAGE_API_KEY fails fast instead of after\n  // the full build. Config-only publishes ship the committed config verbatim;\n  // nothing is uploaded, so no deploy origins are required.\n  const session = readSessionHandle(configDir);\n  let cdnDeploy: CdnDeployInputs = {\n    cdnOrigin: undefined,\n    storageOrigin: \"\",\n    apiKey: undefined,\n  };\n  if (input.build) {\n    const unpublished = await findUnpublishedFrameworkPackages(configDir);\n    if (unpublished.length > 0) {\n      const listing = unpublished.map((pkg) => `${pkg.name}@${pkg.version}`).join(\", \");\n      return fail(\n        `Framework package(s) ${listing} are not published to npm yet — deploys must not ship ` +\n          \"bundles ahead of the registry (child scaffolds and update checks read these versions). \" +\n          \"Re-run the Release workflow (or `pnpm run release`) first.\",\n      );\n    }\n\n    cdnDeploy = resolveCdnDeployInputs({\n      env: process.env as Record<string, string | undefined>,\n      bosConfig,\n      session: session?.credential ?? null,\n      account,\n      gateway,\n      uploadsPlanned: input.build,\n    });\n    if (cdnDeploy.error) {\n      return fail(cdnDeploy.error);\n    }\n    if (cdnDeploy.warning) {\n      console.log(colors.yellow(`  ! ${cdnDeploy.warning}`));\n    }\n    const cdnOrigin = cdnDeploy.cdnOrigin;\n    if (!cdnOrigin) {\n      return fail(\"CDN deploy resolved no bundle origin\");\n    }\n    const probeError = await probeStorageOrigin(cdnDeploy.storageOrigin);\n    if (probeError) {\n      return fail(\n        `The bundle upload origin ${cdnDeploy.storageOrigin} is not running the platform API — ` +\n          `${probeError}. Check BOS_STORAGE_ORIGIN / the bos login session, then re-run.`,\n      );\n    }\n  }\n\n  // Registry reachability + published-state capture: one FastKV read. A\n  // missing config is fine for a first publish — an early signal, not a hard\n  // gate. The captured config is the merge base for a config-only publish on\n  // a TS-form project (authored hand-edits win; live pipeline state carries).\n  let publishedConfig: Record<string, unknown> | null = null;\n  let publishedConfigState: PublishedConfigState = \"missing\";\n  try {\n    publishedConfig = await fetchBosConfigFromFastKv<Record<string, unknown>>(\n      registryUrl,\n      input.registry,\n    );\n    publishedConfigState = \"fetched\";\n  } catch (error) {\n    const message = error instanceof Error ? error.message : String(error);\n    if (message.startsWith(\"No config found\")) {\n      console.log(colors.dim(\"  Note: no published config found yet (first publish) — continuing\"));\n    } else {\n      publishedConfigState = \"unreachable\";\n      console.log(colors.dim(\"  Note: registry read failed — continuing\"));\n    }\n  }\n\n  return {\n    kind: \"ready\",\n    plan: {\n      isStaging,\n      account,\n      gateway,\n      network,\n      registryUrl,\n      registryNamespace: getRegistryNamespaceForNetwork(network, input.registry),\n      targets: selectWorkspaceTargets(input.packages, bosConfig),\n      useWallet,\n      strategy,\n      cdnOrigin: cdnDeploy.cdnOrigin,\n      storageOrigin: cdnDeploy.storageOrigin,\n      storageApiKey: cdnDeploy.apiKey,\n      publishedConfig,\n      publishedConfigState,\n    },\n  };\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 */\nexport async function publishToFastKv(input: PublishToFastKvInput): Promise<PublishToFastKvResult> {\n  const preflight = await preflightPublish(input);\n  if (preflight.kind === \"error\") {\n    return { status: \"error\", registryUrl: preflight.registryUrl, error: preflight.error };\n  }\n  if (preflight.kind === \"dry-run\") {\n    return { status: \"dry-run\", registryUrl: preflight.registryUrl };\n  }\n  const plan = preflight.plan;\n  const {\n    isStaging,\n    account,\n    gateway,\n    network,\n    registryUrl,\n    registryNamespace,\n    targets,\n    useWallet,\n    strategy,\n  } = plan;\n  const storageOrigin = plan.storageOrigin;\n  const storageApiKey = plan.storageApiKey;\n\n  const { configDir } = input;\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  let refreshedRawConfig: BosConfigInput | null = null;\n\n  if (input.build) {\n    await generateCodeArtifacts(configDir, bosConfig, {\n      env: \"production\",\n      runtimeConfig: runtimeConfig ?? undefined,\n    });\n\n    const result = await buildWorkspaceTargets({\n      configDir,\n      bosConfig,\n      runtimeConfig,\n      targets,\n      deploy: true,\n      verbose: input.verbose,\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        return {\n          status: \"error\" as const,\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      return {\n        status: \"error\",\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    refreshedRawConfig = refreshed.rawConfig;\n  }\n\n  const authoredPath = findConfigPath(configDir);\n  const tsForm = authoredPath !== null && isAppDescriptorPath(authoredPath);\n  let rawConfig: BosConfigInput;\n  if (refreshedRawConfig) {\n    rawConfig = refreshedRawConfig;\n  } else {\n    const opened = await openResolution({ cwd: configDir });\n    if (!opened?.rawConfig) {\n      return {\n        status: \"error\",\n        registryUrl,\n        built,\n        skipped,\n        deployResults,\n        error: \"Failed to load the authored config for publish\",\n      };\n    }\n    rawConfig = opened.rawConfig;\n  }\n  if (tsForm && !input.build && plan.publishedConfigState === \"unreachable\") {\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    return {\n      status: \"error\",\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    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((plan.publishedConfig ?? {}) as BosConfigInput, rawConfig)\n      : rawConfig;\n\n  const urlOrigin = plan.cdnOrigin ?? `https://${gateway}`;\n  const deployTargets = (built ?? []).filter((key) => targets.includes(key));\n  const platformEntries: DeployResultEntry[] = [];\n  const fullUpload = input.fullUpload === true || process.env.BOS_FULL_UPLOAD === \"1\";\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.\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  console.log();\n  console.log(`  CDN deploy — uploading workspace dists to ${storageOrigin}...`);\n  for (const key of deployTargets) {\n    const ws = resolveWorkspaceTarget(key, bosConfig, runtimeConfig, configDir);\n    if (!ws) continue;\n\n    const distFiles = await collectDistFiles(join(ws.path, \"dist\"));\n    const workspaceBase = `${urlOrigin}/bundles/${account}/${gateway}/${key}/`;\n    const startedAt = Date.now();\n    // an upload failure aborts the train as a structured error — the\n    // previously published version stays fully live (ticket 05)\n    let outcome: DiffUploadOutcome;\n    try {\n      outcome = await diffUploadWorkspace({\n        origin: storageOrigin,\n        apiKey: storageApiKey,\n        account,\n        gateway,\n        workspace: key,\n        files: distFiles,\n        base: workspaceBase,\n        previousPin: prevPins[key],\n      });\n    } catch (error) {\n      return {\n        status: \"error\",\n        registryUrl,\n        built,\n        skipped,\n        deployResults,\n        error: error instanceof Error ? error.message : `[publish] bundle upload for ${key} failed`,\n      };\n    }\n    const report = readBuildReport(join(ws.path, \"dist\"));\n    const ssrReport = readBuildReport(join(ws.path, \"dist\", \"ssr\"));\n    // the entry SRI keyed by the build report's hashed name\n    const integrity = report ? outcome.fileIntegrity[report.entry] : undefined;\n    const ssrIntegrity = ssrReport?.entry\n      ? outcome.fileIntegrity[`ssr/${ssrReport.entry}`]\n      : undefined;\n\n    const manifestPointer = await pinWorkspaceVersionManifest({\n      origin: storageOrigin,\n      apiKey: storageApiKey,\n      account,\n      gateway,\n      workspace: key,\n      report,\n      ssrReport,\n      integrityMap: outcome.fileIntegrity,\n      files: outcome.fileIntegrity,\n    });\n    if (!manifestPointer) {\n      return {\n        status: \"error\",\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 (outcome.result.storage === \"memory\" || manifestPointer.storage === \"memory\") {\n      return {\n        status: \"error\",\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\n    console.log(\n      `    ${colors.green(icons.ok)} ${padRight(key, 28)} → ${urlOrigin}/bundles/${account}/${gateway}/${key}/ (${outcome.uploaded} uploaded, ${outcome.skipped} skipped, ${formatDuration(Date.now() - startedAt)})`,\n    );\n\n    platformEntries.push(\n      ...platformUrlDeployEntries({\n        origin: urlOrigin,\n        account,\n        gateway,\n        key,\n        kind: ws.kind,\n        integrity,\n        ssrIntegrity,\n        pin: manifestPointer,\n      }),\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    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 uiManifestPointer: VersionManifestPin | undefined;\n      if (existsSync(uiDistDir)) {\n        const uiDistFiles = await collectDistFiles(uiDistDir);\n        const uiStartedAt = Date.now();\n        const uiOutcome = await diffUploadWorkspace({\n          origin: storageOrigin,\n          apiKey: storageApiKey,\n          account,\n          gateway,\n          workspace: `${key}-ui`,\n          files: uiDistFiles,\n          base: `${urlOrigin}/bundles/${account}/${gateway}/${key}-ui/`,\n          previousPin: prevPins[`${key}-ui`],\n        });\n        const uiReport = readBuildReport(uiDistDir);\n        const uiSsrReport = readBuildReport(join(uiDistDir, \"ssr\"));\n        uiIntegrity = uiReport ? uiOutcome.fileIntegrity[uiReport.entry] : undefined;\n        uiSsrIntegrity = uiSsrReport?.entry\n          ? uiOutcome.fileIntegrity[`ssr/${uiSsrReport.entry}`]\n          : undefined;\n\n        uiManifestPointer = await pinWorkspaceVersionManifest({\n          origin: storageOrigin,\n          apiKey: storageApiKey,\n          account,\n          gateway,\n          workspace: `${key}-ui`,\n          report: uiReport,\n          ssrReport: uiSsrReport,\n          integrityMap: uiOutcome.fileIntegrity,\n          files: uiOutcome.fileIntegrity,\n        });\n        if (!uiManifestPointer) {\n          return {\n            status: \"error\",\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\n        if (uiOutcome.result.storage === \"memory\" || uiManifestPointer.storage === \"memory\") {\n          return {\n            status: \"error\",\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\n        console.log(\n          `    ${colors.green(icons.ok)} ${padRight(`${key}-ui`, 28)} → ${urlOrigin}/bundles/${account}/${gateway}/${key}-ui/ (${uiOutcome.uploaded} uploaded, ${uiOutcome.skipped} skipped, ${formatDuration(Date.now() - uiStartedAt)})`,\n        );\n      } else {\n        console.log(\n          `    ${colors.green(icons.ok)} ${padRight(`${key}-ui`, 28)} → ${urlOrigin}/bundles/${account}/${gateway}/${key}-ui/`,\n        );\n      }\n\n      platformEntries.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: uiManifestPointer,\n        }),\n      );\n    }\n  }\n\n  if (platformEntries.length > 0) {\n    const merged = applyDeployResults(rawConfig 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        return {\n          status: \"error\",\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    return {\n      status: \"error\",\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  registryEntries[manifestKey] = JSON.stringify({\n    account,\n    gateway,\n    network,\n    publishedAt,\n    registryUrl,\n  });\n\n  console.log();\n  console.log(\"  Publishing to:\");\n  console.log(`    ${colors.cyan(registryUrl)}`);\n  console.log(`    ${colors.dim(\"Fingerprint:\")} ${fingerprint}`);\n  for (const [slot, pin] of Object.entries(publishSlotPins)) {\n    console.log(`    ${colors.dim(`${slot}:`)}`);\n    console.log(`      ${pin}`);\n  }\n  console.log(\n    `    ${colors.dim(`+ per-deploy manifest ${manifestKey.split(\"/\").pop()} (audit trail)`)}`,\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    const alreadyPublished = await isConfigAlreadyPublished({\n      account,\n      gateway,\n      publishConfig: publishPayload,\n      registry: input.registry,\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    let result: { success: boolean; txHash?: string };\n    if (useWallet) {\n      const session = readSessionHandle(configDir);\n      const credential = session?.credential;\n      if (!credential || credential.accountId !== account) {\n        return {\n          status: \"error\",\n          registryUrl,\n          error: `--wallet requires a CLI session under ${account}. Run bos login first.`,\n        };\n      }\n      const record = await ensureDelegateKey({\n        configDir,\n        account,\n        contract: registryNamespace,\n        network,\n        siteUrl: credential.siteUrl,\n      });\n      result = await submitRegistryWriteDelegated({\n        account,\n        contract: registryNamespace,\n        network,\n        args: registryEntries,\n        delegatePrivateKey: record.privateKey,\n        relayEndpoint: `${credential.siteUrl}/api/auth/near/relay`,\n        apiKey: credential.apiKey,\n      });\n    } else {\n      if (!strategy) {\n        return {\n          status: \"error\",\n          registryUrl,\n          error: \"non-wallet publish requires a resolved signing strategy\",\n        };\n      }\n      result = await submitRegistryWrite(\n        {\n          account,\n          contract: registryNamespace,\n          method: \"__fastdata_kv\",\n          args: registryEntries,\n          network,\n          privateKey: input.privateKey,\n        },\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    await waitForPublishedConfig({\n      account,\n      gateway,\n      publishConfig: publishPayload,\n      registry: input.registry,\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    return {\n      status: \"error\",\n      registryUrl,\n      error: formatNearError(error),\n      built,\n      skipped,\n      deployResults,\n    };\n  }\n}\n\nfunction formatNearError(error: unknown): string {\n  const message = error instanceof Error ? error.message : String(error);\n\n  if (message.includes(\"does not have enough allowance\")) {\n    return (\n      \"The publish access key has insufficient allowance to cover this transaction.\\n\" +\n      \"  Regenerate your key with a higher allowance:\\n\" +\n      \"    bos key generate\\n\" +\n      `  Original: ${message}`\n    );\n  }\n\n  if (message.includes(\"exceeded gas\") || message.includes(\"GasLimitExceeded\")) {\n    return `Transaction exceeded gas limit.\\n  Original: ${message}`;\n  }\n\n  if (message.includes(\"timeout\") || message.includes(\"Timeout\")) {\n    return `Transaction timed out. Check NEAR network status.\\n  Original: ${message}`;\n  }\n\n  return message;\n}\n"],"mappings":"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"}