bulletin-deploy 0.5.3-rc.1 → 0.5.3

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.
@@ -3,7 +3,7 @@ import {
3
3
  DotNS,
4
4
  TX_TIMEOUT_MS,
5
5
  fetchNonce
6
- } from "./chunk-XD7NNFWX.js";
6
+ } from "./chunk-W23LLCZF.js";
7
7
  import {
8
8
  derivePoolAccounts,
9
9
  ensureAuthorized,
@@ -239,7 +239,7 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
239
239
  const MAX_CHUNK_RETRIES = 3;
240
240
  console.log(`
241
241
  Submitting ${chunks.length} chunks in batches of ${BATCH_SIZE}...`);
242
- const stored = [];
242
+ const stored = new Array(chunks.length).fill(null);
243
243
  for (let b = 0; b < chunks.length; b += BATCH_SIZE) {
244
244
  const batch = chunks.slice(b, b + BATCH_SIZE);
245
245
  const batchIndices = batch.map((_, j) => b + j);
@@ -250,9 +250,9 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
250
250
  return storeChunk(unsafeApi, signer, chunkData, nonce, ss58);
251
251
  });
252
252
  const results = await Promise.allSettled(batchPromises);
253
- for (const r of results) {
254
- if (r.status === "fulfilled") stored.push(r.value);
255
- }
253
+ results.forEach((r, j) => {
254
+ if (r.status === "fulfilled") stored[batchIndices[j]] = r.value;
255
+ });
256
256
  const failures = results.map((r, j) => r.status === "rejected" ? { index: batchIndices[j], chunkData: batch[j], error: r.reason } : null).filter(Boolean);
