everything-dev 2.0.0-rc.6 → 2.0.0-rc.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/README.md +2 -2
  2. package/dist/api/auth-middleware.cjs +14 -1
  3. package/dist/api/auth-middleware.cjs.map +1 -1
  4. package/dist/api/auth-middleware.d.cts +9 -0
  5. package/dist/api/auth-middleware.d.mts +9 -0
  6. package/dist/api/auth-middleware.mjs +14 -1
  7. package/dist/api/auth-middleware.mjs.map +1 -1
  8. package/dist/build.cjs +1 -1
  9. package/dist/build.mjs +1 -1
  10. package/dist/bundle-cache.cjs +1 -1
  11. package/dist/bundle-cache.cjs.map +1 -1
  12. package/dist/bundle-cache.mjs +1 -1
  13. package/dist/bundle-cache.mjs.map +1 -1
  14. package/dist/cli/init.cjs +22 -10
  15. package/dist/cli/init.cjs.map +1 -1
  16. package/dist/cli/init.mjs +22 -10
  17. package/dist/cli/init.mjs.map +1 -1
  18. package/dist/cli.cjs +6 -5
  19. package/dist/cli.cjs.map +1 -1
  20. package/dist/cli.mjs +5 -4
  21. package/dist/cli.mjs.map +1 -1
  22. package/dist/commands/deploy.cjs +111 -1
  23. package/dist/commands/deploy.cjs.map +1 -1
  24. package/dist/commands/deploy.mjs +112 -2
  25. package/dist/commands/deploy.mjs.map +1 -1
  26. package/dist/commands/keys.cjs +1 -1
  27. package/dist/commands/keys.cjs.map +1 -1
  28. package/dist/commands/keys.mjs +1 -1
  29. package/dist/commands/keys.mjs.map +1 -1
  30. package/dist/commands/smoke.cjs +41 -0
  31. package/dist/commands/smoke.cjs.map +1 -0
  32. package/dist/commands/smoke.mjs +41 -0
  33. package/dist/commands/smoke.mjs.map +1 -0
  34. package/dist/commands/upgrade.cjs +2 -2
  35. package/dist/commands/upgrade.cjs.map +1 -1
  36. package/dist/commands/upgrade.mjs +1 -1
  37. package/dist/commands/upgrade.mjs.map +1 -1
  38. package/dist/contract.cjs +27 -1
  39. package/dist/contract.cjs.map +1 -1
  40. package/dist/contract.d.cts +65 -1
  41. package/dist/contract.d.mts +65 -1
  42. package/dist/contract.meta.cjs +14 -2
  43. package/dist/contract.meta.cjs.map +1 -1
  44. package/dist/contract.meta.d.cts +24 -2
  45. package/dist/contract.meta.d.mts +24 -2
  46. package/dist/contract.meta.mjs +14 -2
  47. package/dist/contract.meta.mjs.map +1 -1
  48. package/dist/contract.mjs +26 -2
  49. package/dist/contract.mjs.map +1 -1
  50. package/dist/db/core.cjs +22 -4
  51. package/dist/db/core.cjs.map +1 -1
  52. package/dist/db/core.mjs +22 -4
  53. package/dist/db/core.mjs.map +1 -1
  54. package/dist/dev-log-pipeline.cjs +6 -0
  55. package/dist/dev-log-pipeline.cjs.map +1 -1
  56. package/dist/dev-log-pipeline.mjs +6 -0
  57. package/dist/dev-log-pipeline.mjs.map +1 -1
  58. package/dist/dev-program.cjs +20 -3
  59. package/dist/dev-program.cjs.map +1 -1
  60. package/dist/dev-program.mjs +20 -4
  61. package/dist/dev-program.mjs.map +1 -1
  62. package/dist/dev-session.cjs +1 -0
  63. package/dist/dev-session.cjs.map +1 -1
  64. package/dist/dev-session.mjs +1 -0
  65. package/dist/dev-session.mjs.map +1 -1
  66. package/dist/fastkv.cjs +21 -3
  67. package/dist/fastkv.cjs.map +1 -1
  68. package/dist/fastkv.d.cts +14 -1
  69. package/dist/fastkv.d.mts +14 -1
  70. package/dist/fastkv.mjs +21 -5
  71. package/dist/fastkv.mjs.map +1 -1
  72. package/dist/{mf.cjs → federation.cjs} +6 -13
  73. package/dist/federation.cjs.map +1 -0
  74. package/dist/{mf.d.cts → federation.d.cts} +2 -2
  75. package/dist/{mf.d.mts → federation.d.mts} +2 -2
  76. package/dist/{mf.mjs → federation.mjs} +6 -13
  77. package/dist/federation.mjs.map +1 -0
  78. package/dist/http-client.cjs +84 -57
  79. package/dist/http-client.cjs.map +1 -1
  80. package/dist/http-client.mjs +84 -58
  81. package/dist/http-client.mjs.map +1 -1
  82. package/dist/image-deploy.cjs +9 -0
  83. package/dist/image-deploy.cjs.map +1 -1
  84. package/dist/image-deploy.mjs +9 -1
  85. package/dist/image-deploy.mjs.map +1 -1
  86. package/dist/index.cjs +4 -0
  87. package/dist/index.d.cts +3 -3
  88. package/dist/index.d.mts +3 -3
  89. package/dist/index.mjs +3 -3
  90. package/dist/infra/planner.cjs +6 -2
  91. package/dist/infra/planner.cjs.map +1 -1
  92. package/dist/infra/planner.mjs +6 -2
  93. package/dist/infra/planner.mjs.map +1 -1
  94. package/dist/orchestrator.cjs +39 -35
  95. package/dist/orchestrator.cjs.map +1 -1
  96. package/dist/orchestrator.mjs +39 -35
  97. package/dist/orchestrator.mjs.map +1 -1
  98. package/dist/plugin.cjs +2 -0
  99. package/dist/plugin.cjs.map +1 -1
  100. package/dist/plugin.d.cts +24 -0
  101. package/dist/plugin.d.mts +24 -0
  102. package/dist/plugin.mjs +2 -0
  103. package/dist/plugin.mjs.map +1 -1
  104. package/dist/process-registry.cjs +1 -1
  105. package/dist/process-registry.mjs +1 -1
  106. package/dist/publish.cjs +3 -3
  107. package/dist/publish.cjs.map +1 -1
  108. package/dist/publish.mjs +4 -4
  109. package/dist/publish.mjs.map +1 -1
  110. package/dist/resolver.cjs +293 -0
  111. package/dist/resolver.cjs.map +1 -0
  112. package/dist/resolver.d.cts +99 -0
  113. package/dist/resolver.d.mts +99 -0
  114. package/dist/resolver.mjs +284 -0
  115. package/dist/resolver.mjs.map +1 -0
  116. package/dist/smoke.cjs +262 -0
  117. package/dist/smoke.cjs.map +1 -0
  118. package/dist/smoke.mjs +260 -0
  119. package/dist/smoke.mjs.map +1 -0
  120. package/dist/ui/auth.d.cts +217 -123
  121. package/dist/ui/auth.d.mts +217 -123
  122. package/dist/ui/router-client.cjs +2 -1
  123. package/dist/ui/router-client.cjs.map +1 -1
  124. package/dist/ui/router-client.mjs +2 -1
  125. package/dist/ui/router-client.mjs.map +1 -1
  126. package/dist/version-manifest-resolve.cjs +3 -3
  127. package/dist/version-manifest-resolve.cjs.map +1 -1
  128. package/dist/version-manifest-resolve.mjs +1 -1
  129. package/dist/version-manifest-resolve.mjs.map +1 -1
  130. package/dist/workspace.cjs +1 -1
  131. package/dist/workspace.mjs +1 -1
  132. package/package.json +18 -18
  133. package/skills/api-and-auth/SKILL.md +12 -9
  134. package/skills/api-and-auth/references/middleware.md +38 -0
  135. package/skills/cli-reference/SKILL.md +22 -6
  136. package/skills/talk-to-the-app/SKILL.md +32 -5
  137. package/dist/bundle-fs-resolve.cjs +0 -235
  138. package/dist/bundle-fs-resolve.cjs.map +0 -1
  139. package/dist/bundle-fs-resolve.d.cts +0 -82
  140. package/dist/bundle-fs-resolve.d.mts +0 -82
  141. package/dist/bundle-fs-resolve.mjs +0 -228
  142. package/dist/bundle-fs-resolve.mjs.map +0 -1
  143. package/dist/bundle-path.cjs +0 -48
  144. package/dist/bundle-path.cjs.map +0 -1
  145. package/dist/bundle-path.mjs +0 -45
  146. package/dist/bundle-path.mjs.map +0 -1
  147. package/dist/mf.cjs.map +0 -1
  148. package/dist/mf.mjs.map +0 -1
