everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
1 lines • 10.1 kB
Source Map (JSON)
{"version":3,"file":"platform-manifest.mjs","names":[],"sources":["../../../src/services/deploy/platform-manifest.ts"],"sourcesContent":["/**\n * The deploy-side half of the platform release manifest (ADR 0034 pt 1/2):\n * wires the framework repo's release inputs into the pure composer and shapes\n * the registry entry that rides the train's atomic FastKV write. Framework-\n * rooted deploys only — a child deploy publishes no release manifest.\n */\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { satisfiesConstraint } from \"../../utils/semver\";\nimport { walkConfigSlots } from \"../config-slots\";\nimport {\n composePlatformReleaseManifest,\n computeTemplateInventory,\n getPlatformManifestKey,\n getPlatformVersionSlotKey,\n type PlatformReleaseManifest,\n type ReleaseSlotRecord,\n resolvePlatformManifest,\n serializePlatformReleaseManifest,\n} from \"../platform/manifest\";\nimport { readWorkspaceCatalog } from \"../workspace/catalog\";\nimport { readFrameworkVersion } from \"./image\";\nimport { computeSriHash } from \"./integrity\";\n\nexport { getPlatformManifestKey, getPlatformVersionSlotKey };\n\n/** The universal image (ADR 0020/0021) — the release manifest's image ref. */\nexport const PLATFORM_IMAGE_REF = \"ghcr.io/nearbuilders/everything-dev\";\n\nexport interface ReleaseSlotRef extends ReleaseSlotRecord {\n slot: string;\n}\n\n/**\n * The release's pinned slots: every config slot (dotted config path, keyed by\n * the same path shape the release-slot stamping writes back — `app.auth`,\n * `app.auth.ui`, `plugins.votes.ui`, …) with a production URL and an\n * immutable version-manifest pin in the release's publish payload. The\n * release leg records them in the release manifest so pinned children can\n * re-point inherited slots at these bytes.\n */\nexport function collectReleaseSlotPins(config: Record<string, unknown>): ReleaseSlotRef[] {\n const slots: ReleaseSlotRef[] = [];\n walkConfigSlots(config, ({ slot, entry }) => {\n if (typeof entry !== \"object\" || entry === null) return;\n const base = typeof entry.production === \"string\" ? entry.production : undefined;\n const pin = entry.pin as { manifest?: unknown; integrity?: unknown } | undefined;\n const manifest = typeof pin?.manifest === \"string\" ? pin.manifest : undefined;\n const integrity = typeof pin?.integrity === \"string\" ? pin.integrity : undefined;\n if (base && manifest && integrity) {\n slots.push({ slot, base, pin: { manifest, integrity } });\n }\n });\n return slots;\n}\n\n/** The `Record<slot, ReleaseSlotRecord>` shape the manifest schema stores. */\nexport function releaseSlotMap(config: Record<string, unknown>): Record<string, ReleaseSlotRecord> {\n return Object.fromEntries(\n collectReleaseSlotPins(config).map(({ slot, base, pin }) => [slot, { base, pin }]),\n );\n}\n\nfunction readWorkspacePackageVersion(configDir: string, name: string): string | undefined {\n try {\n const raw = readFileSync(join(configDir, \"packages\", name, \"package.json\"), \"utf-8\");\n const pkg = JSON.parse(raw) as { version?: unknown };\n return typeof pkg.version === \"string\" ? pkg.version : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function readEveryPluginVersion(configDir: string): string | undefined {\n return readWorkspacePackageVersion(configDir, \"every-plugin\");\n}\n\nexport interface PlatformManifestPublishEntry {\n key: string;\n value: string;\n integrity: string;\n manifest: PlatformReleaseManifest;\n}\n\nexport function composePlatformManifestPublishEntry(opts: {\n configDir: string;\n account: string;\n gateway: string;\n /** The previous release's framework version — the compat floor it implies. */\n previousFrameworkVersion?: string;\n /** The deploy's repo HEAD — the serving build's identity on the wire. */\n gitSha?: string;\n imageRef?: string;\n /** The release's own publish payload — its pinned slots ride the manifest\n * (ADR 0034 amendment: release-scoped extends inheritance). */\n publishPayload?: Record<string, unknown>;\n}): PlatformManifestPublishEntry | null {\n const frameworkVersion = readFrameworkVersion(opts.configDir);\n const everyPluginVersion = readEveryPluginVersion(opts.configDir);\n if (!frameworkVersion || !everyPluginVersion) return null;\n\n const manifest = composePlatformReleaseManifest({\n frameworkVersion,\n everyPluginVersion,\n ...(opts.gitSha ? { gitSha: opts.gitSha } : {}),\n imageRef: opts.imageRef ?? PLATFORM_IMAGE_REF,\n catalog: readWorkspaceCatalog(opts.configDir),\n templateInventory: computeTemplateInventory(opts.configDir),\n compatMinChild: opts.previousFrameworkVersion ?? frameworkVersion,\n ...(opts.publishPayload ? { slots: releaseSlotMap(opts.publishPayload) } : {}),\n });\n const value = serializePlatformReleaseManifest(manifest);\n return {\n key: getPlatformManifestKey(opts.account, opts.gateway),\n value,\n integrity: computeSriHash(value),\n manifest,\n };\n}\n\nexport interface DerivedImageRef {\n image: string;\n tag: string;\n digest?: string;\n}\n\n/**\n * The truth gate (#546): every uploaded workspace's version manifest declares\n * the shared-singleton versions its build embedded; the release manifest pins\n * the same names from the release catalog. A version that appears in both but\n * disagrees means the workspace's install drifted from the catalog — the\n * manifest would lie about the uploaded bytes and pinned children would boot\n * a skewed composition. Pin shapes mirror `checkPlatformCompat`'s semantics\n * (via `satisfiesConstraint`): an exact pin must match exactly, a range pin\n * must be satisfied by the built version — the catalog pinning every-plugin\n * as `^X` while bundles record the exact resolved version is not a violation.\n * Returns human-readable violations; empty = clean.\n */\nexport function platformTruthViolations(\n manifest: PlatformReleaseManifest,\n sharedByWorkspace: Map<string, Record<string, string> | undefined>,\n): string[] {\n const violations: string[] = [];\n for (const [workspace, shared] of sharedByWorkspace) {\n if (!shared) continue;\n for (const [name, version] of Object.entries(shared)) {\n const pin = manifest.sharedDeps[name];\n if (pin && !satisfiesConstraint(version, pin.version)) {\n violations.push(\n `${workspace} was built against ${name}@${version}, the release manifest pins ${pin.version} — ` +\n `a stale install publishes a manifest that lies about the uploaded bytes; ` +\n `run pnpm install and redeploy`,\n );\n }\n }\n }\n return violations;\n}\n\n/**\n * The derived-pin seam for image refs (ADR 0034 pt 2): when the platform\n * manifest resolves, a runtime's image ref derives as `ref@v<version>` —\n * never hand-pinned. Digest resolution rides the registry and arrives as\n * `digest` when the caller can fetch it; the deploy preflight consumer is\n * `resolveChildImagePin` (`services/deploy/legs.ts`), which resolves the\n * tag's digest and repoints the Railway service source.\n */\nexport async function deriveImageRefFromPlatformManifest(opts: {\n configDir: string;\n localConfig: Record<string, unknown>;\n fetchManifest?: (account: string, gateway: string) => Promise<PlatformReleaseManifest | null>;\n fetchSlot?: (account: string, gateway: string, version: string) => Promise<unknown>;\n fetchParent?: (account: string, gateway: string) => Promise<Record<string, unknown> | null>;\n}): Promise<DerivedImageRef | null> {\n const resolved = await resolvePlatformManifest({\n configDir: opts.configDir,\n localConfig: opts.localConfig,\n fetchManifest: opts.fetchManifest,\n ...(opts.fetchSlot ? { fetchSlot: opts.fetchSlot } : {}),\n ...(opts.fetchParent ? { fetchParent: opts.fetchParent } : {}),\n });\n if (!resolved) return null;\n const tag = resolved.manifest.image.tags[0];\n if (!tag) return null;\n return { image: resolved.manifest.image.ref, tag };\n}\n"],"mappings":"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"}