@parity/product-deploy 0.8.1 → 0.8.2-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.
Files changed (39) hide show
  1. package/README.md +2 -230
  2. package/assets/environments.json +6 -0
  3. package/bin/bulletin-deploy +15 -1
  4. package/dist/bug-report.js +4 -4
  5. package/dist/{chunk-IRT4A7OO.js → chunk-2GBSYVK2.js} +139 -31
  6. package/dist/{chunk-CNPB4VAM.js → chunk-5K3RI5C2.js} +71 -0
  7. package/dist/{chunk-O2BFXY3Y.js → chunk-EJWZGSHD.js} +1 -1
  8. package/dist/{chunk-MXMVZU2Q.js → chunk-H64ZLWW2.js} +2 -2
  9. package/dist/{chunk-WPJADKC7.js → chunk-HPPLVGGC.js} +73 -42
  10. package/dist/{chunk-L2SKSKB6.js → chunk-J3NIXHZZ.js} +108 -0
  11. package/dist/{chunk-RW3GWDGI.js → chunk-JQ5X3VMP.js} +15 -102
  12. package/dist/{chunk-V5N5EYNV.js → chunk-NJPBXF5Z.js} +6 -3
  13. package/dist/{chunk-INVA3XGG.js → chunk-RIAMPAL2.js} +88 -77
  14. package/dist/{chunk-R2CJ5I5R.js → chunk-TQC3S6NP.js} +3 -3
  15. package/dist/{chunk-KB3EII7F.js → chunk-WSBDIHFZ.js} +1 -1
  16. package/dist/chunk-probe.js +3 -3
  17. package/dist/deploy.d.ts +38 -1
  18. package/dist/deploy.js +16 -10
  19. package/dist/dotns.d.ts +33 -2
  20. package/dist/dotns.js +9 -5
  21. package/dist/environments.d.ts +17 -4
  22. package/dist/environments.js +3 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +13 -11
  25. package/dist/manifest/publish.js +11 -11
  26. package/dist/manifest-fetch.d.ts +22 -1
  27. package/dist/manifest-fetch.js +7 -1
  28. package/dist/manifest-roundtrip.js +1 -1
  29. package/dist/memory-report.js +2 -2
  30. package/dist/merkle.js +10 -10
  31. package/dist/personhood/bootstrap.js +5 -5
  32. package/dist/personhood/people-client.js +5 -5
  33. package/dist/pool.d.ts +2 -12
  34. package/dist/pool.js +3 -11
  35. package/dist/run-state.js +1 -1
  36. package/dist/telemetry.js +2 -2
  37. package/dist/version-check.js +3 -3
  38. package/docs/bootstrap.md +1 -1
  39. package/package.json +6 -3
@@ -6,7 +6,7 @@ import * as path from "path";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@parity/product-deploy",
9
- version: "0.8.1",
9
+ version: "0.8.2-rc.1",
10
10
  private: false,
