bulletin-deploy 0.7.14 → 0.7.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +27 -0
  2. package/bin/bulletin-deploy +5 -0
  3. package/dist/bug-report.js +4 -4
  4. package/dist/chunk-5MRZ3V4A.js +171 -0
  5. package/dist/{chunk-LM5U3XDV.js → chunk-5TW653QP.js} +1 -1
  6. package/dist/{chunk-3RNYFSU7.js → chunk-AQUBKPSF.js} +2 -2
  7. package/dist/chunk-C2TS5MER.js +64 -0
  8. package/dist/{chunk-4AP5ZFNV.js → chunk-KMRYJR4E.js} +1 -1
  9. package/dist/chunk-KOSF5FDO.js +49 -0
  10. package/dist/chunk-MJTQOXBC.js +140 -0
  11. package/dist/{chunk-6YJ46BN2.js → chunk-NE5MN2M2.js} +1 -1
  12. package/dist/chunk-S7EM5VMW.js +108 -0
  13. package/dist/{chunk-3ILZFC4E.js → chunk-VQHM3R6N.js} +805 -31
  14. package/dist/chunk-Y2OSXJIZ.js +177 -0
  15. package/dist/{chunk-N7YE5ZN3.js → chunk-ZGU6FOLO.js} +2 -2
  16. package/dist/chunk-probe.d.ts +36 -0
  17. package/dist/chunk-probe.js +19 -0
  18. package/dist/chunker.d.ts +8 -0
  19. package/dist/chunker.js +11 -0
  20. package/dist/deploy.d.ts +73 -2
  21. package/dist/deploy.js +24 -7
  22. package/dist/dotns.js +3 -3
  23. package/dist/incremental-stats.d.ts +65 -0
  24. package/dist/incremental-stats.js +11 -0
  25. package/dist/index.d.ts +6 -1
  26. package/dist/index.js +51 -12
  27. package/dist/manifest-embed.d.ts +18 -0
  28. package/dist/manifest-embed.js +10 -0
  29. package/dist/manifest-fetch.d.ts +26 -0
  30. package/dist/manifest-fetch.js +14 -0
  31. package/dist/manifest-roundtrip.d.ts +15 -0
  32. package/dist/manifest-roundtrip.js +56 -0
  33. package/dist/manifest.d.ts +44 -0
  34. package/dist/manifest.js +21 -0
  35. package/dist/memory-report.js +2 -2
  36. package/dist/merkle.d.ts +38 -1
  37. package/dist/merkle.js +28 -3
  38. package/dist/run-state.js +1 -1
  39. package/dist/telemetry.js +2 -2
  40. package/dist/version-check.js +3 -3
  41. package/package.json +2 -2
  42. package/dist/chunk-B7GUYYAN.js +0 -94
