everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
1 lines • 22.3 kB
Source Map (JSON)
{"version":3,"file":"deploy.mjs","names":[],"sources":["../../src/commands/deploy.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport process from \"node:process\";\nimport { Context } from \"effect\";\nimport { MISSING_CONFIG_MESSAGE } from \"../config\";\nimport {\n type ConfigHistoryEntry,\n fetchBosConfigFromFastKv,\n fetchConfigHistory,\n fetchDeployManifests,\n} from \"../fastkv\";\nimport {\n buildAndPushImage,\n deployImageToRailway,\n hasDocker,\n isValidImageDigest,\n resolveDeployImagePlan,\n resolveImageRef,\n} from \"../image-deploy\";\nimport { publishToFastKv } from \"../publish\";\nimport { openResolution } from \"../resolution/session\";\nimport { buildRollbackPayload, summarizeSlotPins, verifyRollbackSnapshot } from \"../rollback\";\nimport type { BosConfigInput } from \"../types\";\nimport { BosConfigSchema } from \"../types\";\nimport { colors, icons } from \"../utils/theme\";\nimport { type BosBuilder, BosDepsTag } from \"./shared\";\n\nexport function registerDeploy(builder: BosBuilder) {\n return {\n publish: builder.publish.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session?.config) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n const result = await publishToFastKv({\n bosConfig: session.config,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: false,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: \"all\",\n network: input.network,\n privateKey: input.privateKey,\n wallet: input.wallet,\n registry: input.registry,\n });\n\n return {\n status: result.status,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n error: result.error,\n built: result.built,\n skipped: result.skipped,\n deployResults: result.deployResults,\n };\n }),\n\n rollback: builder.rollback.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n const { account, domain } = session.config ?? {};\n if (!account || !domain) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"authored config must define account and domain to roll back\",\n };\n }\n\n let history: ConfigHistoryEntry[];\n try {\n history = await fetchConfigHistory({\n accountId: account,\n gatewayId: domain,\n registry: input.registry,\n limit: input.limit,\n });\n } catch (error) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Failed to fetch publish history: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n\n if (history.length === 0) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `No publish history for ${account}/${domain} — nothing to roll back to`,\n };\n }\n\n const historyEntries = history.map((entry) => ({\n blockHeight: entry.blockHeight,\n blockTimestamp: new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString(),\n ...(entry.txHash ? { txHash: entry.txHash } : {}),\n summary: summarizeSlotPins(entry.value as BosConfigInput),\n }));\n\n if (input.listOnly) {\n return {\n status: \"list\" as const,\n registryUrl: \"\",\n history: historyEntries,\n };\n }\n\n const target =\n input.version !== undefined\n ? history.find((entry) => {\n const iso = new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString();\n return (\n String(entry.blockHeight) === input.version ||\n iso.startsWith(input.version as string)\n );\n })\n : input.previous\n ? history[1]\n : undefined;\n\n if (!target) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n history: historyEntries,\n error: input.version\n ? `No history entry matches \"${input.version}\" — pick a block height from the listing`\n : \"Specify --version <block-height> or --previous (interactive selection happens CLI-side)\",\n };\n }\n\n let liveValue: unknown;\n try {\n liveValue = await fetchBosConfigFromFastKv<unknown>(\n `bos://${account}/${domain}`,\n input.registry,\n );\n } catch {\n liveValue = undefined;\n }\n if (liveValue && JSON.stringify(liveValue) === JSON.stringify(target.value)) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"The selected snapshot is identical to the live config — nothing to do\",\n };\n }\n\n const verification = await verifyRollbackSnapshot(target.value as BosConfigInput);\n const slotChecks = verification.slots.map((check) => ({\n slot: check.slot,\n ok: check.ok,\n ...(check.reason ? { reason: check.reason } : {}),\n }));\n if (!verification.ok && verification.verifiable) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n verification: slotChecks,\n error:\n \"Refusing to roll back — a pinned slot's bytes are gone or no longer match their SRI\",\n };\n }\n\n if (!verification.verifiable && !input.force) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error:\n \"Snapshot predates version manifests and cannot be verified — its bytes were overwritten in place. Re-run with --force to publish it anyway.\",\n };\n }\n\n const parsedTarget = BosConfigSchema.parse(target.value);\n const payload = buildRollbackPayload(parsedTarget, new Date().toISOString());\n\n const result = await publishToFastKv({\n bosConfig: payload,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: false,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: \"all\",\n network: input.network,\n privateKey: input.privateKey,\n wallet: input.wallet,\n registry: input.registry,\n });\n\n return {\n status: result.status,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n error: result.error,\n history: historyEntries,\n ...(slotChecks.length > 0 ? { verification: slotChecks } : {}),\n };\n }),\n\n deploy: builder.deploy.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session?.config) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n if (input.statusList) {\n if (!session.config?.account || !session.config.domain) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: \"authored config must define account and domain to list deploy manifests\",\n };\n }\n try {\n const manifests = await fetchDeployManifests({\n accountId: session.config.account,\n gatewayId: session.config.domain,\n registry: input.registry,\n });\n return {\n status: \"list\" as const,\n registryUrl: \"\",\n history: manifests.map((entry) => ({\n key: entry.key,\n blockHeight: entry.blockHeight,\n blockTimestamp: new Date(Number(entry.blockTimestampNs.slice(0, 13))).toISOString(),\n ...((entry.value as { txHash?: string } | undefined)?.txHash\n ? { txHash: (entry.value as { txHash?: string }).txHash }\n : {}),\n ...((entry.value as { publishedAt?: string } | undefined)?.publishedAt\n ? { publishedAt: (entry.value as { publishedAt?: string }).publishedAt }\n : {}),\n })),\n };\n } catch (error) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Failed to list deploy manifests: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n const imageDigestInput = input.imageDigest ?? process.env.BOS_IMAGE_DIGEST;\n if (imageDigestInput && !isValidImageDigest(imageDigestInput)) {\n return {\n status: \"error\" as const,\n registryUrl: \"\",\n error: `Invalid image digest \"${imageDigestInput}\" — expected sha256:<64 hex characters> (--image-digest / BOS_IMAGE_DIGEST)`,\n };\n }\n\n const result = await publishToFastKv({\n bosConfig: session.config,\n runtimeConfig: session.runtime,\n configDir: session.root,\n env: input.env,\n build: input.build,\n dryRun: input.dryRun,\n verbose: input.verbose,\n packages: input.packages,\n network: input.network,\n privateKey: input.privateKey,\n registry: input.registry,\n fullUpload: input.fullUpload,\n });\n\n if (result.status === \"error\") {\n return {\n status: \"error\" as const,\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n built: result.built,\n skipped: result.skipped,\n error: result.error,\n deployResults: result.deployResults,\n };\n }\n\n if (result.status === \"dry-run\") {\n return {\n status: \"dry-run\" as const,\n registryUrl: result.registryUrl,\n built: result.built,\n skipped: result.skipped,\n };\n }\n\n let nextSession = session;\n if (result.publishConfig) {\n const opened = await openResolution({ cwd: session.root });\n if (opened) {\n nextSession = opened;\n }\n }\n\n const configPublished = {\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n fingerprint: result.fingerprint,\n slotPins: result.slotPins,\n built: result.built,\n skipped: result.skipped,\n deployResults: result.deployResults,\n } as const;\n\n let image: string | undefined;\n let imageDigest: string | undefined;\n let service: string | undefined;\n\n const imagePlan = resolveDeployImagePlan({\n // A prebuilt digest pairs with the pushed ref (BOS_IMAGE from the CI\n // image job, or repository derivation) — ci.image is a build-time\n // choice, not a pin-time one; letting it win here could pin a digest\n // from a different image.\n imageRef: resolveImageRef({\n ciImage: imageDigestInput ? undefined : nextSession.config?.ci?.image,\n repository: nextSession.config?.repository,\n env: process.env,\n }),\n imageDigest: imageDigestInput,\n hasDocker: await hasDocker(),\n hasDockerfile: existsSync(join(session.root, \"Dockerfile\")),\n });\n\n if (imagePlan.kind === \"skip\") {\n console.log();\n console.log(colors.yellow(` Image skipped: ${imagePlan.reason}`));\n } else if (imagePlan.kind === \"prebuilt\") {\n image = imagePlan.image;\n imageDigest = imagePlan.digest;\n console.log();\n console.log(\n colors.green(\n ` ${icons.ok} Using pre-pushed image ${imagePlan.image}@${imagePlan.digest.slice(0, 19)}…`,\n ),\n );\n } else {\n console.log();\n try {\n const imageResult = await buildAndPushImage({\n image: imagePlan.image,\n configDir: session.root,\n verbose: input.verbose,\n });\n image = imageResult.image;\n imageDigest = imageResult.digest;\n console.log(\n colors.green(\n ` ${icons.ok} Image pushed ${imageResult.image}:${imageResult.tag}${imageResult.digest ? ` (${imageResult.digest.slice(0, 19)}…)` : \"\"}`,\n ),\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const imageError =\n message.includes(\"not found\") || message.includes(\"ENOENT\")\n ? \"Docker not found — install Docker to build the runtime image\"\n : `Image build/push failed: ${message}`;\n console.log(colors.yellow(` ${imageError}`));\n return {\n status: \"published\" as const,\n ...configPublished,\n error: `Config published but ${imageError}`,\n };\n }\n }\n\n if (process.env.RAILWAY_TOKEN) {\n const railwayService = input.service ?? nextSession.config?.ci?.railway?.service;\n if (!railwayService) {\n console.log();\n console.log(\n colors.yellow(\n \" Railway deploy skipped: ci.railway.service is not configured in bos.config.json\",\n ),\n );\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n error:\n \"Config published but Railway deploy failed: ci.railway.service is not configured in bos.config.json\",\n };\n }\n if (!image || !imageDigest) {\n console.log();\n console.log(\n colors.yellow(\n \" Railway deploy skipped: no runtime image digest — set ci.image (or pass BOS_IMAGE_DIGEST) and make the image available\",\n ),\n );\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n service: railwayService,\n error:\n \"Config published but Railway deploy requires a runtime image (set ci.image, or pass BOS_IMAGE_DIGEST for a pre-pushed image)\",\n };\n }\n\n service = railwayService;\n try {\n await deployImageToRailway({\n image,\n digest: imageDigest,\n service: railwayService,\n configDir: session.root,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const railError =\n message.includes(\"not found\") || message.includes(\"ENOENT\")\n ? \"Railway CLI not found. Install it: npm i -g @railway/cli\"\n : `Railway deploy failed: ${message}`;\n console.log(colors.yellow(` ${railError}`));\n return {\n status: \"published\" as const,\n ...configPublished,\n image,\n service,\n error: `Config published but ${railError}`,\n };\n }\n } else {\n console.log();\n console.log(colors.yellow(\" Railway deploy skipped (RAILWAY_TOKEN not set)\"));\n }\n\n return {\n status: \"deployed\" as const,\n ...configPublished,\n image,\n service,\n };\n }),\n };\n}\n"],"mappings":"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"}