bulletin-deploy 0.7.24 → 0.7.25-rc.2

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 (36) hide show
  1. package/assets/environments.json +2 -0
  2. package/bin/bulletin-deploy +10 -1
  3. package/dist/bug-report.js +4 -4
  4. package/dist/{chunk-4V6HI3TA.js → chunk-7YMYSLR3.js} +1 -1
  5. package/dist/{chunk-LEYQOOWC.js → chunk-BO22ZDUF.js} +15 -10
  6. package/dist/{chunk-L7KXFYLH.js → chunk-E7JAPAUO.js} +35 -6
  7. package/dist/{chunk-K6RIDRB7.js → chunk-EANLP6ZJ.js} +2 -2
  8. package/dist/{chunk-5MRZ3V4A.js → chunk-JOHTUV2D.js} +99 -2
  9. package/dist/{chunk-5JHQZDWQ.js → chunk-Q7JW7TGW.js} +20 -1
  10. package/dist/{chunk-R6NLVFXP.js → chunk-R7ASM4G6.js} +94 -41
  11. package/dist/{chunk-N6AK5PSE.js → chunk-TQDCA3DN.js} +2 -2
  12. package/dist/{chunk-5VEZVLDN.js → chunk-Y3QD3VWR.js} +1 -1
  13. package/dist/{chunk-RZOZQ2AP.js → chunk-ZQL5AJQM.js} +114 -89
  14. package/dist/chunk-probe.js +3 -3
  15. package/dist/deploy.d.ts +18 -2
  16. package/dist/deploy.js +10 -10
  17. package/dist/dotns.d.ts +7 -8
  18. package/dist/dotns.js +9 -5
  19. package/dist/environments.d.ts +23 -1
  20. package/dist/environments.js +7 -3
  21. package/dist/incremental-stats.d.ts +2 -0
  22. package/dist/incremental-stats.js +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +15 -11
  25. package/dist/manifest-fetch.d.ts +10 -1
  26. package/dist/manifest-fetch.js +8 -3
  27. package/dist/manifest-roundtrip.js +2 -1
  28. package/dist/memory-report.js +2 -2
  29. package/dist/merkle.js +10 -10
  30. package/dist/personhood/bootstrap.js +4 -4
  31. package/dist/personhood/people-client.js +4 -4
  32. package/dist/run-state.js +1 -1
  33. package/dist/telemetry.js +2 -2
  34. package/dist/version-check.d.ts +4 -2
  35. package/dist/version-check.js +7 -3
  36. package/package.json +2 -2
@@ -9,6 +9,7 @@
9
9
  "ipfs": "https://previewnet.substrate.dev/ipfs/",
10
10
  "autoAccountMapping": true,
11
11
  "bulletinAuthorizeV2": true,
