everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
119 lines (117 loc) • 4.05 kB
JavaScript
const require_rollback = require('./rollback.cjs');
let node_fs = require("node:fs");
let node_path = require("node:path");
let node_crypto = require("node:crypto");
//#region src/deploy-diff.ts
const BUNDLE_BASE_PATTERN = /\/bundles\/([^/]+)\/([^/]+)\/([^/]+)\/$/;
function workspaceKeyOfBase(base) {
const match = BUNDLE_BASE_PATTERN.exec(`${base.replace(/\/$/, "")}/`);
return match ? match[3] : null;
}
/** The sha384 SRI the storage route would compute for these bytes. */
function localObjectIntegrity(bytes) {
return `sha384-${(0, node_crypto.createHash)("sha384").update(bytes).digest("base64")}`;
}
function localSriMap(files) {
return Object.fromEntries(files.map((file) => [file.path, localObjectIntegrity(file.bytes)]));
}
const deployStatePath = (configDir) => (0, node_path.join)(configDir, ".bos", "deploy-state.json");
function readDeployState(configDir) {
const path = deployStatePath(configDir);
if (!(0, node_fs.existsSync)(path)) return {
version: 1,
apps: {}
};
try {
const parsed = JSON.parse((0, node_fs.readFileSync)(path, "utf8"));
if (parsed.version !== 1 || typeof parsed.apps !== "object" || parsed.apps === null) return {
version: 1,
apps: {}
};
return {
version: 1,
apps: parsed.apps
};
} catch {
return {
version: 1,
apps: {}
};
}
}
function writeDeployState(configDir, state) {
const path = deployStatePath(configDir);
(0, node_fs.mkdirSync)((0, node_path.dirname)(path), { recursive: true });
(0, node_fs.writeFileSync)(path, `${JSON.stringify(state, null, 2)}\n`);
}
function upsertDeployStatePins(configDir, account, gateway, pins) {
const state = readDeployState(configDir);
const appKey = `${account}/${gateway}`;
state.apps[appKey] = {
...state.apps[appKey],
...pins
};
writeDeployState(configDir, state);
}
/** Previous pins by workspace key, from the local deploy-state pointer. */
function pinsFromDeployState(configDir, account, gateway) {
return readDeployState(configDir).apps[`${account}/${gateway}`] ?? {};
}
/** Previous pins by workspace key, from the published config's slot pins. */
function pinsFromPublishedConfig(config, account, gateway) {
const pins = {};
for (const ref of require_rollback.collectSlotPinRefs(config)) {
const workspace = workspaceKeyOfBase(ref.base);
const nsMatch = BUNDLE_BASE_PATTERN.exec(`${ref.base.replace(/\/$/, "")}/`);
if (!workspace || !nsMatch || nsMatch[1] !== account || nsMatch[2] !== gateway) continue;
pins[workspace] = ref.pin;
}
return pins;
}
function diffWorkspaceFiles(files, localSri, prevFiles) {
const upload = [];
let skipped = 0;
for (const file of files) {
if (prevFiles[file.path] !== void 0 && prevFiles[file.path] === localSri[file.path]) {
skipped += 1;
continue;
}
upload.push(file);
}
return {
upload,
skipped
};
}
/**
* The manifest's merged per-file map for this deploy: uploaded files carry the
* server-computed SRI from the upload response; skipped files carry the
* previous manifest's server-computed SRI (byte-identical to the local hash by
* the skip decision). Files that left the dist carry nothing.
*/
function mergedFileIntegrity(files, uploadedIntegrity, prevFiles) {
const merged = {};
for (const file of files) {
const uploaded = uploadedIntegrity[file.path];
if (uploaded) {
merged[file.path] = uploaded;
continue;
}
const carried = prevFiles?.[file.path];
if (carried) merged[file.path] = carried;
}
return merged;
}
//#endregion
exports.BUNDLE_BASE_PATTERN = BUNDLE_BASE_PATTERN;
exports.diffWorkspaceFiles = diffWorkspaceFiles;
exports.localObjectIntegrity = localObjectIntegrity;
exports.localSriMap = localSriMap;
exports.mergedFileIntegrity = mergedFileIntegrity;
exports.pinsFromDeployState = pinsFromDeployState;
exports.pinsFromPublishedConfig = pinsFromPublishedConfig;
exports.readDeployState = readDeployState;
exports.upsertDeployStatePins = upsertDeployStatePins;
exports.workspaceKeyOfBase = workspaceKeyOfBase;
exports.writeDeployState = writeDeployState;
//# sourceMappingURL=deploy-diff.cjs.map