257
257
  for (const fail of failures) {
258
258
  captureWarning("Chunk upload failed, retrying", { chunkIndex: fail.index + 1, maxRetries: MAX_CHUNK_RETRIES, error: fail.error?.message?.slice(0, 200) });
@@ -263,7 +263,7 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
263
263
  const freshNonce = await fetchNonce(BULLETIN_RPC, ss58);
264
264
  try {
265
265
  const result2 = await storeChunk(unsafeApi, signer, fail.chunkData, freshNonce, ss58);
266
- stored.push(result2);
266
+ stored[fail.index] = result2;
267
267
  retried = true;
268
268
  break;
269
269
  } catch (e) {
@@ -279,9 +279,22 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
279
279
  setDeployAttribute("deploy.pool.account", ss58);
280
280
  console.log(`
281
281
  All ${chunks.length} chunks included in block`);
282
+ console.log(` Verifying chunk integrity...`);
283
+ const missing = stored.map((c, i) => c === null ? i + 1 : null).filter(Boolean);
284
+ if (missing.length > 0) {
285
+ throw new Error(`Chunk verification failed: missing chunks at positions ${missing.join(", ")}`);
286
+ }
287
+ const verifiedStored = stored;
288
+ for (let i = 0; i < chunks.length; i++) {
289
+ const expectedCid = createCID(chunks[i], CID_CONFIG.codec, 18);
290
+ if (verifiedStored[i].cid.toString() !== expectedCid.toString()) {
291
+ throw new Error(`Chunk verification failed: chunk ${i + 1} CID mismatch (expected ${expectedCid}, got ${verifiedStored[i].cid})`);
292
+ }
293
+ }
294
+ console.log(` All ${chunks.length} chunks verified \u2713`);
282
295
  console.log(` Building DAG-PB...`);
283
- const fileData = new UnixFS({ type: "file", blockSizes: stored.map((c) => BigInt(c.len)) });
284
- const dagNode = dagPB.prepare({ Data: fileData.marshal(), Links: stored.map((c) => ({ Name: "", Tsize: c.len, Hash: c.cid })) });
296
+ const fileData = new UnixFS({ type: "file", blockSizes: verifiedStored.map((c) => BigInt(c.len)) });
297
+ const dagNode = dagPB.prepare({ Data: fileData.marshal(), Links: verifiedStored.map((c) => ({ Name: "", Tsize: c.len, Hash: c.cid })) });
285
298
  const dagBytes = dagPB.encode(dagNode);
286
299
  const hashCode = 18;
287
300
  const rootCid = createCID(dagBytes, 112, hashCode);
@@ -181,11 +181,19 @@ function countTrailingDigits(label) {
181
181
  function stripTrailingDigits(label) {
182
182
  return label.replace(/\d+$/, "").replace(/-$/, "");
183
183
  }
184
+ function sanitizeDomainLabel(label) {
185
+ const trailingDigitCount = countTrailingDigits(label);
186
+ if (trailingDigitCount > 2) {
187
+ const sanitized = stripTrailingDigits(label) + label.slice(-2);
188
+ console.log(` Domain label sanitized: "${label}" \u2192 "${sanitized}" (stripped excess trailing digits)`);
189
+ return sanitized;
190
+ }
191
+ return label;
192
+ }
184
193
  function validateDomainLabel(label) {
185
194
  if (!/^[a-z0-9-]{3,}$/.test(label)) throw new Error("Invalid domain label: must contain only lowercase letters, digits, and hyphens, min 3 chars");
186
195
  if (label.startsWith("-") || label.endsWith("-")) throw new Error("Invalid domain label: cannot start or end with hyphen");
187
- const trailingDigitCount = countTrailingDigits(label);
188
- if (trailingDigitCount > 2) throw new Error(`Invalid domain label: max 2 trailing digits allowed, found ${trailingDigitCount}`);
196
+ return sanitizeDomainLabel(label);
189
197
  }
190
198
  function parseProofOfPersonhoodStatus(status) {
191
199
  const s = (status ?? "none").toLowerCase();
@@ -495,7 +503,7 @@ var DotNS = class {
495
503
  this.ensureConnected();
496
504
  console.log(`
497
505
  Generating commitment hash...`);
498
- validateDomainLabel(label);
506
+ label = validateDomainLabel(label);
499
507
  const secret = `0x${crypto.randomBytes(32).toString("hex")}`;
500
508
  const registration = { label, owner: this.evmAddress, secret, reserved: includeReverse };
501
509
  const commitment = await withTimeout(this.contractCall(CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, DOTNS_REGISTRAR_CONTROLLER_ABI, "makeCommitment", [registration]), 3e4, "Commitment generation");
@@ -526,7 +534,7 @@ var DotNS = class {
526
534
  this.ensureConnected();
527
535
  console.log(`
528
536
  Checking price and eligibility...`);
529
- validateDomainLabel(label);
537
+ label = validateDomainLabel(label);
530
538
  const baseName = stripTrailingDigits(label);
531
539
  const reservationInfo = await withTimeout(this.contractCall(CONTRACTS.POP_RULES, POP_RULES_ABI, "isBaseNameReserved", [baseName]), 3e4, "isBaseNameReserved");
532
540
  const [isReserved, reservationOwner] = reservationInfo;
@@ -602,7 +610,7 @@ var DotNS = class {
602
610
  const status = parseProofOfPersonhoodStatus(options.status || process.env.DOTNS_STATUS);
603
611
  const reverse = options.reverse ?? (process.env.DOTNS_REVERSE ?? "false").toLowerCase() === "true";
604
612
  if (!this.connected) await this.connect(options);
605
- validateDomainLabel(label);
613
+ label = validateDomainLabel(label);
606
614
  await Promise.all([
607
615
  this.classifyName(label),
608
616
  this.ensureNotRegistered(label),
@@ -645,6 +653,7 @@ export {
645
653
  computeDomainTokenId,
646
654
  countTrailingDigits,
647
655
  stripTrailingDigits,
656
+ sanitizeDomainLabel,
648
657
  validateDomainLabel,
649
658
  parseProofOfPersonhoodStatus,
650
659
  DotNS,
@@ -0,0 +1,33 @@
1
+ import { CID } from 'multiformats/cid';
2
+ import { PolkadotSigner } from 'polkadot-api';
3
+
4
+ interface DeployResult {
5
+ domainName: string;
6
+ fullDomain: string;
7
+ cid: string;
8
+ ipfsCid?: string;
9
+ }
10
+ type DeployContent = string | Uint8Array | Uint8Array[];
11
+ interface ExistingProvider {
12
+ client?: any;
13
+ unsafeApi?: any;
14
+ signer?: PolkadotSigner;
15
+ ss58?: string;
16
+ }
17
+ declare function createCID(data: Uint8Array, codec?: number, hashCode?: number): CID;
18
+ declare function encodeContenthash(cidString: string): string;
19
+ declare function storeFile(contentBytes: Uint8Array, { client: existingClient, unsafeApi: existingApi, signer: existingSigner }?: ExistingProvider): Promise<string>;
20
+ declare function storeChunkedContent(chunks: Uint8Array[], { client: existingClient, unsafeApi: existingApi, signer: existingSigner, ss58: existingSS58 }?: ExistingProvider): Promise<string>;
21
+ declare function chunk(data: Uint8Array, size?: number): Uint8Array[];
22
+ declare function hasIPFS(): boolean;
23
+ declare function merkleize(directoryPath: string, outputCarPath: string): Promise<{
24
+ carPath: string;
25
+ cid: string;
26
+ }>;
27
+ declare function storeDirectory(directoryPath: string): Promise<{
28
+ storageCid: string;
29
+ ipfsCid: string;
30
+ }>;
31
+ declare function deploy(content: DeployContent, domainName?: string | null): Promise<DeployResult>;
32
+
33
+ export { type DeployContent, type DeployResult, chunk, createCID, deploy, encodeContenthash, hasIPFS, merkleize, storeChunkedContent, storeDirectory, storeFile };
package/dist/deploy.js CHANGED
@@ -8,8 +8,8 @@ import {
8
8
  storeChunkedContent,
9
9
  storeDirectory,
10
10
  storeFile
11
- } from "./chunk-HRMYZ3GK.js";
12
- import "./chunk-XD7NNFWX.js";
11
+ } from "./chunk-JF2UR7FV.js";
12
+ import "./chunk-W23LLCZF.js";
13
13
  import "./chunk-RV7XBIIO.js";
14
14
  import "./chunk-2RURGSQW.js";
15
15
  import "./chunk-QGM4M3NI.js";
@@ -0,0 +1,116 @@
1
+ import { PolkadotSigner } from 'polkadot-api';
2
+
3
+ interface DotNSConnectOptions {
4
+ rpc?: string;
5
+ keyUri?: string;
6
+ mnemonic?: string;
7
+ }
8
+ interface OwnershipResult {
9
+ owned: boolean;
10
+ owner: string | null;
11
+ }
12
+ interface PriceValidationResult {
13
+ priceWei: bigint;
14
+ requiredStatus: number;
15
+ userStatus: number;
16
+ message: string;
17
+ }
18
+ declare const RPC_ENDPOINTS: string[];
19
+ declare const CONTRACTS: {
20
+ readonly DOTNS_REGISTRAR: "0x329aAA5b6bEa94E750b2dacBa74Bf41291E6c2BD";
21
+ readonly DOTNS_REGISTRAR_CONTROLLER: "0xd09e0F1c1E6CE8Cf40df929ef4FC778629573651";
22
+ readonly DOTNS_REGISTRY: "0x4Da0d37aBe96C06ab19963F31ca2DC0412057a6f";
23
+ readonly DOTNS_RESOLVER: "0x95645C7fD0fF38790647FE13F87Eb11c1DCc8514";
24
+ readonly DOTNS_CONTENT_RESOLVER: "0x7756DF72CBc7f062e7403cD59e45fBc78bed1cD7";
25
+ readonly DOTNS_REVERSE_RESOLVER: "0x95D57363B491CF743970c640fe419541386ac8BF";
26
+ readonly STORE_FACTORY: "0x030296782F4d3046B080BcB017f01837561D9702";
27
+ readonly POP_RULES: "0x4e8920B1E69d0cEA9b23CBFC87A17Ee6fE02d2d3";
28
+ };
29
+ declare const DECIMALS: bigint;
30
+ declare const NATIVE_TO_ETH_RATIO: bigint;
31
+ declare const OPERATION_TIMEOUT_MS: number;
32
+ declare const TX_TIMEOUT_MS: number;
33
+ declare const DEFAULT_MNEMONIC: string;
34
+ declare function fetchNonce(rpc: string, ss58Address: string): Promise<number>;
35
+ declare const ProofOfPersonhoodStatus: {
36
+ readonly NoStatus: 0;
37
+ readonly ProofOfPersonhoodLite: 1;
38
+ readonly ProofOfPersonhoodFull: 2;
39
+ readonly Reserved: 3;
40
+ };
41
+ declare const DOT_NODE: `0x${string}`;
42
+ declare function convertWeiToNative(weiValue: bigint): bigint;
43
+ declare function computeDomainTokenId(label: string): bigint;
44
+ declare function countTrailingDigits(label: string): number;
45
+ declare function stripTrailingDigits(label: string): string;
46
+ declare function sanitizeDomainLabel(label: string): string;
47
+ declare function validateDomainLabel(label: string): string;
48
+ declare function parseProofOfPersonhoodStatus(status: string): number;
49
+ declare class ReviveClientWrapper {
50
+ static DRY_RUN_STORAGE_LIMIT: bigint;
51
+ static DRY_RUN_WEIGHT_LIMIT: {
52
+ ref_time: bigint;
53
+ proof_size: bigint;
54
+ };
55
+ client: any;
56
+ mappedAccounts: Set<string>;
57
+ constructor(client: any);
58
+ getEvmAddress(substrateAddress: string): Promise<string>;
59
+ performDryRunCall(originSubstrateAddress: string, contractAddress: string, value: bigint, encodedData: string): Promise<any>;
60
+ estimateGasForCall(originSubstrateAddress: string, contractAddress: string, value: bigint, encodedData: string): Promise<any>;
61
+ checkIfAccountMapped(substrateAddress: string): Promise<boolean>;
62
+ ensureAccountMapped(substrateAddress: string, signer: PolkadotSigner): Promise<void>;
63
+ signAndSubmitExtrinsic(extrinsic: any, signer: PolkadotSigner, statusCallback: (status: string) => void, { rpc, senderSS58, expectedNonce }?: {
64
+ rpc?: string;
65
+ senderSS58?: string;
66
+ expectedNonce?: number;
67
+ }): Promise<string>;
68
+ submitTransaction(contractAddress: string, value: bigint, encodedData: string, signerSubstrateAddress: string, signer: PolkadotSigner, statusCallback: (status: string) => void, { rpc }?: {
69
+ rpc?: string;
70
+ }): Promise<string>;
71
+ }
72
+ declare class DotNS {
73
+ client: any | null;
74
+ clientWrapper: ReviveClientWrapper | null;
75
+ rpc: string | null;
76
+ substrateAddress: string | null;
77
+ evmAddress: string | null;
78
+ signer: PolkadotSigner | null;
79
+ connected: boolean;
80
+ constructor();
81
+ connect(options?: DotNSConnectOptions): Promise<this>;
82
+ ensureConnected(): void;
83
+ contractCall(contractAddress: string, contractAbi: readonly any[], functionName: string, args?: any[]): Promise<any>;
84
+ contractTransaction(contractAddress: string, value: bigint, contractAbi: readonly any[], functionName: string, args?: any[], statusCallback?: (status: string) => void): Promise<string>;
85
+ checkOwnership(label: string, ownerAddress?: string | null): Promise<OwnershipResult>;
86
+ classifyName(label: string): Promise<{
87
+ requiredStatus: number;
88
+ message: string;
89
+ }>;
90
+ getUserPopStatus(ownerAddress?: string | null): Promise<number>;
91
+ setUserPopStatus(status: number): Promise<void>;
92
+ ensureNotRegistered(label: string): Promise<void>;
93
+ generateCommitment(label: string, includeReverse?: boolean): Promise<{
94
+ commitment: any;
95
+ registration: any;
96
+ }>;
97
+ submitCommitment(commitment: any): Promise<void>;
98
+ waitForCommitmentAge(): Promise<void>;
99
+ getPriceAndValidate(label: string): Promise<PriceValidationResult>;
100
+ finalizeRegistration(registration: any, priceWei: bigint): Promise<void>;
101
+ verifyOwnership(label: string): Promise<void>;
102
+ setContenthash(domainName: string, contenthashHex: string): Promise<{
103
+ node: string;
104
+ }>;
105
+ register(label: string, options?: DotNSConnectOptions & {
106
+ status?: string;
107
+ reverse?: boolean;
108
+ }): Promise<{
109
+ label: string;
110
+ owner: string;
111
+ }>;
112
+ disconnect(): void;
113
+ }
114
+ declare const dotns: DotNS;
115
+
116
+ export { CONTRACTS, DECIMALS, DEFAULT_MNEMONIC, DOT_NODE, DotNS, type DotNSConnectOptions, NATIVE_TO_ETH_RATIO, OPERATION_TIMEOUT_MS, type OwnershipResult, type PriceValidationResult, ProofOfPersonhoodStatus, RPC_ENDPOINTS, TX_TIMEOUT_MS, computeDomainTokenId, convertWeiToNative, countTrailingDigits, dotns, fetchNonce, parseProofOfPersonhoodStatus, sanitizeDomainLabel, stripTrailingDigits, validateDomainLabel };
package/dist/dotns.js CHANGED
@@ -15,9 +15,10 @@ import {
15
15
  dotns,
16
16
  fetchNonce,
17
17
  parseProofOfPersonhoodStatus,
18
+ sanitizeDomainLabel,
18
19
  stripTrailingDigits,
19
20
  validateDomainLabel
20
- } from "./chunk-XD7NNFWX.js";
21
+ } from "./chunk-W23LLCZF.js";
21
22
  import "./chunk-2RURGSQW.js";
22
23
  import "./chunk-QGM4M3NI.js";
23
24
  export {
@@ -37,6 +38,7 @@ export {
37
38
  dotns,
38
39
  fetchNonce,
39
40
  parseProofOfPersonhoodStatus,
41
+ sanitizeDomainLabel,
40
42
  stripTrailingDigits,
41
43
  validateDomainLabel
42
44
  };
@@ -0,0 +1,5 @@
1
+ export { DeployContent, DeployResult, deploy } from './deploy.js';
2
+ export { PoolAccount, PoolAuthorization, bootstrapPool, derivePoolAccounts, ensureAuthorized, fetchPoolAuthorizations, selectAccount } from './pool.js';
3
+ export { DotNS, DotNSConnectOptions, OwnershipResult, PriceValidationResult } from './dotns.js';
4
+ import 'multiformats/cid';
5
+ import 'polkadot-api';
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  deploy
3
- } from "./chunk-HRMYZ3GK.js";
3
+ } from "./chunk-JF2UR7FV.js";
4
4
  import {
5
5
  DotNS
6
- } from "./chunk-XD7NNFWX.js";
6
+ } from "./chunk-W23LLCZF.js";
7
7
  import {
8
8
  bootstrapPool,
9
9
  derivePoolAccounts,
package/dist/pool.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { PolkadotSigner } from 'polkadot-api';
2
+
3
+ interface PoolAccount {
4
+ index: number;
5
+ path: string;
6
+ publicKey: Uint8Array;
7
+ signer: PolkadotSigner;
8
+ address: string;
9
+ }
10
+ interface PoolAuthorization extends PoolAccount {
11
+ transactions: bigint;
12
+ bytes: bigint;
13
+ }
14
+ declare function derivePoolAccounts(poolSize?: number, mnemonic?: string): PoolAccount[];
15
+ declare function selectAccount(authorizations: PoolAuthorization[]): PoolAuthorization | null;
16
+ declare function fetchPoolAuthorizations(api: any, accounts: PoolAccount[]): Promise<PoolAuthorization[]>;
17
+ declare function ensureAuthorized(api: any, poolAccount: PoolAccount, bulletinRpc: string): Promise<void>;
18
+ declare function bootstrapPool(bulletinRpc: string, poolSize?: number, mnemonic?: string): Promise<void>;
19
+
20
+ export { type PoolAccount, type PoolAuthorization, bootstrapPool, derivePoolAccounts, ensureAuthorized, fetchPoolAuthorizations, selectAccount };
@@ -0,0 +1,9 @@
1
+ declare function initTelemetry(): void;
2
+ declare function resolveRepo(domain: string): string;
3
+ declare function withSpan<T>(op: string, description: string, attributes: Record<string, string | number | boolean | undefined>, fn: () => T | Promise<T>): Promise<T>;
4
+ declare function withDeploySpan<T>(domain: string, fn: () => T | Promise<T>): Promise<T>;
5
+ declare function setDeployAttribute(key: string, value: string | number | boolean): void;
6
+ declare function captureWarning(message: string, context?: Record<string, unknown>): void;
7
+ declare function flush(): Promise<void>;
8
+
9
+ export { captureWarning, flush, initTelemetry, resolveRepo, setDeployAttribute, withDeploySpan, withSpan };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulletin-deploy",
3
- "version": "0.5.3-rc.1",
3
+ "version": "0.5.3",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",