package/dist/index.js CHANGED
@@ -1,15 +1,39 @@
1
1
  import {
2
- deploy
3
- } from "./chunk-3ILZFC4E.js";
2
+ deploy,
3
+ merkleizeJS,
4
+ merkleizeWithStableOrder
5
+ } from "./chunk-VQHM3R6N.js";
6
+ import {
7
+ computeStats,
8
+ renderSummary,
9
+ telemetryAttributes
10
+ } from "./chunk-MJTQOXBC.js";
11
+ import {
12
+ finaliseEmbeddedManifest,
13
+ writeEmbeddedManifestPlaceholder
14
+ } from "./chunk-KOSF5FDO.js";
15
+ import {
16
+ fetchPreviousManifest
17
+ } from "./chunk-5MRZ3V4A.js";
18
+ import {
19
+ MANIFEST_DIR,
20
+ MANIFEST_FILENAME,
21
+ MANIFEST_PATH,
22
+ MANIFEST_VERSION,
23
+ classifyFile,
24
+ isVolatilePath,
25
+ parseManifest
26
+ } from "./chunk-S7EM5VMW.js";
27
+ import "./chunk-AQUBKPSF.js";
28
+ import "./chunk-NE5MN2M2.js";
4
29
  import {
5
- merkleizeJS
6
- } from "./chunk-B7GUYYAN.js";
7
- import "./chunk-3RNYFSU7.js";
8
- import "./chunk-6YJ46BN2.js";
30
+ probeChunks
31
+ } from "./chunk-Y2OSXJIZ.js";
32
+ import "./chunk-C2TS5MER.js";
9
33
  import {
10
34
  DotNS,
11
35
  parseDomainName
12
- } from "./chunk-LM5U3XDV.js";
36
+ } from "./chunk-5TW653QP.js";
13
37
  import {
14
38
  bootstrapPool,
15
39
  derivePoolAccounts,
@@ -17,10 +41,7 @@ import {
17
41
  fetchPoolAuthorizations,
18
42
  selectAccount
19
43
  } from "./chunk-VOEFHED3.js";
20
- import "./chunk-2VYG7NXN.js";
21
- import "./chunk-ZOC4GITL.js";
22
- import "./chunk-HOTQDYHD.js";
23
- import "./chunk-4AP5ZFNV.js";
44
+ import "./chunk-KMRYJR4E.js";
24
45
  import {
25
46
  VERSION,
26
47
  loadRunState,
@@ -30,24 +51,42 @@ import {
30
51
  shouldSkipStaleWarning,
31
52
  stateFilePath,
32
53
  writeRunState
33
- } from "./chunk-N7YE5ZN3.js";
54
+ } from "./chunk-ZGU6FOLO.js";
55
+ import "./chunk-2VYG7NXN.js";
56
+ import "./chunk-ZOC4GITL.js";
57
+ import "./chunk-HOTQDYHD.js";
34
58
  import "./chunk-QGM4M3NI.js";
35
59
  export {
36
60
  DotNS,
61
+ MANIFEST_DIR,
62
+ MANIFEST_FILENAME,
63
+ MANIFEST_PATH,
64
+ MANIFEST_VERSION,
37
65
  VERSION,
38
66
  bootstrapPool,
67
+ classifyFile,
68
+ computeStats,
39
69
  deploy,
40
70
  derivePoolAccounts,
41
71
  ensureAuthorized,
42
72
  fetchPoolAuthorizations,
73
+ fetchPreviousManifest,
74
+ finaliseEmbeddedManifest,
75
+ isVolatilePath,
43
76
  loadRunState,
44
77
  merkleizeJS,
78
+ merkleizeWithStableOrder,
45
79
  parseDomainName,
80
+ parseManifest,
46
81
  probablyOomRssMb,
82
+ probeChunks,
83
+ renderSummary,
47
84
  resolveStateDir,
48
85
  selectAccount,
49
86
  shouldShowOomHint,
50
87
  shouldSkipStaleWarning,
51
88
  stateFilePath,
89
+ telemetryAttributes,
90
+ writeEmbeddedManifestPlaceholder,
52
91
  writeRunState
53
92
  };
@@ -0,0 +1,18 @@
1
+ import { ManifestFileEntry, ManifestChunkEntry } from './manifest.js';
2
+
3
+ interface PlaceholderInput {
4
+ version: number;
5
+ previousContenthash: string | null;
6
+ deployedAt: string;
7
+ framework: string | null;
8
+ }
9
+ interface FinaliseInput extends PlaceholderInput {
10
+ files: Record<string, ManifestFileEntry>;
11
+ stableBlockOrder: string[];
12
+ blocks: string[];
13
+ chunks: Record<string, ManifestChunkEntry>;
14
+ }
15
+ declare function writeEmbeddedManifestPlaceholder(buildDir: string, data: PlaceholderInput): void;
16
+ declare function finaliseEmbeddedManifest(buildDir: string, data: FinaliseInput): void;
17
+
18
+ export { finaliseEmbeddedManifest, writeEmbeddedManifestPlaceholder };
@@ -0,0 +1,10 @@
1
+ import {
2
+ finaliseEmbeddedManifest,
3
+ writeEmbeddedManifestPlaceholder
4
+ } from "./chunk-KOSF5FDO.js";
5
+ import "./chunk-S7EM5VMW.js";
6
+ import "./chunk-QGM4M3NI.js";
7
+ export {
8
+ finaliseEmbeddedManifest,
9
+ writeEmbeddedManifestPlaceholder
10
+ };
@@ -0,0 +1,26 @@
1
+ import { EmbeddedManifest } from './manifest.js';
2
+
3
+ declare const DEFAULT_GATEWAY = "https://paseo-ipfs.polkadot.io";
4
+ declare const DEFAULT_TIMEOUT_MS = 5000;
5
+ type FetchOutcome = {
6
+ source: "embedded";
7
+ manifest: EmbeddedManifest;
8
+ attempts: number;
9
+ bytesDownloaded?: number;
10
+ } | {
11
+ source: "heuristic_fallback";
12
+ reason: string;
13
+ attempts: number;
14
+ bytesDownloaded?: number;
15
+ } | {
16
+ source: "none";
17
+ };
18
+ interface FetchOptions {
19
+ gateway?: string;
20
+ gateways?: string[];
21
+ timeoutMs?: number;
22
+ }
23
+ declare function fetchPreviousManifest(prevContenthash: string | null, options?: FetchOptions): Promise<FetchOutcome>;
24
+ declare function extractManifestFromCar(carBytes: Uint8Array): Promise<Uint8Array | null>;
25
+
26
+ export { DEFAULT_GATEWAY, DEFAULT_TIMEOUT_MS, type FetchOptions, type FetchOutcome, extractManifestFromCar, fetchPreviousManifest };
@@ -0,0 +1,14 @@
1
+ import {
2
+ DEFAULT_GATEWAY,
3
+ DEFAULT_TIMEOUT_MS,
4
+ extractManifestFromCar,
5
+ fetchPreviousManifest
6
+ } from "./chunk-5MRZ3V4A.js";
7
+ import "./chunk-S7EM5VMW.js";
8
+ import "./chunk-QGM4M3NI.js";
9
+ export {
10
+ DEFAULT_GATEWAY,
11
+ DEFAULT_TIMEOUT_MS,
12
+ extractManifestFromCar,
13
+ fetchPreviousManifest
14
+ };
@@ -0,0 +1,15 @@
1
+ interface RoundtripOptions {
2
+ gateway: string;
3
+ budgetMs?: number;
4
+ pollIntervalMs?: number;
5
+ perRequestTimeoutMs?: number;
6
+ }
7
+ declare function fetchManifestRoundtrip(cid: string, options: RoundtripOptions): Promise<{
8
+ ok: true;
9
+ manifestBytes: Uint8Array;
10
+ } | {
11
+ ok: false;
12
+ reason: string;
13
+ }>;
14
+
15
+ export { type RoundtripOptions, fetchManifestRoundtrip };
@@ -0,0 +1,56 @@
1
+ import {
2
+ extractManifestFromCar
3
+ } from "./chunk-5MRZ3V4A.js";
4
+ import "./chunk-S7EM5VMW.js";
5
+ import "./chunk-QGM4M3NI.js";
6
+
7
+ // src/manifest-roundtrip.ts
8
+ async function fetchManifestRoundtrip(cid, options) {
9
+ const gateway = options.gateway.replace(/\/$/, "");
10
+ const budget = options.budgetMs ?? 3e4;
11
+ const poll = options.pollIntervalMs ?? 2e3;
12
+ const perReq = options.perRequestTimeoutMs ?? 1e4;
13
+ const start = Date.now();
14
+ let lastReason = "no attempts";
15
+ while (Date.now() - start < budget) {
16
+ const ctrl = new AbortController();
17
+ const timer = setTimeout(() => ctrl.abort(), perReq);
18
+ let res;
19
+ try {
20
+ res = await fetch(`${gateway}/ipfs/${cid}`, { signal: ctrl.signal });
21
+ } catch (e) {
22
+ lastReason = `network: ${e?.message ?? e}`;
23
+ clearTimeout(timer);
24
+ await sleep(poll);
25
+ continue;
26
+ } finally {
27
+ clearTimeout(timer);
28
+ }
29
+ if (res.status === 404 || res.status === 504) {
30
+ lastReason = `gateway HTTP ${res.status}`;
31
+ await sleep(poll);
32
+ continue;
33
+ }
34
+ if (res.status !== 200) {
35
+ lastReason = `gateway HTTP ${res.status}`;
36
+ await sleep(poll);
37
+ continue;
38
+ }
39
+ const buf = await res.arrayBuffer();
40
+ const carBytes = new Uint8Array(buf);
41
+ const manifestBytes = await extractManifestFromCar(carBytes);
42
+ if (!manifestBytes) {
43
+ lastReason = "manifest not in deployed DAG";
44
+ await sleep(poll);
45
+ continue;
46
+ }
47
+ return { ok: true, manifestBytes };
48
+ }
49
+ return { ok: false, reason: `roundtrip budget exhausted: ${lastReason}` };
50
+ }
51
+ function sleep(ms) {
52
+ return new Promise((r) => setTimeout(r, ms));
53
+ }
54
+ export {
55
+ fetchManifestRoundtrip
56
+ };
@@ -0,0 +1,44 @@
1
+ declare const MANIFEST_VERSION = 3;
2
+ declare const MANIFEST_DIR = ".bulletin-deploy";
3
+ declare const MANIFEST_FILENAME = "manifest.json";
4
+ declare const MANIFEST_PATH = ".bulletin-deploy/manifest.json";
5
+ type FileType = "stable" | "volatile";
6
+ interface ManifestFileEntry {
7
+ cid: string;
8
+ type: FileType;
9
+ size?: number;
10
+ }
11
+ interface ManifestChunkEntry {
12
+ size: number;
13
+ deployed_at: string;
14
+ block?: number;
15
+ index?: number;
16
+ }
17
+ interface EmbeddedManifest {
18
+ version: number;
19
+ previous_contenthash: string | null;
20
+ deployed_at: string;
21
+ framework: string | null;
22
+ files: Record<string, ManifestFileEntry>;
23
+ stableBlockOrder: string[];
24
+ blocks: string[];
25
+ chunks: Record<string, ManifestChunkEntry>;
26
+ }
27
+ declare function isVolatilePath(p: string): boolean;
28
+ type ClassifyContext = {
29
+ prevManifest?: EmbeddedManifest | null;
30
+ framework?: string | null;
31
+ fileCid?: string;
32
+ };
33
+ declare function classifyFileHeuristic(filePath: string, framework?: string | null): FileType;
34
+ declare function classifyFile(filePath: string, ctx?: ClassifyContext): FileType;
35
+ type ParseResult = {
36
+ ok: true;
37
+ manifest: EmbeddedManifest;
38
+ } | {
39
+ ok: false;
40
+ error: string;
41
+ };
42
+ declare function parseManifest(raw: string): ParseResult;
43
+
44
+ export { type ClassifyContext, type EmbeddedManifest, type FileType, MANIFEST_DIR, MANIFEST_FILENAME, MANIFEST_PATH, MANIFEST_VERSION, type ManifestChunkEntry, type ManifestFileEntry, type ParseResult, classifyFile, classifyFileHeuristic, isVolatilePath, parseManifest };
@@ -0,0 +1,21 @@
1
+ import {
2
+ MANIFEST_DIR,
3
+ MANIFEST_FILENAME,
4
+ MANIFEST_PATH,
5
+ MANIFEST_VERSION,
6
+ classifyFile,
7
+ classifyFileHeuristic,
8
+ isVolatilePath,
9
+ parseManifest
10
+ } from "./chunk-S7EM5VMW.js";
11
+ import "./chunk-QGM4M3NI.js";
12
+ export {
13
+ MANIFEST_DIR,
14
+ MANIFEST_FILENAME,
15
+ MANIFEST_PATH,
16
+ MANIFEST_VERSION,
17
+ classifyFile,
18
+ classifyFileHeuristic,
19
+ isVolatilePath,
20
+ parseManifest
21
+ };
@@ -5,8 +5,8 @@ import {
5
5
  maybeWriteMemoryReport,
6
6
  safeHeap,
7
7
  sampleFromBytes
8
- } from "./chunk-4AP5ZFNV.js";
9
- import "./chunk-N7YE5ZN3.js";
8
+ } from "./chunk-KMRYJR4E.js";
9
+ import "./chunk-ZGU6FOLO.js";
10
10
  import "./chunk-QGM4M3NI.js";
