everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
68 lines (66 loc) • 2.44 kB
JavaScript
import path from "node:path";
import { createHash } from "node:crypto";
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
//#region src/bundle-cache.ts
/**
* Bundle disk cache (ADR 0011 amendment — foreign-namespace resilience):
* the child tier loads base workspaces from foreign origins; this cache
* keeps the last-known-good bytes so an origin outage degrades to stale
* serving instead of a hard failure. One cache root, two entrances: the
* host's `/bundles/*` proxy handler (browser traffic) and the CLI fetch
* adapter (boot-time outbound). Keyed exactly like the staged layout —
* `<account>/<gateway>/<rest>` — but a separate root from BOS_BUNDLE_DIR:
* cached bytes are a resilience artifact, never a deployment (plan 043 —
* never point a runtime's BOS_BUNDLE_DIR at another runtime's layout).
*/
function bundleCacheRoot(input) {
return path.resolve(input?.cacheDir ?? process.env.BOS_BUNDLE_CACHE_DIR ?? joinDefault());
}
function joinDefault() {
return path.join(process.cwd(), ".bos", "bundle-cache");
}
function bundleCachePath(url, input) {
let parsed;
try {
parsed = new URL(url);
} catch {
return null;
}
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
const match = /^\/bundles\/([^/]+)\/([^/]+)\/(.+)$/.exec(parsed.pathname);
if (!match) return null;
const [, account, gateway, rest] = match;
if (!rest || rest.endsWith("/")) return null;
let decoded;
try {
decoded = decodeURIComponent(rest);
} catch {
return null;
}
const root = path.resolve(bundleCacheRoot(input));
const filePath = path.resolve(root, account, gateway, decoded);
if (!filePath.startsWith(root + path.sep)) return null;
return filePath;
}
async function readBundleCache(url, input) {
const filePath = bundleCachePath(url, input);
if (!filePath) return null;
try {
return new Uint8Array(await readFile(filePath));
} catch {
return null;
}
}
async function writeBundleCache(url, bytes, input) {
const filePath = bundleCachePath(url, input);
if (!filePath) return;
try {
await mkdir(path.dirname(filePath), { recursive: true });
const tmp = `${filePath}.${process.pid}.${createHash("sha256").update(bytes).digest("hex").slice(0, 8)}.tmp`;
await writeFile(tmp, bytes);
await rename(tmp, filePath);
} catch {}
}
//#endregion
export { bundleCachePath, bundleCacheRoot, readBundleCache, writeBundleCache };
//# sourceMappingURL=bundle-cache.mjs.map