bulletin-deploy 0.7.3 → 0.7.5

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.
@@ -1,13 +1,14 @@
1
1
  import {
2
2
  setDeployContext
3
- } from "./chunk-4EQERQRG.js";
3
+ } from "./chunk-UXKC7JAM.js";
4
4
  import {
5
5
  DotNS,
6
6
  TX_TIMEOUT_MS,
7
7
  fetchNonce,
8
8
  parseDomainName,
9
- popStatusName
10
- } from "./chunk-M3H3F4FY.js";
9
+ popStatusName,
10
+ verifyNonceAdvanced
11
+ } from "./chunk-SAMH7JFG.js";
11
12
  import {
12
13
  MirrorSkipped,
13
14
  mirrorToGitHubPages,
@@ -26,7 +27,7 @@ import {
26
27
  truncateAddress,
27
28
  withDeploySpan,
28
29
  withSpan
29
- } from "./chunk-BYIVK52G.js";
30
+ } from "./chunk-WOJRQCQV.js";
30
31
  import {
31
32
  merkleizeJS
32
33
  } from "./chunk-B7GUYYAN.js";
@@ -48,7 +49,7 @@ import { sha256 } from "@noble/hashes/sha256";
48
49
  import { blake2b } from "@noble/hashes/blake2b";
49
50
  import { createClient as createPolkadotClient, Enum } from "polkadot-api";
50
51
  import { Binary } from "@polkadot-api/substrate-bindings";
51
- import { getWsProvider } from "polkadot-api/ws-provider";
52
+ import { getWsProvider, WsEvent } from "polkadot-api/ws-provider";
52
53
  import { withPolkadotSdkCompat } from "polkadot-api/polkadot-sdk-compat";
53
54
  import { CID } from "multiformats/cid";
54
55
  import { create as createMultihash } from "multiformats/hashes/digest";
@@ -75,12 +76,23 @@ function friendlyChainError(msg) {
75
76
  }
76
77
  var DEFAULT_BULLETIN_RPC = "wss://paseo-bulletin-rpc.polkadot.io";
77
78
  var DEFAULT_POOL_SIZE = 10;
78
- var BULLETIN_RPC = DEFAULT_BULLETIN_RPC;
79
+ var BULLETIN_ENDPOINTS = [DEFAULT_BULLETIN_RPC];
79
80
  var POOL_SIZE = DEFAULT_POOL_SIZE;
81
+ var _deployRpcFailedOver = false;
82
+ function makeBulletinStatusHandler(primary) {
83
+ return (s) => {
84
+ if (s.type === WsEvent.CONNECTED && s.uri !== primary) {
85
+ _deployRpcFailedOver = true;
86
+ setDeployAttribute("deploy.rpc.failed_over", "true");
87
+ captureWarning("Bulletin RPC failover", { from: primary, to: s.uri });
88
+ }
89
+ };
90
+ }
80
91
  var CHUNK_SIZE = 2 * 1024 * 1024;
81
92
  var MAX_FILE_SIZE = 8 * 1024 * 1024;
82
93
  var MAX_RECONNECTIONS = parseInt(process.env.BULLETIN_MAX_RECONNECTIONS ?? "3", 10);
83
94
  var CHUNK_TIMEOUT_MS = parseInt(process.env.BULLETIN_CHUNK_TIMEOUT_MS ?? "180000", 10);
95
+ var CHUNK_MORTALITY_PERIOD = 16;
84
96
  var RETRY_BASE_DELAY_MS = 2e3;
85
97
  var RETRY_MAX_DELAY_MS = 15e3;
86
98
  var WS_HEARTBEAT_TIMEOUT_MS = 3e5;
@@ -147,8 +159,12 @@ function toHashingEnum(mhCode) {
147
159
  }
148
160
  }