11
11
  export {
12
12
  DEFAULT_THRESHOLD_MB,
package/dist/merkle.d.ts CHANGED
@@ -2,6 +2,43 @@ interface MerkleizeResult {
2
2
  carBytes: Uint8Array;
3
3
  cid: string;
4
4
  }
5
+ interface MerkleizeStableResult extends MerkleizeResult {
6
+ blockOrder: string[];
7
+ stableOrder: string[];
8
+ chunks: Uint8Array[];
9
+ chunkCids: string[];
10
+ section1ChunkCids: string[];
11
+ sectionSizes: {
12
+ section0: number;
13
+ section1: number;
14
+ section2: number;
15
+ };
16
+ /** All DAG blocks from the merkleize backend: cid → block bytes. */
17
+ blocks: Map<string, Uint8Array>;
18
+ /** File path → user-facing CID (leaf for single-block, dag-pb root for multi-block). */
19
+ fileCids: Map<string, string>;
20
+ }
21
+ interface MerkleizeOutput {
22
+ rootCid: string;
23
+ blocks: Map<string, Uint8Array>;
24
+ fileBlocks: Map<string, string[]>;
25
+ fileCids: Map<string, string>;
26
+ rootBlockCids: string[];
27
+ subdirCids: string[];
28
+ }
29
+ declare function merkleizeJSBackend(directoryPath: string): Promise<MerkleizeOutput>;
30
+ declare function merkleizeKuboBackend(directoryPath: string): Promise<MerkleizeOutput>;
31
+ declare function merkleizeBackend(directoryPath: string, useKubo: boolean): Promise<MerkleizeOutput>;
32
+ interface BuildOrderedCarOptions {
33
+ output: MerkleizeOutput;
34
+ classifyFn?: (filePath: string, fileCid?: string) => "stable" | "volatile";
35
+ prevStableOrder?: string[];
36
+ }
37
+ declare function buildOrderedCar(options: BuildOrderedCarOptions): Promise<MerkleizeStableResult>;
38
+ declare function merkleizeWithStableOrder(directoryPath: string, prevStableOrder?: string[], options?: {
39
+ useKubo?: boolean;
40
+ classifyFn?: (filePath: string) => "stable" | "volatile";
41
+ }): Promise<MerkleizeStableResult>;
5
42
  declare function merkleizeJS(directoryPath: string): Promise<MerkleizeResult>;
6
43
 
7
- export { type MerkleizeResult, merkleizeJS };
44
+ export { type BuildOrderedCarOptions, type MerkleizeOutput, type MerkleizeResult, type MerkleizeStableResult, buildOrderedCar, merkleizeBackend, merkleizeJS, merkleizeJSBackend, merkleizeKuboBackend, merkleizeWithStableOrder };
package/dist/merkle.js CHANGED
@@ -1,7 +1,32 @@
1
1
  import {
2
- merkleizeJS
3
- } from "./chunk-B7GUYYAN.js";
2
+ buildOrderedCar,
3
+ merkleizeBackend,
4
+ merkleizeJS,
5
+ merkleizeJSBackend,
6
+ merkleizeKuboBackend,
7
+ merkleizeWithStableOrder
8
+ } from "./chunk-VQHM3R6N.js";
9
+ import "./chunk-MJTQOXBC.js";
10
+ import "./chunk-KOSF5FDO.js";
11
+ import "./chunk-5MRZ3V4A.js";
12
+ import "./chunk-S7EM5VMW.js";
13
+ import "./chunk-AQUBKPSF.js";
14
+ import "./chunk-NE5MN2M2.js";
15
+ import "./chunk-Y2OSXJIZ.js";
16
+ import "./chunk-C2TS5MER.js";
17
+ import "./chunk-5TW653QP.js";
18
+ import "./chunk-VOEFHED3.js";
19
+ import "./chunk-KMRYJR4E.js";
20
+ import "./chunk-ZGU6FOLO.js";
21
+ import "./chunk-2VYG7NXN.js";
22
+ import "./chunk-ZOC4GITL.js";
23
+ import "./chunk-HOTQDYHD.js";
4
24
  import "./chunk-QGM4M3NI.js";
