bulletin-deploy 0.6.6 → 0.6.7-rc.0

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.
@@ -16,6 +16,7 @@ for (let i = 0; i < args.length; i++) {
16
16
  else if (args[i] === "--rpc") { flags.rpc = args[++i]; }
17
17
  else if (args[i] === "--password") { flags.password = args[++i]; }
18
18
  else if (args[i] === "--playground") { flags.playground = true; }
19
+ else if (args[i] === "--js-merkle") { flags.jsMerkle = true; }
19
20
  else if (args[i] === "--version" || args[i] === "-V") { flags.version = true; }
20
21
  else if (args[i] === "--help" || args[i] === "-h") { flags.help = true; }
21
22
  else { positional.push(args[i]); }
@@ -39,6 +40,7 @@ Options:
39
40
  --pool-size N Number of pool accounts (default: 10)
40
41
  --password "..." Encrypt SPA content (users will be prompted to decrypt)
41
42
  --playground Publish to the playground remix registry
43
+ --js-merkle Use pure-JS merkleization (no IPFS Kubo binary required)
42
44
  --version Show version
43
45
  --help Show this help`);
44
46
  process.exit(0);
@@ -61,6 +63,7 @@ try {
61
63
  rpc: flags.rpc,
62
64
  poolSize: flags.poolSize,
63
65
  password: flags.password,
66
+ jsMerkle: flags.jsMerkle,
64
67
  });
65
68
 
66
69
  const output = process.env.GITHUB_OUTPUT;
@@ -4,7 +4,10 @@ import {
4
4
  TX_TIMEOUT_MS,
5
5
  fetchNonce,
6
6
  validateDomainLabel
7
- } from "./chunk-7FNQBFFQ.js";
7
+ } from "./chunk-HMCNHEMO.js";
8
+ import {
9
+ merkleizeJS
10
+ } from "./chunk-GZ5UUECB.js";
8
11
  import {
9
12
  derivePoolAccounts,
10
13
  ensureAuthorized,
@@ -18,7 +21,7 @@ import {
18
21
  setDeployAttribute,
19
22
  withDeploySpan,
20
23
  withSpan
21
- } from "./chunk-BYYVSN7E.js";
24
+ } from "./chunk-DOBGWPA3.js";
22
25
 
23
26
  // src/deploy.ts
24
27
  import { Buffer } from "buffer";
@@ -778,12 +781,23 @@ async function merkleize(directoryPath, outputCarPath) {
778
781
  console.log(` CAR: ${(size / 1024 / 1024).toFixed(2)} MB`);
779
782
  return { carPath: outputCarPath, cid };
780
783
  }
781
- async function storeDirectory(directoryPath, provider = {}, password) {
782
- const carPath = path.join(path.dirname(directoryPath), `${path.basename(directoryPath)}.car`);
783
- const { cid: ipfsCid } = await withSpan("deploy.merkleize", "1a. merkleize", { "deploy.directory": directoryPath }, async () => {
784
- return merkleize(directoryPath, carPath);
785
- });
786
- let carContent = new Uint8Array(fs.readFileSync(carPath));
784
+ async function storeDirectory(directoryPath, provider = {}, password, jsMerkle) {
785
+ let carContent;
786
+ let ipfsCid;
787
+ if (jsMerkle) {
788
+ const result = await withSpan("deploy.merkleize", "1a. merkleize (js)", { "deploy.directory": directoryPath }, async () => {
789
+ return merkleizeJS(directoryPath);
790
+ });
791
+ carContent = result.carBytes;
792
+ ipfsCid = result.cid;
793
+ } else {
794
+ const carPath = path.join(path.dirname(directoryPath), `${path.basename(directoryPath)}.car`);
795
+ const { cid } = await withSpan("deploy.merkleize", "1a. merkleize", { "deploy.directory": directoryPath }, async () => {
796
+ return merkleize(directoryPath, carPath);
797
+ });
798
+ ipfsCid = cid;
799
+ carContent = new Uint8Array(fs.readFileSync(carPath));
800
+ }
787
801
  if (password) {
788
802
  console.log(` Encrypting CAR file...`);
789
803
  carContent = await encryptContent(carContent, password);
@@ -867,7 +881,7 @@ Or deploy with the original account, or use a different domain name.`);
867
881
  console.log(`
868
882
  Mode: Directory`);
