bulletin-deploy 0.13.2-rc.1 → 0.13.2-rc.3
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.
- package/bin/bulletin-deploy +71 -22
- package/dist/auth-config.js +3 -3
- package/dist/bug-report.js +4 -4
- package/dist/{chunk-PFVSY3YT.js → chunk-6IQHSWSZ.js} +1 -1
- package/dist/{chunk-H3D57D5J.js → chunk-ARFQU4A6.js} +4 -3
- package/dist/{chunk-Z6RQSZNM.js → chunk-G3KVQUCG.js} +70 -1
- package/dist/{chunk-LLNSFXHF.js → chunk-P2TGLW2B.js} +1 -1
- package/dist/{chunk-6FP4PGF5.js → chunk-P5WPSCTS.js} +28 -11
- package/dist/{chunk-FH7SSPPT.js → chunk-PWMX6QIS.js} +12 -8
- package/dist/{chunk-CHE5D3OO.js → chunk-S4D4ZCQF.js} +3 -3
- package/dist/{chunk-NNRJLXFB.js → chunk-SBXZ4GDM.js} +1 -1
- package/dist/{chunk-HMJN4XJD.js → chunk-SJEB4RKY.js} +39 -9
- package/dist/{chunk-KCZSMYLV.js → chunk-TNFSFFA6.js} +1 -1
- package/dist/{chunk-362JEZKM.js → chunk-U2SZ3ZRI.js} +29 -6
- package/dist/{chunk-5N5HND6Y.js → chunk-XIVCZUZK.js} +2 -2
- package/dist/chunk-probe.js +3 -3
- package/dist/commands/login.js +10 -10
- package/dist/commands/logout.js +4 -4
- package/dist/commands/transfer.js +3 -3
- package/dist/commands/whoami.js +3 -3
- package/dist/deploy-actors.js +5 -5
- package/dist/deploy.d.ts +80 -1
- package/dist/deploy.js +24 -12
- package/dist/dotns.d.ts +52 -1
- package/dist/dotns.js +15 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +17 -15
- package/dist/manifest/config-load.d.ts +9 -1
- package/dist/manifest/config-load.js +3 -1
- package/dist/manifest/publish.d.ts +6 -2
- package/dist/manifest/publish.js +11 -11
- package/dist/memory-report.js +2 -2
- package/dist/merkle.js +10 -10
- package/dist/personhood/bootstrap.js +10 -10
- package/dist/personhood/people-client.js +3 -3
- package/dist/run-state.js +1 -1
- package/dist/sss-allowance-cache.js +4 -4
- package/dist/storage-signer.js +10 -10
- package/dist/telemetry.d.ts +3 -2
- package/dist/telemetry.js +4 -2
- package/dist/version-check.js +3 -3
- package/package.json +4 -3
- package/tools/verify-baked-dsn.mjs +85 -0
package/bin/bulletin-deploy
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// SDK modules that trigger the "@parity/product-sdk-logger" localStorage warning.
|
|
7
7
|
import "../dist/suppress-localstorage-warning.js";
|
|
8
8
|
|
|
9
|
-
import { deploy, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, NonRetryableError, EXIT_CODE_NO_RETRY, isConnectionError, isBenignTeardownError, unpublish } from "../dist/deploy.js";
|
|
9
|
+
import { deploy, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, NonRetryableError, EXIT_CODE_NO_RETRY, isConnectionError, isBenignTeardownError, unpublish, resolveEffectiveMnemonic, resolveEnvId, shouldPublishManifest, validateNoManifestFlags } from "../dist/deploy.js";
|
|
10
10
|
import { VERSION, setDeployAttribute, captureWarning, closeTelemetry, setRunStateActive, markRelaunchOomHintShown } from "../dist/telemetry.js";
|
|
11
11
|
import { handleFailedDeploy, handlePreflightVersionCheck, fetchVersionInfo, preReleaseWarning, checkNodeVersion } from "../dist/version-check.js";
|
|
12
12
|
import { setDeployContext, installLogCapture, buildCliFlagsSummary } from "../dist/bug-report.js";
|
|
@@ -56,6 +56,7 @@ for (let i = 0; i < args.length; i++) {
|
|
|
56
56
|
else if (args[i] === "--input-car") { flags.inputCar = args[++i]; }
|
|
57
57
|
else if (args[i] === "--tag") { flags.tag = args[++i]; }
|
|
58
58
|
else if (args[i] === "--config") { flags.config = args[++i]; }
|
|
59
|
+
else if (args[i] === "--no-manifest" || args[i] === "--content-only") { flags.noManifest = true; }
|
|
59
60
|
else if (args[i] === "--gh-pages-mirror") { flags.ghPagesMirror = true; }
|
|
60
61
|
else if (args[i] === "--allow-large-deploy") { flags.allowLargeDeploy = true; }
|
|
61
62
|
else if (args[i] === "--reproducible") { flags.reproducibleSource = "commit"; }
|
|
@@ -78,6 +79,34 @@ if (flags.publish && flags.unpublish) {
|
|
|
78
79
|
process.exit(1);
|
|
79
80
|
}
|
|
80
81
|
|
|
82
|
+
// #1163: --no-manifest (--content-only) skips manifest publishing even when a
|
|
83
|
+
// bulletin-deploy.config.* is discoverable; --publish depends on those
|
|
84
|
+
// manifest records (Publisher listing → Browse), so the combination is
|
|
85
|
+
// rejected up front rather than silently publishing a domain with no manifest.
|
|
86
|
+
const noManifestErr = validateNoManifestFlags({ noManifest: !!flags.noManifest, publish: !!flags.publish });
|
|
87
|
+
if (noManifestErr) {
|
|
88
|
+
console.error(noManifestErr);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// #1107: the mnemonic actually used to sign — --mnemonic flag > MNEMONIC env
|
|
93
|
+
// var > DOTNS_MNEMONIC env var. Used everywhere deploy/publish/unpublish need
|
|
94
|
+
// a signer identity (existence guards below intentionally keep checking
|
|
95
|
+
// flags.mnemonic / process.env.MNEMONIC directly — only the VALUE forwarded
|
|
96
|
+
// to options.mnemonic changes here).
|
|
97
|
+
const effectiveMnemonic = resolveEffectiveMnemonic({
|
|
98
|
+
flagMnemonic: flags.mnemonic,
|
|
99
|
+
envMnemonic: process.env.MNEMONIC,
|
|
100
|
+
envDotnsMnemonic: process.env.DOTNS_MNEMONIC,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// #1165: the env id actually targeted this session — --env flag >
|
|
104
|
+
// BULLETIN_DEPLOY_ENV env var. `undefined` here still means "let
|
|
105
|
+
// deploy()/the DEFAULT_ENV_ID fallback below decide" — this only resolves
|
|
106
|
+
// the flag/env-var precedence so a session default doesn't require
|
|
107
|
+
// repeating --env on every invocation.
|
|
108
|
+
const effectiveEnvId = resolveEnvId({ flagEnv: flags.env, envVar: process.env.BULLETIN_DEPLOY_ENV });
|
|
109
|
+
|
|
81
110
|
// --environment-file: propagate to the env var so all internal loadEnvironments()
|
|
82
111
|
// call sites (deploy.ts, manifest/publish.ts, personhood) honor the override.
|
|
83
112
|
if (flags.environmentFile) {
|
|
@@ -119,10 +148,10 @@ if (flags.unpublish) {
|
|
|
119
148
|
}
|
|
120
149
|
try {
|
|
121
150
|
const result = await unpublish(domain, {
|
|
122
|
-
mnemonic:
|
|
151
|
+
mnemonic: effectiveMnemonic,
|
|
123
152
|
derivationPath: flags.derivationPath,
|
|
124
153
|
rpc: flags.rpc,
|
|
125
|
-
env:
|
|
154
|
+
env: effectiveEnvId,
|
|
126
155
|
});
|
|
127
156
|
console.log(`Domain: ${result.domainName}`);
|
|
128
157
|
console.log(`Status: ${result.status}`);
|
|
@@ -148,7 +177,7 @@ function installSsoTeardownGuards() {
|
|
|
148
177
|
{
|
|
149
178
|
const sub = positional[0];
|
|
150
179
|
if (sub === "login" || sub === "logout" || sub === "whoami") {
|
|
151
|
-
const envId =
|
|
180
|
+
const envId = effectiveEnvId ?? DEFAULT_ENV_ID;
|
|
152
181
|
installSsoTeardownGuards();
|
|
153
182
|
try {
|
|
154
183
|
const capSub = sub.charAt(0).toUpperCase() + sub.slice(1);
|
|
@@ -167,7 +196,7 @@ function installSsoTeardownGuards() {
|
|
|
167
196
|
// (or --to). Stand-alone handover + recovery for a deploy whose transfer step
|
|
168
197
|
// failed. Uses the SSO stack to resolve the session recipient.
|
|
169
198
|
if (positional[0] === "transfer") {
|
|
170
|
-
const envId =
|
|
199
|
+
const envId = effectiveEnvId ?? DEFAULT_ENV_ID;
|
|
171
200
|
installSsoTeardownGuards();
|
|
172
201
|
try {
|
|
173
202
|
const { runTransfer } = await import("../dist/commands/transfer.js");
|
|
@@ -237,6 +266,9 @@ Options:
|
|
|
237
266
|
--env <id> Target environment from environments.json (default: paseo-next-v2).
|
|
238
267
|
Drives both the bulletin RPC and the asset-hub RPC used
|
|
239
268
|
by DotNS. See --list-environments for valid ids.
|
|
269
|
+
Precedence: --env > BULLETIN_DEPLOY_ENV env var > paseo-next-v2.
|
|
270
|
+
Set BULLETIN_DEPLOY_ENV to pick a session default without
|
|
271
|
+
repeating --env on every invocation.
|
|
240
272
|
--environment-file <path>
|
|
241
273
|
Path to a JSON file deep-merged over the bundled
|
|
242
274
|
environments.json. Override only the fields you need
|
|
@@ -274,6 +306,11 @@ Options:
|
|
|
274
306
|
<build-dir> looking for bulletin-deploy.config.{ts,js,mjs}). When a
|
|
275
307
|
config is found, deploy ALSO writes the manifest + executable text
|
|
276
308
|
records on <domain> and its app/widget/worker subnames.
|
|
309
|
+
--no-manifest, --content-only
|
|
310
|
+
Skip manifest publishing entirely, even when a
|
|
311
|
+
bulletin-deploy.config.* is discoverable — plain content
|
|
312
|
+
deploy (storage + root contenthash), same as having no
|
|
313
|
+
config at all. Mutually exclusive with --publish.
|
|
277
314
|
--gh-pages-mirror After deploy, push the CAR to the current repo's gh-pages branch
|
|
278
315
|
at bulletin/<domain>.dot.car (opt-in; also set GH_PAGES_MIRROR=1)
|
|
279
316
|
--publish After deploy, list <domain> in the on-chain Publisher
|
|
@@ -445,7 +482,7 @@ try {
|
|
|
445
482
|
rpc: effectiveRpc,
|
|
446
483
|
repo: process.env.GITHUB_REPOSITORY,
|
|
447
484
|
branch: process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME,
|
|
448
|
-
signerMode:
|
|
485
|
+
signerMode: effectiveMnemonic ? "direct" : "pool",
|
|
449
486
|
deployTag,
|
|
450
487
|
cliFlags: buildCliFlagsSummary(flags),
|
|
451
488
|
ci,
|
|
@@ -460,24 +497,30 @@ try {
|
|
|
460
497
|
// + its referenced icon/executable files BEFORE any storage or chain work, so
|
|
461
498
|
// config errors fail fast up front instead of after merkleize + upload. No-op
|
|
462
499
|
// (returns null) for contenthash-only deploys with no config.
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
500
|
+
//
|
|
501
|
+
// #1163: --no-manifest (--content-only) skips this entirely — the deploy is
|
|
502
|
+
// content-only regardless of any discoverable config, so there's nothing to
|
|
503
|
+
// preflight.
|
|
504
|
+
if (!flags.noManifest) {
|
|
505
|
+
try {
|
|
506
|
+
const { preflightProductConfig } = await import("../dist/index.js");
|
|
507
|
+
// config-load resolves a relative cwd internally, so no node:path here
|
|
508
|
+
// (it's only dynamically imported later, in the publish block).
|
|
509
|
+
await preflightProductConfig(
|
|
510
|
+
flags.config ? { path: flags.config } : { cwd: buildDir, walkUp: true },
|
|
511
|
+
);
|
|
512
|
+
} catch (err) {
|
|
513
|
+
console.error(`Error: ${err?.message ?? err}`);
|
|
514
|
+
process.exit(err instanceof NonRetryableError ? EXIT_CODE_NO_RETRY : 1);
|
|
515
|
+
}
|
|
473
516
|
}
|
|
474
517
|
|
|
475
518
|
const result = await deploy(buildDir, domain, {
|
|
476
|
-
mnemonic:
|
|
519
|
+
mnemonic: effectiveMnemonic,
|
|
477
520
|
derivationPath: flags.derivationPath,
|
|
478
521
|
suri: flags.suri,
|
|
479
522
|
rpc: flags.rpc,
|
|
480
|
-
env:
|
|
523
|
+
env: effectiveEnvId,
|
|
481
524
|
poolSize: flags.poolSize,
|
|
482
525
|
password: flags.password,
|
|
483
526
|
contracts: flags.contracts,
|
|
@@ -542,6 +585,12 @@ try {
|
|
|
542
585
|
// Walks up from <build-dir> (or honours --config) looking for
|
|
543
586
|
// bulletin-deploy.config.{ts,js,mjs}. When found, writes the root + per-
|
|
544
587
|
// executable text records, otherwise the legacy flow returns unchanged.
|
|
588
|
+
//
|
|
589
|
+
// #1163: --no-manifest (--content-only) skips manifest publishing even when
|
|
590
|
+
// a config is present. shouldPublishManifest() is the single source of
|
|
591
|
+
// truth for that decision (config discovery still runs either way, so the
|
|
592
|
+
// "config found but --no-manifest set" case is exercised for real, not just
|
|
593
|
+
// in unit tests).
|
|
545
594
|
{
|
|
546
595
|
const { tryLoadProductConfig, publishManifest } = await import("../dist/index.js");
|
|
547
596
|
const path = await import("node:path");
|
|
@@ -549,15 +598,15 @@ try {
|
|
|
549
598
|
const loaded = await tryLoadProductConfig(
|
|
550
599
|
flags.config ? { path: flags.config } : { cwd: buildDirAbs, walkUp: true },
|
|
551
600
|
);
|
|
552
|
-
if (loaded) {
|
|
601
|
+
if (shouldPublishManifest({ configFound: !!loaded, noManifest: !!flags.noManifest })) {
|
|
553
602
|
try {
|
|
554
603
|
await publishManifest({
|
|
555
604
|
loaded,
|
|
556
605
|
domain,
|
|
557
606
|
buildDirCid: { absPath: buildDirAbs, cid: result.cid },
|
|
558
|
-
env:
|
|
607
|
+
env: effectiveEnvId,
|
|
559
608
|
rpc: flags.rpc,
|
|
560
|
-
mnemonic:
|
|
609
|
+
mnemonic: effectiveMnemonic,
|
|
561
610
|
derivationPath: flags.derivationPath,
|
|
562
611
|
});
|
|
563
612
|
} catch (err) {
|
|
@@ -565,7 +614,7 @@ try {
|
|
|
565
614
|
process.exit(err instanceof NonRetryableError ? EXIT_CODE_NO_RETRY : 1);
|
|
566
615
|
}
|
|
567
616
|
}
|
|
568
|
-
// No config → the contenthash-only deploy above is the whole job; nothing else to do.
|
|
617
|
+
// No config (or --no-manifest) → the contenthash-only deploy above is the whole job; nothing else to do.
|
|
569
618
|
}
|
|
570
619
|
|
|
571
620
|
if (!flags.help && !flags.version) {
|
package/dist/auth-config.js
CHANGED
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
getPeopleChainEndpoints,
|
|
10
10
|
hasPersistedSession,
|
|
11
11
|
resolveBulletinEndpoints
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-TNFSFFA6.js";
|
|
13
13
|
import "./chunk-TSPERKUS.js";
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-P5WPSCTS.js";
|
|
15
|
+
import "./chunk-ARFQU4A6.js";
|
|
16
16
|
import "./chunk-3ZEMX4WD.js";
|
|
17
17
|
import "./chunk-ZOC4GITL.js";
|
|
18
18
|
export {
|
package/dist/bug-report.js
CHANGED
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
offerBugReport,
|
|
11
11
|
scrubSecrets,
|
|
12
12
|
setDeployContext
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-S4D4ZCQF.js";
|
|
14
|
+
import "./chunk-6IQHSWSZ.js";
|
|
15
|
+
import "./chunk-P5WPSCTS.js";
|
|
16
|
+
import "./chunk-ARFQU4A6.js";
|
|
17
17
|
export {
|
|
18
18
|
buildCliFlagsSummary,
|
|
19
19
|
buildLabels,
|
|
@@ -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.13.2-rc.
|
|
9
|
+
version: "0.13.2-rc.3",
|
|
10
10
|
private: false,
|
|
11
11
|
repository: {
|
|
12
12
|
type: "git",
|
|
@@ -48,14 +48,15 @@ var package_default = {
|
|
|
48
48
|
"assets",
|
|
49
49
|
"patches",
|
|
50
50
|
"DEPLOYMENT.md",
|
|
51
|
-
"tools/release-retry-wrapper.mjs"
|
|
51
|
+
"tools/release-retry-wrapper.mjs",
|
|
52
|
+
"tools/verify-baked-dsn.mjs"
|
|
52
53
|
],
|
|
53
54
|
scripts: {
|
|
54
55
|
build: "tsup src/suppress-localstorage-warning.ts 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 src/auth/index.ts src/auth/vendor/index.ts src/auth/vendor/ui/index.ts src/auth-config.ts src/commands/login.ts src/commands/logout.ts src/commands/whoami.ts src/commands/transfer.ts src/storage-signer.ts src/spinner.ts src/sss-allowance.ts src/sss-allowance-cache.ts src/deploy-actors.ts --format esm --dts --clean --target node22",
|
|
55
56
|
"refresh-environments": "node scripts/refresh-environments.mjs",
|
|
56
57
|
postinstall: "patch-package || true",
|
|
57
58
|
prepare: "npm run build",
|
|
58
|
-
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 test/auth-config.test.js test/whoami.test.js test/login.test.js test/logout.test.js test/auth-resolve.test.js test/storage-signer.test.js test/spinner.test.js test/sss-allowance.test.js test/sss-allowance-cache.test.js test/dotns-transfer.test.js test/deploy-actors.test.js test/transfer-command.test.js test/dotns-register-fee.test.js test/deploy-label-ordering.test.js test/benign-teardown.test.js && npm run test:vendor",
|
|
59
|
+
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 test/auth-config.test.js test/whoami.test.js test/login.test.js test/logout.test.js test/auth-resolve.test.js test/storage-signer.test.js test/spinner.test.js test/sss-allowance.test.js test/sss-allowance-cache.test.js test/dotns-transfer.test.js test/deploy-actors.test.js test/transfer-command.test.js test/dotns-register-fee.test.js test/deploy-label-ordering.test.js test/benign-teardown.test.js test/verify-baked-dsn.test.js && npm run test:vendor",
|
|
59
60
|
"test:e2e": "npm run build && node --test test/e2e.test.js",
|
|
60
61
|
"test:e2e:smoke": "bash scripts/e2e-pass.sh smoke",
|
|
61
62
|
"test:e2e:pr": "bash scripts/e2e-pass.sh pr",
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
setDeploySentryTag,
|
|
12
12
|
truncateAddress,
|
|
13
13
|
withSpan
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-P5WPSCTS.js";
|
|
15
15
|
import {
|
|
16
16
|
validateContractAddresses
|
|
17
17
|
} from "./chunk-3ZEMX4WD.js";
|
|
@@ -63,6 +63,10 @@ var TX_KIND_HASH = "hash";
|
|
|
63
63
|
var TX_KIND_NONCE_ADVANCED = "nonce-advanced";
|
|
64
64
|
var TX_KIND_BEST_BLOCK = "best-block";
|
|
65
65
|
var ATTR_TX_RESOLUTION_KIND = "deploy.dotns.tx_resolution_kind";
|
|
66
|
+
var TX_KIND_SKIPPED = "skipped";
|
|
67
|
+
function shouldSkipTextWrite(current, target) {
|
|
68
|
+
return current === target;
|
|
69
|
+
}
|
|
66
70
|
var ONE_PAS = 10000000000n;
|
|
67
71
|
var FEE_FLOOR_OWNED = ONE_PAS / 100n;
|
|
68
72
|
var FEE_FLOOR_REGISTER = ONE_PAS / 10n;
|
|
@@ -274,6 +278,42 @@ async function verifyNonceAdvanced(endpoints, ss58Address, originalNonce) {
|
|
|
274
278
|
}
|
|
275
279
|
return { advanced: false };
|
|
276
280
|
}
|
|
281
|
+
var NONCE_CONTENTION_BACKOFF_BASE_MS = 250;
|
|
282
|
+
var NONCE_CONTENTION_BACKOFF_MAX_MS = 2e3;
|
|
283
|
+
function nonceContentionBackoffMs(attempt, rand = Math.random) {
|
|
284
|
+
const base = Math.min(NONCE_CONTENTION_BACKOFF_BASE_MS * 2 ** (attempt - 1), NONCE_CONTENTION_BACKOFF_MAX_MS);
|
|
285
|
+
const jitter = (rand() * 2 - 1) * NONCE_CONTENTION_BACKOFF_BASE_MS;
|
|
286
|
+
return Math.max(0, Math.round(base + jitter));
|
|
287
|
+
}
|
|
288
|
+
var DOTNS_NONCE_CONTENTION_MAX_ATTEMPTS = 5;
|
|
289
|
+
function isNonceContentionAmbiguous(err) {
|
|
290
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
291
|
+
return msg.startsWith("nonce-advance fallback:");
|
|
292
|
+
}
|
|
293
|
+
async function reacquireNonceOnContention(resubmit, nonceFallback, label, opts = {}) {
|
|
294
|
+
const fetchNonceFn = opts.fetchNonce ?? fetchNonce;
|
|
295
|
+
const sleepFn = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
296
|
+
const backoffFn = opts.backoffMs ?? nonceContentionBackoffMs;
|
|
297
|
+
const maxAttempts = opts.maxAttempts ?? DOTNS_NONCE_CONTENTION_MAX_ATTEMPTS;
|
|
298
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
299
|
+
setDeployAttribute("deploy.dotns.nonce_contention_retries", attempt);
|
|
300
|
+
const ms = backoffFn(attempt);
|
|
301
|
+
console.log(` ${label}: nonce contention (attempt ${attempt}/${maxAttempts}) \u2014 re-acquiring nonce and resubmitting in ${ms}ms\u2026`);
|
|
302
|
+
await sleepFn(ms);
|
|
303
|
+
try {
|
|
304
|
+
nonceFallback.expectedNonce = await fetchNonceFn(nonceFallback.rpcs, nonceFallback.senderSS58);
|
|
305
|
+
} catch {
|
|
306
|
+
}
|
|
307
|
+
try {
|
|
308
|
+
return await resubmit();
|
|
309
|
+
} catch (e) {
|
|
310
|
+
if (!isNonceContentionAmbiguous(e)) throw e;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
throw new NonRetryableError(
|
|
314
|
+
`DotNS write could not acquire a nonce slot after ${maxAttempts} attempts \u2014 the shared signer (${nonceFallback.senderSS58}) is under nonce contention; pass your own --mnemonic for an isolated nonce space.`
|
|
315
|
+
);
|
|
316
|
+
}
|
|
277
317
|
var ProofOfPersonhoodStatus = {
|
|
278
318
|
NoStatus: 0,
|
|
279
319
|
ProofOfPersonhoodLite: 1,
|
|
@@ -875,6 +915,19 @@ var ReviveClientWrapper = class _ReviveClientWrapper {
|
|
|
875
915
|
filter.flush();
|
|
876
916
|
throw fastFail;
|
|
877
917
|
}
|
|
918
|
+
if (opts.nonceFallback && isNonceContentionAmbiguous(e)) {
|
|
919
|
+
try {
|
|
920
|
+
return await reacquireNonceOnContention(
|
|
921
|
+
() => this.signAndSubmitExtrinsic(buildExtrinsic(), signer, filter.callback, opts),
|
|
922
|
+
opts.nonceFallback,
|
|
923
|
+
label,
|
|
924
|
+
{ fetchNonce: opts.fetchNonce, sleep: opts.sleep, backoffMs: opts.nonceContentionBackoffMs }
|
|
925
|
+
);
|
|
926
|
+
} catch (contentionErr) {
|
|
927
|
+
filter.flush();
|
|
928
|
+
throw contentionErr;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
878
931
|
const decision = classifyTxRetryDecision(e);
|
|
879
932
|
const msg = e?.message ?? String(e);
|
|
880
933
|
if (!shouldRetryTxAttempt(attempt, DOTNS_TX_MAX_ATTEMPTS, decision)) {
|
|
@@ -1982,6 +2035,16 @@ var DotNS = class {
|
|
|
1982
2035
|
this.ensureConnected();
|
|
1983
2036
|
console.log(` Setting text[${key}]: ${value}`);
|
|
1984
2037
|
const node = namehash(`${domainName}.dot`);
|
|
2038
|
+
try {
|
|
2039
|
+
const current = await this.getTextRecord(domainName, key);
|
|
2040
|
+
if (shouldSkipTextWrite(current, value)) {
|
|
2041
|
+
console.log(` text[${key}] already set \u2014 skipping tx`);
|
|
2042
|
+
setDeployAttribute("deploy.dotns.text_unchanged", "true");
|
|
2043
|
+
return { value, txHash: TX_KIND_SKIPPED };
|
|
2044
|
+
}
|
|
2045
|
+
} catch (_) {
|
|
2046
|
+
}
|
|
2047
|
+
setDeployAttribute("deploy.dotns.text_unchanged", "false");
|
|
1985
2048
|
const MAX_VERIFY_CHAIN_SECONDS = VERIFY_EFFECT_CHAIN_SECONDS;
|
|
1986
2049
|
const TEXT_POLL_INTERVAL_MS = 2e3;
|
|
1987
2050
|
const verifyEffect = async () => {
|
|
@@ -2899,6 +2962,8 @@ export {
|
|
|
2899
2962
|
TX_KIND_NONCE_ADVANCED,
|
|
2900
2963
|
TX_KIND_BEST_BLOCK,
|
|
2901
2964
|
ATTR_TX_RESOLUTION_KIND,
|
|
2965
|
+
TX_KIND_SKIPPED,
|
|
2966
|
+
shouldSkipTextWrite,
|
|
2902
2967
|
MINIMUM_REGISTER_STORAGE_DEPOSIT,
|
|
2903
2968
|
registerDepositWei,
|
|
2904
2969
|
bufferedWeiToNative,
|
|
@@ -2936,6 +3001,10 @@ export {
|
|
|
2936
3001
|
DEFAULT_MNEMONIC,
|
|
2937
3002
|
fetchNonce,
|
|
2938
3003
|
verifyNonceAdvanced,
|
|
3004
|
+
nonceContentionBackoffMs,
|
|
3005
|
+
DOTNS_NONCE_CONTENTION_MAX_ATTEMPTS,
|
|
3006
|
+
isNonceContentionAmbiguous,
|
|
3007
|
+
reacquireNonceOnContention,
|
|
2939
3008
|
ProofOfPersonhoodStatus,
|
|
2940
3009
|
PUBLISHER_ABI,
|
|
2941
3010
|
PublisherNotSupportedError,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
package_default,
|
|
3
3
|
writeRunState
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ARFQU4A6.js";
|
|
5
5
|
|
|
6
6
|
// src/memory-report.ts
|
|
7
7
|
import * as fs2 from "fs";
|
|
@@ -134,7 +134,7 @@ function initTelemetry() {
|
|
|
134
134
|
if (process.env.BULLETIN_DEPLOY_USE_AMBIENT_SENTRY === "1") {
|
|
135
135
|
return;
|
|
136
136
|
}
|
|
137
|
-
const dsn = process.env.SENTRY_DSN || (true ? "" : "");
|
|
137
|
+
const dsn = process.env.SENTRY_DSN || (true ? "https://e021c025d79c4c3ade2862a11f13c40b@o4511059872841728.ingest.de.sentry.io/4511093597405264" : "");
|
|
138
138
|
if (!dsn) return;
|
|
139
139
|
Sentry.init({
|
|
140
140
|
dsn,
|
|
@@ -334,13 +334,13 @@ function computeDeployOutcome(errorCategory, isSad, sadReason) {
|
|
|
334
334
|
return "clean";
|
|
335
335
|
}
|
|
336
336
|
var ERROR_KIND_RULES = [
|
|
337
|
-
[/Contract reverted|Contract execution would revert|revert(?:ed|ing)?\s*\(flags=[0-9]+\)/i, "contract-revert"],
|
|
337
|
+
[/Contract reverted|Contract execution would revert|revert(?:ed|ing)?\s*\(flags=[0-9]+\)|"type"\s*:\s*"ContractReverted"/i, "contract-revert"],
|
|
338
338
|
[/timed out after \d+s waiting for block|Transaction not included after \d+s|Transaction did not settle within/i, "chain-timeout"],
|
|
339
339
|
[/\bstale\b.*nonce|nonce.*\bstale\b|"type"\s*:\s*"(?:Future|Stale)"|Invalid::Future|tx rejected by pool/i, "nonce-stale"],
|
|
340
340
|
[/heartbeat timeout|WS halt|Unable to connect|ChainHead disjointed|websocket.*closed|socket closed|disconnect/i, "connection"],
|
|
341
341
|
[/requires ProofOfPersonhood(?:Full|Lite|Light),\s*but this signer is NoStatus/i, "naming.pop_required"],
|
|
342
342
|
[/requires NoStatus,\s*but this signer is ProofOfPersonhood/i, "naming.nostatus_required"],
|
|
343
|
-
[/Cannot decode zero data.*with ABI parameters/i, "
|
|
343
|
+
[/Cannot decode zero data.*with ABI parameters/i, "dotns.abi_decode_empty"],
|
|
344
344
|
// Issue #1060: contractCall's own empty-`0x`-data guard (src/dotns.ts, #729) throws
|
|
345
345
|
// an actionable wrapper instead of letting the raw viem message above reach a
|
|
346
346
|
// caller. Same failure family (a DotNS contract read came back empty) — classify
|
|
@@ -368,6 +368,13 @@ function classifyErrorKind(msg) {
|
|
|
368
368
|
}
|
|
369
369
|
return "unknown";
|
|
370
370
|
}
|
|
371
|
+
function classifyErrorForSpan(msg) {
|
|
372
|
+
return {
|
|
373
|
+
kind: classifyErrorKind(msg),
|
|
374
|
+
message: sanitizeErrorMessage(msg),
|
|
375
|
+
pattern: analyseErrorPattern(msg)
|
|
376
|
+
};
|
|
377
|
+
}
|
|
371
378
|
function sanitizeErrorMessage(msg) {
|
|
372
379
|
return scrubPaths(msg.slice(0, 500));
|
|
373
380
|
}
|
|
@@ -398,10 +405,11 @@ async function withSpan(op, description, attributes, fn) {
|
|
|
398
405
|
return await fn();
|
|
399
406
|
} catch (error) {
|
|
400
407
|
const msg = error.message ?? String(error);
|
|
408
|
+
const { kind, message, pattern } = classifyErrorForSpan(msg);
|
|
401
409
|
span.setAttribute("error.message", msg);
|
|
402
|
-
span.setAttribute("deploy.error_kind",
|
|
403
|
-
span.setAttribute("deploy.error_message",
|
|
404
|
-
span.setAttribute("deploy.error_pattern_signature",
|
|
410
|
+
span.setAttribute("deploy.error_kind", kind);
|
|
411
|
+
span.setAttribute("deploy.error_message", message);
|
|
412
|
+
span.setAttribute("deploy.error_pattern_signature", pattern);
|
|
405
413
|
span.setStatus({ code: 2, message: "internal_error" });
|
|
406
414
|
throw error;
|
|
407
415
|
}
|
|
@@ -496,12 +504,9 @@ async function withDeploySpan(domain, fn) {
|
|
|
496
504
|
} catch (error) {
|
|
497
505
|
const msg = error.message ?? String(error);
|
|
498
506
|
span.setAttribute("deploy.status", "error");
|
|
499
|
-
span
|
|
507
|
+
setDeployErrorOnSpan(span, msg);
|
|
500
508
|
const errorCategory = classifyDeployError(msg);
|
|
501
509
|
span.setAttribute("deploy.error_category", errorCategory);
|
|
502
|
-
span.setAttribute("deploy.error_kind", classifyErrorKind(msg));
|
|
503
|
-
span.setAttribute("deploy.error_message", sanitizeErrorMessage(msg));
|
|
504
|
-
span.setAttribute("deploy.error_pattern_signature", analyseErrorPattern(msg));
|
|
505
510
|
currentErrorCategory = errorCategory;
|
|
506
511
|
const isExpected = isExpectedError(msg);
|
|
507
512
|
span.setAttribute("deploy.expected", isExpected ? "true" : "false");
|
|
@@ -578,6 +583,17 @@ function setDeployAttribute(key, value) {
|
|
|
578
583
|
if (!deployRootSpan) return;
|
|
579
584
|
deployRootSpan.setAttribute(key, value);
|
|
580
585
|
}
|
|
586
|
+
function setDeployErrorOnSpan(span, msg) {
|
|
587
|
+
const { kind, message, pattern } = classifyErrorForSpan(msg);
|
|
588
|
+
span.setAttribute("deploy.error", msg.slice(0, 500));
|
|
589
|
+
span.setAttribute("deploy.error_kind", kind);
|
|
590
|
+
span.setAttribute("deploy.error_message", message);
|
|
591
|
+
span.setAttribute("deploy.error_pattern_signature", pattern);
|
|
592
|
+
}
|
|
593
|
+
function setDeployError(msg) {
|
|
594
|
+
if (!deployRootSpan) return;
|
|
595
|
+
setDeployErrorOnSpan(deployRootSpan, msg);
|
|
596
|
+
}
|
|
581
597
|
function __setDeployRootSpanForTest(span) {
|
|
582
598
|
deployRootSpan = span;
|
|
583
599
|
}
|
|
@@ -774,6 +790,7 @@ export {
|
|
|
774
790
|
withDeploySpan,
|
|
775
791
|
setDeployReportContext,
|
|
776
792
|
setDeployAttribute,
|
|
793
|
+
setDeployError,
|
|
777
794
|
__setDeployRootSpanForTest,
|
|
778
795
|
__setSentryForTest,
|
|
779
796
|
getCurrentSentryTraceId,
|
|
@@ -4,14 +4,17 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
BLAKE2B_256_MULTIHASH_CODE,
|
|
6
6
|
encodeContenthash,
|
|
7
|
+
resolveBulletinEndpoints,
|
|
7
8
|
resolveDotnsConnectOptions,
|
|
9
|
+
setBulletinEndpoints,
|
|
8
10
|
storeDirectory,
|
|
9
11
|
storeFile
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-SJEB4RKY.js";
|
|
11
13
|
import {
|
|
12
14
|
DotNS
|
|
13
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-G3KVQUCG.js";
|
|
14
16
|
import {
|
|
17
|
+
DEFAULT_ENV_ID,
|
|
15
18
|
getPopSelfServeConfig,
|
|
16
19
|
loadEnvironments,
|
|
17
20
|
resolveEndpoints
|
|
@@ -38,6 +41,11 @@ async function publishManifest(opts) {
|
|
|
38
41
|
);
|
|
39
42
|
}
|
|
40
43
|
const configDir = path.dirname(sourcePath);
|
|
44
|
+
const envId = opts.env ?? DEFAULT_ENV_ID;
|
|
45
|
+
const { doc } = await loadEnvironments();
|
|
46
|
+
const resolved = resolveEndpoints(doc, envId);
|
|
47
|
+
const popSelfServe = getPopSelfServeConfig(doc, envId);
|
|
48
|
+
setBulletinEndpoints(resolveBulletinEndpoints(resolved.bulletin, opts.rpc));
|
|
41
49
|
const iconAbs = path.resolve(configDir, config.icon.path);
|
|
42
50
|
const iconBytes = await readFileOrThrow(iconAbs, "icon");
|
|
43
51
|
console.log(`
|
|
@@ -59,7 +67,7 @@ Manifest publish \u2014 ${config.domain}`);
|
|
|
59
67
|
console.log(` Executable [${exec.kind}] CID: ${storageCid}`);
|
|
60
68
|
executableCids[exec.kind] = storageCid;
|
|
61
69
|
}
|
|
62
|
-
const dotns = await connectDotNS(opts);
|
|
70
|
+
const dotns = await connectDotNS(opts, resolved, popSelfServe, envId);
|
|
63
71
|
try {
|
|
64
72
|
const baseLabel = stripDotSuffix(config.domain);
|
|
65
73
|
await dotns.ensureContentResolver(baseLabel);
|
|
@@ -104,11 +112,7 @@ async function readFileOrThrow(p, label) {
|
|
|
104
112
|
throw new NonRetryableError(`Cannot read ${label} at ${p}: ${err.message}`);
|
|
105
113
|
}
|
|
106
114
|
}
|
|
107
|
-
async function connectDotNS(opts) {
|
|
108
|
-
const envId = opts.env ?? "paseo-next-v2";
|
|
109
|
-
const { doc } = await loadEnvironments();
|
|
110
|
-
const resolved = resolveEndpoints(doc, envId);
|
|
111
|
-
const popSelfServe = getPopSelfServeConfig(doc, envId);
|
|
115
|
+
async function connectDotNS(opts, resolved, popSelfServe, envId) {
|
|
112
116
|
const deployOptsShim = {
|
|
113
117
|
mnemonic: opts.mnemonic,
|
|
114
118
|
derivationPath: opts.derivationPath
|
|
@@ -2,15 +2,15 @@ import {
|
|
|
2
2
|
classifyErrorArea,
|
|
3
3
|
isInteractive,
|
|
4
4
|
promptYesNo
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-6IQHSWSZ.js";
|
|
6
6
|
import {
|
|
7
7
|
VERSION,
|
|
8
8
|
getCurrentSentryTraceId,
|
|
9
9
|
resolveIssueRepoSlug
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-P5WPSCTS.js";
|
|
11
11
|
import {
|
|
12
12
|
package_default
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ARFQU4A6.js";
|
|
14
14
|
|
|
15
15
|
// src/bug-report.ts
|
|
16
16
|
import { execSync, execFileSync } from "child_process";
|