5
25
  export {
6
- merkleizeJS
26
+ buildOrderedCar,
27
+ merkleizeBackend,
28
+ merkleizeJS,
29
+ merkleizeJSBackend,
30
+ merkleizeKuboBackend,
31
+ merkleizeWithStableOrder
7
32
  };
package/dist/run-state.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  shouldSkipStaleWarning,
8
8
  stateFilePath,
9
9
  writeRunState
10
- } from "./chunk-N7YE5ZN3.js";
10
+ } from "./chunk-ZGU6FOLO.js";
11
11
  import "./chunk-QGM4M3NI.js";
12
12
  export {
13
13
  VERSION,
package/dist/telemetry.js CHANGED
@@ -27,8 +27,8 @@ import {
27
27
  truncateAddress,
28
28
  withDeploySpan,
29
29
  withSpan
30
- } from "./chunk-4AP5ZFNV.js";
31
- import "./chunk-N7YE5ZN3.js";
30
+ } from "./chunk-KMRYJR4E.js";
31
+ import "./chunk-ZGU6FOLO.js";
32
32
  import "./chunk-QGM4M3NI.js";
33
33
  export {
34
34
  VERSION,
@@ -8,9 +8,9 @@ import {
8
8
  isPreReleaseVersion,
9
9
  preReleaseWarning,
10
10
  promptYesNo
11
- } from "./chunk-6YJ46BN2.js";
12
- import "./chunk-4AP5ZFNV.js";
13
- import "./chunk-N7YE5ZN3.js";
11
+ } from "./chunk-NE5MN2M2.js";
12
+ import "./chunk-KMRYJR4E.js";
13
+ import "./chunk-ZGU6FOLO.js";
14
14
  import "./chunk-QGM4M3NI.js";
