bulletin-deploy 0.7.18-rc.1 → 0.7.19

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,9 @@
6
6
  "network": "testnet",
7
7
  "description": "Product Preview net, used by Product Teams",
8
8
  "backend": "https://polkadot-app-stg.parity.io/",
9
- "ipfs": "https://previewnet.substrate.dev/ipfs/"
9
+ "ipfs": "https://previewnet.substrate.dev/ipfs/",
10
+ "autoAccountMapping": true,
11
+ "bulletinAuthorizeV2": true
10
12
  },
11
13
  {
12
14
  "id": "paseo-next",
@@ -34,19 +36,35 @@
34
36
  "description": "Next iteration of the Paseo Next testnet",
35
37
  "backend": "https://identity-backend-next.parity-testnet.parity.io",
36
38
  "ipfs": "https://paseo-bulletin-next-ipfs.polkadot.io",
37
- "docsUrl": "https://sre.teleport.parity.io/environments/paseo-next/"
39
+ "docsUrl": "https://sre.teleport.parity.io/environments/paseo-next/",
40
+ "autoAccountMapping": true,
41
+ "bulletinAuthorizeV2": true,
42
+ "nativeToEthRatio": 100000000,
43
+ "contracts": {
44
+ "DOTNS_REGISTRAR": "0xE67B22B285912FFfaE23BdfAc8C80c779d99B3e0",
45
+ "DOTNS_REGISTRAR_CONTROLLER": "0x8403e49Ec12F4EA5788f7bc0C0c2F649205774cC",
46
+ "DOTNS_REGISTRY": "0xDeFE1AAE21eC2455bd04b213a51C16d4b426c7ef",
47
+ "DOTNS_RESOLVER": "0xB436A271Beff1DBa6abDf2dbCc7E6d723d505EE6",
48
+ "DOTNS_CONTENT_RESOLVER": "0xBcFa907Ff85dFc62a21b41d48F23D7A73aC42914",
49
+ "DOTNS_REVERSE_RESOLVER": "0x4Ca32Dd0233D8c1B1709e20D9E4edBF2a77D21c3",
50
+ "POP_RULES": "0xd3F059FA65dA566B294b5d755a06054d4bE7ce7C",
51
+ "STORE_FACTORY": "0x4f1885fB6e0b154dCf9C2A8661e578B94aD50775"
52
+ },
53
+ "skipDotnsCli": true
38
54
  },
39
55
  {
40
56
  "id": "polkadot",
41
57
  "name": "Polkadot",
42
58
  "network": "mainnet",
43
- "description": "Polkadot mainnet"
59
+ "description": "Polkadot mainnet",
60
+ "autoAccountMapping": true
44
61
  },
45
62
  {
46
63
  "id": "kusama",
47
64
  "name": "Kusama",
48
65
  "network": "mainnet",
49
- "description": "Kusama canary network"
66
+ "description": "Kusama canary network",
67
+ "autoAccountMapping": true
50
68
  }
51
69
  ],
52
70
  "chains": [
@@ -260,4 +278,4 @@
260
278
  }
261
279
  ],
262
280
  "source": "https://docs.google.com/document/d/1xQoAmWDpbjhuXKT79DTNKFzv7ZkFr5npjo0BvrxXDIw"
263
- }
281
+ }
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import * as fs from "node:fs/promises";
4
+ import * as path from "node:path";
5
+ import { fileURLToPath } from "node:url";
3
6
  import { DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE } from "../dist/deploy.js";
4
7
  import { bootstrapPool } from "../dist/pool.js";
5
8
  import { VERSION } from "../dist/telemetry.js";
