bulletin-deploy 0.7.10 → 0.7.12-rc.1

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.
@@ -9,10 +9,10 @@ import {
9
9
  offerBugReport,
10
10
  scrubSecrets,
11
11
  setDeployContext
12
- } from "./chunk-E2ZOGJ5R.js";
13
- import "./chunk-DFD2WF67.js";
14
- import "./chunk-IXUFM7P6.js";
15
- import "./chunk-B2MLOHKF.js";
12
+ } from "./chunk-QAJNUXBO.js";
13
+ import "./chunk-N7PS2WTI.js";
14
+ import "./chunk-MWBV5N6B.js";
15
+ import "./chunk-6JL2SBBI.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.10",
9
+ version: "0.7.12-rc.1",
10
10
  private: false,
11
11
  repository: {
12
12
  type: "git",
@@ -2,10 +2,10 @@ import {
2
2
  captureWarning,
3
3
  setDeployAttribute,
4
4
  withSpan
5
- } from "./chunk-IXUFM7P6.js";
5
+ } from "./chunk-MWBV5N6B.js";
6
6
  import {
7
7
  isTestnetSpecName
8
- } from "./chunk-RP4YJYNB.js";
8
+ } from "./chunk-VOEFHED3.js";
9
9
 
10
10
  // src/dotns.ts
11
11
  import { spawn } from "child_process";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  package_default,
3
3
  writeRunState
4
- } from "./chunk-B2MLOHKF.js";
4
+ } from "./chunk-6JL2SBBI.js";
5
5
 
6
6
  // src/memory-report.ts
7
7
  import * as fs2 from "fs";
@@ -214,7 +214,29 @@ function getDeployAttributes(domain) {
214
214
  return attrs;
215
215
  }
216
216
  function isExpectedError(msg) {
217
- return /personhood|owned by|owner mismatch|reserved for original|invalid domain label|not authorized for bulletin|insufficient balance|quota exhausted|insufficient .* authorization/i.test(msg);
217
+ return /personhood|owned by|owner mismatch|reserved for original|invalid domain label|not authorized for bulletin|insufficient balance|insufficient funds|quota exhausted|insufficient .* authorization|bip39 mnemonic|ipfs cli not installed|base name is \d+ chars|NameNotAvailable|name must be lowercase/i.test(msg);
218
+ }
219
+ function classifyDeployError(msg) {
220
+ if (isExpectedError(msg)) return "user";
221
+ if (/chunk.*failed after.*retr|tx dropped from best chain|timed out after \d+s waiting for block|Contract reverted|Contract execution would revert|dotns register failed|All promises were rejected|"type"\s*:\s*"Invalid"|Commitment still too new/i.test(msg)) return "environment";
222
+ if (/javascript heap out of memory|allocation failed.*heap|External signer mode is not supported with dotns-cli/i.test(msg)) return "internal";
223
+ return "unknown";
224
+ }
225
+ function classifySadReason(message) {
226
+ if (/process terminated: SIG/i.test(message)) return "killed";
227
+ if (/memory threshold/i.test(message)) return "memory";
228
+ if (/spektr injection|account map failed/i.test(message)) return "signer";
229
+ if (/chunk upload failed|chunk retry failed/i.test(message)) return "chain_storage";
230
+ if (/websocket connection lost|rpc.*endpoint failed|rpc failover/i.test(message)) return "rpc";
231
+ return "other";
232
+ }
233
+ function computeDeployOutcome(errorCategory, isSad, sadReason) {
234
+ if (errorCategory === "user") return "user_error";
235
+ if (errorCategory === "environment") return "env_error";
236
+ if (errorCategory === "internal") return "internal_error";
237
+ if (errorCategory === "unknown") return "unknown_error";
238
+ if (isSad) return `sad_${sadReason}`;
239
+ return "clean";
218
240
  }