15
15
  export {
16
16
  assessVersion,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulletin-deploy",
3
- "version": "0.7.14",
3
+ "version": "0.7.15",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -31,7 +31,7 @@
31
31
  ],
32
32
  "scripts": {
33
33
  "prebuild": "node scripts/refresh-environments.mjs",
34
- "build": "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/memory-report.ts src/merkle.ts src/gh-pages-mirror.ts src/version-check.ts src/bug-report.ts src/run-state.ts src/environments.ts src/errors.ts --format esm --dts --clean --target node22",
34
+ "build": "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/memory-report.ts src/merkle.ts src/gh-pages-mirror.ts src/version-check.ts src/bug-report.ts src/run-state.ts src/environments.ts src/errors.ts src/manifest.ts src/chunk-probe.ts src/manifest-embed.ts src/manifest-fetch.ts src/manifest-roundtrip.ts src/incremental-stats.ts src/chunker.ts --format esm --dts --clean --target node22",
35
35
  "refresh-environments": "node scripts/refresh-environments.mjs",
36
36
  "prepare": "npm run build",
37
37
  "test": "npm run build && node --test test/test.js test/cli-help.test.js test/helpers/e2e-helpers.test.js test/environments.test.js",
@@ -1,94 +0,0 @@
1
- // src/merkle.ts
2
- import * as fs from "fs";
3
- import * as path from "path";
4
- import { importer } from "ipfs-unixfs-importer";
5
- import { CarWriter } from "@ipld/car/writer";
6
- var CidPreservingBlockstore = class {
7
- data = /* @__PURE__ */ new Map();
8
- async put(cid, bytes) {
9
- this.data.set(cid.toString(), { cid, bytes });
10
- return cid;
11
- }
12
- *all() {
13
- yield* this.data.values();
14
- }
15
- clear() {
16
- this.data.clear();
17
- }
18
- };
19
- function* walkDirectoryLazy(dirPath, prefix = "") {
20
- let dirents;
21
- try {
22
- dirents = fs.readdirSync(dirPath, { withFileTypes: true });
23
- } catch (err) {
24
- const code = err.code;
25
- if (code === "ENOENT") throw new Error(`Directory not found: ${dirPath}`);
26
- if (code === "ENOTDIR") throw new Error(`Not a directory: ${dirPath}`);
27
- throw err;
28
- }
29
- for (const entry of dirents) {
30
- const fullPath = path.join(dirPath, entry.name);
31
- const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
32
- if (entry.isDirectory()) {
33
- yield* walkDirectoryLazy(fullPath, relativePath);
34
- } else if (entry.isFile()) {
35
- yield { path: relativePath, absolutePath: fullPath };
36
- }
37
- }
38
- }
39
- async function collectBytes(iter) {
40
- const parts = [];
41
- let totalLength = 0;
42
- for await (const chunk of iter) {
43
- parts.push(chunk);
44
- totalLength += chunk.length;
45
- }
46
- const result = new Uint8Array(totalLength);
47
- let offset = 0;
48
- for (let i = 0; i < parts.length; i++) {
49
- const part = parts[i];
50
- result.set(part, offset);
51
- offset += part.length;
52
- parts[i] = void 0;
53
- }
54
- return result;
55
- }
56
- async function merkleizeJS(directoryPath) {
57
- console.log(` Merkleizing (JS): ${directoryPath}`);
58
- const blockstore = new CidPreservingBlockstore();
59
- const source = (function* () {
60
- for (const file of walkDirectoryLazy(directoryPath)) {
61
- yield {
62
- path: file.path,
63
- content: (async function* () {
64
- yield fs.readFileSync(file.absolutePath);
65
- })()
66
- };
67
- }
68
- })();
69
- let rootCid;
70
- for await (const entry of importer(source, blockstore, {
71
- cidVersion: 1,
72
- rawLeaves: true,
73
- wrapWithDirectory: true
74
- })) {
75
- rootCid = entry.cid;
76
- }
77
- if (!rootCid) {
78
- throw new Error("Merkleization produced no root CID");
79
- }
80
- const { writer, out } = CarWriter.create([rootCid]);
81
- const collectPromise = collectBytes(out);
82
- for (const { cid, bytes } of blockstore.all()) {
83
- await writer.put({ cid, bytes });
84
- }
85
- await writer.close();
86
- const carBytes = await collectPromise;
87
- blockstore.clear();
88
- console.log(` CAR (JS): ${(carBytes.length / 1024 / 1024).toFixed(2)} MB`);
89
- return { carBytes, cid: rootCid.toString() };
90
- }
91
-
92
- export {
93
- merkleizeJS
94
- };