everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
1 lines • 3.56 kB
Source Map (JSON)
{"version":3,"file":"source-archive.mjs","names":["tarCreate"],"sources":["../../../src/services/deploy/source-archive.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { mkdtempSync, readFileSync, renameSync, rmSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { create as tarCreate } from \"tar\";\nimport { listWorkspaceSubtreeFiles } from \"../../utils/workspace-subtree\";\nimport { computeSriHash } from \"./integrity\";\n\n/** Temp directory for a source archive leg (caller passes it as `outDir`). */\nexport function makeSourceArchiveTempDir(prefix = \"bos-source-archive-\"): string {\n return mkdtempSync(join(tmpdir(), prefix));\n}\n\n/**\n * A per-workspace source archive built for the deploy train (#406): the\n * workspace subtree tar'd under repo-root-relative paths, content-addressed\n * by the sha256 of its own bytes, and paired with the local SRI used for\n * client-side dedupe (the manifest field itself carries the server SRI).\n */\nexport interface SourceArchive {\n /** Object path within the workspace's bundle namespace: `source/<name>.tar.gz`. */\n file: string;\n /** Absolute path of the built archive on disk. */\n path: string;\n /** Local SRI of the archive bytes — dedupe key against the previous pin. */\n integrity: string;\n /** Removes the archive's temp directory. */\n cleanup: () => void;\n}\n\n/**\n * Build the workspace's source archive in `outDir`: the shared subtree ignore\n * set (`listWorkspaceSubtreeFiles`) selects the files; `tar.create` receives\n * that explicit list, so its own ignore logic never re-derives the selection.\n * The archive name is content-addressed — identical source bytes produce the\n * identical `source.<16hex>.tar.gz` (gzip is deterministic for the same input\n * bytes; file mtimes differ only when source files change, which changes the\n * name anyway).\n */\nexport async function buildSourceArchive(input: {\n repoRoot: string;\n workspace: string;\n outDir: string;\n}): Promise<SourceArchive> {\n const files = await listWorkspaceSubtreeFiles(input.repoRoot, input.workspace);\n if (files.length === 0) {\n throw new Error(`[source-archive] workspace subtree is empty: ${input.workspace}`);\n }\n\n const pendingPath = join(input.outDir, \".pending.tar.gz\");\n await tarCreate(\n { file: pendingPath, cwd: input.repoRoot, portable: true, gzip: { level: 9 } },\n files,\n );\n\n const bytes = readFileSync(pendingPath);\n const name = `source.${createHash(\"sha256\").update(bytes).digest(\"hex\").slice(0, 16)}.tar.gz`;\n const path = join(input.outDir, name);\n renameSync(pendingPath, path);\n\n return {\n file: `source/${name}`,\n path,\n integrity: computeSriHash(bytes),\n cleanup: () => rmSync(input.outDir, { recursive: true, force: true }),\n };\n}\n"],"mappings":";;;;;;;;;;AASA,SAAgB,yBAAyB,SAAS,uBAA+B;CAC/E,OAAO,YAAY,KAAK,OAAO,GAAG,MAAM,CAAC;AAC3C;;;;;;;;;;AA4BA,eAAsB,mBAAmB,OAId;CACzB,MAAM,QAAQ,MAAM,0BAA0B,MAAM,UAAU,MAAM,SAAS;CAC7E,IAAI,MAAM,WAAW,GACnB,MAAM,IAAI,MAAM,gDAAgD,MAAM,WAAW;CAGnF,MAAM,cAAc,KAAK,MAAM,QAAQ,iBAAiB;CACxD,MAAMA,OACJ;EAAE,MAAM;EAAa,KAAK,MAAM;EAAU,UAAU;EAAM,MAAM,EAAE,OAAO,EAAE;CAAE,GAC7E,KACF;CAEA,MAAM,QAAQ,aAAa,WAAW;CACtC,MAAM,OAAO,UAAU,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE,EAAE;CACrF,MAAM,OAAO,KAAK,MAAM,QAAQ,IAAI;CACpC,WAAW,aAAa,IAAI;CAE5B,OAAO;EACL,MAAM,UAAU;EAChB;EACA,WAAW,eAAe,KAAK;EAC/B,eAAe,OAAO,MAAM,QAAQ;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;CACtE;AACF"}