869
883
  console.log(` Path: ${contentPath}`);
870
- const dirResult = await storeDirectory(contentPath, providerWithReconnect, options.password);
884
+ const dirResult = await storeDirectory(contentPath, providerWithReconnect, options.password, options.jsMerkle);
871
885
  cid = dirResult.storageCid;
872
886
  ipfsCid = dirResult.ipfsCid;
873
887
  } else {
@@ -907,6 +921,11 @@ Or deploy with the original account, or use a different domain name.`);
907
921
  }
908
922
  });
909
923
  setDeployAttribute("deploy.cid", cid);
924
+ if (options.attributes) {
925
+ for (const [key, value] of Object.entries(options.attributes)) {
926
+ setDeployAttribute(key, value);
927
+ }
928
+ }
910
929
  console.log("\n" + "=".repeat(60));
911
930
  console.log("DotNS");
912
931
  console.log("=".repeat(60));
@@ -6,7 +6,7 @@ import * as path from "path";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "bulletin-deploy",
9
- version: "0.6.6",
9
+ version: "0.6.7-rc.0",
10
10
  private: false,
11
11
  repository: {
12
12
  type: "git",
@@ -34,12 +34,13 @@ var package_default = {
34
34
  "cdm.json"
35
35
  ],
36
36
  scripts: {
37
- build: "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts --format esm --dts --clean --target node22",
37
+ build: "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/merkle.ts --format esm --dts --clean --target node22",
38
38
  test: "npm run build && node --test test/test.js",
39
39
  benchmark: "npm run build && node benchmark.js"
40
40
  },
41
41
  dependencies: {
42
42
  "@dotdm/cdm": "^0.5.1",
43
+ "@ipld/car": "^5.4.3",
43
44
  "@ipld/dag-pb": "^4.1.3",
44
45
  "@noble/hashes": "^1.7.2",
45
46
  "@polkadot-api/substrate-bindings": "^0.16.5",
@@ -48,7 +49,9 @@ var package_default = {
48
49
  "@polkadot/keyring": "^13.0.0",
49
50
  "@polkadot/util-crypto": "^13.0.0",
50
51
  "@sentry/node": "^9.14.0",
52
+ "blockstore-core": "^6.1.3",
51
53
  "ipfs-unixfs": "^11.2.0",
54
+ "ipfs-unixfs-importer": "^16.1.4",
52
55
  multiformats: "^13.4.1",
53
56
  "polkadot-api": "^1.23.1",
54
57
  viem: "^2.30.5"
@@ -0,0 +1,77 @@
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 { MemoryBlockstore } from "blockstore-core/memory";
6
+ import { CarWriter } from "@ipld/car/writer";
7
+ function walkDirectory(dirPath, prefix = "") {
8
+ let dirents;
9
+ try {
10
+ dirents = fs.readdirSync(dirPath, { withFileTypes: true });
11
+ } catch (err) {
12
+ const code = err.code;
13
+ if (code === "ENOENT") throw new Error(`Directory not found: ${dirPath}`);
14
+ if (code === "ENOTDIR") throw new Error(`Not a directory: ${dirPath}`);
15
+ throw err;
16
+ }
17
+ const entries = [];
18
+ for (const entry of dirents) {
19
+ const fullPath = path.join(dirPath, entry.name);
20
+ const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
21
+ if (entry.isDirectory()) {
22
+ entries.push(...walkDirectory(fullPath, relativePath));
23
+ } else if (entry.isFile()) {
24
+ entries.push({ path: relativePath, content: fs.readFileSync(fullPath) });
25
+ }
26
+ }
27
+ return entries;
28
+ }
29
+ async function collectBytes(iter) {
30
+ const parts = [];
31
+ for await (const chunk of iter) {
32
+ parts.push(chunk);
33
+ }
34
+ const totalLength = parts.reduce((sum, p) => sum + p.length, 0);
35
+ const result = new Uint8Array(totalLength);
36
+ let offset = 0;
37
+ for (const part of parts) {
38
+ result.set(part, offset);
39
+ offset += part.length;
40
+ }
41
+ return result;
42
+ }
43
+ async function merkleizeJS(directoryPath) {
44
+ console.log(` Merkleizing (JS): ${directoryPath}`);
45
+ const files = walkDirectory(directoryPath);
46
+ const blockstore = new MemoryBlockstore();
47
+ const source = files.map((file) => ({
48
+ path: file.path,
49
+ content: (async function* () {
50
+ yield file.content;
51
+ })()
52
+ }));
53
+ let rootCid;
54
+ for await (const entry of importer(source, blockstore, {
55
+ cidVersion: 1,
56
+ rawLeaves: true,
57
+ wrapWithDirectory: true
58
+ })) {
59
+ rootCid = entry.cid;
60
+ }
61
+ if (!rootCid) {
62
+ throw new Error("Merkleization produced no root CID");
63
+ }
64
+ const { writer, out } = CarWriter.create([rootCid]);
65
+ const collectPromise = collectBytes(out);
66
+ for await (const { cid, bytes } of blockstore.getAll()) {
67
+ await writer.put({ cid, bytes: await collectBytes(bytes) });
68
+ }
69
+ await writer.close();
70
+ const carBytes = await collectPromise;
71
+ console.log(` CAR (JS): ${(carBytes.length / 1024 / 1024).toFixed(2)} MB`);
72
+ return { carBytes, cid: rootCid.toString() };
73
+ }
74
+
75
+ export {
76
+ merkleizeJS
77
+ };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  captureWarning,
3
3
  withSpan
4
- } from "./chunk-BYYVSN7E.js";
4
+ } from "./chunk-DOBGWPA3.js";
5
5
 
6
6
  // src/dotns.ts
7
7
  import crypto from "crypto";
package/dist/deploy.d.ts CHANGED
@@ -49,7 +49,7 @@ declare function merkleize(directoryPath: string, outputCarPath: string): Promis
49
49
  carPath: string;
50
50
  cid: string;
51
51
  }>;
52
- declare function storeDirectory(directoryPath: string, provider?: ExistingProvider, password?: string): Promise<{
52
+ declare function storeDirectory(directoryPath: string, provider?: ExistingProvider, password?: string, jsMerkle?: boolean): Promise<{
53
53
  storageCid: string;
54
54
  ipfsCid: string;
55
55
  }>;
@@ -63,6 +63,10 @@ interface DeployOptions {
63
63
  rpc?: string;
64
64
  poolSize?: number;
65
65
  password?: string;
66
+ /** Use pure-JS merkleization instead of Kubo CLI. Required for WebContainer environments. */
67
+ jsMerkle?: boolean;
68
+ /** Custom telemetry attributes, merged into the deploy span. Overrides auto-detected values. */
69
+ attributes?: Record<string, string>;
66
70
  }
67
71
  declare function deploy(content: DeployContent, domainName?: string | null, options?: DeployOptions): Promise<DeployResult>;
68
72
 
package/dist/deploy.js CHANGED
@@ -21,10 +21,11 @@ import {
21
21
  storeChunkedContent,
22
22
  storeDirectory,
23
23
  storeFile
24
- } from "./chunk-YB4HKYPR.js";
25
- import "./chunk-7FNQBFFQ.js";
24
+ } from "./chunk-5B6UCUSH.js";
25
+ import "./chunk-HMCNHEMO.js";
26
+ import "./chunk-GZ5UUECB.js";
26
27
  import "./chunk-LGPTJYA3.js";
27
- import "./chunk-BYYVSN7E.js";
28
+ import "./chunk-DOBGWPA3.js";
28
29
  import "./chunk-QGM4M3NI.js";
29
30
  export {
30
31
  DEFAULT_BULLETIN_RPC,
package/dist/dotns.js CHANGED
@@ -19,8 +19,8 @@ import {
19
19
  sanitizeDomainLabel,
20
20
  stripTrailingDigits,
21
21
  validateDomainLabel
22
- } from "./chunk-7FNQBFFQ.js";
23
- import "./chunk-BYYVSN7E.js";
22
+ } from "./chunk-HMCNHEMO.js";
23
+ import "./chunk-DOBGWPA3.js";
24
24
  import "./chunk-QGM4M3NI.js";
25
25
  export {
26
26
  CONNECTION_TIMEOUT_MS,
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { DeployContent, DeployOptions, DeployResult, deploy } from './deploy.js';
2
2
  export { PoolAccount, PoolAuthorization, bootstrapPool, derivePoolAccounts, ensureAuthorized, fetchPoolAuthorizations, selectAccount } from './pool.js';
3
3
  export { DotNS, DotNSConnectOptions, OwnershipResult, PriceValidationResult } from './dotns.js';
4
+ export { MerkleizeResult, merkleizeJS } from './merkle.js';
4
5
  import 'multiformats/cid';
5
6
  import 'polkadot-api';
package/dist/index.js CHANGED
@@ -1,9 +1,12 @@
1
1
  import {
2
2
  deploy
3
- } from "./chunk-YB4HKYPR.js";
3
+ } from "./chunk-5B6UCUSH.js";
4
4
  import {
5
5
  DotNS
6
- } from "./chunk-7FNQBFFQ.js";
6
+ } from "./chunk-HMCNHEMO.js";
7
+ import {
8
+ merkleizeJS
9
+ } from "./chunk-GZ5UUECB.js";
7
10
  import {
8
11
  bootstrapPool,
9
12
  derivePoolAccounts,
@@ -11,7 +14,7 @@ import {
11
14
  fetchPoolAuthorizations,
12
15
  selectAccount
13
16
  } from "./chunk-LGPTJYA3.js";
14
- import "./chunk-BYYVSN7E.js";
17
+ import "./chunk-DOBGWPA3.js";
15
18
  import "./chunk-QGM4M3NI.js";
16
19
  export {
17
20
  DotNS,
@@ -20,5 +23,6 @@ export {
20
23
  derivePoolAccounts,
21
24
  ensureAuthorized,
22
25
  fetchPoolAuthorizations,
26
+ merkleizeJS,
23
27
  selectAccount
24
28
  };
@@ -0,0 +1,7 @@
1
+ interface MerkleizeResult {
2
+ carBytes: Uint8Array;
3
+ cid: string;
4
+ }
5
+ declare function merkleizeJS(directoryPath: string): Promise<MerkleizeResult>;
6
+
7
+ export { type MerkleizeResult, merkleizeJS };
package/dist/merkle.js ADDED
@@ -0,0 +1,7 @@
1
+ import {
2
+ merkleizeJS
3
+ } from "./chunk-GZ5UUECB.js";
4
+ import "./chunk-QGM4M3NI.js";
5
+ export {
6
+ merkleizeJS
7
+ };
package/dist/telemetry.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  setDeployAttribute,
9
9
  withDeploySpan,
10
10
  withSpan
11
- } from "./chunk-BYYVSN7E.js";
11
+ } from "./chunk-DOBGWPA3.js";
12
12
  import "./chunk-QGM4M3NI.js";
13
13
  export {
14
14
  VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulletin-deploy",
3
- "version": "0.6.6",
3
+ "version": "0.6.7-rc.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,12 +28,13 @@
28
28
  "cdm.json"
29
29
  ],
30
30
  "scripts": {
31
- "build": "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts --format esm --dts --clean --target node22",
31
+ "build": "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/merkle.ts --format esm --dts --clean --target node22",
32
32
  "test": "npm run build && node --test test/test.js",
33
33
  "benchmark": "npm run build && node benchmark.js"
34
34
  },
35
35
  "dependencies": {
36
36
  "@dotdm/cdm": "^0.5.1",
37
+ "@ipld/car": "^5.4.3",
37
38
  "@ipld/dag-pb": "^4.1.3",
38
39
  "@noble/hashes": "^1.7.2",
39
40
  "@polkadot-api/substrate-bindings": "^0.16.5",
@@ -42,7 +43,9 @@
42
43
  "@polkadot/keyring": "^13.0.0",
43
44
  "@polkadot/util-crypto": "^13.0.0",
44
45
  "@sentry/node": "^9.14.0",
46
+ "blockstore-core": "^6.1.3",
45
47
  "ipfs-unixfs": "^11.2.0",
48
+ "ipfs-unixfs-importer": "^16.1.4",
46
49
  "multiformats": "^13.4.1",
47
50
  "polkadot-api": "^1.23.1",
48
51
  "viem": "^2.30.5"