149
161
  async function getProvider() {
150
- console.log(` Connecting to Bulletin: ${BULLETIN_RPC}`);
151
- const client = createPolkadotClient(withPolkadotSdkCompat(getWsProvider(BULLETIN_RPC, { heartbeatTimeout: WS_HEARTBEAT_TIMEOUT_MS })));
162
+ const primary = BULLETIN_ENDPOINTS[0];
163
+ console.log(` Connecting to Bulletin: ${primary}`);
164
+ const client = createPolkadotClient(withPolkadotSdkCompat(getWsProvider(
165
+ BULLETIN_ENDPOINTS,
166
+ { heartbeatTimeout: WS_HEARTBEAT_TIMEOUT_MS, onStatusChanged: makeBulletinStatusHandler(primary) }
167
+ )));
152
168
  const unsafeApi = client.getUnsafeApi();
153
169
  try {
154
170
  await cryptoWaitReady();
@@ -159,10 +175,10 @@ async function getProvider() {
159
175
  if (!selected) {
160
176
  const best = authorizations.reduce((a, b) => a.transactions > b.transactions ? a : b);
161
177
  console.log(` All pool accounts low on capacity, auto-authorizing account ${best.index}...`);
162
- await ensureAuthorized(unsafeApi, best.address, BULLETIN_RPC, `pool account ${best.index}`);
178
+ await ensureAuthorized(unsafeApi, best.address, BULLETIN_ENDPOINTS[0], `pool account ${best.index}`);
163
179
  selected = best;
164
180
  } else {
165
- await ensureAuthorized(unsafeApi, selected.address, BULLETIN_RPC, `pool account ${selected.index}`);
181
+ await ensureAuthorized(unsafeApi, selected.address, BULLETIN_ENDPOINTS[0], `pool account ${selected.index}`);
166
182
  }
167
183
  console.log(` Using pool account ${selected.index}: ${selected.address}`);
168
184
  setDeployAttribute("deploy.signer.mode", "pool");
@@ -175,8 +191,12 @@ async function getProvider() {
175
191
  }
176
192
  }
177
193
  async function getDirectProvider(mnemonic, derivationPath = "") {
178
- console.log(` Connecting to Bulletin: ${BULLETIN_RPC}`);
179
- const client = createPolkadotClient(withPolkadotSdkCompat(getWsProvider(BULLETIN_RPC, { heartbeatTimeout: WS_HEARTBEAT_TIMEOUT_MS })));
194
+ const primary = BULLETIN_ENDPOINTS[0];
195
+ console.log(` Connecting to Bulletin: ${primary}`);
196
+ const client = createPolkadotClient(withPolkadotSdkCompat(getWsProvider(
197
+ BULLETIN_ENDPOINTS,
198
+ { heartbeatTimeout: WS_HEARTBEAT_TIMEOUT_MS, onStatusChanged: makeBulletinStatusHandler(primary) }
199
+ )));
180
200
  const unsafeApi = client.getUnsafeApi();
181
201
  const { signer, ss58 } = deriveRootSigner(mnemonic, derivationPath);
182
202
  console.log(` Using direct signer: ${ss58}${derivationPath ? ` (path: ${derivationPath})` : ""}`);
@@ -194,13 +214,12 @@ async function getDirectProvider(mnemonic, derivationPath = "") {
194
214
  setDeployAttribute("deploy.signer.address", truncateAddress(ss58));
195
215
  return { client, unsafeApi, signer, ss58 };
196
216
  }
197
- var MAX_BEST_CHAIN_DROPS = 5;
198
- function watchTransaction(tx, signer, txOpts, onSuccess, { label = "transaction", rpc, senderSS58, expectedNonce, timeoutMs } = {}) {
217
+ function watchTransaction(tx, signer, txOpts, onSuccess, { label = "transaction", rpc, senderSS58, expectedNonce, timeoutMs, fetchNonce: fetchNonceOverride } = {}) {
199
218
  const timeout = timeoutMs ?? TX_TIMEOUT_MS;
219
+ const _fetchNonce = fetchNonceOverride ?? fetchNonce;
200
220
  return new Promise((resolve2, reject) => {
201
221
  let settled = false;
202
222
  let sub;
203
- let dropCount = 0;
204
223
  const settle = (fn) => (...args) => {
205
224
  if (settled) return;
206
225
  settled = true;
@@ -214,10 +233,11 @@ function watchTransaction(tx, signer, txOpts, onSuccess, { label = "transaction"
214
233
  const tryNonceFallback = async () => {
215
234
  if (!rpc || !senderSS58 || expectedNonce == null) return false;
216
235
  try {
217
- const currentNonce = await fetchNonce(rpc, senderSS58);
236
+ const endpoints = Array.isArray(rpc) ? rpc : [rpc];
237
+ const verified = await verifyNonceAdvanced(endpoints, senderSS58, expectedNonce);
218
238
  if (settled) return true;
219
- if (currentNonce > expectedNonce) {
220
- console.log(` ${label}: nonce advanced (${expectedNonce} -> ${currentNonce}), tx was included`);
239
+ if (verified.advanced) {
240
+ console.log(` ${label}: nonce advanced past ${expectedNonce} (witnessed by ${verified.witnessRpc}), tx was included`);
221
241
  settle(resolve2)({ value: onSuccess(), viaFallback: true });
222
242
  return true;
223
243
  }
@@ -234,23 +254,16 @@ function watchTransaction(tx, signer, txOpts, onSuccess, { label = "transaction"
234
254
  }, timeout);
235
255
  sub = tx.signSubmitAndWatch(signer, txOpts).subscribe({
236
256
  next: async (event) => {
237
- if (event.type === "txBestBlocksState") {
238
- if (event.found) {
239
- if (event.ok) {
240
- settle(resolve2)({ value: onSuccess(event), viaFallback: false });
241
- } else {
242
- settle(reject)(new Error(`${label} dispatch error`));
243
- }
244
- } else {
245
- dropCount++;
246
- if (dropCount >= MAX_BEST_CHAIN_DROPS) {
247
- console.log(` ${label}: tx dropped ${dropCount} times, checking nonce...`);
248
- if (await tryNonceFallback()) return;
249
- settle(reject)(new Error(`${label} tx dropped from best chain ${dropCount} times`));
250
- } else {
251
- console.log(` ${label}: tx dropped from best chain (${dropCount}/${MAX_BEST_CHAIN_DROPS}), waiting...`);
252
- }
253
- }
257
+ if (event.type !== "txBestBlocksState") return;
258
+ if (event.found) {
259
+ if (event.ok) settle(resolve2)({ value: onSuccess(event), viaFallback: false });
260
+ else settle(reject)(new Error(`${label} dispatch error`));
261
+ return;
262
+ }
263
+ if (event.isValid === false) {
264
+ console.log(` ${label}: tx rejected by pool (isValid:false), checking nonce fallback...`);
265
+ if (await tryNonceFallback()) return;
266
+ settle(reject)(new Error(`${label} tx rejected by pool (isValid:false)`));
254
267
  }
255
268
  },
256
269
  error: (e) => {
@@ -260,15 +273,15 @@ function watchTransaction(tx, signer, txOpts, onSuccess, { label = "transaction"
260
273
  });
261
274
  });
262
275
  }
263
- async function storeChunk(unsafeApi, signer, chunkBytes, nonce, ss58) {
276
+ async function storeChunk(unsafeApi, signer, chunkBytes, nonce, ss58, opts = {}) {
264
277
  const hashCode = 18;
265
278
  const cid = createCID(chunkBytes, CID_CONFIG.codec, hashCode);
266
279
  const tx = unsafeApi.tx.TransactionStorage.store_with_cid_config({ cid: { codec: BigInt(CID_CONFIG.codec), hashing: toHashingEnum(hashCode) }, data: Binary.fromBytes(chunkBytes) });
267
- const txOpts = { mortality: { mortal: true, period: 256 }, nonce };
280
+ const txOpts = { mortality: { mortal: true, period: CHUNK_MORTALITY_PERIOD }, nonce };
268
281
  const { value, viaFallback } = await watchTransaction(tx, signer, txOpts, () => {
269
282
  console.log(` CID: ${cid.toString()}`);
270
283
  return { cid, len: chunkBytes.length };
271
- }, { label: `chunk(nonce:${nonce})`, rpc: BULLETIN_RPC, senderSS58: ss58, expectedNonce: nonce, timeoutMs: CHUNK_TIMEOUT_MS });
284
+ }, { label: `chunk(nonce:${nonce})`, rpc: BULLETIN_ENDPOINTS, senderSS58: ss58, expectedNonce: nonce, timeoutMs: CHUNK_TIMEOUT_MS, fetchNonce: opts.fetchNonce });
272
285
  return { ...value, viaFallback };
273
286
  }
274
287
  async function storeFile(contentBytes, { client: existingClient, unsafeApi: existingApi, signer: existingSigner } = {}) {
@@ -305,7 +318,8 @@ async function storeFile(contentBytes, { client: existingClient, unsafeApi: exis
305
318
  throw e;
306
319
  }
307
320
  }
308
- async function storeChunkedContent(chunks, { client: existingClient, unsafeApi: existingApi, signer: existingSigner, ss58: existingSS58, reconnect } = {}) {
321
+ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi: existingApi, signer: existingSigner, ss58: existingSS58, reconnect, fetchNonce: fetchNonceOverride } = {}) {
322
+ const _fetchNonce = fetchNonceOverride ?? fetchNonce;
309
323
  console.log(`
310
324
  Chunks: ${chunks.length}`);
311
325
  const totalBytes = chunks.reduce((s, c) => s + c.length, 0);
@@ -337,7 +351,7 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
337
351
  Account has insufficient authorization for this upload (need ${requiredTxs} txs / ${(totalBytes / 1e6).toFixed(1)}MB, have ${txsRemaining} txs / ${Number(bytesRemaining) / 1e6}MB)`);
338
352
  console.log(` Attempting to re-authorize with Alice...`);
339
353
  try {
340
- await ensureAuthorized(unsafeApi, ss58, BULLETIN_RPC, void 0, { txs: requiredTxs, bytes: requiredBytes });
354
+ await ensureAuthorized(unsafeApi, ss58, BULLETIN_ENDPOINTS[0], void 0, { txs: requiredTxs, bytes: requiredBytes });
341
355
  console.log(` Re-authorization successful`);
342
356
  } catch (e) {
343
357
  throw new NonRetryableError(`Account ${ss58} has insufficient Bulletin authorization quota and auto-authorization via Alice failed (${e.message}). Authorize the account on-chain.`);
@@ -368,7 +382,7 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
368
382
  sampleMemory(`reconnect_${reconnectionsUsed}_after`);
369
383
  }
370
384
  try {
371
- let startNonce = await fetchNonce(BULLETIN_RPC, ss58);
385
+ let startNonce = await _fetchNonce(BULLETIN_ENDPOINTS, ss58);
372
386
  console.log(` Starting nonce: ${startNonce}`);
373
387
  const BATCH_SIZE = 2;
374
388
  const MAX_CHUNK_RETRIES = 3;
@@ -394,7 +408,7 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
394
408
  }
395
409
  const nonce = assignedNonces.get(i);
396
410
  console.log(` [${i + 1}/${chunks.length}] ${(chunkData.length / 1024 / 1024).toFixed(2)} MB (nonce: ${nonce})`);
397
- return storeChunk(unsafeApi, signer, chunkData, nonce, ss58);
411
+ return storeChunk(unsafeApi, signer, chunkData, nonce, ss58, { fetchNonce: fetchNonceOverride });
398
412
  });
399
413
  const results = await Promise.allSettled(batchPromises);
400
414
  results.forEach((r, j) => {
@@ -404,11 +418,10 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
404
418
  }
405
419
  });
406
420
  const failures = results.map((r, j) => r.status === "rejected" ? { index: batchIndices[j], chunkData: batchChunks[j], error: r.reason } : null).filter(Boolean);
407
- const succeededViaFallback = results.some((r) => r.status === "fulfilled" && r.value.viaFallback);
408
- const needsReconnect = failures.some((f) => isConnectionError(f.error)) || succeededViaFallback;
421
+ const needsReconnect = failures.some((f) => isConnectionError(f.error));
409
422
  if (needsReconnect && reconnect && reconnectionsUsed < MAX_RECONNECTIONS) {
410
423
  await doReconnect();
411
- const currentNonce = await fetchNonce(BULLETIN_RPC, ss58);
424
+ const currentNonce = await _fetchNonce(BULLETIN_ENDPOINTS, ss58);
412
425
  for (const idx of batchIndices) {
413
426
  const chunkNonce = assignedNonces.get(idx);
414
427
  if (chunkNonce !== void 0 && chunkNonce < currentNonce && stored[idx] === null) {
@@ -439,7 +452,7 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
439
452
  }
440
453
  }
441
454
  try {
442
- const currentNonce = await fetchNonce(BULLETIN_RPC, ss58);
455
+ const currentNonce = await _fetchNonce(BULLETIN_ENDPOINTS, ss58);
443
456
  const originalNonce = assignedNonces.get(fail.index);
444
457
  if (originalNonce !== void 0 && originalNonce < currentNonce) {
445
458
  console.log(` Chunk ${fail.index + 1}: nonce ${originalNonce} consumed (current=${currentNonce}), treating as included`);
@@ -449,7 +462,7 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
449
462
  break;
450
463
  }
451
464
  const retryNonce = originalNonce ?? currentNonce;
452
- const result2 = await storeChunk(unsafeApi, signer, fail.chunkData, retryNonce, ss58);
465
+ const result2 = await storeChunk(unsafeApi, signer, fail.chunkData, retryNonce, ss58, { fetchNonce: fetchNonceOverride });
453
466
  stored[fail.index] = result2;
454
467
  assignedNonces.delete(fail.index);
455
468
  retried = true;
@@ -495,7 +508,7 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
495
508
  const MAX_ROOT_RETRIES = 3;
496
509
  let result;
497
510
  for (let rootAttempt = 1; rootAttempt <= MAX_ROOT_RETRIES; rootAttempt++) {
498
- const rootNonce = await fetchNonce(BULLETIN_RPC, ss58);
511
+ const rootNonce = await _fetchNonce(BULLETIN_ENDPOINTS, ss58);
499
512
  console.log(` Storing root node (nonce: ${rootNonce})...`);
500
513
  const rootTx = unsafeApi.tx.TransactionStorage.store_with_cid_config({ cid: { codec: BigInt(112), hashing: toHashingEnum(hashCode) }, data: Binary.fromBytes(dagBytes) });
501
514
  const rootTxOpts = { mortality: { mortal: true, period: 256 }, nonce: rootNonce };
@@ -504,11 +517,8 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
504
517
  console.log(` Root CID: ${rootCid.toString()}
505
518
  `);
506
519
  return rootCid.toString();
507
- }, { label: "root-node", rpc: BULLETIN_RPC, senderSS58: ss58, expectedNonce: rootNonce, timeoutMs: CHUNK_TIMEOUT_MS });
520
+ }, { label: "root-node", rpc: BULLETIN_ENDPOINTS, senderSS58: ss58, expectedNonce: rootNonce, timeoutMs: CHUNK_TIMEOUT_MS, fetchNonce: fetchNonceOverride });
508
521
  result = watchResult.value;
509
- if (watchResult.viaFallback && reconnect && reconnectionsUsed < MAX_RECONNECTIONS) {
510
- await doReconnect();
511
- }
512
522
  break;
513
523
  } catch (e) {
514
524
  if (reconnect && reconnectionsUsed < MAX_RECONNECTIONS) {
@@ -665,7 +675,9 @@ async function estimateUploadBytes(content) {
665
675
  }
666
676
  }
667
677
  async function deploy(content, domainName = null, options = {}) {
668
- BULLETIN_RPC = options.rpc ?? process.env.BULLETIN_RPC ?? DEFAULT_BULLETIN_RPC;
678
+ const userRpc = options.rpc ?? process.env.BULLETIN_RPC;
679
+ BULLETIN_ENDPOINTS = userRpc ? [userRpc, ...[DEFAULT_BULLETIN_RPC].filter((e) => e !== userRpc)] : [DEFAULT_BULLETIN_RPC];
680
+ _deployRpcFailedOver = false;
669
681
  POOL_SIZE = options.poolSize ?? parseInt(process.env.BULLETIN_POOL_SIZE ?? String(DEFAULT_POOL_SIZE), 10);
670
682
  initTelemetry();
671
683
  const randomSuffix = Math.floor(Math.random() * 100).toString().padStart(2, "0");
@@ -698,22 +710,6 @@ async function deploy(content, domainName = null, options = {}) {
698
710
  await preflight.connect(
699
711
  options.signer && options.signerAddress ? { signer: options.signer, signerAddress: options.signerAddress } : options.mnemonic ? { mnemonic: options.mnemonic, derivationPath: options.derivationPath } : {}
700
712
  );
701
- const mappingDeadline = Date.now() + 15e3;
702
- let mappingConfirmed = false;
703
- while (Date.now() < mappingDeadline) {
704
- if (await preflight.clientWrapper.checkIfAccountMapped(preflight.substrateAddress)) {
705
- mappingConfirmed = true;
706
- break;
707
- }
708
- await new Promise((r) => setTimeout(r, 1500));
709
- }
710
- if (!mappingConfirmed) {
711
- preflight.disconnect();
712
- throw new NonRetryableError(
713
- `Account mapping did not take effect on-chain for ${preflight.substrateAddress}. The map_account tx may have been dropped or hit a dispatch error \u2014 check the signer's balance for existential deposit + fees.`
714
- );
715
- }
716
- console.log(` Account: mapped`);
717
713
  if (parsed?.isSubdomain) {
718
714
  try {
719
715
  const { owned: subOwned } = await preflight.checkSubdomainOwnership(parsed.sublabel, parsed.parentLabel);
@@ -762,7 +758,7 @@ async function deploy(content, domainName = null, options = {}) {
762
758
  const uploadBytes = Math.ceil(estimated * 1.2);
763
759
  const chunksNeeded = Math.max(1, Math.ceil(uploadBytes / CHUNK_SIZE));
764
760
  const needs = { txs: BigInt(chunksNeeded + 2), bytes: BigInt(uploadBytes) };
765
- await topUpBy(provider.ss58, BULLETIN_RPC, needs, "uploader");
761
+ await topUpBy(provider.ss58, BULLETIN_ENDPOINTS[0], needs, "uploader");
766
762
  }
767
763
  console.log("\n" + "=".repeat(60));
768
764
  console.log("Storage");
@@ -808,7 +804,7 @@ async function deploy(content, domainName = null, options = {}) {
808
804
  carBytes,
809
805
  cid: predictedCid,
810
806
  toolVersion: VERSION,
811
- bulletinRpc: options.rpc ?? process.env.BULLETIN_RPC ?? DEFAULT_BULLETIN_RPC,
807
+ bulletinRpc: BULLETIN_ENDPOINTS[0],
812
808
  encrypted: Boolean(options.password)
813
809
  }).catch((err) => err instanceof Error ? err : new Error(String(err)));
814
810
  }
@@ -917,16 +913,11 @@ async function deploy(content, domainName = null, options = {}) {
917
913
  const freshness = await pollMirrorFreshness(mirror.url, cid, { timeoutMs: 3 * 60 * 1e3, intervalMs: 1e4 });
918
914
  if (freshness.verified) {
919
915
  console.log(`ok (${freshness.attempts} attempt${freshness.attempts === 1 ? "" : "s"}, ${(freshness.durationMs / 1e3).toFixed(0)}s).`);
916
+ setDeployAttribute("deploy.gh_pages_freshness_verified", "true");
920
917
  } else {
921
918
  console.log(`timed out.`);
922
919
  console.log(` GitHub Pages last served cid=${freshness.lastCid ?? "n/a"} (expected ${cid}); it should catch up shortly. Non-fatal.`);
923
- captureWarning("gh-pages mirror freshness poll timed out", {
924
- url: mirror.url,
925
- expectedCid: cid,
926
- lastCid: freshness.lastCid ?? "n/a",
927
- durationMs: freshness.durationMs,
928
- attempts: freshness.attempts
929
- });
920
+ setDeployAttribute("deploy.gh_pages_freshness_verified", "false");
930
921
  }
931
922
  });
932
923
  }
@@ -939,6 +930,7 @@ async function deploy(content, domainName = null, options = {}) {
939
930
  console.log("\n" + "=".repeat(60) + "\n");
940
931
  return { domainName: name, fullDomain: `${name}.dot`, cid, ipfsCid };
941
932
  } finally {
933
+ if (_deployRpcFailedOver) setDeployAttribute("deploy.rpc.failed_over", "true");
942
934
  provider?.client.destroy();
943
935
  }
944
936
  });
@@ -950,6 +942,7 @@ export {
950
942
  friendlyChainError,
951
943
  DEFAULT_BULLETIN_RPC,
952
944
  DEFAULT_POOL_SIZE,
945
+ CHUNK_MORTALITY_PERIOD,
953
946
  isConnectionError,
954
947
  deriveRootSigner,
955
948
  createCID,