219
241
  async function withSpan(op, description, attributes, fn) {
220
242
  if (!Sentry) return fn();
@@ -232,6 +254,18 @@ var memoryPeak = null;
232
254
  var deployRootSpan = null;
233
255
  var stageSamples = {};
234
256
  var reportContext = {};
257
+ var currentErrorCategory = null;
258
+ var currentDeploySad = false;
259
+ var currentSadReason = "other";
260
+ var currentSadReasonPriority = 0;
261
+ var SAD_REASON_PRIORITY = {
262
+ killed: 5,
263
+ memory: 4,
264
+ signer: 3,
265
+ chain_storage: 2,
266
+ rpc: 1,
267
+ other: 0
268
+ };
235
269
  function toMb(bytes) {
236
270
  return Math.round(bytes / 1024 / 1024 * 100) / 100;
237
271
  }
@@ -275,6 +309,10 @@ async function withDeploySpan(domain, fn) {
275
309
  memoryPeak = { rss: m0.rss, heapUsed: m0.heapUsed, external: m0.external, arrayBuffers: m0.arrayBuffers };
276
310
  stageSamples = {};
277
311
  reportContext = {};
312
+ currentErrorCategory = null;
313
+ currentDeploySad = false;
314
+ currentSadReason = "other";
315
+ currentSadReasonPriority = 0;
278
316
  const deployStartMs = Date.now();
279
317
  try {
280
318
  return await Sentry.startSpan({ op: "deploy", name: `deploy ${domain}`, attributes: attrs }, async (span) => {
@@ -299,7 +337,10 @@ async function withDeploySpan(domain, fn) {
299
337
  } catch (error) {
300
338
  const msg = error.message;
301
339
  span.setAttribute("deploy.status", "error");
302
- span.setAttribute("deploy.error", msg.slice(0, 200));
340
+ span.setAttribute("deploy.error", msg.slice(0, 500));
341
+ const errorCategory = classifyDeployError(msg);
342
+ span.setAttribute("deploy.error_category", errorCategory);
343
+ currentErrorCategory = errorCategory;
303
344
  const isExpected = isExpectedError(msg);
304
345
  span.setAttribute("deploy.expected", isExpected ? "true" : "false");
305
346
  span.setAttribute("deploy.sad", isExpected ? "false" : "true");
@@ -309,6 +350,10 @@ async function withDeploySpan(domain, fn) {
309
350
  throw error;
310
351
  } finally {
311
352
  sampleMemory("end");
353
+ span.setAttribute(
354
+ "deploy.outcome",
355
+ computeDeployOutcome(currentErrorCategory, currentDeploySad, currentSadReason)
356
+ );
312
357
  if (memoryPeak) {
313
358
  try {
314
359
  const report = maybeWriteMemoryReport({
@@ -354,6 +399,10 @@ async function withDeploySpan(domain, fn) {
354
399
  deployRootSpan = null;
355
400
  stageSamples = {};
356
401
  reportContext = {};
402
+ currentErrorCategory = null;
403
+ currentDeploySad = false;
404
+ currentSadReason = "other";
405
+ currentSadReasonPriority = 0;
357
406
  await Sentry.flush(5e3);
358
407
  }
359
408
  }
@@ -382,6 +431,13 @@ function captureWarning(message, context) {
382
431
  Sentry.captureMessage(message, { level: "warning", extra: context });
383
432
  const root = Sentry.getRootSpan(Sentry.getActiveSpan());
384
433
  if (root) root.setAttribute("deploy.sad", "true");
434
+ const reason = classifySadReason(message);
435
+ const priority = SAD_REASON_PRIORITY[reason] ?? 0;
436
+ if (priority >= currentSadReasonPriority) {
437
+ currentSadReason = reason;
438
+ currentSadReasonPriority = priority;
439
+ }
440
+ currentDeploySad = true;
385
441
  } catch {
386
442
  }
387
443
  }
@@ -527,6 +583,9 @@ export {
527
583
  resolveRunnerType,
528
584
  getDeployAttributes,
529
585
  isExpectedError,
586
+ classifyDeployError,
587
+ classifySadReason,
588
+ computeDeployOutcome,
530
589
  withSpan,
531
590
  sampleMemory,
532
591
  withDeploySpan,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-IXUFM7P6.js";
3
+ } from "./chunk-MWBV5N6B.js";
4
4
 
5
5
  // src/version-check.ts
6
6
  import { execSync, execFileSync } from "child_process";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  setDeployContext
3
- } from "./chunk-E2ZOGJ5R.js";
3
+ } from "./chunk-QAJNUXBO.js";
4
4
  import {
5
5
  DotNS,
6
6
  TX_TIMEOUT_MS,
@@ -8,7 +8,7 @@ import {
8
8
  parseDomainName,
9
9
  popStatusName,
10
10
  verifyNonceAdvanced
11
- } from "./chunk-TOFKHL4S.js";
11
+ } from "./chunk-CORAWOVZ.js";
12
12
  import {
13
13
  MirrorSkipped,
14
14
  mirrorToGitHubPages,
@@ -27,7 +27,7 @@ import {
27
27
  truncateAddress,
28
28
  withDeploySpan,
29
29
  withSpan
30
- } from "./chunk-IXUFM7P6.js";
30
+ } from "./chunk-MWBV5N6B.js";
31
31
  import {
32
32
  merkleizeJS
33
33
  } from "./chunk-B7GUYYAN.js";
@@ -38,7 +38,7 @@ import {
38
38
  fetchPoolAuthorizations,
39
39
  selectAccount,
40
40
  topUpBy
41
- } from "./chunk-RP4YJYNB.js";
41
+ } from "./chunk-VOEFHED3.js";
42
42
 
43
43
  // src/deploy.ts
44
44
  import { Buffer } from "buffer";
@@ -170,8 +170,11 @@ async function getProvider() {
170
170
  await cryptoWaitReady();
171
171
  const poolMnemonic = process.env.BULLETIN_POOL_MNEMONIC || void 0;
172
172
  const poolAccounts = derivePoolAccounts(POOL_SIZE, poolMnemonic);
173
- const authorizations = await fetchPoolAuthorizations(unsafeApi, poolAccounts);
174
- let selected = selectAccount(authorizations);
173
+ const [authorizations, currentBlockForPool] = await Promise.all([
174
+ fetchPoolAuthorizations(unsafeApi, poolAccounts),
175
+ unsafeApi.query.System.Number.getValue()
176
+ ]);
177
+ let selected = selectAccount(authorizations, Math.random, currentBlockForPool);
175
178
  if (!selected) {
176
179
  const best = authorizations.reduce((a, b) => a.transactions > b.transactions ? a : b);
177
180
  console.log(` All pool accounts low on capacity, auto-authorizing account ${best.index}...`);
@@ -200,16 +203,16 @@ async function getDirectProvider(mnemonic, derivationPath = "") {
200
203
  const unsafeApi = client.getUnsafeApi();
201
204
  const { signer, ss58 } = deriveRootSigner(mnemonic, derivationPath);
202
205
  console.log(` Using direct signer: ${ss58}${derivationPath ? ` (path: ${derivationPath})` : ""}`);
203
- const auth = await unsafeApi.query.TransactionStorage.Authorizations.getValue(
204
- Enum("Account", ss58)
205
- );
206
- const txsRemaining = auth ? BigInt(auth.extent.transactions) : 0n;
207
- const bytesRemaining = auth ? auth.extent.bytes : 0n;
208
- if (txsRemaining === 0n && bytesRemaining === 0n) {
206
+ const [auth, currentBlock] = await Promise.all([
207
+ unsafeApi.query.TransactionStorage.Authorizations.getValue(Enum("Account", ss58)),
208
+ client.getFinalizedBlock()
209
+ ]);
210
+ const now = currentBlock.number;
211
+ if (!auth || Number(auth.expiration ?? 0) <= now) {
209
212
  client.destroy();
210
213
  throw new NonRetryableError(`Account ${ss58} is not authorized for Bulletin storage.`);
211
214
  }
212
- console.log(` Authorization: ${txsRemaining} txs, ${Number(bytesRemaining) / 1e6}MB remaining`);
215
+ console.log(` Authorization: expires at block ${Number(auth.expiration)} (current: ${now})`);
213
216
  setDeployAttribute("deploy.signer.mode", "direct");
214
217
  setDeployAttribute("deploy.signer.address", truncateAddress(ss58));
215
218
  return { client, unsafeApi, signer, ss58 };
@@ -341,20 +344,22 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
341
344
  }
342
345
  const requiredTxs = BigInt(chunks.length + 1);
343
346
  const requiredBytes = BigInt(totalBytes);
344
- const auth = await unsafeApi.query.TransactionStorage.Authorizations.getValue(
345
- Enum("Account", ss58)
346
- );
347
- const txsRemaining = auth ? BigInt(auth.extent.transactions) : 0n;
348
- const bytesRemaining = auth ? auth.extent.bytes : 0n;
349
- if (txsRemaining < requiredTxs || bytesRemaining < requiredBytes) {
347
+ const [uploadAuth, currentBlockNum] = await Promise.all([
348
+ unsafeApi.query.TransactionStorage.Authorizations.getValue(Enum("Account", ss58)),
349
+ unsafeApi.query.System.Number.getValue()
350
+ ]);
351
+ const txsRemaining = uploadAuth ? BigInt(uploadAuth.extent.transactions_allowance) - BigInt(uploadAuth.extent.transactions) : 0n;
352
+ const bytesRemaining = uploadAuth ? BigInt(uploadAuth.extent.bytes_allowance) - BigInt(uploadAuth.extent.bytes) : 0n;
353
+ const isAuthorized = uploadAuth !== void 0 && Number(uploadAuth.expiration ?? 0) > currentBlockNum;
354
+ if (!isAuthorized || txsRemaining < requiredTxs || bytesRemaining < requiredBytes) {
350
355
  console.log(`
351
- Account has insufficient authorization for this upload (need ${requiredTxs} txs / ${(totalBytes / 1e6).toFixed(1)}MB, have ${txsRemaining} txs / ${Number(bytesRemaining) / 1e6}MB)`);
356
+ Account needs re-authorization (authorized=${isAuthorized}, need ${requiredTxs} txs / ${(totalBytes / 1e6).toFixed(1)}MB, have ${txsRemaining} txs / ${Number(bytesRemaining) / 1e6}MB)`);
352
357
  console.log(` Attempting to re-authorize with Alice...`);
353
358
  try {
354
- await ensureAuthorized(unsafeApi, ss58, void 0, { txs: requiredTxs, bytes: requiredBytes });
359
+ await ensureAuthorized(unsafeApi, ss58);
355
360
  console.log(` Re-authorization successful`);
356
361
  } catch (e) {
357
- throw new NonRetryableError(`Account ${ss58} has insufficient Bulletin authorization quota and auto-authorization via Alice failed (${e.message}). Authorize the account on-chain.`);
362
+ throw new NonRetryableError(`Account ${ss58} has insufficient Bulletin authorization and auto-authorization via Alice failed (${e.message}). Authorize the account on-chain.`);
358
363
  }
359
364
  }
360
365
  let reconnectionsUsed = 0;
@@ -2,11 +2,11 @@ import {
2
2
  classifyErrorArea,
3
3
  isInteractive,
4
4
  promptYesNo
5
- } from "./chunk-DFD2WF67.js";
5
+ } from "./chunk-N7PS2WTI.js";
6
6
  import {
7
7
  VERSION,
8
8
  getCurrentSentryTraceId
9
- } from "./chunk-IXUFM7P6.js";
9
+ } from "./chunk-MWBV5N6B.js";
10
10
 
11
11
  // src/bug-report.ts
12
12
  import { execSync, execFileSync } from "child_process";
@@ -14,9 +14,8 @@ function formatPasBalance(plancks) {
14
14
  var DEPLOY_PATH_PREFIX = "//deploy";
15
15
  var TOPUP_TRANSACTIONS = 1e3;
16
16
  var TOPUP_BYTES = 100000000n;
17
- var TOPUP_THRESHOLD_TXS = 50n;
18
- var TOPUP_THRESHOLD_BYTES = 50000000n;
19
17
  var WS_HEARTBEAT_TIMEOUT_MS = 3e5;
18
+ var AUTHORIZATION_EXTENSION_BLOCKS = 2e6;
20
19
  function derivePoolAccounts(poolSize = 10, mnemonic = DEV_PHRASE) {
21
20
  const entropy = mnemonicToEntropy(mnemonic);
22
21
  const miniSecret = entropyToMiniSecret(entropy);
@@ -34,9 +33,12 @@ function derivePoolAccounts(poolSize = 10, mnemonic = DEV_PHRASE) {
34
33
  }
35
34
  var MIN_TRANSACTIONS = 30n;
36
35
  var MIN_BYTES = 20000000n;
37
- function selectAccount(authorizations, random = Math.random) {
36
+ function isAuthorizationActive(auth, currentBlock) {
37
+ return auth !== void 0 && Number(auth.expiration ?? 0) > currentBlock;
38
+ }
39
+ function selectAccount(authorizations, random = Math.random, currentBlock) {
38
40
  const eligible = authorizations.filter(
39
- (a) => a.transactions > MIN_TRANSACTIONS && a.bytes > MIN_BYTES
41
+ (a) => a.transactions > MIN_TRANSACTIONS && a.bytes > MIN_BYTES && (currentBlock === void 0 || a.expiration > currentBlock)
40
42
  );
41
43
  if (eligible.length === 0) return null;
42
44
  return eligible[Math.floor(random() * eligible.length)];
@@ -50,11 +52,12 @@ async function fetchPoolAuthorizations(api, accounts) {
50
52
  );
51
53
  return {
52
54
  ...account,
53
- transactions: auth ? BigInt(auth.extent.transactions) : 0n,
54
- bytes: auth ? auth.extent.bytes : 0n
55
+ transactions: auth ? BigInt(auth.extent.transactions_allowance) - BigInt(auth.extent.transactions) : 0n,
56
+ bytes: auth ? BigInt(auth.extent.bytes_allowance) - BigInt(auth.extent.bytes) : 0n,
57
+ expiration: auth ? Number(auth.expiration) : 0
55
58
  };
56
59
  } catch {
57
- return { ...account, transactions: 0n, bytes: 0n };
60
+ return { ...account, transactions: 0n, bytes: 0n, expiration: 0 };
58
61
  }
59
62
  })
60
63
  );
@@ -131,61 +134,50 @@ function aliceKeyring() {
131
134
  const signer = getPolkadotSigner(alice.publicKey, "Sr25519", (data) => alice.sign(data));
132
135
  return { alice, signer };
133
136
  }
134
- var U32_MAX = 0xFFFFFFFFn;
135
- function clampU32(n, name) {
136
- if (n < 0n) throw new Error(`${name} must be non-negative`);
137
- if (n > U32_MAX) throw new Error(`${name} (${n}) exceeds u32 max \u2014 split the deploy into smaller batches`);
138
- return Number(n);
139
- }
140
- async function ensureAuthorized(api, address, label, minimum = { txs: TOPUP_THRESHOLD_TXS, bytes: TOPUP_THRESHOLD_BYTES }) {
141
- const auth = await api.query.TransactionStorage.Authorizations.getValue(
142
- Enum("Account", address)
143
- );
144
- const txsRemaining = auth ? BigInt(auth.extent.transactions) : 0n;
145
- const bytesRemaining = auth ? auth.extent.bytes : 0n;
146
- if (txsRemaining >= minimum.txs && bytesRemaining >= minimum.bytes) {
147
- return;
148
- }
137
+ async function ensureAuthorized(api, address, label) {
138
+ const [auth, currentBlock] = await Promise.all([
139
+ api.query.TransactionStorage.Authorizations.getValue(Enum("Account", address)),
140
+ api.query.System.Number.getValue()
141
+ ]);
142
+ if (isAuthorizationActive(auth, currentBlock)) return;
149
143
  console.log(` Auto-authorizing ${label ?? "account"} (${address.slice(0, 8)}...)...`);
150
144
  const { signer } = aliceKeyring();
145
+ const newExpiration = currentBlock + AUTHORIZATION_EXTENSION_BLOCKS;
151
146
  await submitAliceTxWithRetry(
152
147
  () => api.tx.TransactionStorage.authorize_account({
153
148
  who: address,
154
- transactions: TOPUP_TRANSACTIONS,
155
- bytes: TOPUP_BYTES
149
+ expiration: newExpiration
156
150
  }),
157
151
  signer,
158
152
  `authorize_account(${label ?? "account"})`
159
153
  );
160
- console.log(` Authorized: ${TOPUP_TRANSACTIONS} txs, ${TOPUP_BYTES / 1000000n}MB`);
154
+ console.log(` Authorized: expires at block ${newExpiration} (current: ${currentBlock})`);
161
155
  }
162
156
  async function topUpBy(api, address, needs, label) {
163
- const currentAuth = await api.query.TransactionStorage.Authorizations.getValue(
164
- Enum("Account", address)
165
- );
166
- const current = {
167
- transactions: currentAuth ? BigInt(currentAuth.extent.transactions) : 0n,
168
- bytes: currentAuth ? currentAuth.extent.bytes : 0n
169
- };
170
- const fmtMB = (b) => (Number(b) / 1e6).toFixed(1);
171
- const target = computeTopUpTarget(current, needs);
172
- if (!target) {
173
- console.log(` Pre-auth skipped for ${label ?? "account"} (${address.slice(0, 8)}...): current ${current.transactions} txs / ${fmtMB(current.bytes)}MB covers needs + floor.`);
157
+ const [currentAuth, currentBlock] = await Promise.all([
158
+ api.query.TransactionStorage.Authorizations.getValue(Enum("Account", address)),
159
+ api.query.System.Number.getValue()
160
+ ]);
161
+ if (isAuthorizationActive(currentAuth, currentBlock)) {
162
+ const fmtMB = (b) => (Number(b) / 1e6).toFixed(1);
163
+ const txsRemaining = BigInt(currentAuth.extent.transactions_allowance) - BigInt(currentAuth.extent.transactions);
164
+ const bytesRemaining = BigInt(currentAuth.extent.bytes_allowance) - BigInt(currentAuth.extent.bytes);
165
+ const expiration = Number(currentAuth.expiration);
166
+ console.log(` Pre-auth skipped for ${label ?? "account"} (${address.slice(0, 8)}...): authorized until block ${expiration}, ${txsRemaining} txs / ${fmtMB(bytesRemaining)}MB remaining.`);
174
167
  return;
175
168
  }
176
- const transactions = clampU32(target.transactions, "topUpBy.txs");
169
+ const newExpiration = currentBlock + AUTHORIZATION_EXTENSION_BLOCKS;
177
170
  const { signer } = aliceKeyring();
178
- console.log(` Pre-authorizing ${label ?? "account"} (${address.slice(0, 8)}...): current ${current.transactions} txs / ${fmtMB(current.bytes)}MB \u2192 target ${target.transactions} txs / ${fmtMB(target.bytes)}MB...`);
171
+ console.log(` Pre-authorizing ${label ?? "account"} (${address.slice(0, 8)}...): extending authorization to block ${newExpiration}...`);
179
172
  await submitAliceTxWithRetry(
180
173
  () => api.tx.TransactionStorage.authorize_account({
181
174
  who: address,
182
- transactions,
183
- bytes: target.bytes
175
+ expiration: newExpiration
184
176
  }),
185
177
  signer,
186
178
  `topUpBy(${label ?? "account"})`
187
179
  );
188
- console.log(` Pre-authorized: target ${transactions} txs / ${fmtMB(target.bytes)}MB`);
180
+ console.log(` Pre-authorized: expires at block ${newExpiration}`);
189
181
  }
190
182
  async function bootstrapPool(bulletinRpc, poolSize = 10, mnemonic) {
191
183
  console.log(`Bootstrapping ${poolSize} pool accounts on ${bulletinRpc}...
@@ -203,18 +195,21 @@ async function bootstrapPool(bulletinRpc, poolSize = 10, mnemonic) {
203
195
  const aliceAccount = await api.query.System.Account.getValue(alice.address);
204
196
  const aliceBalance = BigInt(aliceAccount.data.free);
205
197
  console.log(`Alice balance: ${formatPasBalance(aliceBalance)} PAS
198
+ `);
199
+ const currentBlock = await api.query.System.Number.getValue();
200
+ const authExpiration = currentBlock + AUTHORIZATION_EXTENSION_BLOCKS;
201
+ console.log(`Authorizing accounts until block ${authExpiration} (current: ${currentBlock})
206
202
  `);
207
203
  for (const account of accounts) {
208
204
  console.log(`Account ${account.index}: ${account.address}`);
209
205
  try {
210
206
  const tx = api.tx.TransactionStorage.authorize_account({
211
207
  who: account.address,
212
- transactions: TOPUP_TRANSACTIONS,
213
- bytes: TOPUP_BYTES
208
+ expiration: authExpiration
214
209
  });
215
210
  const result = await tx.signAndSubmit(aliceSigner);
216
211
  if (!result.ok) throw new Error("dispatch failed");
217
- console.log(` Authorized: ${TOPUP_TRANSACTIONS} txs, ${Number(TOPUP_BYTES) / 1e6}MB`);
212
+ console.log(` Authorized: expires at block ${authExpiration}`);
218
213
  } catch (e) {
219
214
  console.log(` Authorization failed: ${e.message?.slice(0, 80)}`);
220
215
  }
package/dist/deploy.js CHANGED
@@ -26,15 +26,15 @@ import {
26
26
  storeChunkedContent,
27
27
  storeDirectory,
28
28
  storeFile
29
- } from "./chunk-PGCTJF2J.js";
30
- import "./chunk-E2ZOGJ5R.js";
31
- import "./chunk-DFD2WF67.js";
32
- import "./chunk-TOFKHL4S.js";
29
+ } from "./chunk-OG3S2NTO.js";
30
+ import "./chunk-QAJNUXBO.js";
31
+ import "./chunk-N7PS2WTI.js";
32
+ import "./chunk-CORAWOVZ.js";
33
33
  import "./chunk-HOTQDYHD.js";
34
- import "./chunk-IXUFM7P6.js";
35
- import "./chunk-B2MLOHKF.js";
34
+ import "./chunk-MWBV5N6B.js";
35
+ import "./chunk-6JL2SBBI.js";
36
36
  import "./chunk-B7GUYYAN.js";
37
- import "./chunk-RP4YJYNB.js";
37
+ import "./chunk-VOEFHED3.js";
38
38
  import "./chunk-QGM4M3NI.js";
39
39
  export {
40
40
  CHUNK_MORTALITY_PERIOD,
package/dist/dotns.js CHANGED
@@ -35,10 +35,10 @@ import {
35
35
  stripTrailingDigits,
36
36
  validateDomainLabel,
37
37
  verifyNonceAdvanced
38
- } from "./chunk-TOFKHL4S.js";
39
- import "./chunk-IXUFM7P6.js";
40
- import "./chunk-B2MLOHKF.js";
41
- import "./chunk-RP4YJYNB.js";
38
+ } from "./chunk-CORAWOVZ.js";
39
+ import "./chunk-MWBV5N6B.js";
40
+ import "./chunk-6JL2SBBI.js";
41
+ import "./chunk-VOEFHED3.js";
42
42
  import "./chunk-QGM4M3NI.js";
43
43
  export {
44
44
  CONNECTION_TIMEOUT_MS,
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  deploy
3
- } from "./chunk-PGCTJF2J.js";
4
- import "./chunk-E2ZOGJ5R.js";
5
- import "./chunk-DFD2WF67.js";
3
+ } from "./chunk-OG3S2NTO.js";
4
+ import "./chunk-QAJNUXBO.js";
5
+ import "./chunk-N7PS2WTI.js";
6
6
  import {
7
7
  DotNS,
8
8
  parseDomainName
9
- } from "./chunk-TOFKHL4S.js";
9
+ } from "./chunk-CORAWOVZ.js";
10
10
  import "./chunk-HOTQDYHD.js";
11
- import "./chunk-IXUFM7P6.js";
11
+ import "./chunk-MWBV5N6B.js";
12
12
  import {
13
13
  VERSION,
14
14
  loadRunState,
@@ -18,7 +18,7 @@ import {
18
18
  shouldSkipStaleWarning,
19
19
  stateFilePath,
20
20
  writeRunState
21
- } from "./chunk-B2MLOHKF.js";
21
+ } from "./chunk-6JL2SBBI.js";
22
22
  import {
23
23
  merkleizeJS
24
24
  } from "./chunk-B7GUYYAN.js";
@@ -28,7 +28,7 @@ import {
28
28
  ensureAuthorized,
29
29
  fetchPoolAuthorizations,
30
30
  selectAccount
31
- } from "./chunk-RP4YJYNB.js";
31
+ } from "./chunk-VOEFHED3.js";
32
32
  import "./chunk-QGM4M3NI.js";
33
33
  export {
34
34
  DotNS,
@@ -5,8 +5,8 @@ import {
5
5
  maybeWriteMemoryReport,
6
6
  safeHeap,
7
7
  sampleFromBytes
8
- } from "./chunk-IXUFM7P6.js";
9
- import "./chunk-B2MLOHKF.js";
8
+ } from "./chunk-MWBV5N6B.js";
9
+ import "./chunk-6JL2SBBI.js";
10
10
  import "./chunk-QGM4M3NI.js";
11
11
  export {
12
12
  DEFAULT_THRESHOLD_MB,
package/dist/pool.d.ts CHANGED
@@ -11,9 +11,10 @@ interface PoolAccount {
11
11
  interface PoolAuthorization extends PoolAccount {
12
12
  transactions: bigint;
13
13
  bytes: bigint;
14
+ expiration: number;
14
15
  }
15
16
  declare function derivePoolAccounts(poolSize?: number, mnemonic?: string): PoolAccount[];
16
- declare function selectAccount(authorizations: PoolAuthorization[], random?: () => number): PoolAuthorization | null;
17
+ declare function selectAccount(authorizations: PoolAuthorization[], random?: () => number, currentBlock?: number): PoolAuthorization | null;
17
18
  declare function fetchPoolAuthorizations(api: any, accounts: PoolAccount[]): Promise<PoolAuthorization[]>;
18
19
  interface AuthorizationNeeds {
19
20
  txs: bigint;
@@ -31,7 +32,7 @@ declare function classifyAliceTxError(err: unknown): TxRetryDecision;
31
32
  declare function isTestnetSpecName(specName: string | undefined | null): boolean;
32
33
  declare function detectTestnet(api: any): Promise<boolean>;
33
34
  declare function _resetTestnetCacheForTests(): void;
34
- declare function ensureAuthorized(api: any, address: string, label?: string, minimum?: AuthorizationNeeds): Promise<void>;
35
+ declare function ensureAuthorized(api: any, address: string, label?: string): Promise<void>;
35
36
  declare function topUpBy(api: any, address: string, needs: AuthorizationNeeds, label?: string): Promise<void>;
36
37
  declare function bootstrapPool(bulletinRpc: string, poolSize?: number, mnemonic?: string): Promise<void>;
37
38
 
package/dist/pool.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  isTestnetSpecName,
12
12
  selectAccount,
13
13
  topUpBy
14
- } from "./chunk-RP4YJYNB.js";
14
+ } from "./chunk-VOEFHED3.js";
15
15
  import "./chunk-QGM4M3NI.js";
16
16
  export {
17
17
  _resetTestnetCacheForTests,
package/dist/run-state.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  shouldSkipStaleWarning,
8
8
  stateFilePath,
9
9
  writeRunState
10
- } from "./chunk-B2MLOHKF.js";
10
+ } from "./chunk-6JL2SBBI.js";
11
11
  import "./chunk-QGM4M3NI.js";
12
12
  export {
13
13
  VERSION,
@@ -23,6 +23,10 @@ declare function resolveRunner(): string;
23
23
  declare function resolveRunnerType(): string;
24
24
  declare function getDeployAttributes(domain: string): Record<string, string | number | boolean | undefined>;
25
25
  declare function isExpectedError(msg: string): boolean;
26
+ type DeployErrorCategory = 'user' | 'environment' | 'internal' | 'unknown';
27
+ declare function classifyDeployError(msg: string): DeployErrorCategory;
28
+ declare function classifySadReason(message: string): string;
29
+ declare function computeDeployOutcome(errorCategory: DeployErrorCategory | null, isSad: boolean, sadReason: string): string;
26
30
  declare function withSpan<T>(op: string, description: string, attributes: Record<string, string | number | boolean | undefined>, fn: () => T | Promise<T>): Promise<T>;
27
31
  declare function sampleMemory(stage: string): void;
28
32
  declare function withDeploySpan<T>(domain: string, fn: () => T | Promise<T>): Promise<T>;
@@ -35,4 +39,4 @@ declare function setDeploySentryTag(key: string, value: string): void;
35
39
  declare function captureWarning(message: string, context?: Record<string, unknown>): void;
36
40
  declare function flush(): Promise<void>;
37
41
 
38
- export { type InternalContextSignals, VERSION, captureWarning, closeTelemetry, flush, getCurrentSentryTraceId, getDeployAttributes, initTelemetry, isExpectedError, isInternalContext, isInternalContextFromSignals, markRelaunchOomHintShown, resolveRepo, resolveRunner, resolveRunnerType, sampleMemory, sanitizeBranch, sanitizeRepo, scrubPaths, setDeployAttribute, setDeployReportContext, setDeploySentryTag, setRunStateActive, truncateAddress, withDeploySpan, withSpan };
42
+ export { type DeployErrorCategory, type InternalContextSignals, VERSION, captureWarning, classifyDeployError, classifySadReason, closeTelemetry, computeDeployOutcome, flush, getCurrentSentryTraceId, getDeployAttributes, initTelemetry, isExpectedError, isInternalContext, isInternalContextFromSignals, markRelaunchOomHintShown, resolveRepo, resolveRunner, resolveRunnerType, sampleMemory, sanitizeBranch, sanitizeRepo, scrubPaths, setDeployAttribute, setDeployReportContext, setDeploySentryTag, setRunStateActive, truncateAddress, withDeploySpan, withSpan };
package/dist/telemetry.js CHANGED
@@ -1,7 +1,10 @@
1
1
  import {
2
2
  VERSION,
3
3
  captureWarning,
4
+ classifyDeployError,
5
+ classifySadReason,
4
6
  closeTelemetry,
7
+ computeDeployOutcome,
5
8
  flush,
6
9
  getCurrentSentryTraceId,
7
10
  getDeployAttributes,
@@ -24,13 +27,16 @@ import {
24
27
  truncateAddress,
25
28
  withDeploySpan,
26
29
  withSpan
27
- } from "./chunk-IXUFM7P6.js";
28
- import "./chunk-B2MLOHKF.js";
30
+ } from "./chunk-MWBV5N6B.js";
31
+ import "./chunk-6JL2SBBI.js";
29
32
  import "./chunk-QGM4M3NI.js";
30
33
  export {
31
34
  VERSION,
32
35
  captureWarning,
36
+ classifyDeployError,
37
+ classifySadReason,
33
38
  closeTelemetry,
39
+ computeDeployOutcome,
34
40
  flush,
35
41
  getCurrentSentryTraceId,
36
42
  getDeployAttributes,
@@ -8,9 +8,9 @@ import {
8
8
  isPreReleaseVersion,
9
9
  preReleaseWarning,
10
10
  promptYesNo
11
- } from "./chunk-DFD2WF67.js";
12
- import "./chunk-IXUFM7P6.js";
13
- import "./chunk-B2MLOHKF.js";
11
+ } from "./chunk-N7PS2WTI.js";
12
+ import "./chunk-MWBV5N6B.js";
13
+ import "./chunk-6JL2SBBI.js";
14
14
  import "./chunk-QGM4M3NI.js";
15
15
  export {
16
16
  assessVersion,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulletin-deploy",
3
- "version": "0.7.10",
3
+ "version": "0.7.12-rc.1",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",