UNPKG

everything-dev

Version:

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

1 lines • 4.1 kB
{"version":3,"file":"bundle-cache.mjs","names":[],"sources":["../src/bundle-cache.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { mkdir, readFile, rename, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\n/**\n * Bundle disk cache (ADR 0011 amendment — foreign-namespace resilience):\n * the child tier loads base workspaces from foreign origins; this cache\n * keeps the last-known-good bytes so an origin outage degrades to stale\n * serving instead of a hard failure. One cache root, two entrances: the\n * host's `/bundles/*` proxy handler (browser traffic) and the CLI fetch\n * adapter (boot-time outbound). Keyed exactly like the staged layout —\n * `<account>/<gateway>/<rest>` — but a separate root from BOS_BUNDLE_DIR:\n * cached bytes are a resilience artifact, never a deployment (plan 043 —\n * never point a runtime's BOS_BUNDLE_DIR at another runtime's layout).\n */\n\nexport function bundleCacheRoot(input?: { cacheDir?: string }): string {\n return path.resolve(input?.cacheDir ?? process.env.BOS_BUNDLE_CACHE_DIR ?? joinDefault());\n}\n\nfunction joinDefault(): string {\n return path.join(process.cwd(), \".bos\", \"bundle-cache\");\n}\n\nexport function bundleCachePath(url: string, input?: { cacheDir?: string }): string | null {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return null;\n }\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") return null;\n const match = /^\\/bundles\\/([^/]+)\\/([^/]+)\\/(.+)$/.exec(parsed.pathname);\n if (!match) return null;\n const [, account, gateway, rest] = match;\n if (!rest || rest.endsWith(\"/\")) return null;\n let decoded: string;\n try {\n decoded = decodeURIComponent(rest);\n } catch {\n return null;\n }\n const root = path.resolve(bundleCacheRoot(input));\n const filePath = path.resolve(root, account, gateway, decoded);\n if (!filePath.startsWith(root + path.sep)) return null;\n return filePath;\n}\n\nexport async function readBundleCache(\n url: string,\n input?: { cacheDir?: string },\n): Promise<Uint8Array | null> {\n const filePath = bundleCachePath(url, input);\n if (!filePath) return null;\n try {\n return new Uint8Array(await readFile(filePath));\n } catch {\n return null;\n }\n}\n\nexport async function writeBundleCache(\n url: string,\n bytes: Uint8Array,\n input?: { cacheDir?: string },\n): Promise<void> {\n const filePath = bundleCachePath(url, input);\n if (!filePath) return;\n try {\n await mkdir(path.dirname(filePath), { recursive: true });\n const tmp = `${filePath}.${process.pid}.${createHash(\"sha256\").update(bytes).digest(\"hex\").slice(0, 8)}.tmp`;\n await writeFile(tmp, bytes);\n await rename(tmp, filePath);\n } catch {\n // cache writes are best-effort — never fail the serving path\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,SAAgB,gBAAgB,OAAuC;CACrE,OAAO,KAAK,QAAQ,OAAO,YAAY,QAAQ,IAAI,wBAAwB,YAAY,CAAC;AAC1F;AAEA,SAAS,cAAsB;CAC7B,OAAO,KAAK,KAAK,QAAQ,IAAI,GAAG,QAAQ,cAAc;AACxD;AAEA,SAAgB,gBAAgB,KAAa,OAA8C;CACzF,IAAI;CACJ,IAAI;EACF,SAAS,IAAI,IAAI,GAAG;CACtB,QAAQ;EACN,OAAO;CACT;CACA,IAAI,OAAO,aAAa,YAAY,OAAO,aAAa,SAAS,OAAO;CACxE,MAAM,QAAQ,sCAAsC,KAAK,OAAO,QAAQ;CACxE,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,GAAG,SAAS,SAAS,QAAQ;CACnC,IAAI,CAAC,QAAQ,KAAK,SAAS,GAAG,GAAG,OAAO;CACxC,IAAI;CACJ,IAAI;EACF,UAAU,mBAAmB,IAAI;CACnC,QAAQ;EACN,OAAO;CACT;CACA,MAAM,OAAO,KAAK,QAAQ,gBAAgB,KAAK,CAAC;CAChD,MAAM,WAAW,KAAK,QAAQ,MAAM,SAAS,SAAS,OAAO;CAC7D,IAAI,CAAC,SAAS,WAAW,OAAO,KAAK,GAAG,GAAG,OAAO;CAClD,OAAO;AACT;AAEA,eAAsB,gBACpB,KACA,OAC4B;CAC5B,MAAM,WAAW,gBAAgB,KAAK,KAAK;CAC3C,IAAI,CAAC,UAAU,OAAO;CACtB,IAAI;EACF,OAAO,IAAI,WAAW,MAAM,SAAS,QAAQ,CAAC;CAChD,QAAQ;EACN,OAAO;CACT;AACF;AAEA,eAAsB,iBACpB,KACA,OACA,OACe;CACf,MAAM,WAAW,gBAAgB,KAAK,KAAK;CAC3C,IAAI,CAAC,UAAU;CACf,IAAI;EACF,MAAM,MAAM,KAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;EACvD,MAAM,MAAM,GAAG,SAAS,GAAG,QAAQ,IAAI,GAAG,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;EACvG,MAAM,UAAU,KAAK,KAAK;EAC1B,MAAM,OAAO,KAAK,QAAQ;CAC5B,QAAQ,CAER;AACF"}