12
+ "registerStorageDeposit": 2000000000000,
12
13
  "contracts": {
13
14
  "DOTNS_PROTOCOL_REGISTRY": "0xc07A2F24387DA27283CD87b9F24573b74C9e0c9b",
14
15
  "DOTNS_REGISTRAR": "0x6c40817cdb96Ab57A4d9E9fa21D0eEa8307BDDE8",
@@ -56,6 +57,7 @@
56
57
  "autoAccountMapping": true,
57
58
  "bulletinAuthorizeV2": true,
58
59
  "nativeToEthRatio": 100000000,
60
+ "registerStorageDeposit": 2000000000000,
59
61
  "popSelfServe": {
60
62
  "sudoEnvLabel": "Next V2",
61
63
  "faucetUrl": "https://faucet.polkadot.io/?parachain=1500",
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { deploy, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, NonRetryableError, EXIT_CODE_NO_RETRY, isConnectionError } from "../dist/deploy.js";
4
4
  import { VERSION, setDeployAttribute, captureWarning, closeTelemetry, setRunStateActive, markRelaunchOomHintShown } from "../dist/telemetry.js";
5
- import { handleFailedDeploy, preReleaseWarning, checkNodeVersion } from "../dist/version-check.js";
5
+ import { handleFailedDeploy, handlePreflightVersionCheck, fetchVersionInfo, preReleaseWarning, checkNodeVersion } from "../dist/version-check.js";
6
6
  import { setDeployContext, installLogCapture, buildCliFlagsSummary } from "../dist/bug-report.js";
7
7
  import { loadRunState, writeRunState, shouldSkipStaleWarning, shouldShowOomHint, probablyOomRssMb } from "../dist/run-state.js";
8
8
  import { loadEnvironments, listEnvironments, formatEnvironmentTable, DEFAULT_ENV_ID } from "../dist/environments.js";
@@ -113,6 +113,11 @@ Options:
113
113
  const rcWarning = preReleaseWarning(VERSION);
114
114
  if (rcWarning) console.error(rcWarning);
115
115
 
116
+ // Fire in background immediately; await just before deploy() to stay non-blocking during flag-parse.
117
+ const _versionCheckPromise = process.env.BULLETIN_DEPLOY_UPDATE_CHECK !== "0"
118
+ ? fetchVersionInfo()
119
+ : Promise.resolve(null);
120
+
116
121
  // ── Crash capture (issue #154) ───────────────────────────────────
117
122
  // Only wire crash capture for actual deploy runs — skip for --help / --version
118
123
  // (which exit above).
@@ -251,6 +256,10 @@ try {
251
256
  ci,
252
257
  });
253
258
 
259
+ // Await the background version check started at startup.
260
+ const _versionInfo = await _versionCheckPromise;
261
+ if (handlePreflightVersionCheck(_versionInfo) === "abort") process.exit(1);
262
+
254
263
  const result = await deploy(buildDir, domain, {
255
264
  mnemonic: flags.mnemonic,
256
265
  derivationPath: flags.derivationPath,
@@ -9,10 +9,10 @@ import {
9
9
  offerBugReport,
10
10
  scrubSecrets,
11
11
  setDeployContext
12
- } from "./chunk-K6RIDRB7.js";
13
- import "./chunk-L7KXFYLH.js";
14
- import "./chunk-5VEZVLDN.js";
15
- import "./chunk-N6AK5PSE.js";
12
+ } from "./chunk-EANLP6ZJ.js";
13
+ import "./chunk-E7JAPAUO.js";
14
+ import "./chunk-Y3QD3VWR.js";
15
+ import "./chunk-TQDCA3DN.js";
16
16
  export {
17
17
  buildCliFlagsSummary,
18
18
  buildLabels,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  captureWarning
3
- } from "./chunk-5VEZVLDN.js";
3
+ } from "./chunk-Y3QD3VWR.js";
4
4
 
5
5
  // src/chunk-probe.ts
6
6
  import { Twox128, Blake2128Concat, decAnyMetadata, unifyMetadata } from "@polkadot-api/substrate-bindings";
@@ -25,6 +25,7 @@ function computeStats(input) {
25
25
  recycledCids: recycled.length,
26
26
  retentionPeriodBlocks: input.retentionPeriodBlocks,
27
27
  bytesProbePresent: input.bytesProbePresent,
28
+ bytesProbeAbsent: input.bytesProbeAbsent ?? 0,
28
29
  bytesSkipped: input.bytesSkipped,
29
30
  bytesUploaded: input.bytesUploaded,
30
31
  chunksTotal: input.chunksTotal,
@@ -64,6 +65,7 @@ function telemetryAttributes(s) {
64
65
  "deploy.cache.chunks_uploaded": String(s.chunksUploaded),
65
66
  "deploy.cache.chunks_skipped": String(s.chunksSkipped),
66
67
  "deploy.cache.bytes_probe_present": String(s.bytesProbePresent),
68
+ "deploy.cache.bytes_probe_absent": String(s.bytesProbeAbsent),
67
69
  "deploy.cache.bytes_skipped": String(s.bytesSkipped),
68
70
  "deploy.cache.bytes_uploaded": String(s.bytesUploaded),
69
71
  "deploy.cache.car_bytes": String(s.carBytes),
@@ -84,8 +86,9 @@ function fmtKb(bytes) {
84
86
  }
85
87
  function renderSummary(s) {
86
88
  const lines = [];
89
+ const attemptsWord = s.manifestFetchAttempts === 1 ? "attempt" : "attempts";
87
90
  if (s.manifestSource === "heuristic_fallback") {
88
- lines.push(` \u26A0 Previous manifest fetch failed after ${s.manifestFetchAttempts} attempts (gateway timeout).`);
91
+ lines.push(` \u26A0 Previous manifest fetch failed after ${s.manifestFetchAttempts} ${attemptsWord} (gateway timeout).`);
89
92
  lines.push(` Using heuristic classification \u2014 hit rate may be lower this run.`);
90
93
  lines.push(` Subsequent deploys recover automatically.`);
91
94
  lines.push("");
@@ -94,15 +97,15 @@ function renderSummary(s) {
94
97
  if (s.manifestSource === "none") {
95
98
  lines.push(` Manifest: first deploy (no previous manifest)`);
96
99
  } else if (s.manifestSource === "embedded") {
97
- const attemptsStr = `${s.manifestFetchAttempts} attempt${s.manifestFetchAttempts === 1 ? "" : "s"}`;
98
100
  const sizeStr = s.manifestBytes > 0 ? `, ${fmtKb(s.manifestBytes)} KB Range hit` : "";
99
- lines.push(` Manifest: embedded (${attemptsStr}${sizeStr})`);
101
+ lines.push(` Manifest: embedded (${s.manifestFetchAttempts} ${attemptsWord}${sizeStr})`);
100
102
  } else {
101
- lines.push(` Manifest: heuristic_fallback (${s.manifestFetchAttempts} attempts)`);
103
+ lines.push(` Manifest: heuristic_fallback (${s.manifestFetchAttempts} ${attemptsWord})`);
102
104
  }
103
105
  if (s.filesTotal > 0 && s.manifestSource !== "none") {
104
106
  const pct = s.filesTotal === 0 ? 0 : Math.round(s.filesStable / s.filesTotal * 100);
105
- lines.push(` Files: ${s.filesStable} unchanged, ${s.filesVolatile} changed (${pct} % stable)`);
107
+ const heuristicNote = s.manifestSource === "heuristic_fallback" ? " (heuristic estimate)" : "";
108
+ lines.push(` Files: ${s.filesStable} unchanged, ${s.filesVolatile} changed (${pct} % stable)${heuristicNote}`);
106
109
  }
107
110
  if (s.probedTotal > 0) {
108
111
  let probeFailedStr = "";
@@ -115,7 +118,7 @@ function renderSummary(s) {
115
118
  }
116
119
  lines.push(` Probed: ${s.probedTotal} chunks \u2192 ${s.probePresent} cached, ${s.probeAbsent} to upload${probeFailedStr}`);
117
120
  }
118
- if (s.recycledCids > 0) {
121
+ if (s.recycledCids > 0 && s.manifestSource === "embedded") {
119
122
  lines.push(` Recycled: ${s.recycledCids} CIDs found on-chain that weren't in the previous manifest`);
120
123
  }
121
124
  if (s.tier2FallbackCount > 0) {
@@ -123,10 +126,12 @@ function renderSummary(s) {
123
126
  lines.push(` Verify: ${s.tier2VerifiedCount}/${s.tier2FallbackCount} via-fallback chunks confirmed on chain${inconclusiveStr}`);
124
127
  }
125
128
  lines.push(` CAR sections: manifest ${fmtKb(s.section0Bytes)} KB \xB7 stable ${fmtMb(s.section1Bytes)} MB \xB7 volatile ${fmtMb(s.section2Bytes)} MB`);
126
- if (s.chunksUploaded > 0 && s.bytesSkipped > 0) {
127
- lines.push(` Upload: ${fmtMb(s.bytesUploaded)} MB across ${s.chunksUploaded} chunks (vs ${fmtMb(s.carBytes)} MB if full deploy)`);
128
- } else if (s.chunksUploaded > 0) {
129
- lines.push(` Upload: ${fmtMb(s.bytesUploaded)} MB across ${s.chunksUploaded} chunks`);
129
+ if (s.chunksUploaded > 0) {
130
+ if (s.bytesSkipped > 0) {
131
+ lines.push(` Upload: ${fmtMb(s.bytesUploaded)} MB across ${s.chunksUploaded} chunks (vs ${fmtMb(s.carBytes)} MB if full deploy)`);
132
+ } else {
133
+ lines.push(` Upload: ${fmtMb(s.bytesUploaded)} MB across ${s.chunksUploaded} chunks`);
134
+ }
130
135
  }
131
136
  if (s.estimatedSecondsSaved > 0 || s.bytesSkipped > 0) {
132
137
  lines.push(` Saved: ~${s.estimatedSecondsSaved} s and ${fmtMb(s.bytesSkipped)} MB`);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-5VEZVLDN.js";
3
+ } from "./chunk-Y3QD3VWR.js";
4
4
 
5
5
  // src/version-check.ts
6
6
  import { execSync, execFileSync } from "child_process";
@@ -70,15 +70,42 @@ async function fetchVersionInfo() {
70
70
  killSwitchMessage: killSwitch?.message ?? null
71
71
  };
72
72
  }
73
- function isInternalUser() {
73
+ function handlePreflightVersionCheck(info) {
74
+ if (!info) return "ok";
75
+ const effectiveMinimum = [info.minimumFromRegistry, info.minimumFromKillSwitch].filter(Boolean).sort((a, b) => compareSemver(b, a))[0] ?? null;
76
+ if (effectiveMinimum && compareSemver(VERSION, effectiveMinimum) < 0) {
77
+ console.error(`
78
+ bulletin-deploy ${VERSION} is no longer supported (minimum: ${effectiveMinimum}).`);
79
+ const ks = info.killSwitchMessage;
80
+ if (ks) console.error(` Reason: ${ks}`);
81
+ console.error(` Please update: npm install -g bulletin-deploy@latest
82
+ `);
83
+ return "abort";
84
+ }
85
+ if (compareSemver(VERSION, info.latest) < 0) {
86
+ console.error(`
87
+ A newer version of bulletin-deploy is available (${VERSION} \u2192 ${info.latest}).`);
88
+ console.error(` Run: npm install -g bulletin-deploy@latest
89
+ `);
90
+ return "nudge";
91
+ }
92
+ return "ok";
93
+ }
94
+ function isInternalUser(cwd) {
74
95
  const repo = process.env.GITHUB_REPOSITORY;
75
96
  if (repo?.startsWith("paritytech/")) return true;
97
+ const opts = { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], ...cwd ? { cwd } : {} };
98
+ try {
99
+ const remote = execSync("git remote get-url origin", opts).trim();
100
+ if (remote.includes("paritytech/")) return true;
101
+ } catch {
102
+ }
76
103
  try {
77
- const remote = execSync("git remote get-url origin", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
78
- return remote.includes("paritytech/");
104
+ const email = execSync("git config user.email", opts).trim();
105
+ if (email.endsWith("@parity.io")) return true;
79
106
  } catch {
80
- return false;
81
107
  }
108
+ return false;
82
109
  }
83
110
  function isInteractive() {
84
111
  return Boolean(process.stdin.isTTY && !process.env.CI);
@@ -168,7 +195,7 @@ async function handleFailedDeploy(error) {
168
195
  `);
169
196
  break;
170
197
  case "suggest_update":
171
- if (verdict.internal && isInteractive()) {
198
+ if (isInteractive()) {
172
199
  const yes = await promptYesNo(`
173
200
  bulletin-deploy ${verdict.currentVersion} \u2192 ${verdict.latestVersion} available. Update and retry? [Y/n] `);
174
201
  if (yes) updateAndRetry();
@@ -194,6 +221,8 @@ export {
194
221
  compareSemver,
195
222
  isPreReleaseVersion,
196
223
  preReleaseWarning,
224
+ fetchVersionInfo,
225
+ handlePreflightVersionCheck,
197
226
  isInternalUser,
198
227
  isInteractive,
199
228
  promptYesNo,
@@ -2,11 +2,11 @@ import {
2
2
  classifyErrorArea,
3
3
  isInteractive,
4
4
  promptYesNo
5
- } from "./chunk-L7KXFYLH.js";
5
+ } from "./chunk-E7JAPAUO.js";
6
6
  import {
7
7
  VERSION,
8
8
  getCurrentSentryTraceId
9
- } from "./chunk-5VEZVLDN.js";
9
+ } from "./chunk-Y3QD3VWR.js";
10
10
 
11
11
  // src/bug-report.ts
12
12
  import { execSync, execFileSync } from "child_process";
@@ -1,15 +1,24 @@
1
1
  import {
2
2
  MANIFEST_DIR,
3
3
  MANIFEST_FILENAME,
4
+ MANIFEST_PATH,
4
5
  parseManifest
5
6
  } from "./chunk-S7EM5VMW.js";
7
+ import {
8
+ mirrorUrl,
9
+ normalizeDomainFilename,
10
+ resolveOwnerRepo
11
+ } from "./chunk-HOTQDYHD.js";
6
12
 
7
13
  // src/manifest-fetch.ts
14
+ import * as fs from "fs";
15
+ import * as path from "path";
8
16
  import { CarReader } from "@ipld/car/reader";
9
17
  import * as dagPB from "@ipld/dag-pb";
10
18
  import { CID } from "multiformats/cid";
11
19
  var DEFAULT_GATEWAY = "https://paseo-ipfs.polkadot.io";
12
20
  var DEFAULT_TIMEOUT_MS = 5e3;
21
+ var SIDECAR_FILENAME = ".last_deploy_cid";
13
22
  var RANGE_TIERS = [
14
23
  "bytes=0-4095",
15
24
  "bytes=0-65535",
@@ -17,6 +26,67 @@ var RANGE_TIERS = [
17
26
  void 0
18
27
  // full body
19
28
  ];
29
+ function readLocalManifest(buildDir, prevContenthash) {
30
+ const sidePath = path.join(buildDir, MANIFEST_DIR, SIDECAR_FILENAME);
31
+ try {
32
+ const lastCid = fs.readFileSync(sidePath, "utf8").trim();
33
+ if (lastCid !== prevContenthash) return null;
34
+ } catch {
35
+ return null;
36
+ }
37
+ const manifestPath = path.join(buildDir, MANIFEST_PATH);
38
+ let text;
39
+ try {
40
+ text = fs.readFileSync(manifestPath, "utf8");
41
+ } catch {
42
+ return null;
43
+ }
44
+ const parsed = parseManifest(text);
45
+ if (!parsed.ok) return null;
46
+ return {
47
+ source: "embedded",
48
+ manifest: parsed.manifest,
49
+ attempts: 0,
50
+ bytesDownloaded: text.length
51
+ };
52
+ }
53
+ async function fetchFromGitHubPages(domain, prevContenthash, options, start) {
54
+ let ownerRepo;
55
+ try {
56
+ ownerRepo = resolveOwnerRepo(process.cwd());
57
+ } catch {
58
+ return null;
59
+ }
60
+ if (!ownerRepo) return null;
61
+ const { owner, repo } = ownerRepo;
62
+ let domainFilename;
63
+ try {
64
+ domainFilename = normalizeDomainFilename(domain);
65
+ } catch {
66
+ return null;
67
+ }
68
+ const carUrl = mirrorUrl(owner, repo, domainFilename);
69
+ const sidecarUrl = carUrl.replace(/\.car$/, ".json");
70
+ const budget = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
71
+ try {
72
+ const sidecarBudget = Math.min(2e3, budget - (Date.now() - start));
73
+ if (sidecarBudget <= 0) return null;
74
+ const ctrl = new AbortController();
75
+ const timer = setTimeout(() => ctrl.abort(), sidecarBudget);
76
+ let sidecarRes;
77
+ try {
78
+ sidecarRes = await fetch(sidecarUrl, { signal: ctrl.signal });
79
+ } finally {
80
+ clearTimeout(timer);
81
+ }
82
+ if (!sidecarRes.ok) return null;
83
+ const sidecar = await sidecarRes.json();
84
+ if (sidecar.cid !== prevContenthash) return null;
85
+ } catch {
86
+ return null;
87
+ }
88
+ return fetchAcrossTiers(carUrl, budget, start);
89
+ }
20
90
  async function fetchAcrossTiers(url, budget, start) {
21
91
  let lastReason = "unknown";
22
92
  let attempts = 0;
@@ -91,9 +161,34 @@ async function fetchAcrossTiers(url, budget, start) {
91
161
  }
92
162
  async function fetchPreviousManifest(prevContenthash, options = {}) {
93
163
  if (prevContenthash === null) return { source: "none" };
94
- const gatewayList = (options.gateways ?? (options.gateway ? [options.gateway] : [DEFAULT_GATEWAY])).map((g) => g.replace(/\/$/, ""));
95
- const budget = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
164
+ if (options.buildDir) {
165
+ const local = readLocalManifest(options.buildDir, prevContenthash);
166
+ if (local) return local;
167
+ }
96
168
  const start = Date.now();
169
+ const budget = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
170
+ if (options.domain) {
171
+ const ghResult = await fetchFromGitHubPages(options.domain, prevContenthash, options, start);
172
+ if (ghResult) {
173
+ if (ghResult.outcome === "success") {
174
+ return {
175
+ source: "embedded",
176
+ manifest: ghResult.manifest,
177
+ attempts: ghResult.attempts,
178
+ bytesDownloaded: ghResult.bytesDownloaded
179
+ };
180
+ }
181
+ if (ghResult.outcome === "404" || ghResult.outcome === "parse_error") {
182
+ return {
183
+ source: "heuristic_fallback",
184
+ reason: ghResult.outcome === "404" ? "gh-pages 404" : ghResult.reason,
185
+ attempts: ghResult.attempts,
186
+ bytesDownloaded: ghResult.bytesDownloaded
187
+ };
188
+ }
189
+ }
190
+ }
191
+ const gatewayList = (options.gateways ?? (options.gateway ? [options.gateway] : [DEFAULT_GATEWAY])).map((g) => g.replace(/\/$/, ""));
97
192
  let lastReason = "unknown";
98
193
  let totalAttempts = 0;
99
194
  let bytesDownloaded = 0;
@@ -166,6 +261,8 @@ async function extractManifestFromCar(carBytes) {
166
261
  export {
167
262
  DEFAULT_GATEWAY,
168
263
  DEFAULT_TIMEOUT_MS,
264
+ SIDECAR_FILENAME,
265
+ readLocalManifest,
169
266
  fetchPreviousManifest,
170
267
  extractManifestFromCar
171
268
  };
@@ -18,6 +18,7 @@ var environments_default = {
18
18
  ipfs: "https://previewnet.substrate.dev/ipfs/",
19
19
  autoAccountMapping: true,
20
20
  bulletinAuthorizeV2: true,
21
+ registerStorageDeposit: 2e12,
21
22
  contracts: {
22
23
  DOTNS_PROTOCOL_REGISTRY: "0xc07A2F24387DA27283CD87b9F24573b74C9e0c9b",
23
24
  DOTNS_REGISTRAR: "0x6c40817cdb96Ab57A4d9E9fa21D0eEa8307BDDE8",
@@ -65,6 +66,7 @@ var environments_default = {
65
66
  autoAccountMapping: true,
66
67
  bulletinAuthorizeV2: true,
67
68
  nativeToEthRatio: 1e8,
69
+ registerStorageDeposit: 2e12,
68
70
  popSelfServe: {
69
71
  sudoEnvLabel: "Next V2",
70
72
  faucetUrl: "https://faucet.polkadot.io/?parachain=1500",
@@ -362,6 +364,20 @@ var HARDCODED_FALLBACK = {
362
364
  function defaultBundledPath() {
363
365
  return fileURLToPath(new URL("../assets/environments.json", import.meta.url));
364
366
  }
367
+ var EVM_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/i;
368
+ var ZERO_ADDRESS = "0x" + "0".repeat(40);
369
+ function isValidContractAddress(addr) {
370
+ return typeof addr === "string" && EVM_ADDRESS_RE.test(addr) && addr.toLowerCase() !== ZERO_ADDRESS;
371
+ }
372
+ function validateContractAddresses(contracts, envId) {
373
+ for (const [name, addr] of Object.entries(contracts)) {
374
+ if (!isValidContractAddress(addr)) {
375
+ throw new Error(
376
+ `Invalid contract address for ${name} in environment ${envId}: ${addr}. Check assets/environments.json against https://github.com/paritytech/dotns#deployments`
377
+ );
378
+ }
379
+ }
380
+ }
365
381
  function isValidDoc(value) {
366
382
  if (!value || typeof value !== "object") return false;
367
383
  const v = value;
@@ -455,7 +471,8 @@ function resolveEndpoints(doc, envId) {
455
471
  autoAccountMapping: env.autoAccountMapping ?? false,
456
472
  bulletinAuthorizeV2: env.bulletinAuthorizeV2 ?? false,
457
473
  contracts: env.contracts ?? {},
458
- nativeToEthRatio: BigInt(env.nativeToEthRatio ?? 1e6)
474
+ nativeToEthRatio: BigInt(env.nativeToEthRatio ?? 1e6),
475
+ ...env.registerStorageDeposit !== void 0 ? { registerStorageDeposit: BigInt(env.registerStorageDeposit) } : {}
459
476
  };
460
477
  }
461
478
  function getPopSelfServeConfig(doc, envId) {
@@ -495,6 +512,8 @@ function formatEnvironmentTable(rows) {
495
512
  export {
496
513
  DEFAULT_ENV_ID,
497
514
  defaultBundledPath,
515
+ isValidContractAddress,
516
+ validateContractAddresses,
498
517
  loadEnvironments,
499
518
  resolveEndpoints,
500
519
  getPopSelfServeConfig,