11
11
  repository: {
12
12
  type: "git",
@@ -35,6 +35,10 @@ var package_default = {
35
35
  "./manifest-roundtrip": {
36
36
  types: "./dist/manifest-roundtrip.d.ts",
37
37
  import: "./dist/manifest-roundtrip.js"
38
+ },
39
+ "./telemetry": {
40
+ types: "./dist/telemetry.d.ts",
41
+ import: "./dist/telemetry.js"
38
42
  }
39
43
  },
40
44
  files: [
@@ -47,9 +51,8 @@ var package_default = {
47
51
  scripts: {
48
52
  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/personhood/encoding.ts src/personhood/hashing.ts src/personhood/constants.ts src/personhood/member-key.ts src/personhood/people-client.ts src/personhood/proof-validity.ts src/personhood/reprove.ts src/personhood/bind-personal-id.ts src/personhood/claim-pgas.ts src/personhood/bind-paid-alias.ts src/personhood/bootstrap.ts src/personhood/chain-prereqs.ts src/manifest/types.ts src/manifest/schema.ts src/manifest/byte-budget.ts src/manifest/config-load.ts src/manifest/publish.ts --format esm --dts --clean --target node22",
49
53
  "refresh-environments": "node scripts/refresh-environments.mjs",
50
- "check:watched-dependencies": "node tools/check-watched-dependencies.mjs",
51
54
  prepare: "npm run build",
52
- test: "npm run build && node --test test/test.js test/cli-help.test.js test/helpers/e2e-helpers.test.js test/environments.test.js test/refresh-environments.test.js test/watched-dependencies.test.js test/chunk-sharing-report.test.js test/product-manifest.test.js test/cache-savings-totals.test.js test/error-pattern-signature.test.js test/exit-codes.test.js test/probe-env-health.test.js test/e2e-chain-calls.test.js",
55
+ test: "npm run build && node --test test/test.js test/cli-help.test.js test/helpers/e2e-helpers.test.js test/environments.test.js test/refresh-environments.test.js test/chunk-sharing-report.test.js test/product-manifest.test.js test/cache-savings-totals.test.js test/error-pattern-signature.test.js test/exit-codes.test.js test/probe-env-health.test.js test/e2e-chain-calls.test.js",
53
56
  "test:e2e": "npm run build && node --test test/e2e.test.js",
54
57
  "test:e2e:smoke": "bash scripts/e2e-pass.sh smoke",
55
58
  "test:e2e:pr": "bash scripts/e2e-pass.sh pr",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  package_default,
3
3
  writeRunState
4
- } from "./chunk-V5N5EYNV.js";
4
+ } from "./chunk-NJPBXF5Z.js";
5
5
 
6
6
  // src/memory-report.ts
7
7
  import * as fs2 from "fs";
@@ -185,94 +185,104 @@ function resolveRunnerType() {
185
185
  if (process.env.RUNNER_NAME?.startsWith("parity-")) return "self-hosted";
186
186
  return "github-hosted";
187
187
  }
188
+ var DEPLOY_SEED_OUTCOME = {
189
+ "deploy.sad": "false",
190
+ "deploy.expected": "false"
191
+ };
192
+ var DEPLOY_SEED_RPC = {
193
+ "deploy.rpc.failed_over": "false"
194
+ };
195
+ var DEPLOY_SEED_DOTNS = {
196
+ // Preflight balance gate. Seeded "false" so successful spans form the denominator
197
+ // for "% hitting the floor" and "% recovered via testnet auto-top-up". Flipped by gateOnFeeBalance.
198
+ "deploy.dotns.signer_below_floor": "false",
199
+ "deploy.dotns.toppedup": "false",
200
+ // Seeded "hash" so spans for non-DotNS deploys group cleanly in the "hash" bucket.
201
+ "deploy.dotns.tx_resolution_kind": "hash",
202
+ // Backend identity (module constants — stable across calls).
203
+ "deploy.dotns_backend": DOTNS_BACKEND,
204
+ "deploy.dotns_pop_source": DOTNS_POP_SOURCE
205
+ };
206
+ var DEPLOY_SEED_CONTENT = {
207
+ // Flipped by deploy.ts storage phase when content is encrypted.
208
+ "deploy.encrypted": "false",
209
+ // Flipped by deploy.ts after parseDomainName resolves isSubdomain.
210
+ "deploy.subdomain": "false",
211
+ // Flipped by deploy.ts after readPreviousContenthashSafe when a prior CID is found.
212
+ "deploy.incremental": "false"
213
+ };
214
+ var DEPLOY_SEED_STORAGE = {
215
+ // Seeded "false"; flipped by storeDirectoryV2 when Phase A root node is already on-chain.
216
+ "deploy.storage.phase_a.root_already_onchain": "false",
217
+ // Seeded 0; incremented per Phase B chunk confirmed on-chain (probe hit → skip re-upload).
218
+ "deploy.storage.phase_b.probe_hit_count": 0,
219
+ "deploy.phase_a.chunks_uploaded": 0,
220
+ // Manifest-aware Phase A trust: count of section-1 CIDs trusted from prev manifest.
221
+ "deploy.phase_a.chunks_trusted": 0
222
+ };
223
+ var DEPLOY_SEED_PROBE = {
224
+ "deploy.probe.finality_miss_count": 0,
225
+ "deploy.probe.finality_miss_reupload_count": 0
226
+ };
227
+ var DEPLOY_SEED_POOL = {
228
+ "deploy.pool.eligible_count": 0,
229
+ // Nonce-advance collision probe counters. Seeded 0 so every span carries them.
230
+ "deploy.pool.nonce_collision_count": 0,
231
+ "deploy.pool.nonce_collision_missing": 0,
232
+ "deploy.pool.nonce_collision_reupload_count": 0
233
+ };
234
+ var DEPLOY_SEED_MANIFEST = {
235
+ "deploy.manifest.fetch_source": "none",
236
+ "deploy.manifest.fetch_attempts": "0",
237
+ "deploy.manifest.bytes_downloaded": "0"
238
+ };
239
+ var DEPLOY_SEED_BULLETIN_UPLOAD = {
240
+ "bulletin.upload.tx_hash": "",
241
+ "bulletin.upload.block_hash": "",
242
+ "bulletin.upload.block_number": ""
243
+ };
244
+ var DEPLOY_SEED_RECEIPTS = {
245
+ "deploy.contenthash.tx": "",
246
+ "deploy.contenthash.block": "",
247
+ "deploy.contenthash.block_hash": "",
248
+ "deploy.register.tx": "",
249
+ "deploy.register.block": "",
250
+ "deploy.register.block_hash": "",
251
+ "deploy.subnode.tx": "",
252
+ "deploy.subnode.block": "",
253
+ "deploy.subnode.block_hash": ""
254
+ };
255
+ var DEPLOY_SEED_P2P = {
256
+ "deploy.p2p.retrievable": "false",
257
+ "deploy.p2p.check_ms": "0",
258
+ "deploy.p2p.error_variant": "none"
259
+ };
188
260
  function getDeployAttributes(domain) {
189
261
  const hostApp = process.env.BULLETIN_DEPLOY_HOST_APP;
190
262
  const attrs = {
263
+ ...DEPLOY_SEED_OUTCOME,
264
+ ...DEPLOY_SEED_RPC,
265
+ ...DEPLOY_SEED_DOTNS,
266
+ ...DEPLOY_SEED_CONTENT,
267
+ ...DEPLOY_SEED_STORAGE,
268
+ ...DEPLOY_SEED_PROBE,
269
+ ...DEPLOY_SEED_POOL,
270
+ ...DEPLOY_SEED_MANIFEST,
271
+ ...DEPLOY_SEED_BULLETIN_UPLOAD,
272
+ ...DEPLOY_SEED_RECEIPTS,
273
+ ...DEPLOY_SEED_P2P,
274
+ // Computed at call time (depend on domain arg, env vars, or external process calls):
191
275
  "deploy.repo": sanitizeRepo(resolveRepo(domain)),
192
276
  "deploy.branch": sanitizeBranch(process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME || tryGitBranch()),
193
277
  "deploy.source": process.env.CI ? "ci" : "local",
194
278
  "deploy.pr": process.env.GITHUB_PR_NUMBER || void 0,
195
279
  "deploy.tool_version": VERSION,
196
280
  "deploy.runner": resolveRunner(),
197
- "deploy.runner_type": resolveRunnerType(),
198
- // Seed "false" so successful spans form the %SAD denominator; the catch block and
199
- // captureWarning flip it to "true" on friction.
200
- "deploy.sad": "false",
201
- // Same ratio-denominator reasoning as deploy.sad above, but for the
202
- // %EXPECTED-refusal metric: catch block flips to "true" when the error
203
- // matches isExpectedError (user-facing product rule, not tool friction).
204
- "deploy.expected": "false",
205
- // Seed "false" so every span carries the attribute (boolean-both-values rule).
206
- // Flipped to "true" by getWsProvider's onStatusChanged when papi connects to a
207
- // non-primary endpoint, and flushed again in deploy()'s finally block.
208
- "deploy.rpc.failed_over": "false",
209
- // DotNS preflight balance gate. Seeded "false" so successful spans form the
210
- // denominator for "% of deploys hitting the floor" and "% recovered via
211
- // testnet auto-top-up" metrics. Flipped by gateOnFeeBalance.
212
- "deploy.dotns.signer_below_floor": "false",
213
- "deploy.dotns.toppedup": "false",
214
- // Seeded "false" so every span carries the attribute for ratio queries.
215
- // Flipped to "true" by pool.ts ensureAuthorized / topUpBy when authorize_account
216
- // actually submits (i.e. re-auth was needed, not short-circuited).
217
- "deploy.unblock.bulletin_auth.fired": "false",
218
- // Seeded "hash" so spans missing an explicit set (non-DotNS deploys) group
219
- // cleanly in the "hash" bucket.
220
- "deploy.dotns.tx_resolution_kind": "hash",
221
- // Seeded "false" so every span carries the attribute for ratio queries.
222
- // Flipped by deploy.ts storage phase when content is encrypted.
223
- "deploy.encrypted": "false",
224
- // Flipped by deploy.ts after parseDomainName resolves isSubdomain.
225
- "deploy.subdomain": "false",
226
- // Flipped by deploy.ts after readPreviousContenthashSafe when a prior CID is found.
227
- "deploy.incremental": "false",
228
- // Seeded "false" so every span carries the attribute for ratio queries.
229
- // Flipped to "true" by storeDirectoryV2 when the Phase A root node is already on-chain.
230
- "deploy.storage.phase_a.root_already_onchain": "false",
231
- // Seeded 0 so every span carries the attribute; incremented by storeDirectoryV2
232
- // for each Phase B chunk confirmed present on-chain (probe hit → skip re-upload).
233
- "deploy.storage.phase_b.probe_hit_count": 0,
234
- "deploy.phase_a.chunks_uploaded": 0,
235
- "deploy.probe.finality_miss_count": 0,
236
- "deploy.probe.finality_miss_reupload_count": 0,
237
- "deploy.pool.eligible_count": 0,
238
- // Nonce-advance collision probe counters. Seeded to 0 so every span carries
239
- // the attribute for ratio queries even when no collision is detected.
240
- "deploy.pool.nonce_collision_count": 0,
241
- "deploy.pool.nonce_collision_missing": 0,
242
- "deploy.pool.nonce_collision_reupload_count": 0,
243
- // Manifest-aware Phase A trust: count of section-1 CIDs trusted from prev manifest.
244
- "deploy.phase_a.chunks_trusted": 0,
245
- // Manifest fetch outcome. Seeded so every span carries the attributes even when
246
- // fetchPreviousManifest is never reached (first deploy, early error, non-incremental
247
- // path). "none" + "0" form the denominator for ratio queries:
248
- // count_if(deploy.manifest.fetch_source, "heuristic_fallback") / count().
249
- // Both string-valued per @sentry/node EAP numeric-attribute caveat.
250
- "deploy.manifest.fetch_source": "none",
251
- "deploy.manifest.fetch_attempts": "0",
252
- "deploy.manifest.bytes_downloaded": "0",
253
- // Bulletin storage upload chain receipt (root-node tx, or last chunk when root skipped).
254
- // Empty-string default so every span carries the attribute for filter queries.
255
- "bulletin.upload.tx_hash": "",
256
- "bulletin.upload.block_hash": "",
257
- "bulletin.upload.block_number": 0,
258
- // DotNS setContenthash chain receipt.
259
- "deploy.contenthash.tx": "",
260
- "deploy.contenthash.block": 0,
261
- "deploy.contenthash.block_hash": "",
262
- // DotNS register chain receipt (fresh registrations only).
263
- "deploy.register.tx": "",
264
- "deploy.register.block": 0,
265
- "deploy.register.block_hash": "",
266
- // DotNS setSubnodeOwner chain receipt (subdomain registrations only).
267
- "deploy.subnode.tx": "",
268
- "deploy.subnode.block": 0,
269
- "deploy.subnode.block_hash": ""
281
+ "deploy.runner_type": resolveRunnerType()
270
282
  };
271
283
  if (hostApp) attrs["deploy.host_app"] = hostApp;
272
284
  const hostAppVersion = process.env.BULLETIN_DEPLOY_HOST_APP_VERSION;
273
285
  if (hostAppVersion) attrs["deploy.host_app_version"] = hostAppVersion;
274
- attrs["deploy.dotns_backend"] = DOTNS_BACKEND;
275
- attrs["deploy.dotns_pop_source"] = DOTNS_POP_SOURCE;
276
286
  return attrs;
277
287
  }
278
288
  function isExpectedError(msg) {
@@ -280,7 +290,7 @@ function isExpectedError(msg) {
280
290
  }
281
291
  function classifyDeployError(msg) {
282
292
  if (isExpectedError(msg)) return "user";
283
- 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|not finalised after \d+s|chain may have (dropped|evicted)|ReviveApi.*timed out|\b(?:commit|register|setSubnodeOwner|setResolver|setContenthash|setText|publish|unpublish|Revive\.call|Utility\.batch_all) timed out after \d+ms|transaction watcher silent for/i.test(msg)) return "environment";
293
+ 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|not finalised after \d+s|chain may have (dropped|evicted)|ReviveApi.*timed out|ReviveApi.*returned empty result|\b(?:commit|register|setSubnodeOwner|setResolver|setContenthash|setText|publish|unpublish|Revive\.call|Utility\.batch_all) timed out after \d+ms|transaction watcher silent for/i.test(msg)) return "environment";
284
294
  if (/javascript heap out of memory|allocation failed.*heap|External signer mode is not supported with dotns-cli/i.test(msg)) return "internal";
285
295
  return "unknown";
286
296
  }
@@ -312,6 +322,7 @@ var ERROR_KIND_RULES = [
312
322
  [/Deploy verification failed:\s*DAG-PB root.+not finalised/i, "verify.dagpb_not_finalised"],
313
323
  [/Retry budget exhausted:.*recovery attempts/i, "network.recovery_exhausted"],
314
324
  [/ReviveApi\.\w+ timed out after \d+ms/i, "chain.api_timeout"],
325
+ [/ReviveApi\.\w+ returned empty result/i, "chain.api_timeout"],
315
326
  [/transaction watcher silent for \d+s/i, "chain.tx_silent"],
316
327
  [/^(?:commit|register|setSubnodeOwner|setResolver|setContenthash|setText|publish|unpublish|Revive\.call|Utility\.batch_all) timed out after \d+ms/i, "chain.tx_timeout"],
317
328
  [/^INVARIANT FAILED:/i, "tool.invariant"]
@@ -6,15 +6,15 @@ import {
6
6
  resolveDotnsConnectOptions,
7
7
  storeDirectory,
8
8
  storeFile
9
- } from "./chunk-WPJADKC7.js";
9
+ } from "./chunk-HPPLVGGC.js";
10
10
  import {
11
11
  DotNS
12
- } from "./chunk-IRT4A7OO.js";
12
+ } from "./chunk-2GBSYVK2.js";
13
13
  import {
14
14
  getPopSelfServeConfig,
15
15
  loadEnvironments,
16
16
  resolveEndpoints
17
- } from "./chunk-CNPB4VAM.js";
17
+ } from "./chunk-5K3RI5C2.js";
18
18
  import {
19
19
  NonRetryableError
20
20
  } from "./chunk-ZOC4GITL.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  captureWarning