@@ -1 +1 @@
1
- {"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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"}
1
+ {"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 fetchPublishedConfigFromFastKv,\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 /** 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\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 fetchPublishedConfigFromFastKv<Record<string, unknown>>(registryUrl);\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 (\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 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 input.exactPayload === true\n ? input.bosConfig\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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"}
@@ -0,0 +1,293 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
3
+ const require_http_client = require('./http-client.cjs');
4
+ const require_bundle_cache = require('./bundle-cache.cjs');
5
+ const require_config = require('./config.cjs');
6
+ let node_fs = require("node:fs");
7
+ let node_path = require("node:path");
8
+ node_path = require_runtime.__toESM(node_path, 1);
9
+ let effect = require("effect");
10
+ let node_fs_promises = require("node:fs/promises");
11
+ let every_plugin_build_artifact_names = require("every-plugin/build/artifact-names");
12
+
13
+ //#region src/resolver.ts
14
+ var BundleReadError = class extends effect.Schema.TaggedError()("BundleReadError", {
15
+ path: effect.Schema.String,
16
+ cause: effect.Schema.optional(effect.Schema.Unknown)
17
+ }) {};
18
+ const MIME_TYPES = {
19
+ ".js": "text/javascript",
20
+ ".mjs": "text/javascript",
21
+ ".cjs": "text/javascript",
22
+ ".css": "text/css",
23
+ ".json": "application/json",
24
+ ".map": "application/json",
25
+ ".svg": "image/svg+xml",
26
+ ".png": "image/png",
27
+ ".jpg": "image/jpeg",
28
+ ".jpeg": "image/jpeg",
29
+ ".gif": "image/gif",
30
+ ".webp": "image/webp",
31
+ ".avif": "image/avif",
32
+ ".ico": "image/x-icon",
33
+ ".html": "text/html",
34
+ ".htm": "text/html",
35
+ ".webmanifest": "application/manifest+json",
36
+ ".md": "text/markdown",
37
+ ".ts": "text/plain",
38
+ ".woff": "font/woff",
39
+ ".woff2": "font/woff2",
40
+ ".ttf": "font/ttf",
41
+ ".otf": "font/otf",
42
+ ".eot": "application/vnd.ms-opentype",
43
+ ".wasm": "application/wasm",
44
+ ".txt": "text/xml",
45
+ ".xml": "application/xml"
46
+ };
47
+ /**
48
+ * Maps a bundle URL onto the staged namespace layout. Bundle URLs carry their
49
+ * namespace in the path (`…/bundles/<account>/<gateway>/<workspace>/…`); the
50
+ * staged layout mirrors it under `<bundleDir>/<account>/<gateway>/…`. The
51
+ * namespace is taken from the URL itself — this answers "which staged
52
+ * directory do these bytes live in?" rather than "is this my namespace?" —
53
+ * and the result is contained within the account/gateway directory. Returns
54
+ * null for foreign shapes.
55
+ */
56
+ function bundleUrlToStagedPath(url, bundleDir) {
57
+ let parsed;
58
+ try {
59
+ parsed = new URL(url);
60
+ } catch {
61
+ return null;
62
+ }
63
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
64
+ const segments = parsed.pathname.split("/").filter(Boolean);
65
+ if (segments[0] !== "bundles" || segments.length < 3) return null;
66
+ let decoded;
67
+ try {
68
+ decoded = segments.slice(1).map((segment) => decodeURIComponent(segment));
69
+ } catch {
70
+ return null;
71
+ }
72
+ const [account, gateway, ...rest] = decoded;
73
+ if (!account || !gateway || rest.length === 0) return null;
74
+ const nsDir = node_path.default.resolve(bundleDir, account, gateway);
75
+ const filePath = node_path.default.resolve(nsDir, ...rest);
76
+ if (filePath === nsDir || !filePath.startsWith(nsDir + node_path.default.sep)) return null;
77
+ return filePath;
78
+ }
79
+ /** Resolve a relative config-supplied path inside `dir`, or null on escape. */
80
+ function resolveContained(dir, relative) {
81
+ const resolved = node_path.default.resolve(dir, ...relative.split("/").filter(Boolean));
82
+ if (resolved === dir || !resolved.startsWith(dir + node_path.default.sep)) return null;
83
+ return resolved;
84
+ }
85
+ /**
86
+ * Own-namespace path for a bundle URL: the shared URL→staged-path mapping,
87
+ * narrowed to the runtime identity — a URL whose encoded namespace differs
88
+ * from `namespace.account`/`namespace.gateway` must fall to the network,
89
+ * never serve a sibling namespace's staged bytes.
90
+ */
91
+ function bundleUrlToLocalPath(url, namespace) {
92
+ const filePath = bundleUrlToStagedPath(url, namespace.bundleDir);
93
+ if (!filePath) return null;
94
+ const nsDir = node_path.default.resolve(namespace.bundleDir, namespace.account, namespace.gateway);
95
+ if (filePath !== nsDir && !filePath.startsWith(nsDir + node_path.default.sep)) return null;
96
+ return filePath;
97
+ }
98
+ var BundleResolver = class BundleResolver extends effect.Context.Service()("everything-dev/resolver/BundleResolver") {
99
+ static layer(namespace) {
100
+ if (!namespace) return effect.Layer.succeed(BundleResolver, BundleResolver.of({ lookup: () => effect.Effect.succeed(null) }));
101
+ const respond = effect.Effect.fn("BundleResolver.respond")(function* (url) {
102
+ const filePath = bundleUrlToLocalPath(url, namespace);
103
+ if (!filePath) return null;
104
+ const bytes = yield* effect.Effect.tryPromise({
105
+ try: () => (0, node_fs_promises.readFile)(filePath),
106
+ catch: (cause) => new BundleReadError({
107
+ path: filePath,
108
+ cause
109
+ })
110
+ }).pipe(effect.Effect.catchTag("BundleReadError", () => effect.Effect.succeed(null)));
111
+ if (bytes === null) return null;
112
+ const name = node_path.default.basename(filePath);
113
+ const contentType = MIME_TYPES[node_path.default.extname(name).toLowerCase()] ?? "application/octet-stream";
114
+ return new Response(new Uint8Array(bytes), { headers: {
115
+ "content-type": contentType,
116
+ "cache-control": (0, every_plugin_build_artifact_names.cacheControlOf)(name),
117
+ etag: `"${Buffer.from(bytes.subarray(0, 4096)).toString("base64").slice(0, 24)}"`
118
+ } });
119
+ });
120
+ return effect.Layer.effect(BundleResolver, effect.Effect.succeed(BundleResolver.of({ lookup: (input) => {
121
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
122
+ return respond(url);
123
+ } })));
124
+ }
125
+ };
126
+ const staleResponse = (bytes, url) => {
127
+ const name = url.split("?")[0]?.split("/").pop() ?? "";
128
+ const contentType = MIME_TYPES[node_path.default.extname(name).toLowerCase()] ?? "application/octet-stream";
129
+ return new Response(bytes.slice().buffer, {
130
+ status: 200,
131
+ headers: {
132
+ "content-type": contentType,
133
+ "x-bundle-cache": "stale"
134
+ }
135
+ });
136
+ };
137
+ const DEFAULT_ATTEMPT_TIMEOUT = "30 seconds";
138
+ const RETRY_BASE_DELAY = "250 millis";
139
+ const RETRY_CAP = "5 seconds";
140
+ const RETRY_TIMES = 4;
141
+ const isTransientStatus = (status) => status === 429 || status >= 500;
142
+ function requestMethod(input, init) {
143
+ if (init?.method) return init.method.toUpperCase();
144
+ if (typeof input === "string" || input instanceof URL) return "GET";
145
+ return input.method.toUpperCase();
146
+ }
147
+ const asError = (cause) => cause instanceof Error ? cause : new Error(String(cause));
148
+ /** A 429/5xx response — carried as a failure so the Schedule can retry it,
149
+ * with the Response kept for the exhausted-retries fallthrough. */
150
+ var TransientBundleResponse = class extends effect.Data.TaggedError("TransientBundleResponse") {};
151
+ /**
152
+ * One network attempt through the `HttpFetch` policy: the fetch runs under
153
+ * the fiber's interruption signal, and `Effect.timeout` interrupts at the
154
+ * deadline — aborting the in-flight request. The response is returned
155
+ * regardless of status; transient statuses are lifted by the caller.
156
+ */
157
+ const fetchAttempt = effect.Effect.fn("resolver.attempt")(function* (http, input, init, timeout) {
158
+ return yield* http.attempt(input, init).pipe(effect.Effect.timeoutOrElse({
159
+ duration: effect.Duration.toMillis(timeout),
160
+ orElse: () => effect.Effect.fail(new effect.Cause.TimeoutError())
161
+ }), effect.Effect.filterOrFail((response) => !isTransientStatus(response.status), (response) => new TransientBundleResponse({ response })));
162
+ });
163
+ /**
164
+ * The resilience policy for idempotent GETs crossing the interceptor
165
+ * (ADR 0021 amendment — the CDN-only image): a cold boot has no staged
166
+ * fallback, so one edge hiccup or a hung connection during the load window
167
+ * must not hard-fail the host or a plugin. Transient statuses and network
168
+ * errors (including the deadline's TimeoutError) retry on a capped
169
+ * exponential schedule before propagating; the last transient response is
170
+ * returned so an explicit stale-if-error cache still sees it. Non-GETs pass
171
+ * through untouched; a caller-initiated cancellation is never spent on the
172
+ * schedule.
173
+ */
174
+ const resilientFetch = effect.Effect.fn("resolver.fetch")(function* (http, input, init, timeout) {
175
+ if (requestMethod(input, init) !== "GET") return yield* http.attempt(input, init).pipe(effect.Effect.mapError((cause) => asError(cause.cause)));
176
+ return yield* fetchAttempt(http, input, init, timeout).pipe(effect.Effect.retry({
177
+ schedule: effect.Schedule.exponential(RETRY_BASE_DELAY).pipe(effect.Schedule.upTo({
178
+ duration: RETRY_CAP,
179
+ times: RETRY_TIMES
180
+ })),
181
+ while: (error) => !((error instanceof require_http_client.FetchNetworkError || error instanceof effect.Cause.TimeoutError) && init?.signal?.aborted)
182
+ }), effect.Effect.catchTags({
183
+ TransientBundleResponse: (error) => effect.Effect.succeed(error.response),
184
+ FetchNetworkError: (error) => effect.Effect.fail(asError(error.cause))
185
+ }));
186
+ });
187
+ /**
188
+ * Installs the resolver as a global fetch interceptor — the one seam every
189
+ * boot-time consumer shares (config manifest discovery, contract-type
190
+ * fetches, orchestrator host loading, MF remoteEntry/identity probes) and
191
+ * the SSR serving path. One layered resolution policy, as a single Effect
192
+ * program on the managed runtime: staged disk → network → (explicitly
193
+ * opted-in) stale-if-error. Own-namespace URLs resolve from the staged
194
+ * directory and fall through to the network on a miss; a miss never touches
195
+ * the write-through cache — for the own namespace the staged disk IS the
196
+ * resilience artifact. Inert when neither a staged namespace nor an
197
+ * explicit cache is configured.
198
+ */
199
+ function installGlobalBundleFetch(options) {
200
+ const namespace = options.namespace;
201
+ const cacheDir = options.cacheDir;
202
+ const timeout = effect.Duration.millis(options.timeoutMs ?? effect.Duration.toMillis(DEFAULT_ATTEMPT_TIMEOUT));
203
+ const original = globalThis.fetch;
204
+ const runtime = effect.ManagedRuntime.make(effect.Layer.mergeAll(BundleResolver.layer(namespace), require_http_client.HttpFetch.layerWith({ fetchImpl: original })));
205
+ const program = effect.Effect.fn("resolver.program")(function* (input, init) {
206
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
207
+ const http = yield* require_http_client.HttpFetch;
208
+ if (namespace && bundleUrlToLocalPath(url, namespace)) {
209
+ const local = yield* (yield* BundleResolver).lookup(input);
210
+ if (local !== null) return local;
211
+ return yield* resilientFetch(http, input, init, timeout);
212
+ }
213
+ if (cacheDir !== void 0 && require_bundle_cache.bundleCachePath(url, { cacheDir })) {
214
+ const cachedRead = effect.Effect.tryPromise(() => require_bundle_cache.readBundleCache(url, { cacheDir }));
215
+ return yield* effect.Effect.gen(function* () {
216
+ const response = yield* resilientFetch(http, input, init, timeout);
217
+ if (response.ok) yield* effect.Effect.tryPromise(async () => {
218
+ const bytes = new Uint8Array(await response.clone().arrayBuffer());
219
+ await require_bundle_cache.writeBundleCache(url, bytes, { cacheDir });
220
+ }).pipe(effect.Effect.ignore);
221
+ else {
222
+ const cached = yield* cachedRead;
223
+ if (cached) return staleResponse(cached, url);
224
+ }
225
+ return response;
226
+ }).pipe(effect.Effect.catch((error) => effect.Effect.gen(function* () {
227
+ const cached = yield* cachedRead;
228
+ if (cached) return staleResponse(cached, url);
229
+ return yield* effect.Effect.fail(error);
230
+ })));
231
+ }
232
+ return yield* resilientFetch(http, input, init, timeout);
233
+ });
234
+ const patched = ((input, init) => runtime.runPromise(program(input, init)));
235
+ const originalPreconnect = original.preconnect;
236
+ if (originalPreconnect) patched.preconnect = originalPreconnect.bind(original);
237
+ globalThis.fetch = patched;
238
+ return { uninstall: async () => {
239
+ if (globalThis.fetch === patched) globalThis.fetch = original;
240
+ await runtime.dispose();
241
+ } };
242
+ }
243
+ /**
244
+ * Boot-time installer for the CLI and the host server: derives the own
245
+ * namespace from `BOS_BUNDLE_DIR` plus the runtime identity
246
+ * (`BOS_ACCOUNT`/`BOS_GATEWAY` registry env taking precedence over the
247
+ * bos.config.json fields), and the stale-if-error cache from an explicit
248
+ * `BOS_BUNDLE_CACHE_DIR` — never implicit. Tier auto-detection (ADR 0021):
249
+ * an identity whose namespace is not actually staged under the bundle dir
250
+ * drops to the registry tier — plain resilient network fetch — instead of
251
+ * deterministically 404ing own-namespace URLs against a foreign image's
252
+ * staged bytes. Never throws — a missing or malformed identity leaves the
253
+ * default fetch in place.
254
+ */
255
+ function installBundleFetchFromEnv(input) {
256
+ const bundleDir = process.env.BOS_BUNDLE_DIR;
257
+ const cacheDir = process.env.BOS_BUNDLE_CACHE_DIR;
258
+ if (!bundleDir && cacheDir === void 0) return null;
259
+ let configAccount;
260
+ let configGateway;
261
+ const configPath = input.configPath;
262
+ if (configPath && !require_config.isAppDescriptorPath(configPath)) try {
263
+ const parsed = JSON.parse((0, node_fs.readFileSync)(configPath, "utf8"));
264
+ configAccount = parsed.account;
265
+ configGateway = parsed.domain;
266
+ } catch {}
267
+ const account = process.env.BOS_ACCOUNT ?? configAccount;
268
+ const gateway = process.env.BOS_GATEWAY ?? configGateway;
269
+ if (bundleDir && (!account || !gateway)) return null;
270
+ let namespace;
271
+ if (bundleDir && account && gateway) {
272
+ if ((0, node_fs.existsSync)(node_path.default.join(bundleDir, account, gateway))) namespace = {
273
+ bundleDir,
274
+ account,
275
+ gateway
276
+ };
277
+ else console.warn(`[bundles] staged namespace ${account}/${gateway} not found under ${bundleDir} — registry tier (network fetch)`);
278
+ }
279
+ return installGlobalBundleFetch({
280
+ namespace,
281
+ cacheDir
282
+ });
283
+ }
284
+
285
+ //#endregion
286
+ exports.BundleReadError = BundleReadError;
287
+ exports.BundleResolver = BundleResolver;
288
+ exports.bundleUrlToLocalPath = bundleUrlToLocalPath;
289
+ exports.bundleUrlToStagedPath = bundleUrlToStagedPath;
290
+ exports.installBundleFetchFromEnv = installBundleFetchFromEnv;
291
+ exports.installGlobalBundleFetch = installGlobalBundleFetch;
292
+ exports.resolveContained = resolveContained;
293
+ //# sourceMappingURL=resolver.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.cjs","names":["Schema","path","Context","Layer","Effect","readFile","cacheControlOf","Data","Duration","Cause","Schedule","FetchNetworkError","ManagedRuntime","HttpFetch","bundleCachePath","readBundleCache","writeBundleCache","isAppDescriptorPath","readFileSync","existsSync"],"sources":["../src/resolver.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n Cause,\n Context,\n Data,\n Duration,\n Effect,\n Layer,\n ManagedRuntime,\n Schedule,\n Schema,\n} from \"effect\";\nimport { cacheControlOf } from \"every-plugin/build/artifact-names\";\nimport { bundleCachePath, readBundleCache, writeBundleCache } from \"./bundle-cache\";\nimport { isAppDescriptorPath } from \"./config\";\nimport { FetchNetworkError, HttpFetch, type HttpFetchShape } from \"./http-client\";\n\ntype FetchImpl = typeof globalThis.fetch;\n\n/**\n * Bundle resolution — the one seam every boot-time byte crosses (config\n * manifest discovery, contract-type fetches, federation remote loading, SSR\n * serving). Two tiers, one policy (ADR 0011/0021):\n *\n * - Self-contained runtime image: a staged namespace under `BOS_BUNDLE_DIR`\n * resolves from disk; a miss falls through to the network so a partially-\n * staged namespace boots over the wire instead of failing.\n * - Registry tier: plain resilient network fetch — CDN is the single\n * distribution source. The stale-if-error disk cache exists only behind an\n * explicit `BOS_BUNDLE_CACHE_DIR` opt-in; cached bytes are a resilience\n * artifact, never a deployment, so a post-reset boot can never satisfy\n * itself with pre-reset bytes.\n */\n\nexport interface BundleNamespace {\n readonly bundleDir: string;\n readonly account: string;\n readonly gateway: string;\n}\n\nexport class BundleReadError extends Schema.TaggedError<BundleReadError>()(\"BundleReadError\", {\n path: Schema.String,\n cause: Schema.optional(Schema.Unknown),\n}) {}\n\nconst MIME_TYPES: Record<string, string> = {\n \".js\": \"text/javascript\",\n \".mjs\": \"text/javascript\",\n \".cjs\": \"text/javascript\",\n \".css\": \"text/css\",\n \".json\": \"application/json\",\n \".map\": \"application/json\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".ico\": \"image/x-icon\",\n \".html\": \"text/html\",\n \".htm\": \"text/html\",\n \".webmanifest\": \"application/manifest+json\",\n \".md\": \"text/markdown\",\n \".ts\": \"text/plain\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".otf\": \"font/otf\",\n \".eot\": \"application/vnd.ms-opentype\",\n \".wasm\": \"application/wasm\",\n \".txt\": \"text/xml\",\n \".xml\": \"application/xml\",\n};\n\n/**\n * Maps a bundle URL onto the staged namespace layout. Bundle URLs carry their\n * namespace in the path (`…/bundles/<account>/<gateway>/<workspace>/…`); the\n * staged layout mirrors it under `<bundleDir>/<account>/<gateway>/…`. The\n * namespace is taken from the URL itself — this answers \"which staged\n * directory do these bytes live in?\" rather than \"is this my namespace?\" —\n * and the result is contained within the account/gateway directory. Returns\n * null for foreign shapes.\n */\nexport function bundleUrlToStagedPath(url: string, bundleDir: string): string | null {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return null;\n }\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") return null;\n\n const segments = parsed.pathname.split(\"/\").filter(Boolean);\n if (segments[0] !== \"bundles\" || segments.length < 3) return null;\n\n let decoded: string[];\n try {\n decoded = segments.slice(1).map((segment) => decodeURIComponent(segment));\n } catch {\n return null;\n }\n const [account, gateway, ...rest] = decoded;\n if (!account || !gateway || rest.length === 0) return null;\n\n const nsDir = path.resolve(bundleDir, account, gateway);\n const filePath = path.resolve(nsDir, ...rest);\n if (filePath === nsDir || !filePath.startsWith(nsDir + path.sep)) return null;\n return filePath;\n}\n\n/** Resolve a relative config-supplied path inside `dir`, or null on escape. */\nexport function resolveContained(dir: string, relative: string): string | null {\n const resolved = path.resolve(dir, ...relative.split(\"/\").filter(Boolean));\n if (resolved === dir || !resolved.startsWith(dir + path.sep)) return null;\n return resolved;\n}\n\n/**\n * Own-namespace path for a bundle URL: the shared URL→staged-path mapping,\n * narrowed to the runtime identity — a URL whose encoded namespace differs\n * from `namespace.account`/`namespace.gateway` must fall to the network,\n * never serve a sibling namespace's staged bytes.\n */\nexport function bundleUrlToLocalPath(url: string, namespace: BundleNamespace): string | null {\n const filePath = bundleUrlToStagedPath(url, namespace.bundleDir);\n if (!filePath) return null;\n\n const nsDir = path.resolve(namespace.bundleDir, namespace.account, namespace.gateway);\n if (filePath !== nsDir && !filePath.startsWith(nsDir + path.sep)) return null;\n\n return filePath;\n}\n\nexport class BundleResolver extends Context.Service<\n BundleResolver,\n {\n /** Resolve a fetch target from the staged namespace; null = miss or not our namespace — fall through to the network. */\n readonly lookup: (input: string | URL | Request) => Effect.Effect<Response | null>;\n }\n>()(\"everything-dev/resolver/BundleResolver\") {\n static layer(namespace: BundleNamespace | undefined): Layer.Layer<BundleResolver> {\n if (!namespace) {\n return Layer.succeed(\n BundleResolver,\n BundleResolver.of({ lookup: () => Effect.succeed(null) }),\n );\n }\n const respond = Effect.fn(\"BundleResolver.respond\")(function* (\n url: string,\n ): Effect.fn.Return<Response | null, never> {\n const filePath = bundleUrlToLocalPath(url, namespace);\n if (!filePath) return null;\n const bytes = yield* Effect.tryPromise({\n try: () => readFile(filePath),\n catch: (cause) => new BundleReadError({ path: filePath, cause }),\n }).pipe(Effect.catchTag(\"BundleReadError\", () => Effect.succeed(null)));\n if (bytes === null) return null;\n const name = path.basename(filePath);\n const contentType =\n MIME_TYPES[path.extname(name).toLowerCase()] ?? \"application/octet-stream\";\n return new Response(new Uint8Array(bytes), {\n headers: {\n \"content-type\": contentType,\n \"cache-control\": cacheControlOf(name),\n etag: `\"${Buffer.from(bytes.subarray(0, 4096)).toString(\"base64\").slice(0, 24)}\"`,\n },\n });\n });\n\n return Layer.effect(\n BundleResolver,\n Effect.succeed(\n BundleResolver.of({\n lookup: (input) => {\n const url =\n typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n return respond(url);\n },\n }),\n ),\n );\n }\n}\n\nexport interface BundleFetchHandle {\n readonly uninstall: () => Promise<void>;\n}\n\nexport interface BundleFetchOptions {\n /** Own-namespace FS resolution — requires a staged `BOS_BUNDLE_DIR`. */\n namespace?: BundleNamespace;\n /**\n * Explicit opt-in stale-if-error cache (child tier): `/bundles/…` URLs\n * write through to disk on success and serve last-known-good bytes when\n * the origin fails. Never derived implicitly — a cache that activates\n * itself can serve pre-reset bytes after a deploy.\n */\n cacheDir?: string;\n /** Per-attempt deadline for idempotent GETs crossing the interceptor. */\n timeoutMs?: number;\n}\n\nconst staleResponse = (bytes: Uint8Array, url: string): Response => {\n const name = url.split(\"?\")[0]?.split(\"/\").pop() ?? \"\";\n const contentType = MIME_TYPES[path.extname(name).toLowerCase()] ?? \"application/octet-stream\";\n return new Response(bytes.slice().buffer, {\n status: 200,\n headers: { \"content-type\": contentType, \"x-bundle-cache\": \"stale\" },\n });\n};\n\nconst DEFAULT_ATTEMPT_TIMEOUT = \"30 seconds\";\nconst RETRY_BASE_DELAY = \"250 millis\";\nconst RETRY_CAP = \"5 seconds\";\nconst RETRY_TIMES = 4;\n\nconst isTransientStatus = (status: number): boolean => status === 429 || status >= 500;\n\nfunction requestMethod(input: Parameters<FetchImpl>[0], init?: Parameters<FetchImpl>[1]): string {\n if (init?.method) return init.method.toUpperCase();\n if (typeof input === \"string\" || input instanceof URL) return \"GET\";\n return input.method.toUpperCase();\n}\n\nconst asError = (cause: unknown): Error =>\n cause instanceof Error ? cause : new Error(String(cause));\n\n/** A 429/5xx response — carried as a failure so the Schedule can retry it,\n * with the Response kept for the exhausted-retries fallthrough. */\nclass TransientBundleResponse extends Data.TaggedError(\"TransientBundleResponse\")<{\n readonly response: Response;\n}> {}\n\n/**\n * One network attempt through the `HttpFetch` policy: the fetch runs under\n * the fiber's interruption signal, and `Effect.timeout` interrupts at the\n * deadline — aborting the in-flight request. The response is returned\n * regardless of status; transient statuses are lifted by the caller.\n */\nconst fetchAttempt = Effect.fn(\"resolver.attempt\")(function* (\n http: HttpFetchShape,\n input: Parameters<FetchImpl>[0],\n init: Parameters<FetchImpl>[1],\n timeout: Duration.Duration,\n): Effect.fn.Return<Response, FetchNetworkError | Cause.TimeoutError | TransientBundleResponse> {\n return yield* http.attempt(input, init).pipe(\n Effect.timeoutOrElse({\n duration: Duration.toMillis(timeout),\n orElse: () => Effect.fail(new Cause.TimeoutError()),\n }),\n Effect.filterOrFail(\n (response) => !isTransientStatus(response.status),\n (response) => new TransientBundleResponse({ response }),\n ),\n );\n});\n\n/**\n * The resilience policy for idempotent GETs crossing the interceptor\n * (ADR 0021 amendment — the CDN-only image): a cold boot has no staged\n * fallback, so one edge hiccup or a hung connection during the load window\n * must not hard-fail the host or a plugin. Transient statuses and network\n * errors (including the deadline's TimeoutError) retry on a capped\n * exponential schedule before propagating; the last transient response is\n * returned so an explicit stale-if-error cache still sees it. Non-GETs pass\n * through untouched; a caller-initiated cancellation is never spent on the\n * schedule.\n */\nconst resilientFetch = Effect.fn(\"resolver.fetch\")(function* (\n http: HttpFetchShape,\n input: Parameters<FetchImpl>[0],\n init: Parameters<FetchImpl>[1],\n timeout: Duration.Duration,\n): Effect.fn.Return<Response, Cause.TimeoutError | Error> {\n if (requestMethod(input, init) !== \"GET\") {\n return yield* http.attempt(input, init).pipe(Effect.mapError((cause) => asError(cause.cause)));\n }\n return yield* fetchAttempt(http, input, init, timeout).pipe(\n Effect.retry({\n schedule: Schedule.exponential(RETRY_BASE_DELAY).pipe(\n Schedule.upTo({ duration: RETRY_CAP, times: RETRY_TIMES }),\n ),\n // A caller-initiated cancellation is not transient — propagate it\n // immediately instead of spending the schedule on a canceled request.\n while: (error) =>\n !(\n (error instanceof FetchNetworkError || error instanceof Cause.TimeoutError) &&\n init?.signal?.aborted\n ),\n }),\n Effect.catchTags({\n TransientBundleResponse: (error) => Effect.succeed(error.response),\n FetchNetworkError: (error) => Effect.fail(asError(error.cause)),\n }),\n );\n});\n\n/**\n * Installs the resolver as a global fetch interceptor — the one seam every\n * boot-time consumer shares (config manifest discovery, contract-type\n * fetches, orchestrator host loading, MF remoteEntry/identity probes) and\n * the SSR serving path. One layered resolution policy, as a single Effect\n * program on the managed runtime: staged disk → network → (explicitly\n * opted-in) stale-if-error. Own-namespace URLs resolve from the staged\n * directory and fall through to the network on a miss; a miss never touches\n * the write-through cache — for the own namespace the staged disk IS the\n * resilience artifact. Inert when neither a staged namespace nor an\n * explicit cache is configured.\n */\nexport function installGlobalBundleFetch(options: BundleFetchOptions): BundleFetchHandle {\n const namespace = options.namespace;\n const cacheDir = options.cacheDir;\n const timeout = Duration.millis(options.timeoutMs ?? Duration.toMillis(DEFAULT_ATTEMPT_TIMEOUT));\n const original: FetchImpl = globalThis.fetch;\n\n const runtime = ManagedRuntime.make(\n Layer.mergeAll(BundleResolver.layer(namespace), HttpFetch.layerWith({ fetchImpl: original })),\n );\n\n const program = Effect.fn(\"resolver.program\")(function* (\n input: Parameters<FetchImpl>[0],\n init?: Parameters<FetchImpl>[1],\n ): Effect.fn.Return<Response, Cause.TimeoutError | Error, BundleResolver | HttpFetch> {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n const http = yield* HttpFetch;\n\n if (namespace && bundleUrlToLocalPath(url, namespace)) {\n const resolver = yield* BundleResolver;\n const local = yield* resolver.lookup(input);\n if (local !== null) return local;\n return yield* resilientFetch(http, input, init, timeout);\n }\n\n if (cacheDir !== undefined && bundleCachePath(url, { cacheDir })) {\n const cachedRead = Effect.tryPromise(() => readBundleCache(url, { cacheDir }));\n return yield* Effect.gen(function* () {\n const response = yield* resilientFetch(http, input, init, timeout);\n if (response.ok) {\n // write-through is best-effort\n yield* Effect.tryPromise(async () => {\n const bytes = new Uint8Array(await response.clone().arrayBuffer());\n await writeBundleCache(url, bytes, { cacheDir });\n }).pipe(Effect.ignore);\n } else {\n const cached = yield* cachedRead;\n if (cached) return staleResponse(cached, url);\n }\n return response;\n }).pipe(\n Effect.catch((error) =>\n Effect.gen(function* () {\n const cached = yield* cachedRead;\n if (cached) return staleResponse(cached, url);\n return yield* Effect.fail(error);\n }),\n ),\n );\n }\n\n return yield* resilientFetch(http, input, init, timeout);\n });\n\n interface FetchWithPreconnect {\n (input: Parameters<FetchImpl>[0], init?: Parameters<FetchImpl>[1]): Promise<Response>;\n preconnect?: (...args: unknown[]) => unknown;\n }\n\n const patched = ((input: Parameters<FetchImpl>[0], init?: Parameters<FetchImpl>[1]) =>\n runtime.runPromise(program(input, init))) as FetchWithPreconnect;\n const originalPreconnect = (original as FetchWithPreconnect).preconnect;\n if (originalPreconnect) {\n patched.preconnect = originalPreconnect.bind(original);\n }\n globalThis.fetch = patched as unknown as FetchImpl;\n return {\n uninstall: async () => {\n if (globalThis.fetch === patched) {\n globalThis.fetch = original;\n }\n await runtime.dispose();\n },\n };\n}\n\n/**\n * Boot-time installer for the CLI and the host server: derives the own\n * namespace from `BOS_BUNDLE_DIR` plus the runtime identity\n * (`BOS_ACCOUNT`/`BOS_GATEWAY` registry env taking precedence over the\n * bos.config.json fields), and the stale-if-error cache from an explicit\n * `BOS_BUNDLE_CACHE_DIR` — never implicit. Tier auto-detection (ADR 0021):\n * an identity whose namespace is not actually staged under the bundle dir\n * drops to the registry tier — plain resilient network fetch — instead of\n * deterministically 404ing own-namespace URLs against a foreign image's\n * staged bytes. Never throws — a missing or malformed identity leaves the\n * default fetch in place.\n */\nexport function installBundleFetchFromEnv(input: {\n configPath?: string | null;\n}): BundleFetchHandle | null {\n const bundleDir = process.env.BOS_BUNDLE_DIR;\n const cacheDir = process.env.BOS_BUNDLE_CACHE_DIR;\n if (!bundleDir && cacheDir === undefined) return null;\n\n let configAccount: string | undefined;\n let configGateway: string | undefined;\n const configPath = input.configPath;\n if (configPath && !isAppDescriptorPath(configPath)) {\n try {\n const parsed = JSON.parse(readFileSync(configPath, \"utf8\")) as {\n account?: string;\n domain?: string;\n };\n configAccount = parsed.account;\n configGateway = parsed.domain;\n } catch {\n // unreadable config — identity may still come from the registry env\n }\n }\n\n const account = process.env.BOS_ACCOUNT ?? configAccount;\n const gateway = process.env.BOS_GATEWAY ?? configGateway;\n if (bundleDir && (!account || !gateway)) return null;\n\n let namespace: BundleNamespace | undefined;\n if (bundleDir && account && gateway) {\n if (existsSync(path.join(bundleDir, account, gateway))) {\n namespace = { bundleDir, account, gateway };\n } else {\n console.warn(\n `[bundles] staged namespace ${account}/${gateway} not found under ${bundleDir} — registry tier (network fetch)`,\n );\n }\n }\n return installGlobalBundleFetch({ namespace, cacheDir });\n}\n"],"mappings":"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"}