UNPKG

everything-dev

Version:

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

113 lines (111 loc) • 4.03 kB
import { resolveExtendsRef } from "./merge.mjs"; import { BosConfigSchema } from "../../types.mjs"; import { CircularExtendsError, ConfigExtendsError, ConfigLoadError, ConfigNotfoundError, PUBLISHED_CONFIG_ENV } from "./load.mjs"; import { walkExtendsChain } from "./session.mjs"; //#region src/services/resolution/boot-check.ts function extendsRefOf(payload) { return payload !== null && typeof payload === "object" && payload.extends ? resolveExtendsRef(payload.extends, PUBLISHED_CONFIG_ENV) : void 0; } /** * The boot walk itself, exposed so consumers beside `verifyBootPayload` can * gate on the merged shape (the deploy train's composition gate) instead of * re-walking under their own walker. Throws on chain failure; the caller * decides how to report it. */ async function resolveBootShape(payload, slot, opts = {}) { if (payload === null || typeof payload !== "object") throw new Error("payload is not a config object"); const input = payload; if (!extendsRefOf(input)) return { chain: [], config: structuredClone(input) }; const walked = await walkExtendsChain(`bos://${slot.account}/${slot.gateway}`, { env: PUBLISHED_CONFIG_ENV, ...opts.registry ? { registry: opts.registry } : {}, ...opts.io ? { io: opts.io } : {}, seedConfig: structuredClone(input), visit: async () => {} }); return { chain: walked.chain.slice(1), config: structuredClone(walked.config) }; } /** Verify a payload against a shape the caller already walked with * `resolveBootShape` for this exact payload — the pure half of * `verifyBootPayload`, so a shared walk cannot drift from its verification. */ function verifyResolvedBootShape(payload, shape) { if (!extendsRefOf(payload)) return { chain: [], ...parseShape(payload, payload, false) }; return { chain: shape.chain, ...parseShape(payload, shape.config, true) }; } async function verifyBootPayload(payload, slot, opts = {}) { if (payload === null || typeof payload !== "object") return { ok: false, issues: [{ code: "schema", path: "", origin: "payload", message: "payload is not a config object" }], chain: [] }; try { return verifyResolvedBootShape(payload, await resolveBootShape(payload, slot, opts)); } catch (error) { if (!(error instanceof Error)) throw error; return { ok: false, chain: [], issues: [{ code: "chain", path: extendsRefOf(payload) ?? "", origin: "parent", message: chainFailureMessage(error) }] }; } } /** Parse a shape with BosConfigSchema and map the outcome onto a report — * the merged shape in the child path, the payload itself in the root path. * Origin attribution (child path only): a failing dotted path that exists * in the leaf payload is the leaf's; anything else came from the chain. */ function parseShape(payload, shape, attributed) { const parsed = BosConfigSchema.safeParse(shape); if (parsed.success) return { ok: true, issues: [] }; return { ok: false, issues: parsed.error.issues.map((issue) => ({ code: "schema", path: issue.path.join("."), origin: !attributed || pathExistsIn(payload, issue.path) ? "payload" : "parent", message: issue.message })) }; } function pathExistsIn(payload, path) { let cursor = payload; for (const key of path) { if (cursor === null || typeof cursor !== "object" || !(key in cursor)) return false; cursor = cursor[key]; } return true; } function chainFailureMessage(error) { if (error instanceof CircularExtendsError) return `circular extends: ${error.message}`; if (error instanceof ConfigNotfoundError) return `a parent config could not be found: ${error.message}`; if (error instanceof ConfigLoadError) return `a parent config could not be loaded: ${error.message}`; if (error instanceof ConfigExtendsError) return `the extends chain could not be resolved: ${error.message}`; return `the extends chain could not be resolved: ${error.message}`; } //#endregion export { resolveBootShape, verifyBootPayload, verifyResolvedBootShape }; //# sourceMappingURL=boot-check.mjs.map