bulletin-deploy 0.6.5 → 0.6.6-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { deploy, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE } from "../dist/deploy.js";
3
+ import { deploy, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, NonRetryableError, EXIT_CODE_NO_RETRY } from "../dist/deploy.js";
4
4
  import { bootstrapPool } from "../dist/pool.js";
5
5
  import { VERSION } from "../dist/telemetry.js";
6
6
  import * as fs from "fs";
@@ -74,6 +74,7 @@ try {
74
74
  }
75
75
  process.exit(0);
76
76
  } catch (error) {
77
- console.error("Deployment failed:", error.message);
78
- process.exit(1);
77
+ const noRetry = error instanceof NonRetryableError;
78
+ console.error(`Deployment failed${noRetry ? " (not retryable)" : ""}:`, error.message);
79
+ process.exit(noRetry ? EXIT_CODE_NO_RETRY : 1);
79
80
  }
@@ -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.6.5",
9
+ version: "0.6.6-rc.0",
10
10
  private: false,
11
11
  repository: {
12
12
  type: "git",
@@ -65,7 +65,7 @@ var package_default = {
65
65
 
66
66
  // src/telemetry.ts
67
67
  var VERSION = package_default.version;
68
- var DEFAULT_DSN = "https://e021c025d79c4c3ade2862a11f13c40b@o4509440811401216.ingest.de.sentry.io/4511093597405264";
68
+ var DEFAULT_DSN = "https://e021c025d79c4c3ade2862a11f13c40b@o4511059872841728.ingest.de.sentry.io/4511093597405264";
69
69
  var DISABLED = process.env.BULLETIN_DEPLOY_TELEMETRY === "0";
70
70
  var Sentry = null;
71
71
  if (!DISABLED) {
@@ -87,7 +87,7 @@ function extractRepoSlug(url) {
87
87
  }
88
88
  function tryGitRemote() {
89
89
  try {
90
- return extractRepoSlug(execSync("git remote get-url origin", { encoding: "utf-8" }).trim());
90
+ return extractRepoSlug(execSync("git remote get-url origin", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim());
91
91
  } catch {
92
92
  return void 0;
93
93
  }
@@ -106,7 +106,7 @@ function resolveRepo(domain) {
106
106
  }
107
107
  function tryGitBranch() {
108
108
  try {
109
- return execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf-8" }).trim();
109
+ return execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
110
110
  } catch {
111
111
  return "unknown";
112
112
  }
@@ -4,13 +4,13 @@ import {
4
4
  TX_TIMEOUT_MS,
5
5
  fetchNonce,
6
6
  validateDomainLabel
7
- } from "./chunk-S7ZSIIY4.js";
7
+ } from "./chunk-DEUNAION.js";
8
8
  import {
9
9
  derivePoolAccounts,
10
10
  ensureAuthorized,
11
11
  fetchPoolAuthorizations,
12
12
  selectAccount
13
- } from "./chunk-AIHW2WLO.js";
13
+ } from "./chunk-LGPTJYA3.js";
14
14
  import {
15
15
  VERSION,
16
16
  captureWarning,
@@ -18,7 +18,7 @@ import {
18
18
  setDeployAttribute,
19
19
  withDeploySpan,
20
20
  withSpan
21
- } from "./chunk-BR35ORSD.js";
21
+ } from "./chunk-3MATO55H.js";
22
22
 
23
23
  // src/deploy.ts
24
24
  import { Buffer } from "buffer";
@@ -294,6 +294,13 @@ var cdm_default = {
294
294
  };
295
295
 
296
296
  // src/deploy.ts
297
+ var NonRetryableError = class extends Error {
298
+ constructor(message) {
299
+ super(message);
300
+ this.name = "NonRetryableError";
301
+ }
302
+ };
303
+ var EXIT_CODE_NO_RETRY = 78;
297
304
  var DEFAULT_BULLETIN_RPC = "wss://paseo-bulletin-rpc.polkadot.io";
298
305
  var DEFAULT_POOL_SIZE = 10;
299
306
  var BULLETIN_RPC = DEFAULT_BULLETIN_RPC;
@@ -301,7 +308,7 @@ var POOL_SIZE = DEFAULT_POOL_SIZE;
301
308
  var CHUNK_SIZE = 1 * 1024 * 1024;
302
309
  var MAX_FILE_SIZE = 8 * 1024 * 1024;
303
310
  var MAX_RECONNECTIONS = parseInt(process.env.BULLETIN_MAX_RECONNECTIONS ?? "3", 10);
304
- var CHUNK_TIMEOUT_MS = 3e4;
311
+ var CHUNK_TIMEOUT_MS = parseInt(process.env.BULLETIN_CHUNK_TIMEOUT_MS ?? "60000", 10);
305
312
  var RETRY_BASE_DELAY_MS = 2e3;
306
313
  var RETRY_MAX_DELAY_MS = 15e3;
307
314
  function isConnectionError(error) {
@@ -395,10 +402,10 @@ async function getProvider() {
395
402
  if (!selected) {
396
403
  const best = authorizations.reduce((a, b) => a.transactions > b.transactions ? a : b);
397
404
  console.log(` All pool accounts low on capacity, auto-authorizing account ${best.index}...`);
398
- await ensureAuthorized(unsafeApi, best, BULLETIN_RPC);
405
+ await ensureAuthorized(unsafeApi, best.address, BULLETIN_RPC, `pool account ${best.index}`);
399
406
  selected = best;
400
407
  } else {
401
- await ensureAuthorized(unsafeApi, selected, BULLETIN_RPC);
408
+ await ensureAuthorized(unsafeApi, selected.address, BULLETIN_RPC, `pool account ${selected.index}`);
402
409
  }
403
410
  console.log(` Using pool account ${selected.index}: ${selected.address}`);
404
411
  setDeployAttribute("deploy.signer.mode", "pool");
@@ -423,7 +430,7 @@ async function getDirectProvider(mnemonic) {
423
430
  const bytesRemaining = auth ? auth.extent.bytes : 0n;
424
431
  if (txsRemaining === 0n && bytesRemaining === 0n) {
425
432
  client.destroy();
426
- throw new Error(`Account ${ss58} is not authorized for Bulletin storage. Run 'bulletin-deploy --bootstrap --mnemonic "..."' or authorize the account on-chain first.`);
433
+ throw new NonRetryableError(`Account ${ss58} is not authorized for Bulletin storage.`);
427
434
  }
428
435
  console.log(` Authorization: ${txsRemaining} txs, ${Number(bytesRemaining) / 1e6}MB remaining`);
429
436
  setDeployAttribute("deploy.signer.mode", "direct");
@@ -561,6 +568,23 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
561
568
  ss58 = provider.ss58;
562
569
  ownsClient = true;
563
570
  }
571
+ const requiredTxs = BigInt(chunks.length + 1);
572
+ const auth = await unsafeApi.query.TransactionStorage.Authorizations.getValue(
573
+ Enum("Account", ss58)
574
+ );
575
+ const txsRemaining = auth ? BigInt(auth.extent.transactions) : 0n;
576
+ const bytesRemaining = auth ? auth.extent.bytes : 0n;
577
+ if (txsRemaining < requiredTxs || bytesRemaining < BigInt(totalBytes)) {
578
+ console.log(`
579
+ Account has insufficient authorization for this upload (need ${requiredTxs} txs / ${(totalBytes / 1e6).toFixed(1)}MB, have ${txsRemaining} txs / ${Number(bytesRemaining) / 1e6}MB)`);
580
+ console.log(` Attempting to re-authorize with Alice...`);
581
+ try {
582
+ await ensureAuthorized(unsafeApi, ss58, BULLETIN_RPC);
583
+ console.log(` Re-authorization successful`);
584
+ } catch (e) {
585
+ throw new Error(`Re-authorization failed: ${e.message}`);
586
+ }
587
+ }
564
588
  let reconnectionsUsed = 0;
565
589
  async function doReconnect() {
566
590
  if (!reconnect || reconnectionsUsed >= MAX_RECONNECTIONS) {
@@ -790,6 +814,24 @@ async function deploy(content, domainName = null, options = {}) {
790
814
  let provider;
791
815
  const reconnect = options.mnemonic ? () => getDirectProvider(options.mnemonic) : () => getProvider();
792
816
  try {
817
+ console.log("\n" + "=".repeat(60));
818
+ console.log("Preflight");
819
+ console.log("=".repeat(60));
820
+ const preflight = new DotNS();
821
+ await preflight.connect(
822
+ options.signer && options.signerAddress ? { signer: options.signer, signerAddress: options.signerAddress } : options.mnemonic ? { mnemonic: options.mnemonic } : {}
823
+ );
824
+ const { owned, owner } = await preflight.checkOwnership(name);
825
+ if (owner && owner !== "0x0000000000000000000000000000000000000000" && !owned) {
826
+ preflight.disconnect();
827
+ throw new NonRetryableError(`Domain ${name}.dot is owned by a different account (${owner}). To fix, transfer it:
828
+
829
+ dotns lookup transfer ${name} -d ${preflight.evmAddress}
830
+
831
+ Or deploy with the original account, or use a different domain name.`);
832
+ }
833
+ console.log(` Domain: ${owned ? "owned by you" : "available"}`);
834
+ preflight.disconnect();
793
835
  provider = await reconnect();
794
836
  const providerWithReconnect = { ...provider, reconnect };
795
837
  console.log("\n" + "=".repeat(60));
@@ -873,11 +915,9 @@ async function deploy(content, domainName = null, options = {}) {
873
915
  await dotns.connect(
874
916
  options.signer && options.signerAddress ? { signer: options.signer, signerAddress: options.signerAddress } : options.mnemonic ? { mnemonic: options.mnemonic } : {}
875
917
  );
876
- const { owned, owner } = await dotns.checkOwnership(name);
877
- if (owned) {
918
+ const { owned: owned2 } = await dotns.checkOwnership(name);
919
+ if (owned2) {
878
920
  console.log(` Status: Already owned`);
879
- } else if (owner && owner !== "0x0000000000000000000000000000000000000000") {
880
- throw new Error(`Domain ${name}.dot is owned by ${owner}, not ${dotns.evmAddress}`);
881
921
  } else {
882
922
  console.log(` Status: Registering...`);
883
923
  await dotns.register(name);
@@ -942,6 +982,8 @@ async function deploy(content, domainName = null, options = {}) {
942
982
  }
943
983
 
944
984
  export {
985
+ NonRetryableError,
986
+ EXIT_CODE_NO_RETRY,
945
987
  DEFAULT_BULLETIN_RPC,
946
988
  DEFAULT_POOL_SIZE,
947
989
  isConnectionError,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  captureWarning,
3
3
  withSpan
4
- } from "./chunk-BR35ORSD.js";
4
+ } from "./chunk-3MATO55H.js";
5
5
 
6
6
  // src/dotns.ts
7
7
  import crypto from "crypto";
@@ -55,16 +55,16 @@ async function fetchPoolAuthorizations(api, accounts) {
55
55
  );
56
56
  return results;
57
57
  }
58
- async function ensureAuthorized(api, poolAccount, bulletinRpc) {
58
+ async function ensureAuthorized(api, address, bulletinRpc, label) {
59
59
  const auth = await api.query.TransactionStorage.Authorizations.getValue(
60
- Enum("Account", poolAccount.address)
60
+ Enum("Account", address)
61
61
  );
62
62
  const txsRemaining = auth ? BigInt(auth.extent.transactions) : 0n;
63
63
  const bytesRemaining = auth ? auth.extent.bytes : 0n;
64
64
  if (txsRemaining >= TOPUP_THRESHOLD_TXS && bytesRemaining >= TOPUP_THRESHOLD_BYTES) {
65
65
  return;
66
66
  }
67
- console.log(` Auto-authorizing pool account ${poolAccount.index} (${poolAccount.address.slice(0, 8)}...)...`);
67
+ console.log(` Auto-authorizing ${label ?? "account"} (${address.slice(0, 8)}...)...`);
68
68
  const aliceClient = createClient(withPolkadotSdkCompat(getWsProvider(bulletinRpc)));
69
69
  const aliceApi = aliceClient.getUnsafeApi();
70
70
  try {
@@ -72,7 +72,7 @@ async function ensureAuthorized(api, poolAccount, bulletinRpc) {
72
72
  const alice = keyring.addFromUri("//Alice");
73
73
  const aliceSigner = getPolkadotSigner(alice.publicKey, "Sr25519", (data) => alice.sign(data));
74
74
  const tx = aliceApi.tx.TransactionStorage.authorize_account({
75
- who: poolAccount.address,
75
+ who: address,
76
76
  transactions: TOPUP_TRANSACTIONS,
77
77
  bytes: TOPUP_BYTES
78
78
  });
package/dist/deploy.d.ts CHANGED
@@ -8,6 +8,10 @@ interface DeployResult {
8
8
  ipfsCid?: string;
9
9
  }
10
10
  type DeployContent = string | Uint8Array | Uint8Array[];
11
+ declare class NonRetryableError extends Error {
12
+ constructor(message: string);
13
+ }
14
+ declare const EXIT_CODE_NO_RETRY = 78;
11
15
  interface ProviderResult {
12
16
  client: any;
13
17
  unsafeApi: any;
@@ -62,4 +66,4 @@ interface DeployOptions {
62
66
  }
63
67
  declare function deploy(content: DeployContent, domainName?: string | null, options?: DeployOptions): Promise<DeployResult>;
64
68
 
65
- export { 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, chunk, createCID, deploy, deriveRootSigner, encodeContenthash, encryptContent, hasIPFS, isConnectionError, merkleize, storeChunkedContent, storeDirectory, storeFile };
69
+ export { 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, chunk, createCID, deploy, deriveRootSigner, encodeContenthash, encryptContent, hasIPFS, isConnectionError, merkleize, storeChunkedContent, storeDirectory, storeFile };
package/dist/deploy.js CHANGED
@@ -7,6 +7,8 @@ import {
7
7
  ENCRYPT_PBKDF2_ITERATIONS,
8
8
  ENCRYPT_SALT_LEN,
9
9
  ENCRYPT_TAG_LEN,
10
+ EXIT_CODE_NO_RETRY,
11
+ NonRetryableError,
10
12
  chunk,
11
13
  createCID,
12
14
  deploy,
@@ -19,10 +21,10 @@ import {
19
21
  storeChunkedContent,
20
22
  storeDirectory,
21
23
  storeFile
22
- } from "./chunk-QB7UH3NR.js";
23
- import "./chunk-S7ZSIIY4.js";
24
- import "./chunk-AIHW2WLO.js";
25
- import "./chunk-BR35ORSD.js";
24
+ } from "./chunk-BDJLYUP6.js";
25
+ import "./chunk-DEUNAION.js";
26
+ import "./chunk-LGPTJYA3.js";
27
+ import "./chunk-3MATO55H.js";
26
28
  import "./chunk-QGM4M3NI.js";
27
29
  export {
28
30
  DEFAULT_BULLETIN_RPC,
@@ -33,6 +35,8 @@ export {
33
35
  ENCRYPT_PBKDF2_ITERATIONS,
34
36
  ENCRYPT_SALT_LEN,
35
37
  ENCRYPT_TAG_LEN,
38
+ EXIT_CODE_NO_RETRY,
39
+ NonRetryableError,
36
40
  chunk,
37
41
  createCID,
38
42
  deploy,
package/dist/dotns.js CHANGED
@@ -19,8 +19,8 @@ import {
19
19
  sanitizeDomainLabel,
20
20
  stripTrailingDigits,
21
21
  validateDomainLabel
22
- } from "./chunk-S7ZSIIY4.js";
23
- import "./chunk-BR35ORSD.js";
22
+ } from "./chunk-DEUNAION.js";
23
+ import "./chunk-3MATO55H.js";
24
24
  import "./chunk-QGM4M3NI.js";
25
25
  export {
26
26
  CONNECTION_TIMEOUT_MS,
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  deploy
3
- } from "./chunk-QB7UH3NR.js";
3
+ } from "./chunk-BDJLYUP6.js";
4
4
  import {
5
5
  DotNS
6
- } from "./chunk-S7ZSIIY4.js";
6
+ } from "./chunk-DEUNAION.js";
7
7
  import {
8
8
  bootstrapPool,
9
9
  derivePoolAccounts,
10
10
  ensureAuthorized,
11
11
  fetchPoolAuthorizations,
12
12
  selectAccount
13
- } from "./chunk-AIHW2WLO.js";
14
- import "./chunk-BR35ORSD.js";
13
+ } from "./chunk-LGPTJYA3.js";
14
+ import "./chunk-3MATO55H.js";
15
15
  import "./chunk-QGM4M3NI.js";
16
16
  export {
17
17
  DotNS,
package/dist/pool.d.ts CHANGED
@@ -14,7 +14,7 @@ interface PoolAuthorization extends PoolAccount {
14
14
  declare function derivePoolAccounts(poolSize?: number, mnemonic?: string): PoolAccount[];
15
15
  declare function selectAccount(authorizations: PoolAuthorization[]): PoolAuthorization | null;
16
16
  declare function fetchPoolAuthorizations(api: any, accounts: PoolAccount[]): Promise<PoolAuthorization[]>;
17
- declare function ensureAuthorized(api: any, poolAccount: PoolAccount, bulletinRpc: string): Promise<void>;
17
+ declare function ensureAuthorized(api: any, address: string, bulletinRpc: string, label?: string): Promise<void>;
18
18
  declare function bootstrapPool(bulletinRpc: string, poolSize?: number, mnemonic?: string): Promise<void>;
19
19
 
20
20
  export { type PoolAccount, type PoolAuthorization, bootstrapPool, derivePoolAccounts, ensureAuthorized, fetchPoolAuthorizations, selectAccount };
package/dist/pool.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  ensureAuthorized,
5
5
  fetchPoolAuthorizations,
6
6
  selectAccount
7
- } from "./chunk-AIHW2WLO.js";
7
+ } from "./chunk-LGPTJYA3.js";
8
8
  import "./chunk-QGM4M3NI.js";
9
9
  export {
10
10
  bootstrapPool,
package/dist/telemetry.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  setDeployAttribute,
9
9
  withDeploySpan,
10
10
  withSpan
11
- } from "./chunk-BR35ORSD.js";
11
+ } from "./chunk-3MATO55H.js";
12
12
  import "./chunk-QGM4M3NI.js";
13
13
  export {
14
14
  VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulletin-deploy",
3
- "version": "0.6.5",
3
+ "version": "0.6.6-rc.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",