@@ -11,6 +14,7 @@ for (let i = 0; i < args.length; i++) {
11
14
  if (args[i] === "--pool-size") { flags.poolSize = parseInt(args[++i], 10); }
12
15
  else if (args[i] === "--mnemonic") { flags.mnemonic = args[++i]; }
13
16
  else if (args[i] === "--rpc") { flags.rpc = args[++i]; }
17
+ else if (args[i] === "--env") { flags.env = args[++i]; }
14
18
  else if (args[i] === "--version" || args[i] === "-V") { flags.version = true; }
15
19
  else if (args[i] === "--help" || args[i] === "-h") { flags.help = true; }
16
20
  else {
@@ -33,6 +37,7 @@ Usage:
33
37
  Options:
34
38
  --mnemonic "..." Pool root mnemonic (or set BULLETIN_POOL_MNEMONIC / MNEMONIC env var)
35
39
  --rpc wss://... Bulletin RPC (or set BULLETIN_RPC env var)
40
+ --env <id> Load environment by id from environments.json (sets default RPC and V2 flag)
36
41
  --pool-size N Number of pool accounts to initialize (default: 10)
37
42
  --version Show version
38
43
  --help Show this help
@@ -41,8 +46,39 @@ Initialize pool accounts for Bulletin storage authorization.`);
41
46
  process.exit(0);
42
47
  }
43
48
 
44
- const rpc = flags.rpc ?? process.env.BULLETIN_RPC ?? DEFAULT_BULLETIN_RPC;
49
+ let rpc = flags.rpc ?? process.env.BULLETIN_RPC ?? DEFAULT_BULLETIN_RPC;
45
50
  const poolSize = flags.poolSize ?? parseInt(process.env.BULLETIN_POOL_SIZE ?? String(DEFAULT_POOL_SIZE), 10);
46
51
  const mnemonic = flags.mnemonic ?? process.env.BULLETIN_POOL_MNEMONIC ?? process.env.MNEMONIC;
47
52
 
48
- await bootstrapPool(rpc, poolSize, mnemonic);
53
+ const bootstrapOpts = {};
54
+
55
+ if (flags.env) {
56
+ const envJsonPath = fileURLToPath(new URL("../assets/environments.json", import.meta.url));
57
+ let envDoc;
58
+ try {
59
+ const raw = await fs.readFile(envJsonPath, "utf8");
60
+ envDoc = JSON.parse(raw);
61
+ } catch (e) {
62
+ console.error(`Error: could not load environments.json: ${e.message}`);
63
+ process.exit(1);
64
+ }
65
+
66
+ const envEntry = envDoc.environments.find(e => e.id === flags.env);
67
+ if (!envEntry) {
68
+ const valid = envDoc.environments.map(e => e.id).join(", ");
69
+ console.error(`Error: unknown environment '${flags.env}'. Valid: ${valid}.`);
70
+ process.exit(1);
71
+ }
72
+
73
+ if (!flags.rpc) {
74
+ const bulletinChain = envDoc.chains.find(c => c.id === "bulletin");
75
+ const ep = bulletinChain?.endpoints?.[flags.env];
76
+ if (ep?.wss) {
77
+ rpc = Array.isArray(ep.wss) ? ep.wss[0] : ep.wss;
78
+ }
79
+ }
80
+
81
+ bootstrapOpts.bulletinAuthorizeV2 = envEntry.bulletinAuthorizeV2 ?? false;
82
+ }
83
+
84
+ await bootstrapPool(rpc, poolSize, mnemonic, bootstrapOpts);
@@ -5,7 +5,7 @@ import { VERSION, setDeployAttribute, captureWarning, closeTelemetry, setRunStat
5
5
  import { handleFailedDeploy, 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
- import { loadEnvironments, listEnvironments, formatEnvironmentTable, DEFAULT_ENV_ID, DEFAULT_ENVIRONMENTS_URL } from "../dist/environments.js";
8
+ import { loadEnvironments, listEnvironments, formatEnvironmentTable, DEFAULT_ENV_ID } from "../dist/environments.js";
9
9
  import { shouldMirrorToPaseoNextV2 } from "../dist/mirror.js";
10
10
  import * as fs from "fs";
11
11
 
@@ -33,7 +33,6 @@ for (let i = 0; i < args.length; i++) {
33
33
  else if (args[i] === "--rpc") { flags.rpc = args[++i]; }
34
34
  else if (args[i] === "--env") { flags.env = args[++i]; }
35
35
  else if (args[i] === "--list-environments") { flags.listEnvironments = true; }
36
- else if (args[i] === "--refresh-environments") { flags.refreshEnvironments = true; }
37
36
  else if (args[i] === "--password") { flags.password = args[++i]; }
38
37
  else if (args[i] === "--js-merkle") { flags.jsMerkle = true; }
39
38
  else if (args[i] === "--input-car") { flags.inputCar = args[++i]; }
@@ -44,6 +43,7 @@ for (let i = 0; i < args.length; i++) {
44
43
  else if (args[i] === "--allow-large-deploy") { flags.allowLargeDeploy = true; }
45
44
  else if (args[i] === "--reproducible") { flags.reproducibleSource = "commit"; }
46
45
  else if (args[i].startsWith("--reproducible=")) { flags.reproducibleSource = args[i].slice("--reproducible=".length); }
46
+ else if (args[i] === "--skip-dotns-cli") { flags.skipDotnsCli = true; }
47
47
  else if (args[i] === "--skip-automated-deployment-to-paseo-next-v2") { flags.skipMirrorToPaseoNextV2 = true; }
48
48
  else if (args[i] === "--fail-on-mirror-error") { flags.failOnMirrorError = true; }
49
49
  else if (args[i] === "--version" || args[i] === "-V") { flags.version = true; }
@@ -74,18 +74,7 @@ if (flags.listEnvironments) {
74
74
  }
75
75
  }
76
76
 
77
- // --refresh-environments alone (no positional args): refresh and exit. With
78
- // positional args, refresh first, then deploy.
79
- if (flags.refreshEnvironments && positional.length === 0) {
80
- try {
81
- const { doc } = await loadEnvironments({ forceRefresh: true });
82
- console.log(`Refreshed ${doc.environments.length} environments from ${process.env.BULLETIN_ENVIRONMENTS_URL ?? DEFAULT_ENVIRONMENTS_URL}`);
83
- process.exit(0);
84
- } catch (e) {
85
- console.error(`Error: failed to refresh environments: ${e?.message ?? e}`);
86
- process.exit(1);
87
- }
88
- }
77
+
89
78
 
90
79
  if (flags.help || positional.length === 0) {
91
80
  console.log(`bulletin-deploy v${VERSION}
@@ -98,8 +87,6 @@ Options:
98
87
  Drives both the bulletin RPC and the asset-hub RPC used
99
88
  by DotNS. See --list-environments for valid ids.
100
89
  --list-environments Print the environments table and exit.
101
- --refresh-environments Bust the cache and re-fetch environments.json. Composes
102
- with --env (refresh-then-deploy) or runs solo.
103
90
  --mnemonic "..." DotNS owner mnemonic (or set MNEMONIC env var)
104
91
  --derivation-path "..." Optional Substrate-style path applied to --mnemonic (e.g. //deploy/3)
105
92
  --rpc wss://... Override the bulletin RPC for the chosen --env (or set BULLETIN_RPC).
@@ -114,6 +101,10 @@ Options:
114
101
  --description "..." Optional. Sets the "description" text record (≤100 chars recommended).
115
102
  --gh-pages-mirror After deploy, push the CAR to the current repo's gh-pages branch
116
103
  at bulletin/<domain>.dot.car (opt-in; also set GH_PAGES_MIRROR=1)
104
+ --skip-dotns-cli Use direct contract calls for DotNS operations instead of
105
+ dotns-cli. Auto-set for envs with custom contract addresses
106
+ (e.g. paseo-next-v2). Use to override when dotns-cli lacks
107
+ support for the target chain.
117
108
  --skip-automated-deployment-to-paseo-next-v2
118
109
  Suppress the automatic mirror deploy to paseo-next-v2.
119
110
  --fail-on-mirror-error
@@ -244,16 +235,6 @@ try {
244
235
  if (!fs.existsSync(buildDir)) { console.error(`Error: ${buildDir} does not exist`); process.exit(1); }
245
236
  }
246
237
 
247
- // --refresh-environments composed with a deploy: bust the cache before
248
- // deploy() loads it, so deploy() picks up fresh data on the next loadEnvironments().
249
- if (flags.refreshEnvironments) {
250
- try {
251
- await loadEnvironments({ forceRefresh: true });
252
- } catch (e) {
253
- console.error(`Error: failed to refresh environments: ${e?.message ?? e}`);
254
- process.exit(1);
255
- }
256
- }
257
238
  const effectiveRpc = flags.rpc ?? process.env.BULLETIN_RPC ?? DEFAULT_BULLETIN_RPC;
258
239
  const deployTag = flags.tag ?? process.env.DEPLOY_TAG;
259
240
  const ci = process.env.GITHUB_ACTIONS === "true" ? {
@@ -290,6 +271,7 @@ try {
290
271
  description: flags.description,
291
272
  allowLargeDeploy: flags.allowLargeDeploy,
292
273
  reproducibleSource: flags.reproducibleSource,
274
+ skipDotnsCli: flags.skipDotnsCli,
293
275
  });
294
276
 
295
277
  const output = process.env.GITHUB_OUTPUT;
@@ -9,10 +9,10 @@ import {
9
9
  offerBugReport,
10
10
  scrubSecrets,
11
11
  setDeployContext
12
- } from "./chunk-BVCNV2VK.js";
13
- import "./chunk-5BHSSRH7.js";
14
- import "./chunk-X7G2XUB6.js";
15
- import "./chunk-IU6LUQFY.js";
12
+ } from "./chunk-I5ZGHKNT.js";
13
+ import "./chunk-VQBSWH77.js";
14
+ import "./chunk-KQ352MBU.js";
15
+ import "./chunk-3BOARQQO.js";
16
16
  import "./chunk-QGM4M3NI.js";
17
17
  export {
18
18
  buildCliFlagsSummary,
@@ -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.18-rc.1",
9
+ version: "0.7.19",
10
10
  private: false,
11
11
  repository: {
12
12
  type: "git",
@@ -36,7 +36,6 @@ var package_default = {
36
36
  "assets"
37
37
  ],
38
38
  scripts: {
39
- prebuild: "node scripts/refresh-environments.mjs",
40
39
  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 src/manifest.ts src/chunk-probe.ts src/manifest-embed.ts src/manifest-fetch.ts src/manifest-roundtrip.ts src/incremental-stats.ts src/chunker.ts src/mirror.ts --format esm --dts --clean --target node22",
41
40
  "refresh-environments": "node scripts/refresh-environments.mjs",
42
41
  prepare: "npm run build",
@@ -133,7 +133,13 @@ function aliceKeyring() {
133
133
  const signer = getPolkadotSigner(alice.publicKey, "Sr25519", (data) => alice.sign(data));
134
134
  return { alice, signer };
135
135
  }
136
- async function ensureAuthorized(api, address, label) {
136
+ var U32_MAX = 0xFFFFFFFFn;
137
+ function clampU32(n, name) {
138
+ if (n < 0n) throw new Error(`${name} must be non-negative`);
139
+ if (n > U32_MAX) throw new Error(`${name} (${n}) exceeds u32 max \u2014 split the deploy into smaller batches`);
140
+ return Number(n);
141
+ }
142
+ async function ensureAuthorized(api, address, label, bulletinAuthorizeV2) {
137
143
  const [auth, currentBlock] = await Promise.all([
138
144
  api.query.TransactionStorage.Authorizations.getValue(Enum("Account", address)),
139
145
  api.query.System.Number.getValue()
@@ -141,18 +147,31 @@ async function ensureAuthorized(api, address, label) {
141
147
  if (isAuthorizationActive(auth, currentBlock)) return;
142
148
  console.log(` Auto-authorizing ${label ?? "account"} (${address.slice(0, 8)}...)...`);
143
149
  const { signer } = aliceKeyring();
144
- const newExpiration = currentBlock + AUTHORIZATION_EXTENSION_BLOCKS;
145
- await submitAliceTxWithRetry(
146
- () => api.tx.TransactionStorage.authorize_account({
147
- who: address,
148
- expiration: newExpiration
149
- }),
150
- signer,
151
- `authorize_account(${label ?? "account"})`
152
- );
153
- console.log(` Authorized: expires at block ${newExpiration} (current: ${currentBlock})`);
150
+ if (bulletinAuthorizeV2) {
151
+ await submitAliceTxWithRetry(
152
+ () => api.tx.TransactionStorage.authorize_account({
153
+ who: address,
154
+ transactions: clampU32(BigInt(TOPUP_TRANSACTIONS), "transactions"),
155
+ bytes: TOPUP_BYTES
156
+ }),
157
+ signer,
158
+ `authorize_account(${label ?? "account"})`
159
+ );
160
+ console.log(` Authorized: ${TOPUP_TRANSACTIONS} txs / ${Number(TOPUP_BYTES) / 1e6}MB`);
161
+ } else {
162
+ const newExpiration = currentBlock + AUTHORIZATION_EXTENSION_BLOCKS;
163
+ await submitAliceTxWithRetry(
164
+ () => api.tx.TransactionStorage.authorize_account({
165
+ who: address,
166
+ expiration: newExpiration
167
+ }),
168
+ signer,
169
+ `authorize_account(${label ?? "account"})`
170
+ );
171
+ console.log(` Authorized: expires at block ${newExpiration} (current: ${currentBlock})`);
172
+ }
154
173
  }
155
- async function topUpBy(api, address, needs, label) {
174
+ async function topUpBy(api, address, needs, label, bulletinAuthorizeV2) {
156
175
  const [currentAuth, currentBlock] = await Promise.all([
157
176
  api.query.TransactionStorage.Authorizations.getValue(Enum("Account", address)),
158
177
  api.query.System.Number.getValue()
@@ -165,20 +184,34 @@ async function topUpBy(api, address, needs, label) {
165
184
  console.log(` Pre-auth skipped for ${label ?? "account"} (${address.slice(0, 8)}...): authorized until block ${expiration}, ${txsRemaining} txs / ${fmtMB(bytesRemaining)}MB remaining.`);
166
185
  return;
167
186
  }
168
- const newExpiration = currentBlock + AUTHORIZATION_EXTENSION_BLOCKS;
169
187
  const { signer } = aliceKeyring();
170
- console.log(` Pre-authorizing ${label ?? "account"} (${address.slice(0, 8)}...): extending authorization to block ${newExpiration}...`);
171
- await submitAliceTxWithRetry(
172
- () => api.tx.TransactionStorage.authorize_account({
173
- who: address,
174
- expiration: newExpiration
175
- }),
176
- signer,
177
- `topUpBy(${label ?? "account"})`
178
- );
179
- console.log(` Pre-authorized: expires at block ${newExpiration}`);
188
+ if (bulletinAuthorizeV2) {
189
+ console.log(` Pre-authorizing ${label ?? "account"} (${address.slice(0, 8)}...): granting ${TOPUP_TRANSACTIONS} txs / ${Number(TOPUP_BYTES) / 1e6}MB...`);
190
+ await submitAliceTxWithRetry(
191
+ () => api.tx.TransactionStorage.authorize_account({
192
+ who: address,
193
+ transactions: clampU32(BigInt(TOPUP_TRANSACTIONS), "transactions"),
194
+ bytes: TOPUP_BYTES
195
+ }),
196
+ signer,
197
+ `topUpBy(${label ?? "account"})`
198
+ );
199
+ console.log(` Pre-authorized: ${TOPUP_TRANSACTIONS} txs / ${Number(TOPUP_BYTES) / 1e6}MB`);
200
+ } else {
201
+ const newExpiration = currentBlock + AUTHORIZATION_EXTENSION_BLOCKS;
202
+ console.log(` Pre-authorizing ${label ?? "account"} (${address.slice(0, 8)}...): extending authorization to block ${newExpiration}...`);
203
+ await submitAliceTxWithRetry(
204
+ () => api.tx.TransactionStorage.authorize_account({
205
+ who: address,
206
+ expiration: newExpiration
207
+ }),
208
+ signer,
209
+ `topUpBy(${label ?? "account"})`
210
+ );
211
+ console.log(` Pre-authorized: expires at block ${newExpiration}`);
212
+ }
180
213
  }
181
- async function bootstrapPool(bulletinRpc, poolSize = 10, mnemonic) {
214
+ async function bootstrapPool(bulletinRpc, poolSize = 10, mnemonic, opts = {}) {
182
215
  console.log(`Bootstrapping ${poolSize} pool accounts on ${bulletinRpc}...
183
216
  `);
184
217
  await cryptoWaitReady();
@@ -196,19 +229,39 @@ async function bootstrapPool(bulletinRpc, poolSize = 10, mnemonic) {
196
229
  console.log(`Alice balance: ${formatPasBalance(aliceBalance)} PAS
197
230
  `);
198
231
  const currentBlock = await api.query.System.Number.getValue();
199
- const authExpiration = currentBlock + AUTHORIZATION_EXTENSION_BLOCKS;
200
- console.log(`Authorizing accounts until block ${authExpiration} (current: ${currentBlock})
232
+ if (opts.bulletinAuthorizeV2) {
233
+ console.log(`Authorizing accounts with V2 (${TOPUP_TRANSACTIONS} txs / ${Number(TOPUP_BYTES) / 1e6}MB)
201
234
  `);
235
+ } else {
236
+ const authExpiration = currentBlock + AUTHORIZATION_EXTENSION_BLOCKS;
237
+ console.log(`Authorizing accounts until block ${authExpiration} (current: ${currentBlock})
238
+ `);
239
+ }
202
240
  for (const account of accounts) {
203
241
  console.log(`Account ${account.index}: ${account.address}`);
204
242
  try {
205
- const tx = api.tx.TransactionStorage.authorize_account({
206
- who: account.address,
207
- expiration: authExpiration
208
- });
243
+ let tx;
244
+ if (opts.bulletinAuthorizeV2) {
245
+ tx = api.tx.TransactionStorage.authorize_account({
246
+ who: account.address,
247
+ transactions: clampU32(BigInt(TOPUP_TRANSACTIONS), "transactions"),
248
+ bytes: TOPUP_BYTES
249
+ });
250
+ } else {
251
+ const authExpiration = currentBlock + AUTHORIZATION_EXTENSION_BLOCKS;
252
+ tx = api.tx.TransactionStorage.authorize_account({
253
+ who: account.address,
254
+ expiration: authExpiration
255
+ });
256
+ }
209
257
  const result = await tx.signAndSubmit(aliceSigner);
210
258
  if (!result.ok) throw new Error("dispatch failed");
211
- console.log(` Authorized: expires at block ${authExpiration}`);
259
+ if (opts.bulletinAuthorizeV2) {
260
+ console.log(` Authorized: ${TOPUP_TRANSACTIONS} txs / ${Number(TOPUP_BYTES) / 1e6}MB`);
261
+ } else {
262
+ const authExpiration = currentBlock + AUTHORIZATION_EXTENSION_BLOCKS;
263
+ console.log(` Authorized: expires at block ${authExpiration}`);
264
+ }
212
265
  } catch (e) {
213
266
  console.log(` Authorization failed: ${e.message?.slice(0, 80)}`);
214
267
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  captureWarning
3
- } from "./chunk-X7G2XUB6.js";
3
+ } from "./chunk-KQ352MBU.js";
4
4
 
5
5
  // src/chunk-probe.ts
6
6
  import { Twox128, Blake2128Concat, decAnyMetadata, unifyMetadata } from "@polkadot-api/substrate-bindings";
@@ -2,11 +2,11 @@ import {
2
2
  classifyErrorArea,
3
3
  isInteractive,
4
4
  promptYesNo
5
- } from "./chunk-5BHSSRH7.js";
5
+ } from "./chunk-VQBSWH77.js";
6
6
  import {
7
7
  VERSION,
8
8
  getCurrentSentryTraceId
9
- } from "./chunk-X7G2XUB6.js";
9
+ } from "./chunk-KQ352MBU.js";
10
10
 
11
11
  // src/bug-report.ts
12
12
  import { execSync, execFileSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  package_default,
3
3
  writeRunState
4
- } from "./chunk-IU6LUQFY.js";
4
+ } from "./chunk-3BOARQQO.js";
5
5
 
6
6
  // src/memory-report.ts
7
7
  import * as fs2 from "fs";
@@ -4,13 +4,8 @@ import {
4
4
 
5
5
  // src/environments.ts
6
6
  import * as fs from "fs/promises";
7
- import * as path from "path";
8
- import * as os from "os";
9
7
  import { fileURLToPath } from "url";
10
- var DEFAULT_ENVIRONMENTS_URL = "https://raw.githubusercontent.com/paritytech/triangle-deploy/main/assets/environments.json";
11
8
  var DEFAULT_ENV_ID = "paseo-next";
12
- var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
13
- var FETCH_TIMEOUT_MS = 5e3;
14
9
  var HARDCODED_FALLBACK = {
15
10
  environments: [
16
11
  {
@@ -47,14 +42,6 @@ var HARDCODED_FALLBACK = {
47
42
  }
48
43
  ]
49
44
  };
50
- function defaultCacheDir() {
51
- const xdg = process.env.XDG_CACHE_HOME;
52
- const base = xdg && xdg.length > 0 ? xdg : path.join(os.homedir(), ".cache");
53
- return path.join(base, "bulletin-deploy");
54
- }
55
- function defaultCachePath() {
56
- return path.join(defaultCacheDir(), "environments.json");
57
- }
58
45
  function defaultBundledPath() {
59
46
  return fileURLToPath(new URL("../assets/environments.json", import.meta.url));
60
47
  }
@@ -63,51 +50,6 @@ function isValidDoc(value) {
63
50
  const v = value;
64
51
  return Array.isArray(v.environments) && Array.isArray(v.chains);
65
52
  }
66
- async function readCache(cachePath) {
67
- try {
68
- const raw = await fs.readFile(cachePath, "utf8");
69
- const parsed = JSON.parse(raw);
70
- if (parsed && typeof parsed === "object" && typeof parsed.fetchedAt === "string" && isValidDoc(parsed.doc)) {
71
- return parsed;
72
- }
73
- return null;
74
- } catch {
75
- return null;
76
- }
77
- }
78
- async function writeCache(cachePath, doc, now) {
79
- try {
80
- await fs.mkdir(path.dirname(cachePath), { recursive: true });
81
- const payload = {
82
- fetchedAt: new Date(now).toISOString(),
83
- doc
84
- };
85
- await fs.writeFile(cachePath, JSON.stringify(payload, null, 2), "utf8");
86
- } catch {
87
- }
88
- }
89
- function isFresh(cache, now) {
90
- const fetched = Date.parse(cache.fetchedAt);
91
- if (Number.isNaN(fetched)) return false;
92
- return now - fetched < CACHE_TTL_MS;
93
- }
94
- async function fetchLive(url, fetchImpl) {
95
- const ctrl = new AbortController();
96
- const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
97
- try {
98
- const res = await fetchImpl(url, { signal: ctrl.signal });
99
- if (!res.ok) {
100
- throw new Error(`fetch ${url} returned HTTP ${res.status}`);
101
- }
102
- const json = await res.json();
103
- if (!isValidDoc(json)) {
104
- throw new Error(`fetch ${url} returned malformed environments doc`);
105
- }
106
- return json;
107
- } finally {
108
- clearTimeout(timer);
109
- }
110
- }
111
53
  async function readBundled(bundledPath) {
112
54
  try {
113
55
  const raw = await fs.readFile(bundledPath, "utf8");
@@ -118,48 +60,14 @@ async function readBundled(bundledPath) {
118
60
  }
119
61
  }
120
62
  async function loadEnvironments(opts = {}) {
121
- const url = opts.url ?? process.env.BULLETIN_ENVIRONMENTS_URL ?? DEFAULT_ENVIRONMENTS_URL;
122
- const cachePath = path.join(opts.cacheDir ?? defaultCacheDir(), "environments.json");
123
63
  const bundledPath = opts.bundledPath ?? defaultBundledPath();
124
- const fetchImpl = opts.fetchImpl ?? fetch;
125
- const nowFn = opts.now ?? Date.now;
126
64
  const warn = opts.warn ?? ((msg) => console.error(msg));
127
65
  const capture = opts.capture ?? (() => {
128
66
  });
129
- const now = nowFn();
130
- if (opts.forceRefresh) {
131
- const doc = await fetchLive(url, fetchImpl);
132
- await writeCache(cachePath, doc, now);
133
- return { doc, source: "live" };
134
- }
135
- const cache = await readCache(cachePath);
136
- if (cache && isFresh(cache, now)) {
137
- return { doc: cache.doc, source: "cache-fresh" };
138
- }
139
- try {
140
- const doc = await fetchLive(url, fetchImpl);
141
- await writeCache(cachePath, doc, now);
142
- return { doc, source: "live" };
143
- } catch (err) {
144
- if (cache) {
145
- warn(
146
- `bulletin-deploy: live environments.json fetch failed; using cached copy from ${cache.fetchedAt} (${err.message ?? err})`
147
- );
148
- return { doc: cache.doc, source: "cache-stale" };
149
- }
150
- const bundled = await readBundled(bundledPath);
151
- if (bundled) {
152
- warn(
153
- `bulletin-deploy: live environments.json fetch failed and no cache; using bundled snapshot (${err.message ?? err})`
154
- );
155
- return { doc: bundled, source: "bundled" };
156
- }
157
- capture(err);
158
- warn(
159
- `bulletin-deploy: live and bundled environments.json both unavailable; using hardcoded paseo-next fallback`
160
- );
161
- return { doc: HARDCODED_FALLBACK, source: "hardcoded-fallback" };
162
- }
67
+ const bundled = await readBundled(bundledPath);
68
+ if (bundled) return { doc: bundled, source: "bundled" };
69
+ warn("bulletin-deploy: bundled environments.json unavailable; using hardcoded paseo-next fallback");
70
+ return { doc: HARDCODED_FALLBACK, source: "hardcoded-fallback" };
163
71
  }
164
72
  function normalizeWss(value) {
165
73
  if (value === void 0) return [];
@@ -218,7 +126,17 @@ function resolveEndpoints(doc, envId) {
218
126
  `Asset Hub endpoint missing for environment '${envId}'. Check https://github.com/paritytech/triangle-status/blob/main/environments.json.`
219
127
  );
220
128
  }
221
- return { bulletin, assetHub, network: env.network, envName: env.name };
129
+ return {
130
+ bulletin,
131
+ assetHub,
132
+ network: env.network,
133
+ envName: env.name,
134
+ autoAccountMapping: env.autoAccountMapping ?? false,
135
+ bulletinAuthorizeV2: env.bulletinAuthorizeV2 ?? false,
136
+ skipDotnsCli: env.skipDotnsCli ?? false,
137
+ contracts: env.contracts ?? {},
138
+ nativeToEthRatio: BigInt(env.nativeToEthRatio ?? 1e6)
139
+ };
222
140
  }
223
141
  function listEnvironments(doc) {
224
142
  const bulletinChain = doc.chains.find((c) => c.id === "bulletin");
@@ -252,12 +170,7 @@ function formatEnvironmentTable(rows) {
252
170
  }
253
171
 
254
172
  export {
255
- DEFAULT_ENVIRONMENTS_URL,
256
173
  DEFAULT_ENV_ID,
257
- CACHE_TTL_MS,
258
- FETCH_TIMEOUT_MS,
259
- defaultCacheDir,
260
- defaultCachePath,
261
174
  defaultBundledPath,
262
175
  loadEnvironments,
263
176
  resolveEndpoints,