bulletin-deploy 0.7.12 → 0.7.13

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.
@@ -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.7.12",
9
+ version: "0.7.13",
10
10
  private: false,
11
11
  repository: {
12
12
  type: "git",
@@ -32,12 +32,15 @@ var package_default = {
32
32
  files: [
33
33
  "dist",
34
34
  "bin",
35
- "docs"
35
+ "docs",
36
+ "assets"
36
37
  ],
37
38
  scripts: {
38
- 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 --format esm --dts --clean --target node22",
39
+ prebuild: "node scripts/refresh-environments.mjs",
40
+ 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",
41
+ "refresh-environments": "node scripts/refresh-environments.mjs",
39
42
  prepare: "npm run build",
40
- test: "npm run build && node --test test/test.js test/cli-help.test.js test/helpers/e2e-helpers.test.js",
43
+ test: "npm run build && node --test test/test.js test/cli-help.test.js test/helpers/e2e-helpers.test.js test/environments.test.js",
41
44
  "test:e2e": "npm run build && node --test test/e2e.test.js",
42
45
  "test:e2e:smoke": "bash scripts/e2e-pass.sh smoke",
43
46
  "test:e2e:pr": "bash scripts/e2e-pass.sh pr",
@@ -48,12 +51,12 @@ var package_default = {
48
51
  "@ipld/car": "^5.4.3",
49
52
  "@ipld/dag-pb": "^4.1.3",
50
53
  "@noble/hashes": "^1.7.2",
51
- "@parity/dotns-cli": "^0.6.0",
54
+ "@parity/dotns-cli": "^0.6.1",
52
55
  "@polkadot-api/substrate-bindings": "^0.16.5",
53
56
  "@polkadot-labs/hdkd": "^0.0.25",
54
57
  "@polkadot-labs/hdkd-helpers": "^0.0.26",
55
- "@polkadot/keyring": "^13.0.0",
56
- "@polkadot/util-crypto": "^13.0.0",
58
+ "@polkadot/keyring": "^14.0.1",
59
+ "@polkadot/util-crypto": "^14.0.1",
57
60
  "@sentry/node": "^9.14.0",
58
61
  "ipfs-unixfs": "^11.2.0",
59
62
  "ipfs-unixfs-importer": "^16.1.4",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  package_default,
3
3
  writeRunState
4
- } from "./chunk-VQJLGE5J.js";
4
+ } from "./chunk-KU6N5DD3.js";
5
5
 
6
6
  // src/memory-report.ts
7
7
  import * as fs2 from "fs";
@@ -277,10 +277,10 @@ function sampleMemory(stage) {
277
277
  console.error(`[sampleMemory] stage=${stage} active=${active ? active.description ?? active.name ?? "?" : "null"} rss=${toMb(m.rss)}MB`);
278
278
  }
279
279
  if (active) {
280
- active.setAttribute(`mem.${stage}.rss_mb`, String(toMb(m.rss)));
281
- active.setAttribute(`mem.${stage}.heap_used_mb`, String(toMb(m.heapUsed)));
282
- active.setAttribute(`mem.${stage}.external_mb`, String(toMb(m.external)));
283
- active.setAttribute(`mem.${stage}.array_buffers_mb`, String(toMb(m.arrayBuffers)));
280
+ active.setAttribute(`mem.${stage}.rss_bytes`, m.rss);
281
+ active.setAttribute(`mem.${stage}.heap_used_bytes`, m.heapUsed);
282
+ active.setAttribute(`mem.${stage}.external_bytes`, m.external);
283
+ active.setAttribute(`mem.${stage}.array_buffers_bytes`, m.arrayBuffers);
284
284
  }
285
285
  stageSamples[stage] = sampleFromBytes(m);
286
286
  if (memoryPeak) {
@@ -289,10 +289,10 @@ function sampleMemory(stage) {
289
289
  if (m.external > memoryPeak.external) memoryPeak.external = m.external;
290
290
  if (m.arrayBuffers > memoryPeak.arrayBuffers) memoryPeak.arrayBuffers = m.arrayBuffers;
291
291
  if (deployRootSpan) {
292
- deployRootSpan.setAttribute("deploy.mem.peak_rss_mb", String(toMb(memoryPeak.rss)));
293
- deployRootSpan.setAttribute("deploy.mem.peak_heap_used_mb", String(toMb(memoryPeak.heapUsed)));
294
- deployRootSpan.setAttribute("deploy.mem.peak_external_mb", String(toMb(memoryPeak.external)));
295
- deployRootSpan.setAttribute("deploy.mem.peak_array_buffers_mb", String(toMb(memoryPeak.arrayBuffers)));
292
+ deployRootSpan.setAttribute("deploy.mem.peak_rss_bytes", memoryPeak.rss);
293
+ deployRootSpan.setAttribute("deploy.mem.peak_heap_used_bytes", memoryPeak.heapUsed);
294
+ deployRootSpan.setAttribute("deploy.mem.peak_external_bytes", memoryPeak.external);
295
+ deployRootSpan.setAttribute("deploy.mem.peak_array_buffers_bytes", memoryPeak.arrayBuffers);
296
296
  }
297
297
  }
298
298
  if (runStateActive && memoryPeak) {
@@ -1,11 +1,11 @@
1
+ import {
2
+ isTestnetSpecName
3
+ } from "./chunk-VOEFHED3.js";
1
4
  import {
2
5
  captureWarning,
3
6
  setDeployAttribute,
4
7
  withSpan
5
- } from "./chunk-LOZ5PSD3.js";
6
- import {
7
- isTestnetSpecName
8
- } from "./chunk-VOEFHED3.js";
8
+ } from "./chunk-MRB5E7YM.js";
9
9
 
10
10
  // src/dotns.ts
11
11
  import { spawn } from "child_process";
@@ -35,17 +35,56 @@ import {
35
35
  import { CID } from "multiformats/cid";
36
36
  import { createRequire } from "module";
37
37
  var _require = createRequire(import.meta.url);
38
- var _dotnsCliPath;
39
- var _dotnsCliVersion;
40
- try {
41
- _dotnsCliPath = _require.resolve("@parity/dotns-cli");
42
- const pkgDir = dirname(dirname(_dotnsCliPath));
38
+ var DOTNS_CLI_ENV = "BULLETIN_DEPLOY_DOTNS_CLI";
39
+ var DOTNS_CLI_HOST_VALUES = /* @__PURE__ */ new Set(["host", "host-dispatch"]);
40
+ function resolveDotnsCliPackage() {
41
+ const cliPath = _require.resolve("@parity/dotns-cli");
42
+ const pkgDir = dirname(dirname(cliPath));
43
43
  const pkg = JSON.parse(readFileSync(join(pkgDir, "package.json"), "utf-8"));
44
- _dotnsCliVersion = pkg.version;
45
- } catch (err) {
46
- _dotnsCliVersion = "unknown";
47
- _dotnsCliPath = "dotns";
48
- console.warn(`[bulletin-deploy] @parity/dotns-cli not found in node_modules \u2014 falling back to "dotns" in PATH. Install with: npm install @parity/dotns-cli. Underlying: ${err.message}`);
44
+ return { path: cliPath, version: pkg.version };
45
+ }
46
+ function resolveDotnsCliInvocation(env = process.env, packageResolver = resolveDotnsCliPackage) {
47
+ const override = env[DOTNS_CLI_ENV]?.trim();
48
+ if (override) {
49
+ if (DOTNS_CLI_HOST_VALUES.has(override)) {
50
+ return { command: process.execPath, argsPrefix: ["dotns"], version: "host-dispatch", source: "host-dispatch" };
51
+ }
52
+ return { command: override, argsPrefix: [], version: "override", source: "command-override" };
53
+ }
54
+ try {
55
+ const pkg = packageResolver();
56
+ return { command: process.execPath, argsPrefix: [pkg.path], version: pkg.version, source: "package" };
57
+ } catch (err) {
58
+ return {
59
+ command: process.execPath,
60
+ argsPrefix: ["dotns"],
61
+ version: "unknown",
62
+ source: "host-dispatch-fallback",
63
+ resolutionError: err instanceof Error ? err.message : String(err)
64
+ };
65
+ }
66
+ }
67
+ function describeDotnsCliInvocation(cli) {
68
+ if (cli.source === "package") return `${cli.command} ${cli.argsPrefix[0]}`;
69
+ if (cli.source === "command-override") return `${cli.command} (from ${DOTNS_CLI_ENV})`;
70
+ return `${cli.command} dotns`;
71
+ }
72
+ function dotnsCliFailureHint(cli) {
73
+ if (cli.source === "host-dispatch-fallback") {
74
+ return `@parity/dotns-cli was not resolvable from node_modules, so bulletin-deploy tried host binary dispatch (${process.execPath} dotns ...). Set ${DOTNS_CLI_ENV}=host to opt into that path explicitly, set ${DOTNS_CLI_ENV} to a dotns command/path, or install @parity/dotns-cli. Underlying resolution error: ${cli.resolutionError ?? "unknown"}`;
75
+ }
76
+ if (cli.source === "host-dispatch") {
77
+ return `${DOTNS_CLI_ENV}=host uses host binary dispatch (${process.execPath} dotns ...).`;
78
+ }
79
+ if (cli.source === "command-override") {
80
+ return `${DOTNS_CLI_ENV} uses a direct command/path (${cli.command}).`;
81
+ }
82
+ return null;
83
+ }
84
+ function withDotnsCliFailureHint(message, cli) {
85
+ const hint = dotnsCliFailureHint(cli);
86
+ return hint ? `${message}
87
+ ${hint}` : message;
49
88
  }
50
89
  var ONE_PAS = 10000000000n;
51
90
  var FEE_FLOOR_OWNED = ONE_PAS / 100n;
@@ -597,7 +636,13 @@ var ReviveClientWrapper = class _ReviveClientWrapper {
597
636
  };
598
637
  async function runDotnsCli(argv, env) {
599
638
  return new Promise((resolve, reject) => {
600
- const proc = spawn(process.execPath, [_dotnsCliPath, ...argv], {
639
+ const cli = resolveDotnsCliInvocation();
640
+ try {
641
+ setDeployAttribute("deploy.dotns_cli.version", cli.version);
642
+ setDeployAttribute("deploy.dotns_cli.source", cli.source);
643
+ } catch {
644
+ }
645
+ const proc = spawn(cli.command, [...cli.argsPrefix, ...argv], {
601
646
  stdio: ["ignore", "pipe", "pipe"],
602
647
  env: { ...process.env, ...env }
603
648
  });
@@ -635,9 +680,9 @@ async function runDotnsCli(argv, env) {
635
680
  } else if (out) {
636
681
  errorMsg = out.slice(0, 500);
637
682
  }
638
- reject(new Error(errorMsg));
683
+ reject(new Error(withDotnsCliFailureHint(errorMsg, cli)));
639
684
  });
640
- proc.on("error", (err) => reject(new Error(`Failed to spawn dotns CLI: ${err.message}`)));
685
+ proc.on("error", (err) => reject(new Error(withDotnsCliFailureHint(`Failed to spawn DotNS CLI via ${describeDotnsCliInvocation(cli)}: ${err.message}`, cli))));
641
686
  });
642
687
  }
643
688
  function buildAuthEnv(opts) {
@@ -660,6 +705,10 @@ var DotNS = class {
660
705
  evmAddress;
661
706
  signer;
662
707
  connected;
708
+ // Per-instance failover list. Populated from options.assetHubEndpoints when
709
+ // bulletin-deploy resolves the asset-hub list via environments.json; falls
710
+ // back to the legacy paseo-only RPC_ENDPOINTS for direct library callers.
711
+ assetHubEndpoints;
663
712
  // Stored credentials for CLI subprocess calls. Never logged or exposed.
664
713
  _mnemonic = null;
665
714
  _keyUri = null;
@@ -672,9 +721,13 @@ var DotNS = class {
672
721
  this.evmAddress = null;
673
722
  this.signer = null;
674
723
  this.connected = false;
724
+ this.assetHubEndpoints = RPC_ENDPOINTS;
675
725
  }
676
726
  async connect(options = {}) {
677
- const rpc = options.rpc || process.env.DOTNS_RPC || RPC_ENDPOINTS[0];
727
+ if (options.assetHubEndpoints && options.assetHubEndpoints.length > 0) {
728
+ this.assetHubEndpoints = options.assetHubEndpoints;
729
+ }
730
+ const rpc = options.rpc || process.env.DOTNS_RPC || this.assetHubEndpoints[0];
678
731
  this.rpc = rpc;
679
732
  this._usesExternalSigner = Boolean(options.signer && options.signerAddress);
680
733
  let authEnv = {};
@@ -740,10 +793,6 @@ var DotNS = class {
740
793
  }
741
794
  }
742
795
  console.log(` Account: mapped`);
743
- try {
744
- setDeployAttribute("deploy.dotns_cli.version", _dotnsCliVersion);
745
- } catch {
746
- }
747
796
  this.connected = true;
748
797
  return this;
749
798
  }
@@ -914,7 +963,7 @@ var DotNS = class {
914
963
  this.ensureConnected();
915
964
  if (!this.clientWrapper) throw new Error("contractTransaction: polkadot-api client not available");
916
965
  const encodedCallData = encodeFunctionData({ abi: contractAbi, functionName, args });
917
- const rpcs = this.rpc ? [this.rpc, ...RPC_ENDPOINTS.filter((ep) => ep !== this.rpc)] : RPC_ENDPOINTS;
966
+ const rpcs = this.rpc ? [this.rpc, ...this.assetHubEndpoints.filter((ep) => ep !== this.rpc)] : this.assetHubEndpoints;
918
967
  return await withTimeout(
919
968
  this.clientWrapper.submitTransaction(contractAddress, value, encodedCallData, this.substrateAddress, this.signer, statusCallback, { rpcs, useNoncePolling, functionName, args }),
920
969
  OPERATION_TIMEOUT_MS,
@@ -1574,6 +1623,7 @@ var DotNS = class {
1574
1623
  var dotns = new DotNS();
1575
1624
 
1576
1625
  export {
1626
+ resolveDotnsCliInvocation,
1577
1627
  fmtPas,
1578
1628
  feeFloorFor,
1579
1629
  RPC_ENDPOINTS,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-LOZ5PSD3.js";
3
+ } from "./chunk-MRB5E7YM.js";
4
4
 
5
5
  // src/version-check.ts
6
6
  import { execSync, execFileSync } from "child_process";
@@ -2,11 +2,11 @@ import {
2
2
  classifyErrorArea,
3
3
  isInteractive,
4
4
  promptYesNo
5
- } from "./chunk-RVCY2VEY.js";
5
+ } from "./chunk-TTSFL3JB.js";
6
6
  import {
7
7
  VERSION,
8
8
  getCurrentSentryTraceId
9
- } from "./chunk-LOZ5PSD3.js";
9
+ } from "./chunk-MRB5E7YM.js";
10
10
 
11
11
  // src/bug-report.ts
12
12
  import { execSync, execFileSync } from "child_process";
@@ -1,6 +1,9 @@
1
+ import {
2
+ merkleizeJS
3
+ } from "./chunk-B7GUYYAN.js";
1
4
  import {
2
5
  setDeployContext
3
- } from "./chunk-N2OZLFJA.js";
6
+ } from "./chunk-Y54W6NVZ.js";
4
7
  import {
5
8
  DotNS,
6
9
  TX_TIMEOUT_MS,
@@ -8,7 +11,23 @@ import {
8
11
  parseDomainName,
9
12
  popStatusName,
10
13
  verifyNonceAdvanced
11
- } from "./chunk-7WKHLBZA.js";
14
+ } from "./chunk-RBFXJVAG.js";
15
+ import {
16
+ derivePoolAccounts,
17
+ detectTestnet,
18
+ ensureAuthorized,
19
+ fetchPoolAuthorizations,
20
+ selectAccount,
21
+ topUpBy
22
+ } from "./chunk-VOEFHED3.js";
23
+ import {
24
+ DEFAULT_ENV_ID,
25
+ loadEnvironments,
26
+ resolveEndpoints
27
+ } from "./chunk-2VYG7NXN.js";
28
+ import {
29
+ NonRetryableError
30
+ } from "./chunk-ZOC4GITL.js";
12
31
  import {
13
32
  MirrorSkipped,
14
33
  mirrorToGitHubPages,
@@ -27,18 +46,7 @@ import {
27
46
  truncateAddress,
28
47
  withDeploySpan,
29
48
  withSpan
30
- } from "./chunk-LOZ5PSD3.js";
31
- import {
32
- merkleizeJS
33
- } from "./chunk-B7GUYYAN.js";
34
- import {
35
- derivePoolAccounts,
36
- detectTestnet,
37
- ensureAuthorized,
38
- fetchPoolAuthorizations,
39
- selectAccount,
40
- topUpBy
41
- } from "./chunk-VOEFHED3.js";
49
+ } from "./chunk-MRB5E7YM.js";
42
50
 
43
51
  // src/deploy.ts
44
52
  import { Buffer } from "buffer";
@@ -61,13 +69,6 @@ import { cryptoWaitReady } from "@polkadot/util-crypto";
61
69
  import { getPolkadotSigner } from "polkadot-api/signer";
62
70
  import { sr25519CreateDerive } from "@polkadot-labs/hdkd";
63
71
  import { mnemonicToEntropy, entropyToMiniSecret, ss58Address } from "@polkadot-labs/hdkd-helpers";
64
- var NonRetryableError = class extends Error {
65
- constructor(message) {
66
- super(message);
67
- this.name = "NonRetryableError";
68
- }
69
- };
70
- var EXIT_CODE_NO_RETRY = 78;
71
72
  function friendlyChainError(msg) {
72
73
  if (/"type":\s*"Invalid"[\s\S]*?"type":\s*"Payment"/i.test(msg)) {
73
74
  return "Bulletin quota exhausted (signed extension rejected the tx \u2014 signer is out of allowed txs or bytes; grant quota on-chain)";
@@ -368,6 +369,7 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
368
369
  throw new Error(`Connection lost and max reconnections (${MAX_RECONNECTIONS}) exhausted`);
369
370
  }
370
371
  reconnectionsUsed++;
372
+ setDeployAttribute("deploy.reconnects", reconnectionsUsed);
371
373
  const delay = Math.min(RETRY_BASE_DELAY_MS * Math.pow(2, reconnectionsUsed - 1), RETRY_MAX_DELAY_MS);
372
374
  console.log(`
373
375
  Connection lost, reconnecting to Bulletin in ${(delay / 1e3).toFixed(0)}s (${reconnectionsUsed}/${MAX_RECONNECTIONS})...`);
@@ -639,7 +641,7 @@ async function storeDirectory(directoryPath, providerOrOptions = {}, password, j
639
641
  totalSize: `${(carContent.length / 1024 / 1024).toFixed(2)} MB`
640
642
  });
641
643
  const carMb = String(Math.round(carContent.length / 1024 / 1024 * 100) / 100);
642
- const storageCid = await withSpan("deploy.chunk-upload", "1b. chunk-upload", { "deploy.chunks.total": String(carChunks.length), "deploy.car.bytes": String(carContent.length), "deploy.car.mb": carMb }, async () => {
644
+ const storageCid = await withSpan("deploy.chunk-upload", "1b. chunk-upload", { "deploy.chunks.total": carChunks.length, "deploy.car.bytes": carContent.length, "deploy.car.mb": carMb }, async () => {
643
645
  sampleMemory("chunk_upload_start");
644
646
  const r = await storeChunkedContent(carChunks, provider);
645
647
  sampleMemory("chunk_upload_end");
@@ -653,11 +655,12 @@ async function storeDirectory(directoryPath, providerOrOptions = {}, password, j
653
655
  }
654
656
  return { storageCid, ipfsCid, carBytes: carContent };
655
657
  }
656
- function resolveDotnsConnectOptions(options) {
658
+ function resolveDotnsConnectOptions(options, assetHubEndpoints) {
659
+ const tail = assetHubEndpoints && assetHubEndpoints.length > 0 ? { assetHubEndpoints } : {};
657
660
  if (options.signer && options.signerAddress) {
658
- return { signer: options.signer, signerAddress: options.signerAddress };
661
+ return { signer: options.signer, signerAddress: options.signerAddress, ...tail };
659
662
  }
660
- return { mnemonic: options.mnemonic, derivationPath: options.derivationPath };
663
+ return { mnemonic: options.mnemonic, derivationPath: options.derivationPath, ...tail };
661
664
  }
662
665
  async function estimateUploadBytes(content) {
663
666
  try {
@@ -686,8 +689,29 @@ async function estimateUploadBytes(content) {
686
689
  }
687
690
  }
688
691
  async function deploy(content, domainName = null, options = {}) {
692
+ const envId = options.env ?? DEFAULT_ENV_ID;
693
+ let envBulletin = [DEFAULT_BULLETIN_RPC];
694
+ let envAssetHub;
695
+ let envSource;
696
+ let envNetwork;
697
+ if (options.bulletinEndpoints && options.bulletinEndpoints.length > 0) {
698
+ envBulletin = options.bulletinEndpoints;
699
+ envAssetHub = options.assetHubEndpoints;
700
+ } else {
701
+ try {
702
+ const { doc, source } = await loadEnvironments();
703
+ const resolved = resolveEndpoints(doc, envId);
704
+ envBulletin = resolved.bulletin;
705
+ envAssetHub = options.assetHubEndpoints ?? resolved.assetHub;
706
+ envSource = source;
707
+ envNetwork = resolved.network;
708
+ } catch (e) {
709
+ if (e instanceof NonRetryableError) throw e;
710
+ captureWarning(`environments load failed: ${e?.message ?? e}`);
711
+ }
712
+ }
689
713
  const userRpc = options.rpc ?? process.env.BULLETIN_RPC;
690
- BULLETIN_ENDPOINTS = userRpc ? [userRpc, ...[DEFAULT_BULLETIN_RPC].filter((e) => e !== userRpc)] : [DEFAULT_BULLETIN_RPC];
714
+ BULLETIN_ENDPOINTS = userRpc ? [userRpc, ...envBulletin.filter((e) => e !== userRpc)] : envBulletin;
691
715
  _deployRpcFailedOver = false;
692
716
  POOL_SIZE = options.poolSize ?? parseInt(process.env.BULLETIN_POOL_SIZE ?? String(DEFAULT_POOL_SIZE), 10);
693
717
  initTelemetry();
@@ -700,6 +724,9 @@ async function deploy(content, domainName = null, options = {}) {
700
724
  setDeployAttribute("deploy.tag", deployTag);
701
725
  setDeploySentryTag("deploy.tag", deployTag);
702
726
  }
727
+ setDeployAttribute("deploy.env", envId);
728
+ if (envNetwork) setDeployAttribute("deploy.network", envNetwork);
729
+ if (envSource) setDeployAttribute("deploy.environments_source", envSource);
703
730
  let cid;
704
731
  let ipfsCid;
705
732
  let mirrorPromise = Promise.resolve(null);
@@ -719,7 +746,7 @@ async function deploy(content, domainName = null, options = {}) {
719
746
  console.log("Preflight");
720
747
  console.log("=".repeat(60));
721
748
  const preflight = new DotNS();
722
- await preflight.connect(resolveDotnsConnectOptions(options));
749
+ await preflight.connect(resolveDotnsConnectOptions(options, envAssetHub));
723
750
  if (parsed?.isSubdomain) {
724
751
  try {
725
752
  const { owned: subOwned } = await preflight.checkSubdomainOwnership(parsed.sublabel, parsed.parentLabel);
@@ -868,7 +895,7 @@ async function deploy(content, domainName = null, options = {}) {
868
895
  console.log("=".repeat(60));
869
896
  await withSpan("deploy.dotns", "2. dotns", { "deploy.domain": name, "deploy.subdomain": String(parsed?.isSubdomain ?? false) }, async () => {
870
897
  const dotns = new DotNS();
871
- await dotns.connect(resolveDotnsConnectOptions(options));
898
+ await dotns.connect(resolveDotnsConnectOptions(options, envAssetHub));
872
899
  if (parsed?.isSubdomain) {
873
900
  const { owned, owner } = await dotns.checkSubdomainOwnership(parsed.sublabel, parsed.parentLabel);
874
901
  if (owned) {
@@ -950,8 +977,6 @@ async function deploy(content, domainName = null, options = {}) {
950
977
  }
951
978
 
952
979
  export {
953
- NonRetryableError,
954
- EXIT_CODE_NO_RETRY,
955
980
  friendlyChainError,
956
981
  DEFAULT_BULLETIN_RPC,
957
982
  DEFAULT_POOL_SIZE,
@@ -0,0 +1,13 @@
1
+ // src/errors.ts
2
+ var NonRetryableError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "NonRetryableError";
6
+ }
7
+ };
8
+ var EXIT_CODE_NO_RETRY = 78;
9
+
10
+ export {
11
+ NonRetryableError,
12
+ EXIT_CODE_NO_RETRY
13
+ };
package/dist/deploy.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { CID } from 'multiformats/cid';
2
2
  import { PolkadotSigner } from 'polkadot-api';
3
+ export { EXIT_CODE_NO_RETRY, NonRetryableError } from './errors.js';
3
4
 
4
5
  interface DeployResult {
5
6
  domainName: string;
@@ -8,10 +9,7 @@ interface DeployResult {
8
9
  ipfsCid?: string;
9
10
  }
10
11
  type DeployContent = string | Uint8Array | Uint8Array[];
11
- declare class NonRetryableError extends Error {
12
- constructor(message: string);
13
- }
14
- declare const EXIT_CODE_NO_RETRY = 78;
12
+
15
13
  declare function friendlyChainError(msg: string): string;
16
14
  interface ProviderResult {
17
15
  client: any;
@@ -105,14 +103,30 @@ interface DeployOptions {
105
103
  name?: string;
106
104
  /** When set, writes the "description" text record. ≤100 chars recommended for host-app cards. */
107
105
  description?: string;
106
+ /**
107
+ * Environment id from environments.json (e.g. "paseo-next", "paseo-review").
108
+ * Drives both the bulletin RPC and the asset-hub RPC. Defaults to
109
+ * DEFAULT_ENV_ID. `--rpc` / BULLETIN_RPC still override the bulletin endpoint
110
+ * within the chosen env.
111
+ */
112
+ env?: string;
113
+ /**
114
+ * Pre-resolved bulletin endpoints (escape hatch for tests / library callers
115
+ * that want to skip environments.json loading). When provided, the loader
116
+ * is not called and `env` is ignored.
117
+ */
118
+ bulletinEndpoints?: string[];
119
+ /** Pre-resolved asset-hub endpoints. Same escape-hatch semantics. */
120
+ assetHubEndpoints?: string[];
108
121
  }
109
- declare function resolveDotnsConnectOptions(options: Pick<DeployOptions, "mnemonic" | "derivationPath" | "signer" | "signerAddress">): {
122
+ declare function resolveDotnsConnectOptions(options: Pick<DeployOptions, "mnemonic" | "derivationPath" | "signer" | "signerAddress">, assetHubEndpoints?: string[]): {
110
123
  signer?: PolkadotSigner;
111
124
  signerAddress?: string;
112
125
  mnemonic?: string;
113
126
  derivationPath?: string;
127
+ assetHubEndpoints?: string[];
114
128
  };
115
129
  declare function estimateUploadBytes(content: DeployContent): Promise<number | null>;
116
130
  declare function deploy(content: DeployContent, domainName?: string | null, options?: DeployOptions): Promise<DeployResult>;
117
131
 
118
- export { CHUNK_MORTALITY_PERIOD, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, type DeployContent, type DeployOptions, type DeployResult, ENCRYPT_KEY_LEN, ENCRYPT_MAGIC, ENCRYPT_NONCE_LEN, ENCRYPT_PBKDF2_ITERATIONS, ENCRYPT_SALT_LEN, ENCRYPT_TAG_LEN, EXIT_CODE_NO_RETRY, NonRetryableError, type StoreDirectoryOptions, chunk, computeStorageCid, createCID, deploy, deriveRootSigner, encodeContenthash, encryptContent, estimateUploadBytes, friendlyChainError, hasIPFS, isConnectionError, merkleize, resolveDotnsConnectOptions, storeChunkedContent, storeDirectory, storeFile };
132
+ export { CHUNK_MORTALITY_PERIOD, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, type DeployContent, type DeployOptions, type DeployResult, ENCRYPT_KEY_LEN, ENCRYPT_MAGIC, ENCRYPT_NONCE_LEN, ENCRYPT_PBKDF2_ITERATIONS, ENCRYPT_SALT_LEN, ENCRYPT_TAG_LEN, type StoreDirectoryOptions, chunk, computeStorageCid, createCID, deploy, deriveRootSigner, encodeContenthash, encryptContent, estimateUploadBytes, friendlyChainError, hasIPFS, isConnectionError, merkleize, resolveDotnsConnectOptions, storeChunkedContent, storeDirectory, storeFile };
package/dist/deploy.js CHANGED
@@ -8,8 +8,6 @@ import {
8
8
  ENCRYPT_PBKDF2_ITERATIONS,
9
9
  ENCRYPT_SALT_LEN,
10
10
  ENCRYPT_TAG_LEN,
11
- EXIT_CODE_NO_RETRY,
12
- NonRetryableError,
13
11
  chunk,
14
12
  computeStorageCid,
15
13
  createCID,
@@ -26,15 +24,20 @@ import {
26
24
  storeChunkedContent,
27
25
  storeDirectory,
28
26
  storeFile
29
- } from "./chunk-WK2GKDMX.js";
30
- import "./chunk-N2OZLFJA.js";
31
- import "./chunk-RVCY2VEY.js";
32
- import "./chunk-7WKHLBZA.js";
33
- import "./chunk-HOTQDYHD.js";
34
- import "./chunk-LOZ5PSD3.js";
35
- import "./chunk-VQJLGE5J.js";
27
+ } from "./chunk-YX5USCHH.js";
36
28
  import "./chunk-B7GUYYAN.js";
29
+ import "./chunk-Y54W6NVZ.js";
30
+ import "./chunk-TTSFL3JB.js";
31
+ import "./chunk-RBFXJVAG.js";
37
32
  import "./chunk-VOEFHED3.js";
33
+ import "./chunk-2VYG7NXN.js";
34
+ import {
35
+ EXIT_CODE_NO_RETRY,
36
+ NonRetryableError
37
+ } from "./chunk-ZOC4GITL.js";
38
+ import "./chunk-HOTQDYHD.js";
39
+ import "./chunk-MRB5E7YM.js";
40
+ import "./chunk-KU6N5DD3.js";
38
41
  import "./chunk-QGM4M3NI.js";
39
42
  export {
40
43
  CHUNK_MORTALITY_PERIOD,
package/dist/dotns.d.ts CHANGED
@@ -1,12 +1,33 @@
1
1
  import { PolkadotSigner } from 'polkadot-api';
2
2
 
3
+ type DotnsCliInvocationSource = "package" | "host-dispatch" | "host-dispatch-fallback" | "command-override";
4
+ interface DotnsCliInvocation {
5
+ command: string;
6
+ argsPrefix: string[];
7
+ version: string;
8
+ source: DotnsCliInvocationSource;
9
+ resolutionError?: string;
10
+ }
11
+ interface DotnsCliPackageResolution {
12
+ path: string;
13
+ version: string;
14
+ }
15
+ declare function resolveDotnsCliInvocation(env?: NodeJS.ProcessEnv | Record<string, string | undefined>, packageResolver?: () => DotnsCliPackageResolution): DotnsCliInvocation;
3
16
  interface DotNSConnectOptions {
4
17
  rpc?: string;
5
18
  keyUri?: string;
6
19
  mnemonic?: string;
7
20
  derivationPath?: string;
8
21
  signer?: PolkadotSigner;
9
- signerAddress?: string;
22
+ signerAddress?: string; /**
23
+ * Optional override for the Asset Hub RPC failover list. When provided, the
24
+ * primary RPC (this.rpc) is followed by these endpoints for retries. When
25
+ * omitted, the legacy hardcoded RPC_ENDPOINTS list (paseo) is used —
26
+ * preserves backwards-compatibility for external library consumers. The
27
+ * bulletin-deploy CLI passes the list resolved from environments.json so
28
+ * `--env <id>` drives both bulletin and asset-hub endpoints.
29
+ */
30
+ assetHubEndpoints?: string[];
10
31
  }
11
32
  interface OwnershipResult {
12
33
  owned: boolean;
@@ -157,6 +178,7 @@ declare class DotNS {
157
178
  evmAddress: string | null;
158
179
  signer: PolkadotSigner | null;
159
180
  connected: boolean;
181
+ assetHubEndpoints: string[];
160
182
  private _mnemonic;
161
183
  private _keyUri;
162
184
  private _usesExternalSigner;
@@ -219,4 +241,4 @@ declare class DotNS {
219
241
  }
220
242
  declare const dotns: DotNS;
221
243
 
222
- export { CONNECTION_TIMEOUT_MS, CONTRACTS, DECIMALS, DEFAULT_MNEMONIC, DOTNS_TX_MAX_ATTEMPTS, DOT_NODE, DotNS, type DotNSConnectOptions, type DotnsPreflightResult, type DotnsSuccessAction, NATIVE_TO_ETH_RATIO, OPERATION_TIMEOUT_MS, type OwnershipResult, type ParsedDomainName, type PriceValidationResult, ProofOfPersonhoodStatus, RPC_ENDPOINTS, TX_CHAIN_TIME_BUDGET_MS, TX_TIMEOUT_MS, TX_WALL_CLOCK_CEILING_MS, WS_HEARTBEAT_TIMEOUT_MS, canRegister, classifyDotnsLabel, classifyTxRetryDecision, computeDomainTokenId, convertWeiToNative, countTrailingDigits, dotns, feeFloorFor, fetchNonce, fmtPas, isCommitmentMature, isExplicitCommitmentBuffer, parseDomainName, parseProofOfPersonhoodStatus, popStatusName, runDotnsCli, sanitizeDomainLabel, simulateUserStatus, stripTrailingDigits, validateDomainLabel, verifyNonceAdvanced };
244
+ export { CONNECTION_TIMEOUT_MS, CONTRACTS, DECIMALS, DEFAULT_MNEMONIC, DOTNS_TX_MAX_ATTEMPTS, DOT_NODE, DotNS, type DotNSConnectOptions, type DotnsCliInvocation, type DotnsCliInvocationSource, type DotnsPreflightResult, type DotnsSuccessAction, NATIVE_TO_ETH_RATIO, OPERATION_TIMEOUT_MS, type OwnershipResult, type ParsedDomainName, type PriceValidationResult, ProofOfPersonhoodStatus, RPC_ENDPOINTS, TX_CHAIN_TIME_BUDGET_MS, TX_TIMEOUT_MS, TX_WALL_CLOCK_CEILING_MS, WS_HEARTBEAT_TIMEOUT_MS, canRegister, classifyDotnsLabel, classifyTxRetryDecision, computeDomainTokenId, convertWeiToNative, countTrailingDigits, dotns, feeFloorFor, fetchNonce, fmtPas, isCommitmentMature, isExplicitCommitmentBuffer, parseDomainName, parseProofOfPersonhoodStatus, popStatusName, resolveDotnsCliInvocation, runDotnsCli, sanitizeDomainLabel, simulateUserStatus, stripTrailingDigits, validateDomainLabel, verifyNonceAdvanced };
package/dist/dotns.js CHANGED
@@ -29,16 +29,17 @@ import {
29
29
  parseDomainName,
30
30
  parseProofOfPersonhoodStatus,
31
31
  popStatusName,
32
+ resolveDotnsCliInvocation,
32
33
  runDotnsCli,
33
34
  sanitizeDomainLabel,
34
35
  simulateUserStatus,
35
36
  stripTrailingDigits,
36
37
  validateDomainLabel,
37
38
  verifyNonceAdvanced
38
- } from "./chunk-7WKHLBZA.js";
39
- import "./chunk-LOZ5PSD3.js";
40
- import "./chunk-VQJLGE5J.js";
39
+ } from "./chunk-RBFXJVAG.js";
41
40
  import "./chunk-VOEFHED3.js";
41
+ import "./chunk-MRB5E7YM.js";
42
+ import "./chunk-KU6N5DD3.js";
42
43
  import "./chunk-QGM4M3NI.js";
43
44
  export {
44
45
  CONNECTION_TIMEOUT_MS,
@@ -71,6 +72,7 @@ export {
71
72
  parseDomainName,
72
73
  parseProofOfPersonhoodStatus,
73
74
  popStatusName,
75
+ resolveDotnsCliInvocation,
74
76
  runDotnsCli,
75
77
  sanitizeDomainLabel,
76
78
  simulateUserStatus,