3
- } from "./chunk-INVA3XGG.js";
3
+ } from "./chunk-RIAMPAL2.js";
4
4
 
5
5
  // src/chunk-probe.ts
6
6
  import { Twox128, Blake2128Concat, decAnyMetadata, unifyMetadata } from "@polkadot-api/substrate-bindings";
@@ -5,9 +5,9 @@ import {
5
5
  _decodeStorageValue,
6
6
  _resetProbeSession,
7
7
  probeChunks
8
- } from "./chunk-KB3EII7F.js";
9
- import "./chunk-INVA3XGG.js";
10
- import "./chunk-V5N5EYNV.js";
8
+ } from "./chunk-WSBDIHFZ.js";
9
+ import "./chunk-RIAMPAL2.js";
10
+ import "./chunk-NJPBXF5Z.js";
11
11
  export {
12
12
  ChainProbeCrossValidationError,
13
13
  ChainProbeMetadataError,
package/dist/deploy.d.ts CHANGED
@@ -303,6 +303,43 @@ declare function unpublish(domainName: string, options?: {
303
303
  status: "unpublished" | "already-unpublished";
304
304
  txHash?: string;
305
305
  }>;
306
+ /**
307
+ * Returns the dot.li browser URL for the given domain name, optionally
308
+ * suffixed with a network query parameter so the SPA opens the right chain.
309
+ * Currently only the "preview" env needs a suffix — the SPA defaults to
310
+ * paseo-next-v2 which would show "no content" for preview deployments.
311
+ * @param name - the DotNS label (e.g. "myapp")
312
+ * @param envId - the environment id from options.env ?? DEFAULT_ENV_ID
313
+ */
314
+ declare function browserUrlFor(name: string, envId: string | undefined): string;
315
+ type BitswapErrorVariant = "none" | "not_found" | "timeout" | "error";
316
+ interface BitswapProbeResult {
317
+ retrievable: boolean;
318
+ errorVariant: BitswapErrorVariant;
319
+ durationMs: number;
320
+ }
321
+ /**
322
+ * Pure classifier — maps a raw response or thrown error to {retrievable, errorVariant}.
323
+ * Exported for unit tests; does NOT touch telemetry or console.
324
+ */
325
+ declare function interpretBitswapResult(outcome: {
326
+ ok: true;
327
+ response: unknown;
328
+ } | {
329
+ ok: false;
330
+ error: unknown;
331
+ }): {
332
+ retrievable: boolean;
333
+ errorVariant: BitswapErrorVariant;
334
+ };
335
+ /**
336
+ * Calls bitswap_v1_get on the bulletin RPC client for the given base32 CIDv1 string.
337
+ * Never throws — wraps every outcome in BitswapProbeResult.
338
+ * @param client - polkadot-api client (ProviderResult.client)
339
+ * @param cid - base32 CIDv1 string (e.g. "bafyrei...")
340
+ * @param timeoutMs - safety ceiling; the RPC typically responds in ~600ms
341
+ */
342
+ declare function probeP2pRetrieval(client: any, cid: string, timeoutMs?: number): Promise<BitswapProbeResult>;
306
343
  declare function deploy(content: DeployContent, domainName?: string | null, options?: DeployOptions): Promise<DeployResult>;
307
344
 
308
- export { CHUNK_MORTALITY_PERIOD, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, type DeployContent, type DeployOptions, type DeployResult, ENCRYPT_KEY_LEN, ENCRYPT_MAGIC, ENCRYPT_NONCE_LEN, ENCRYPT_PBKDF2_ITERATIONS, ENCRYPT_SALT_LEN, ENCRYPT_TAG_LEN, type SizeDecision, type StoreDirectoryOptions, __assignDenseNoncesForTest, __selectStorageProviderModeForTest, applyManifestFetchAttributes, assertSubdomainOwnerMatchesSigner, buildFilesMap, checkDeploySize, chunk, computeStorageCid, createCID, deploy, deriveRootSigner, detectFramework, encodeContenthash, encryptContent, estimateUploadBytes, friendlyChainError, hasIPFS, isConnectionError, merkleize, resolveDotnsConnectOptions, resolveReproducibleTimestamp, retryBudgetExhausted, setWsHaltCallback, storeChunkedContent, storeDirectory, storeDirectoryV2, storeFile, unpublish };
345
+ export { type BitswapErrorVariant, type BitswapProbeResult, CHUNK_MORTALITY_PERIOD, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, type DeployContent, type DeployOptions, type DeployResult, ENCRYPT_KEY_LEN, ENCRYPT_MAGIC, ENCRYPT_NONCE_LEN, ENCRYPT_PBKDF2_ITERATIONS, ENCRYPT_SALT_LEN, ENCRYPT_TAG_LEN, type SizeDecision, type StoreDirectoryOptions, __assignDenseNoncesForTest, __selectStorageProviderModeForTest, applyManifestFetchAttributes, assertSubdomainOwnerMatchesSigner, browserUrlFor, buildFilesMap, checkDeploySize, chunk, computeStorageCid, createCID, deploy, deriveRootSigner, detectFramework, encodeContenthash, encryptContent, estimateUploadBytes, friendlyChainError, hasIPFS, interpretBitswapResult, isConnectionError, merkleize, probeP2pRetrieval, resolveDotnsConnectOptions, resolveReproducibleTimestamp, retryBudgetExhausted, setWsHaltCallback, storeChunkedContent, storeDirectory, storeDirectoryV2, storeFile, unpublish };
package/dist/deploy.js CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  __selectStorageProviderModeForTest,
13
13
  applyManifestFetchAttributes,
14
14
  assertSubdomainOwnerMatchesSigner,
15
+ browserUrlFor,
15
16
  buildFilesMap,
16
17
  checkDeploySize,
17
18
  chunk,
@@ -25,8 +26,10 @@ import {
25
26
  estimateUploadBytes,
26
27
  friendlyChainError,
27
28
  hasIPFS,
29
+ interpretBitswapResult,
28
30
  isConnectionError,
29
31
  merkleize,
32
+ probeP2pRetrieval,
30
33
  resolveDotnsConnectOptions,
31
34
  resolveReproducibleTimestamp,
32
35
  retryBudgetExhausted,
@@ -36,20 +39,20 @@ import {
36
39
  storeDirectoryV2,
37
40
  storeFile,
38
41
  unpublish
39
- } from "./chunk-WPJADKC7.js";
42
+ } from "./chunk-HPPLVGGC.js";
40
43
  import "./chunk-IW3X2MJF.js";
41
44
  import "./chunk-KOSF5FDO.js";
42
- import "./chunk-L2SKSKB6.js";
45
+ import "./chunk-J3NIXHZZ.js";
43
46
  import "./chunk-S7EM5VMW.js";
44
- import "./chunk-MXMVZU2Q.js";
45
- import "./chunk-O2BFXY3Y.js";
46
- import "./chunk-KB3EII7F.js";
47
+ import "./chunk-H64ZLWW2.js";
48
+ import "./chunk-EJWZGSHD.js";
49
+ import "./chunk-WSBDIHFZ.js";
47
50
  import "./chunk-C2TS5MER.js";
48
- import "./chunk-IRT4A7OO.js";
49
- import "./chunk-RW3GWDGI.js";
50
- import "./chunk-INVA3XGG.js";
51
- import "./chunk-V5N5EYNV.js";
52
- import "./chunk-CNPB4VAM.js";
51
+ import "./chunk-2GBSYVK2.js";
52
+ import "./chunk-JQ5X3VMP.js";
53
+ import "./chunk-RIAMPAL2.js";
54
+ import "./chunk-NJPBXF5Z.js";
55
+ import "./chunk-5K3RI5C2.js";
53
56
  import {
54
57
  EXIT_CODE_NO_RETRY,
55
58
  NonRetryableError
@@ -71,6 +74,7 @@ export {
71
74
  __selectStorageProviderModeForTest,
72
75
  applyManifestFetchAttributes,
73
76
  assertSubdomainOwnerMatchesSigner,
77
+ browserUrlFor,
74
78
  buildFilesMap,
75
79
  checkDeploySize,
76
80
  chunk,
@@ -84,8 +88,10 @@ export {
84
88
  estimateUploadBytes,
85
89
  friendlyChainError,
86
90
  hasIPFS,
91
+ interpretBitswapResult,
87
92
  isConnectionError,
88
93
  merkleize,
94
+ probeP2pRetrieval,
89
95
  resolveDotnsConnectOptions,
90
96
  resolveReproducibleTimestamp,
91
97
  retryBudgetExhausted,
package/dist/dotns.d.ts CHANGED
@@ -94,7 +94,7 @@ interface DotnsPreflightResult {
94
94
  declare const MINIMUM_REGISTER_STORAGE_DEPOSIT = 2000000000000n;
95
95
  declare function fmtPas(plancks: bigint): string;
96
96
  type DotnsSuccessAction = Exclude<DotnsPreflightResult["plannedAction"], "abort">;
97
- declare function feeFloorFor(plannedAction: DotnsSuccessAction, storageDeposit?: bigint): bigint;
97
+ declare function feeFloorFor(plannedAction: DotnsSuccessAction, storageDeposit?: bigint, rentPriceNative?: bigint): bigint;
98
98
  declare const RPC_ENDPOINTS: string[];
99
99
  declare const CONTRACTS: {
100
100
  readonly DOTNS_REGISTRAR: "0x329aAA5b6bEa94E750b2dacBa74Bf41291E6c2BD";
@@ -117,6 +117,25 @@ declare const TX_NO_PROGRESS_MS: number;
117
117
  declare const WS_HEARTBEAT_TIMEOUT_MS: number;
118
118
  declare const DOTNS_TX_MAX_ATTEMPTS: number;
119
119
  declare function classifyTxRetryDecision(err: unknown): "retry" | "abort";
120
+ declare function dotnsRetryBackoffMs(attempt: number, rand?: () => number): number;
121
+ /** Wraps `sink` so that "failed" status events are buffered and only forwarded
122
+ * when `flush()` is called (i.e. on final abort). All other statuses pass
123
+ * through immediately. Call `reset()` at the top of each retry attempt to
124
+ * discard a buffered "failed" from the previous attempt.
125
+ *
126
+ * Closes two leak paths (issue #704):
127
+ * 1. Retry-recovered: attempt N emits "failed" before throwing; a later attempt
128
+ * succeeds → reset() at the top of the next iteration discards the buffer,
129
+ * and flush() is never called on the success return → sink never sees it.
130
+ * 2. Late watcher event: papi can emit a delayed drop/reorg after
131
+ * signAndSubmitExtrinsic has already resolved with "finalized"; the buffer
132
+ * is never flushed on the success path → silently dropped.
133
+ */
134
+ declare function makeRetryStatusFilter(sink: (status: string) => void): {
135
+ callback: (status: string) => void;
136
+ flush: () => void;
137
+ reset: () => void;
138
+ };
120
139
  declare const DEFAULT_MNEMONIC: string;
121
140
  declare function fetchNonce(rpc: string | string[], ss58Address: string): Promise<number>;
122
141
  declare function verifyNonceAdvanced(endpoints: string[], ss58Address: string, originalNonce: number): Promise<{
@@ -257,6 +276,7 @@ declare class ReviveClientWrapper {
257
276
  getEvmAddress(substrateAddress: string): Promise<string>;
258
277
  performDryRunCall(originSubstrateAddress: string, contractAddress: string, value: bigint, encodedData: string): Promise<any>;
259
278
  estimateGasForCall(originSubstrateAddress: string, contractAddress: string, value: bigint, encodedData: string): Promise<any>;
279
+ hasContractCode(address: string): Promise<boolean | null>;
260
280
  checkIfAccountMapped(substrateAddress: string): Promise<boolean>;
261
281
  ensureAccountMapped(substrateAddress: string, signer: PolkadotSigner): Promise<void>;
262
282
  signAndSubmitExtrinsic(extrinsic: any, signer: PolkadotSigner, statusCallback: (status: string) => void, opts?: {
@@ -392,6 +412,17 @@ declare class DotNS {
392
412
  ensureMappedAccountReady(autoAccountMapping?: boolean): Promise<void>;
393
413
  ensureAutoMappedAccountReady(): Promise<void>;
394
414
  ensureConnected(): void;
415
+ /**
416
+ * Resolve the authoritative nativeToEthRatio for this session.
417
+ *
418
+ * Priority: chain constant (Revive.NativeToEthRatio) > options.nativeToEthRatio > default.
419
+ * On mismatch between the env-configured value and the chain value, logs a WARNING naming
420
+ * both values and proceeds with the chain value (it is the source of truth).
421
+ * On query failure, falls back to the configured/default value without throwing.
422
+ *
423
+ * Must be called after clientWrapper is established (i.e. inside connect()).
424
+ */
425
+ resolveNativeToEthRatio(options: DotNSConnectOptions): Promise<void>;
395
426
  private _testnetCache;
396
427
  isTestnet(): Promise<boolean>;
397
428
  /**
@@ -529,4 +560,4 @@ declare class DotNS {
529
560
  }
530
561
  declare const dotns: DotNS;
531
562
 
532
- export { ATTR_TX_RESOLUTION_KIND, type AliasAccountClassification, type AliasAccountState, CONNECTION_TIMEOUT_MS, CONTRACTS, ContractDryRunRevertError, DECIMALS, DEFAULT_MNEMONIC, DOTNS_TX_MAX_ATTEMPTS, DOT_NODE, DotNS, type DotNSConnectOptions, type DotnsPreflightResult, type DotnsSuccessAction, MINIMUM_REGISTER_STORAGE_DEPOSIT, NATIVE_TO_ETH_RATIO, OPERATION_TIMEOUT_MS, type OwnershipResult, PUBLISHER_ABI, type ParsedDomainName, type PriceValidationResult, ProofOfPersonhoodStatus, PublisherNotSupportedError, RPC_ENDPOINTS, TX_CHAIN_TIME_BUDGET_MS, TX_KIND_HASH, TX_KIND_NONCE_ADVANCED, TX_NO_PROGRESS_MS, TX_TIMEOUT_MS, TX_WALL_CLOCK_CEILING_MS, type TxResolution, WS_HEARTBEAT_TIMEOUT_MS, __formatContractDryRunFailureForTest, canRegister, classifyAliasAccountRow, classifyDotnsLabel, classifyTxRetryDecision, computeDomainTokenId, convertToHexString, convertWeiToNative, countTrailingDigits, decodePublisherRevert, dotns, feeFloorFor, fetchNonce, fmtPas, formatDispatchError, formatPersonhoodRemediation, formatPopShortfallReason, isCommitmentMature, isCommitmentTimingBarerevert, parseDomainName, parseProofOfPersonhoodStatus, popStatusName, sanitizeDomainLabel, stripTrailingDigits, validateDomainLabel, verifyNonceAdvanced };
563
+ export { ATTR_TX_RESOLUTION_KIND, type AliasAccountClassification, type AliasAccountState, CONNECTION_TIMEOUT_MS, CONTRACTS, ContractDryRunRevertError, DECIMALS, DEFAULT_MNEMONIC, DOTNS_TX_MAX_ATTEMPTS, DOT_NODE, DotNS, type DotNSConnectOptions, type DotnsPreflightResult, type DotnsSuccessAction, MINIMUM_REGISTER_STORAGE_DEPOSIT, NATIVE_TO_ETH_RATIO, OPERATION_TIMEOUT_MS, type OwnershipResult, PUBLISHER_ABI, type ParsedDomainName, type PriceValidationResult, ProofOfPersonhoodStatus, PublisherNotSupportedError, RPC_ENDPOINTS, TX_CHAIN_TIME_BUDGET_MS, TX_KIND_HASH, TX_KIND_NONCE_ADVANCED, TX_NO_PROGRESS_MS, TX_TIMEOUT_MS, TX_WALL_CLOCK_CEILING_MS, type TxResolution, WS_HEARTBEAT_TIMEOUT_MS, __formatContractDryRunFailureForTest, canRegister, classifyAliasAccountRow, classifyDotnsLabel, classifyTxRetryDecision, computeDomainTokenId, convertToHexString, convertWeiToNative, countTrailingDigits, decodePublisherRevert, dotns, dotnsRetryBackoffMs, feeFloorFor, fetchNonce, fmtPas, formatDispatchError, formatPersonhoodRemediation, formatPopShortfallReason, isCommitmentMature, isCommitmentTimingBarerevert, makeRetryStatusFilter, parseDomainName, parseProofOfPersonhoodStatus, popStatusName, sanitizeDomainLabel, stripTrailingDigits, validateDomainLabel, verifyNonceAdvanced };
package/dist/dotns.js CHANGED
@@ -33,6 +33,7 @@ import {
33
33
  countTrailingDigits,
34
34
  decodePublisherRevert,
35
35
  dotns,
36
+ dotnsRetryBackoffMs,
36
37
  feeFloorFor,
37
38
  fetchNonce,
38
39
  fmtPas,
@@ -41,6 +42,7 @@ import {
41
42
  formatPopShortfallReason,
42
43
  isCommitmentMature,
43
44
  isCommitmentTimingBarerevert,
45
+ makeRetryStatusFilter,
44
46
  parseDomainName,
45
47
  parseProofOfPersonhoodStatus,
46
48
  popStatusName,
@@ -48,11 +50,11 @@ import {
48
50
  stripTrailingDigits,
49
51
  validateDomainLabel,
50
52
  verifyNonceAdvanced
51
- } from "./chunk-IRT4A7OO.js";
52
- import "./chunk-RW3GWDGI.js";
53
- import "./chunk-INVA3XGG.js";
54
- import "./chunk-V5N5EYNV.js";
55
- import "./chunk-CNPB4VAM.js";
53
+ } from "./chunk-2GBSYVK2.js";
54
+ import "./chunk-JQ5X3VMP.js";
55
+ import "./chunk-RIAMPAL2.js";
56
+ import "./chunk-NJPBXF5Z.js";
57
+ import "./chunk-5K3RI5C2.js";
56
58
  import "./chunk-ZOC4GITL.js";
57
59
  export {
58
60
  ATTR_TX_RESOLUTION_KIND,
@@ -89,6 +91,7 @@ export {
89
91
  countTrailingDigits,
90
92
  decodePublisherRevert,
91
93
  dotns,
94
+ dotnsRetryBackoffMs,
92
95
  feeFloorFor,
93
96
  fetchNonce,
94
97
  fmtPas,
@@ -97,6 +100,7 @@ export {
97
100
  formatPopShortfallReason,
98
101
  isCommitmentMature,
99
102
  isCommitmentTimingBarerevert,
103
+ makeRetryStatusFilter,
100
104
  parseDomainName,
101
105
  parseProofOfPersonhoodStatus,
102
106
  popStatusName,
@@ -2,8 +2,8 @@ declare const DEFAULT_ENV_ID = "paseo-next-v2";
2
2
  interface PopSelfServeConfig {
3
3
  /** The label users select in the sudo.personhood.dev env dropdown — e.g. "Next V2". */
4
4
  sudoEnvLabel: string;
5
- /** Faucet URL for funding the service account on this env. */
6
- faucetUrl: string;
5
+ /** Faucet URL for funding the service account on this env. Omit on envs with no public faucet (accounts funded by ops). */
6
+ faucetUrl?: string;
7
7
  /** Personhood recognition flow URL on the sudo app. */
8
8
  personhoodFaucetUrl: string;
9
9
  /** Asset-Hub alias-binding flow URL on the sudo app. */
@@ -44,13 +44,15 @@ interface EnvironmentsDoc {
44
44
  environments: Environment[];
45
45
  chains: Chain[];
46
46
  }
47
- type EnvironmentsSource = "bundled" | "hardcoded-fallback";
47
+ type EnvironmentsSource = "bundled" | "hardcoded-fallback" | "file";
48
48
  interface LoadResult {
49
49
  doc: EnvironmentsDoc;
50
50
  source: EnvironmentsSource;
51
51
  }
52
52
  interface LoadOptions {
53
53
  bundledPath?: string;
54
+ /** Explicit path to a user-supplied environments JSON file (deep-merged over bundled). */
55
+ userFilePath?: string;
54
56
  warn?: (msg: string) => void;
55
57
  capture?: (err: unknown) => void;
56
58
  }
@@ -86,6 +88,17 @@ declare function isValidContractAddress(addr: unknown): boolean;
86
88
  * @param envId The environment ID, used in the error message.
87
89
  */
88
90
  declare function validateContractAddresses(contracts: Record<string, string>, envId: string): void;
91
+ /**
92
+ * Deep-merges a user-supplied partial EnvironmentsDoc over a base doc.
93
+ *
94
+ * - `environments` and `chains` arrays are merged by `id`: a user entry with a
95
+ * matching id is recursively merged into the base entry; unmatched user entries
96
+ * are appended.
97
+ * - Within each entry, nested plain objects (e.g. `contracts`, `endpoints`) are
98
+ * merged key-by-key; scalars and arrays (e.g. `wss`) replace wholesale.
99
+ * - Top-level fields not present in the user doc are kept from base.
100
+ */
101
+ declare function deepMergeEnvironments(base: EnvironmentsDoc, override: Partial<EnvironmentsDoc>): EnvironmentsDoc;
89
102
  declare function loadEnvironments(opts?: LoadOptions): Promise<LoadResult>;
90
103
  declare function resolveEndpoints(doc: EnvironmentsDoc, envId: string): ResolvedEndpoints;
91
104
  declare function getPopSelfServeConfig(doc: EnvironmentsDoc, envId: string): PopSelfServeConfig | null;
@@ -99,4 +112,4 @@ interface EnvironmentListing {
99
112
  declare function listEnvironments(doc: EnvironmentsDoc): EnvironmentListing[];
100
113
  declare function formatEnvironmentTable(rows: EnvironmentListing[]): string;
101
114
 
102
- export { type Chain, type ChainEndpoint, DEFAULT_ENV_ID, type Environment, type EnvironmentListing, type EnvironmentsDoc, type EnvironmentsSource, type LoadOptions, type LoadResult, type PopSelfServeConfig, type ResolvedEndpoints, defaultBundledPath, formatEnvironmentTable, getPopSelfServeConfig, isValidContractAddress, listEnvironments, loadEnvironments, resolveEndpoints, validateContractAddresses };
115
+ export { type Chain, type ChainEndpoint, DEFAULT_ENV_ID, type Environment, type EnvironmentListing, type EnvironmentsDoc, type EnvironmentsSource, type LoadOptions, type LoadResult, type PopSelfServeConfig, type ResolvedEndpoints, deepMergeEnvironments, defaultBundledPath, formatEnvironmentTable, getPopSelfServeConfig, isValidContractAddress, listEnvironments, loadEnvironments, resolveEndpoints, validateContractAddresses };
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  DEFAULT_ENV_ID,
3
+ deepMergeEnvironments,
3
4
  defaultBundledPath,
4
5
  formatEnvironmentTable,
5
6
  getPopSelfServeConfig,
@@ -8,10 +9,11 @@ import {
8
9
  loadEnvironments,
9
10
  resolveEndpoints,
10
11
  validateContractAddresses
11
- } from "./chunk-CNPB4VAM.js";
12
+ } from "./chunk-5K3RI5C2.js";
12
13
  import "./chunk-ZOC4GITL.js";
13
14
  export {
14
15
  DEFAULT_ENV_ID,
16
+ deepMergeEnvironments,
15
17
  defaultBundledPath,
16
18
  formatEnvironmentTable,
17
19
  getPopSelfServeConfig,
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export { ChainProbeOptions, ChunkProbeResult, probeChunks } from './chunk-probe.
7
7
  export { finaliseEmbeddedManifest, writeEmbeddedManifestPlaceholder } from './manifest-embed.js';
8
8
  export { FetchOptions, FetchOutcome, fetchPreviousManifest } from './manifest-fetch.js';
9
9
  export { ComputeStatsInput, IncrementalStats, computeStats, renderSummary, telemetryAttributes } from './incremental-stats.js';
10
- export { Chain, ChainEndpoint, DEFAULT_ENV_ID, Environment, EnvironmentListing, EnvironmentsDoc, EnvironmentsSource, LoadOptions, LoadResult, ResolvedEndpoints, defaultBundledPath, formatEnvironmentTable, isValidContractAddress, listEnvironments, loadEnvironments, resolveEndpoints, validateContractAddresses } from './environments.js';
10
+ export { Chain, ChainEndpoint, DEFAULT_ENV_ID, Environment, EnvironmentListing, EnvironmentsDoc, EnvironmentsSource, LoadOptions, LoadResult, ResolvedEndpoints, deepMergeEnvironments, defaultBundledPath, formatEnvironmentTable, isValidContractAddress, listEnvironments, loadEnvironments, resolveEndpoints, validateContractAddresses } from './environments.js';
11
11
  export { RunState, RunStatus, VERSION, loadRunState, probablyOomRssMb, resolveStateDir, shouldShowOomHint, shouldSkipStaleWarning, stateFilePath, writeRunState } from './run-state.js';
12
12
  export { AppExecutableConfig, AppManifest, AppVersion, ExecutableConfig, ExecutableKind, ExecutableManifest, Icon, IconConfig, IconFormat, ProductConfig, RootManifest, WidgetDimensions, WidgetExecutableConfig, WidgetManifest, WorkerExecutableConfig, WorkerIncludes, WorkerManifest, defineConfig } from './manifest/types.js';
13
13
  export { ValidationErr, ValidationOk, ValidationResult, validateExecutableManifest, validateProductConfig, validateRootManifest } from './manifest/schema.js';