everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
131 lines (129 loc) • 6.33 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_runtime = require('../../_virtual/_rolldown/runtime.cjs');
const require_services_resolution_resolver = require('../resolution/resolver.cjs');
const require_manifest_verify = require('./manifest-verify.cjs');
let node_fs = require("node:fs");
let node_path = require("node:path");
node_path = require_runtime.__toESM(node_path, 1);
let every_plugin_build_artifact_names = require("every-plugin/build/artifact-names");
let every_plugin_version_manifest = require("every-plugin/version-manifest");
//#region src/services/deploy/version-manifest.ts
/** Read a workspace dist's build-report.json (ticket 01's entry-name report). */
function readBuildReport(distRoot) {
const reportPath = (0, node_path.join)(distRoot, "build-report.json");
if (!(0, node_fs.existsSync)(reportPath)) return null;
try {
return every_plugin_build_artifact_names.BuildEntryReportSchema.parse(JSON.parse((0, node_fs.readFileSync)(reportPath, "utf8")));
} catch {
return null;
}
}
/**
* Compose the workspace's version manifest from the dist build reports and
* the **server-computed** SRI map of the upload response (MAP decision 6 —
* SRI is authoritative from the storage boundary, never computed
* client-side). Returns null when the dist predates hashed entry names
* (no report, or the SRI map lacks the entry) — the deploy leg then aborts:
* uploaded workspaces must pin.
*/
function composeWorkspaceVersionManifest(input) {
const { report, ssrReport, integrityMap, files, source, gitSha } = input;
const entryIntegrity = integrityMap[report.entry];
if (!entryIntegrity) return null;
const ssrEntry = ssrReport?.entry;
const ssrIntegrity = ssrEntry ? integrityMap[`ssr/${ssrEntry}`] : void 0;
return (0, every_plugin_version_manifest.composeVersionManifest)({
entry: report.entry,
entryIntegrity,
...ssrEntry && ssrIntegrity ? { ssr: {
entry: `ssr/${ssrEntry}`,
integrity: ssrIntegrity
} } : {},
...report.browserManifest && integrityMap[report.browserManifest] ? { browserManifest: {
file: report.browserManifest,
integrity: integrityMap[report.browserManifest]
} } : {},
...report.css && integrityMap[report.css] ? { assets: { css: integrityMap[report.css] } } : {},
...report.shared ?? ssrReport?.shared ? { shared: report.shared ?? ssrReport?.shared } : {},
...files ? { files } : {},
...source ? { source } : {},
...gitSha ? { gitSha } : {}
});
}
const cache = /* @__PURE__ */ new Map();
function clearSlotVersionCache() {
cache.clear();
}
function slotVersionFromManifest(base, manifest) {
const trimmedBase = base.replace(/\/$/, "");
return {
entryUrl: `${trimmedBase}/${manifest.entry}`,
entryIntegrity: manifest.entryIntegrity,
...manifest.browserManifest ? { browserManifestUrl: `${trimmedBase}/${manifest.browserManifest.file}` } : {},
...manifest.ssr ? {
ssrEntryUrl: `${trimmedBase}/${manifest.ssr.entry}`,
ssrIntegrity: manifest.ssr.integrity
} : {},
...manifest.shared ? { sharedVersions: manifest.shared } : {},
...manifest.files ? { files: manifest.files } : {},
...manifest.source ? { source: manifest.source } : {}
};
}
/**
* Staged-slot preference (ADR 0020/0021 self-contained tier): when a runtime
* stages its own namespace under `BOS_BUNDLE_DIR`, a slot resolves from the
* staged dist's own version manifest instead of the config's pin — pinned
* manifest bytes that predate the image (deploy lag after a release bump)
* cannot exist in the staged namespace, so their hashed files would 404 the
* disk and fall through to the network, where the stale immutable bytes
* still answer 200 and boot a foreign build. The staged manifest is trusted
* (staged by the image build itself) and skipped entirely when the slot is
* absent from the staged namespace or the pinned manifest is present (the
* normal healthy case, which keeps the pin's SRI check).
*/
function readStagedSlotVersion(base, pin) {
const bundleDir = process.env.BOS_BUNDLE_DIR;
if (!bundleDir) return null;
const slotDir = require_services_resolution_resolver.bundleUrlToStagedPath(base, bundleDir);
if (!slotDir || !(0, node_fs.existsSync)(slotDir)) return null;
const pinnedManifestPath = require_services_resolution_resolver.resolveContained(slotDir, pin.manifest);
if (!pinnedManifestPath || (0, node_fs.existsSync)(pinnedManifestPath)) return null;
const versionsDir = node_path.default.join(slotDir, "versions");
if (!(0, node_fs.existsSync)(versionsDir)) return null;
const manifests = (0, node_fs.readdirSync)(versionsDir).filter((name) => name.endsWith(".json")).map((name) => node_path.default.join(versionsDir, name)).filter((file) => (0, node_fs.statSync)(file).isFile()).sort((a, b) => (0, node_fs.statSync)(b).mtimeMs - (0, node_fs.statSync)(a).mtimeMs || (a < b ? -1 : 1));
if (manifests.length === 0) return null;
const manifestPath = manifests[0];
if (!manifestPath) return null;
try {
return slotVersionFromManifest(base, every_plugin_version_manifest.WorkspaceVersionManifestSchema.parse(JSON.parse((0, node_fs.readFileSync)(manifestPath, "utf8"))));
} catch {
return null;
}
}
async function resolveSlotVersion(input) {
const key = `${input.base}::${input.pin.manifest}::${input.pin.integrity}`;
const cached = cache.get(key);
if (cached) return cached;
const staged = readStagedSlotVersion(input.base, input.pin);
if (staged) {
cache.set(key, staged);
return staged;
}
const manifestUrl = require_manifest_verify.manifestDocumentUrl(input.base, input.pin.manifest);
const verified = await require_manifest_verify.fetchVerifiedManifest({
base: input.base,
pin: input.pin,
fetchImpl: input.fetchImpl
});
if (!verified.ok) throw new Error(`[SRI] version manifest verification failed for ${manifestUrl}: ${verified.reason}`);
const manifest = every_plugin_version_manifest.WorkspaceVersionManifestSchema.parse(JSON.parse(verified.text));
const resolved = slotVersionFromManifest(input.base, manifest);
cache.set(key, resolved);
return resolved;
}
//#endregion
exports.clearSlotVersionCache = clearSlotVersionCache;
exports.composeWorkspaceVersionManifest = composeWorkspaceVersionManifest;
exports.readBuildReport = readBuildReport;
exports.resolveSlotVersion = resolveSlotVersion;
//# sourceMappingURL=version-manifest.cjs.map