UNPKG

everything-dev

Version:

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

1 lines • 26.2 kB
{"version":3,"file":"image.cjs","names":["run","readFileSync","join","fetchResponse","colors","icons"],"sources":["../../../src/services/deploy/image.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fetchResponse } from \"../../utils/http-client\";\nimport { run } from \"../../utils/run\";\nimport { colors, icons } from \"../../utils/theme\";\n\nexport interface ResolvedImageRef {\n image: string;\n source: \"env\" | \"repository\";\n}\n\n/**\n * Image reference resolution precedence (ADR 0021): `BOS_IMAGE` env → derived\n * from `repository`. Only the root runtime builds — children never own image\n * bytes; their ref derives from the platform release manifest (ADR 0034).\n */\nexport function resolveImageRef(input: {\n repository?: string;\n env?: Record<string, string | undefined>;\n}): ResolvedImageRef | undefined {\n const envImage = input.env?.BOS_IMAGE;\n if (envImage) return { image: envImage, source: \"env\" };\n\n const repo = input.repository\n ?.replace(/^https?:\\/\\/(www\\.)?github\\.com\\//i, \"\")\n .replace(/\\.git$/i, \"\")\n .replace(/\\/+$/, \"\")\n .toLowerCase();\n if (!repo?.includes(\"/\") || repo.split(\"/\").length !== 2) return undefined;\n return { image: `ghcr.io/${repo}`, source: \"repository\" };\n}\n\n/** Compose the runnable image ref: `image@sha256:…` when a digest exists,\n * `image` alone otherwise. Never docker-run the bare ref in a deploy flow —\n * the implicit `:latest` is held to the last stable release during\n * prereleases (ADR 0021), which boots a different framework build than the\n * one this train pinned. */\nexport function imageRefWithDigest(image: string, digest?: string): string {\n return digest ? `${image}@${digest}` : image;\n}\n\nexport async function hasDocker(): Promise<boolean> {\n try {\n const result = await run(\"docker\", [\"info\", \"--format\", \"{{.ServerVersion}}\"], {\n capture: true,\n });\n return result?.exitCode === 0;\n } catch {\n return false;\n }\n}\n\nfunction parseDigest(pushOutput: string): string | undefined {\n const match = pushOutput.match(/digest:\\s*(sha256:[a-f0-9]+)/i);\n return match?.[1];\n}\n\nconst SEMVER_PATTERN = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?$/;\n\n/**\n * The runtime framework version baked into the image is the workspace source's\n * `everything-dev` package version — the image builds from `configDir`, so that\n * file is the truth. Missing (child repos without the workspace) → undefined.\n * Exported for the platform release manifest composer (ADR 0034) — one version\n * source for the image, the manifest, and the npm gate.\n */\nexport function readFrameworkVersion(configDir: string): string | undefined {\n try {\n const raw = readFileSync(\n join(configDir, \"packages\", \"everything-dev\", \"package.json\"),\n \"utf-8\",\n );\n const pkg = JSON.parse(raw) as { version?: unknown };\n return typeof pkg.version === \"string\" && SEMVER_PATTERN.test(pkg.version)\n ? pkg.version\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface ImageTags {\n /** Exact refs to build and push, in push order (latest excluded). */\n tags: string[];\n /** Push `:latest` after the pinned tags. */\n pushLatest: boolean;\n /** Human-readable reason when `latest` is held. */\n latestHoldReason?: string;\n /** Push `:rc` after the pinned tags — the floating prerelease-train ref. */\n pushRc: boolean;\n}\n\n/**\n * Tag scheme (ADR 0021): `sha-<short>` always; the exact `v<version>` tag; a\n * floating major tag (`v2`) on stable releases only. `latest` is held during\n * prereleases (npm's `rc` dist-tag analog) so existing deployments pinned to\n * `:latest` keep serving the last stable image — and `:rc` is the floating\n * ref for the prerelease train (npm's `rc` dist-tag mirror): it moves on\n * every prerelease deploy and freezes at the last rc-train build once the\n * workspace releases a stable version.\n */\nexport function computeImageTags(input: { shortSha: string; version?: string }): ImageTags {\n const tags = [`sha-${input.shortSha}`];\n const match = input.version?.trim().match(SEMVER_PATTERN);\n if (!match) {\n return { tags, pushLatest: true, pushRc: false };\n }\n const [, major, minor, patch, prerelease] = match;\n const exact = prerelease\n ? `v${major}.${minor}.${patch}-${prerelease}`\n : `v${major}.${minor}.${patch}`;\n if (prerelease) {\n return {\n tags: [...tags, exact],\n pushLatest: false,\n latestHoldReason: `${exact} is a prerelease — :latest still serves the last stable image`,\n pushRc: true,\n };\n }\n return { tags: [...tags, exact, `v${major}`], pushLatest: true, pushRc: false };\n}\n\nexport interface ImageDeployResult {\n image: string;\n /** Primary pinned tag (the sha tag). */\n tag: string;\n /** All tags pushed, including the primary. */\n tags: string[];\n latestPushed: boolean;\n /** Whether the floating `:rc` prerelease-train ref was pushed. */\n rcPushed: boolean;\n digest?: string;\n}\n\nexport type DeployImagePlan =\n | { kind: \"prebuilt\"; image: string; digest: string }\n | { kind: \"build\"; image: string }\n | { kind: \"skip\"; reason: string };\n\nconst DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/;\n\n/** A Railway pin is `FROM image@<digest>` — anything else cannot resolve. */\nexport function isValidImageDigest(digest: string): boolean {\n return DIGEST_PATTERN.test(digest);\n}\n\nexport interface RegistryRef {\n registry: string;\n repository: string;\n tag?: string;\n digest?: string;\n}\n\n/**\n * Split a container image ref into registry/repository/tag/digest. The\n * registry must be explicit (a dotted host, optionally ported, or\n * `localhost`) — the platform's refs are always `ghcr.io/<owner>/<name>`\n * (ADR 0034 manifest ref, or the `repository` derivation).\n */\nexport function parseRegistryRef(ref: string): RegistryRef | undefined {\n const slash = ref.indexOf(\"/\");\n if (slash <= 0) return undefined;\n const registry = ref.slice(0, slash);\n if (\n !/^[a-z0-9-]+(?:\\.[a-z0-9-]+)+(?::\\d+)?$/.test(registry) &&\n !/^localhost(?::\\d+)?$/.test(registry)\n ) {\n return undefined;\n }\n const rest = ref.slice(slash + 1);\n if (!rest.includes(\"/\")) return undefined;\n let name = rest;\n let tag: string | undefined;\n let digest: string | undefined;\n const at = rest.indexOf(\"@\");\n if (at >= 0) {\n digest = rest.slice(at + 1);\n const addressed = rest.slice(0, at);\n // A digest wins over a tag (docker ref semantics) — the tag is dropped.\n const colon = addressed.lastIndexOf(\":\");\n name = colon > addressed.lastIndexOf(\"/\") ? addressed.slice(0, colon) : addressed;\n } else {\n const colon = rest.lastIndexOf(\":\");\n if (colon > rest.lastIndexOf(\"/\")) {\n tag = rest.slice(colon + 1);\n name = rest.slice(0, colon);\n }\n }\n if (!name) return undefined;\n return { registry, repository: name, tag, digest };\n}\n\n/** Manifest media types a registry may serve — both OCI and Docker, index\n * and manifest, so the HEAD is answered for any image layout. */\nconst MANIFEST_ACCEPT = [\n \"application/vnd.oci.image.index.v1+json\",\n \"application/vnd.oci.image.manifest.v1+json\",\n \"application/vnd.docker.distribution.manifest.list.v2+json\",\n \"application/vnd.docker.distribution.manifest.v2+json\",\n].join(\", \");\n\n/**\n * Resolve a tag's digest from the OCI distribution API (ADR 0034: the digest\n * derives, never embeds). Follows the spec's token flow — an anonymous probe\n * reads the `WWW-Authenticate` challenge, mints a pull token at the realm,\n * and retries; public images (ghcr.io) never need credentials. A missing\n * manifest throws — the child pin cannot be verified, and that is a failure.\n */\nexport async function resolveRegistryDigest(input: {\n ref: string;\n fetch?: typeof fetchResponse;\n}): Promise<string> {\n const parsed = parseRegistryRef(input.ref);\n if (!parsed) {\n throw new Error(`Cannot resolve a digest — unparsable image ref \"${input.ref}\"`);\n }\n const doFetch = input.fetch ?? fetchResponse;\n const manifestUrl = `https://${parsed.registry}/v2/${parsed.repository}/manifests/${parsed.digest ?? parsed.tag ?? \"latest\"}`;\n\n const head = async (headers: Record<string, string>): Promise<Response> => {\n try {\n return await doFetch(manifestUrl, {\n method: \"HEAD\",\n headers: { Accept: MANIFEST_ACCEPT, ...headers },\n });\n } catch (cause) {\n throw new Error(\n `Registry ${parsed.registry} unreachable while resolving ${input.ref}: ${cause instanceof Error ? cause.message : String(cause)}`,\n );\n }\n };\n\n let res = await head({});\n if (res.status === 401) {\n const challenge = res.headers.get(\"www-authenticate\") ?? \"\";\n const realm = /realm=\"([^\"]+)\"/.exec(challenge)?.[1];\n if (realm) {\n const tokenUrl = new URL(realm);\n const service = /service=\"([^\"]+)\"/.exec(challenge)?.[1];\n const scope = /scope=\"([^\"]+)\"/.exec(challenge)?.[1];\n if (service) tokenUrl.searchParams.set(\"service\", service);\n if (scope) tokenUrl.searchParams.set(\"scope\", scope);\n const tokenRes = await doFetch(tokenUrl.href, { headers: { Accept: \"application/json\" } });\n if (!tokenRes.ok) {\n throw new Error(\n `Registry ${parsed.registry} token realm returned HTTP ${tokenRes.status} while resolving ${input.ref}`,\n );\n }\n const body = (await tokenRes.json()) as { token?: string };\n if (body.token) {\n res = await head({ Authorization: `Bearer ${body.token}` });\n }\n }\n }\n\n const digest = res.headers.get(\"docker-content-digest\");\n if (!res.ok || !digest) {\n throw new Error(\n `The registry has no manifest for ${input.ref} (HTTP ${res.status}) — the pin cannot be verified`,\n );\n }\n return digest;\n}\n\n/**\n * Decide the image leg's source: a digest handed over from a pre-pushed image\n * (the CI image job) wins; otherwise the local docker build runs when the\n * toolchain and Dockerfile are present (ADR 0021, as amended).\n */\nexport function resolveDeployImagePlan(input: {\n imageRef: ResolvedImageRef | undefined;\n imageDigest?: string;\n hasDocker: boolean;\n hasDockerfile: boolean;\n}): DeployImagePlan {\n if (!input.imageRef) {\n return {\n kind: \"skip\",\n reason:\n \"set BOS_IMAGE (or repository in bos.config.json) to build and push the runtime image\",\n };\n }\n if (input.imageDigest) {\n return { kind: \"prebuilt\", image: input.imageRef.image, digest: input.imageDigest };\n }\n if (!input.hasDocker) {\n return { kind: \"skip\", reason: \"docker is not available\" };\n }\n if (!input.hasDockerfile) {\n return { kind: \"skip\", reason: \"no Dockerfile at the config root\" };\n }\n return { kind: \"build\", image: input.imageRef.image };\n}\n\n/**\n * Image leg (ADR 0021): build the runtime stage, tag `sha-<short>` + version\n * tags, push them, capture the digest, then push the floating refs — `:latest`\n * unless the version is a prerelease, and `:rc` when it is. Callers skip the\n * leg with a notice when no image is configured (child repos get\n * build+upload+publish only).\n */\nexport async function buildAndPushImage(input: {\n image: string;\n configDir: string;\n verbose?: boolean;\n}): Promise<ImageDeployResult> {\n const shaResult = await run(\"git\", [\"rev-parse\", \"--short=7\", \"HEAD\"], {\n cwd: input.configDir,\n capture: true,\n });\n const shortSha = shaResult?.stdout.trim();\n if (!shaResult || shaResult.exitCode !== 0 || !shortSha) {\n const detail = shaResult?.stderr.trim();\n throw new Error(\n `Failed to resolve the current git SHA in ${input.configDir} (exit code ${shaResult?.exitCode ?? \"unknown\"}${detail ? `: ${detail}` : \"\"})`,\n );\n }\n // The full HEAD rides a build arg into the in-image platform manifest\n // (#537) — docker contexts carry no .git for the composer to read.\n const fullShaResult = await run(\"git\", [\"rev-parse\", \"HEAD\"], {\n cwd: input.configDir,\n capture: true,\n });\n const fullSha = fullShaResult?.exitCode === 0 ? fullShaResult.stdout.trim() : undefined;\n\n const version = readFrameworkVersion(input.configDir);\n const { tags, pushLatest, latestHoldReason, pushRc } = computeImageTags({\n shortSha,\n version,\n });\n const refs = tags.map((tag) => `${input.image}:${tag}`);\n const latestRef = `${input.image}:latest`;\n const rcRef = `${input.image}:rc`;\n const buildRefs = pushLatest ? [...refs, latestRef] : [...refs];\n if (pushRc) buildRefs.push(rcRef);\n\n console.log(\n ` Building runtime image ${colors.cyan(buildRefs.join(\", \"))}${pushLatest ? \"\" : colors.yellow(\" (latest held)\")}`,\n );\n await run(\n \"docker\",\n [\n \"build\",\n \"--target\",\n \"runtime\",\n ...(fullSha ? [\"--build-arg\", `BOS_GIT_SHA=${fullSha}`] : []),\n ...buildRefs.flatMap((ref) => [\"-t\", ref]),\n \".\",\n ],\n { cwd: input.configDir },\n );\n\n console.log(` Pushing ${colors.cyan(refs.join(\", \"))}...`);\n let digest: string | undefined;\n for (const ref of refs) {\n const push = await run(\"docker\", [\"push\", ref], {\n cwd: input.configDir,\n capture: true,\n });\n if (!push || push.exitCode !== 0) {\n throw new Error(`docker push ${ref} failed with exit code ${push?.exitCode ?? \"unknown\"}`);\n }\n digest ??= parseDigest(push.stdout);\n if (input.verbose && push.stdout.trim()) {\n console.log(colors.dim(push.stdout.trim()));\n }\n }\n\n const pushFloating = async (ref: string): Promise<boolean> => {\n const push = await run(\"docker\", [\"push\", ref], {\n cwd: input.configDir,\n capture: true,\n });\n if (!push || push.exitCode !== 0) {\n throw new Error(`docker push ${ref} failed with exit code ${push?.exitCode ?? \"unknown\"}`);\n }\n digest ??= parseDigest(push.stdout);\n if (input.verbose && push.stdout.trim()) {\n console.log(colors.dim(push.stdout.trim()));\n }\n return true;\n };\n\n let latestPushed = false;\n if (pushLatest) {\n latestPushed = await pushFloating(latestRef);\n } else {\n console.log(colors.yellow(` latest held: ${latestHoldReason}`));\n }\n const rcPushed = pushRc ? await pushFloating(rcRef) : false;\n\n if (!digest) {\n console.log(colors.yellow(\" Could not capture the image digest from push output\"));\n }\n\n return { image: input.image, tag: tags[0]!, tags, latestPushed, rcPushed, digest };\n}\n\nasync function requireRailwayCli(configDir: string): Promise<string> {\n // The probe is authoritative: runners don't ship the CLI, and a spawn\n // failure resolves (reject:false) as exitCode 1 with empty output — the\n // 2026-10-13 deploy surfaced exactly that as a silent instant failure.\n let version: string | undefined;\n try {\n version = (await run(\"railway\", [\"--version\"], { cwd: configDir, capture: true }))?.stdout;\n } catch {\n version = undefined;\n }\n if (!version?.trim()) {\n throw new Error(\"Railway CLI not found. Install it: npm i -g @railway/cli\");\n }\n console.log(` ${colors.dim(`railway ${version.trim()}`)}`);\n return version.trim();\n}\n\nasync function runRailwayStreaming(\n args: readonly string[],\n input: { configDir: string },\n): Promise<void> {\n // Stream the CLI's output live — a silent exit (empty stdout+stderr, seen\n // on the 2026-10-13 deploy) must still be diagnosable from the workflow log.\n const collected = { stdout: \"\", stderr: \"\" };\n const result = await run(\"railway\", [...args], {\n cwd: input.configDir,\n capture: true,\n onChunk: (stream, chunk) => {\n collected[stream] += chunk.toString(\"utf-8\");\n for (const line of chunk.toString(\"utf-8\").split(\"\\n\")) {\n if (line.trim()) console.log(` ${colors.dim(line.trim())}`);\n }\n },\n });\n if (!result || result.exitCode !== 0) {\n const exitCode = result?.exitCode ?? \"unknown\";\n const tail = (stream: string, text: string) =>\n text.trim()\n ? `\\nrailway ${stream} (tail):\\n${text.trim().split(\"\\n\").slice(-20).join(\"\\n\")}`\n : \"\";\n throw new Error(\n `railway ${args[0]} failed with exit code ${exitCode}` +\n tail(\"stdout\", collected.stdout) +\n tail(\"stderr\", collected.stderr),\n );\n }\n}\n\n/**\n * Pin the service's source to an exact image ref (Railway `ServiceConnect`):\n * a child deploy repoints the dashboard-connected source at the platform\n * manifest's `ref:tag` (ADR 0034), so the following `redeploy --from-source`\n * pulls the pinned bytes instead of whatever a floating ref moved to. The\n * project-scoped RAILWAY_TOKEN already authorizes the redeploy — connect\n * runs in the same context. The ref pins by tag: the train's version/sha\n * tags are append-only, and Railway's deployment history pins the exact\n * digest each deployment pulled (ADR 0021).\n */\nexport async function repointServiceSource(input: {\n service: string;\n image: string;\n configDir: string;\n}): Promise<void> {\n console.log(\n ` Pinning Railway service ${colors.cyan(input.service)} source to ${colors.cyan(input.image)}...`,\n );\n await requireRailwayCli(input.configDir);\n await runRailwayStreaming(\n [\"service\", \"source\", \"connect\", \"--image\", input.image, \"--service\", input.service, \"--json\"],\n input,\n );\n console.log(colors.green(` ${icons.ok} Railway service source pinned`));\n}\n\n/**\n * Railway leg (ADR 0021, amended): image-backed deploy. The service's source\n * is a Docker image ref (connected once in the dashboard — `:rc` during the\n * prerelease train — or repointed to the child's platform-manifest pin by\n * `repointServiceSource`), and `redeploy --from-source` pulls and deploys\n * whatever that ref points at. The image leg pushes `:rc` (and the\n * `sha-<short>` / version tags) immediately before this step, so the pulled\n * bytes are exactly what this train validated. Railway skips the build\n * entirely for Docker-image sources — nothing is uploaded, nothing is built\n * on Railway, and the digest-pin Dockerfile mechanism this replaces is gone\n * (the CLI v5 dropped RAILWAY_DOCKERFILE_PATH, its snapshot respects\n * .gitignore so generated Dockerfiles never shipped, and its Metal builder\n * rejected the repo Dockerfile's cache-mount ids).\n */\nexport async function deployImageToRailway(input: {\n service: string;\n configDir: string;\n}): Promise<void> {\n console.log(` Deploying to Railway service ${colors.cyan(input.service)} (image-backed)...`);\n await requireRailwayCli(input.configDir);\n await runRailwayStreaming(\n [\"redeploy\", \"--service\", input.service, \"--from-source\", \"--yes\"],\n input,\n );\n console.log(colors.green(` ${icons.ok} Railway deploy complete`));\n}\n"],"mappings":"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"}