bulletin-deploy 0.21.0 → 0.22.0-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.
- package/bin/bulletin-deploy +12 -8
- package/dist/auth-config.js +3 -3
- package/dist/bug-report.js +4 -4
- package/dist/chain-health.js +3 -3
- package/dist/{chunk-IOLWREZB.js → chunk-4FAL7DFB.js} +5 -5
- package/dist/{chunk-CQA3JPYX.js → chunk-6RQY4VPG.js} +4 -4
- package/dist/{chunk-E77HESGN.js → chunk-7G475SPF.js} +1 -1
- package/dist/{chunk-7QQZ57E6.js → chunk-BMUDRQYV.js} +1 -1
- package/dist/{chunk-K57H4IRT.js → chunk-DKTKQS2N.js} +1 -1
- package/dist/{chunk-WYZUDE6I.js → chunk-FUU5U5GB.js} +2 -2
- package/dist/{chunk-GL7JKE7O.js → chunk-KDVHMIKK.js} +1 -1
- package/dist/{chunk-4FIMYLWV.js → chunk-KXYSKT5U.js} +142 -45
- package/dist/{chunk-EWQ2QZ44.js → chunk-LTUECTW2.js} +66 -18
- package/dist/{chunk-UPENVZ7J.js → chunk-NTJRL6TA.js} +1 -1
- package/dist/{chunk-BDUL42WH.js → chunk-OFR4K7P3.js} +115 -1
- package/dist/{chunk-GLLLSFMA.js → chunk-RMO7G7X2.js} +3 -3
- package/dist/{chunk-KOLWOUWP.js → chunk-S2N25SYI.js} +1 -1
- package/dist/{chunk-LPG3QSOM.js → chunk-Z6EIQVNP.js} +1 -1
- package/dist/chunk-probe.js +3 -3
- package/dist/commands/login.js +13 -13
- package/dist/commands/logout.js +4 -4
- package/dist/commands/transfer.js +6 -6
- package/dist/commands/whoami.js +3 -3
- package/dist/deploy-actors.js +7 -7
- package/dist/deploy.js +13 -13
- package/dist/dotns.js +6 -6
- package/dist/index.js +26 -26
- package/dist/manifest/product-preflight.js +3 -3
- package/dist/manifest/publish.js +17 -17
- package/dist/memory-report.js +2 -2
- package/dist/merkle.js +13 -13
- package/dist/personhood/bootstrap.js +9 -9
- package/dist/personhood/people-client.js +6 -6
- package/dist/pool.d.ts +62 -1
- package/dist/pool.js +21 -5
- package/dist/run-state.js +1 -1
- package/dist/sss-allowance-cache.js +4 -4
- package/dist/storage-signer.js +13 -13
- package/dist/telemetry.d.ts +4 -2
- package/dist/telemetry.js +6 -2
- package/dist/version-check.js +3 -3
- package/dist/ws.js +4 -4
- package/package.json +1 -1
- package/tools/release-retry-wrapper.mjs +8 -0
- package/dist/{chunk-DBDOISNQ.js → chunk-EHAL4CJM.js} +3 -3
package/bin/bulletin-deploy
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import "../dist/suppress-localstorage-warning.js";
|
|
8
8
|
|
|
9
9
|
import { deploy, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, NonRetryableError, EXIT_CODE_NO_RETRY, isConnectionError, isBenignTeardownError, resolveEffectiveMnemonic, mnemonicConflictNotice, resolveEnvId, shouldPublishManifest, nonInteractivePhoneConfirmationError, printDeploymentCompleteBanner } from "../dist/deploy.js";
|
|
10
|
-
import { VERSION, setDeployAttribute, captureWarning, closeTelemetry, setRunStateActive, markRelaunchOomHintShown, setVersionFreshness } from "../dist/telemetry.js";
|
|
10
|
+
import { VERSION, setDeployAttribute, captureWarning, closeTelemetry, markDeployFatal, setRunStateActive, markRelaunchOomHintShown, setVersionFreshness } from "../dist/telemetry.js";
|
|
11
11
|
import { handleFailedDeploy, handlePreflightVersionCheck, fetchVersionInfo, preReleaseWarning, checkNodeVersion, classifyVersionFreshness, isInteractive } from "../dist/version-check.js";
|
|
12
12
|
import { setDeployContext, installLogCapture, buildCliFlagsSummary } from "../dist/bug-report.js";
|
|
13
13
|
import { loadRunState, writeRunState, shouldSkipStaleWarning, shouldShowOomHint, probablyOomRssMb } from "../dist/run-state.js";
|
|
@@ -355,9 +355,6 @@ if (!flags.help && !flags.version) {
|
|
|
355
355
|
if (finalizing) return;
|
|
356
356
|
finalizing = true;
|
|
357
357
|
try {
|
|
358
|
-
setDeployAttribute("deploy.status", "killed");
|
|
359
|
-
setDeployAttribute("deploy.killed", reason);
|
|
360
|
-
setDeployAttribute("deploy.sad", "true");
|
|
361
358
|
captureWarning(`deploy process terminated: ${reason}`);
|
|
362
359
|
} catch { /* telemetry best-effort */ }
|
|
363
360
|
try { await closeTelemetry(1000); } catch { /* ignore */ }
|
|
@@ -390,7 +387,7 @@ if (!flags.help && !flags.version) {
|
|
|
390
387
|
} catch { /* telemetry best-effort */ }
|
|
391
388
|
return;
|
|
392
389
|
}
|
|
393
|
-
try {
|
|
390
|
+
try { markDeployFatal(e); } catch {}
|
|
394
391
|
finalize(kind, 2);
|
|
395
392
|
};
|
|
396
393
|
process.on("uncaughtException", (e) => handleUnhandled(e, "uncaught"));
|
|
@@ -400,9 +397,16 @@ if (!flags.help && !flags.version) {
|
|
|
400
397
|
// and are retryable from the consumer's perspective. Contrast with
|
|
401
398
|
// NonRetryableError exits (code 78, POSIX EX_CONFIG) which callers must
|
|
402
399
|
// NOT retry — see EXIT_CODE_NO_RETRY in src/errors.ts.
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
400
|
+
const onSignal = (sig, exitCode) => {
|
|
401
|
+
try {
|
|
402
|
+
setDeployAttribute("deploy.status", "killed");
|
|
403
|
+
setDeployAttribute("deploy.killed", sig);
|
|
404
|
+
} catch { /* telemetry best-effort */ }
|
|
405
|
+
finalize(sig, exitCode);
|
|
406
|
+
};
|
|
407
|
+
process.on("SIGINT", () => onSignal("SIGINT", 130));
|
|
408
|
+
process.on("SIGTERM", () => onSignal("SIGTERM", 143));
|
|
409
|
+
process.on("SIGHUP", () => onSignal("SIGHUP", 129));
|
|
406
410
|
}
|
|
407
411
|
|
|
408
412
|
try {
|
package/dist/auth-config.js
CHANGED
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
hasPersistedSession,
|
|
11
11
|
readNetworkSuffix,
|
|
12
12
|
resolveBulletinEndpoints
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-KDVHMIKK.js";
|
|
14
14
|
import "./chunk-3NR3T7US.js";
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-KXYSKT5U.js";
|
|
16
|
+
import "./chunk-BMUDRQYV.js";
|
|
17
17
|
import "./chunk-SH2LG52Z.js";
|
|
18
18
|
import "./chunk-DNXE3Q5D.js";
|
|
19
19
|
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-RMO7G7X2.js";
|
|
14
|
+
import "./chunk-S2N25SYI.js";
|
|
15
|
+
import "./chunk-KXYSKT5U.js";
|
|
16
|
+
import "./chunk-BMUDRQYV.js";
|
|
17
17
|
import "./chunk-SH2LG52Z.js";
|
|
18
18
|
export {
|
|
19
19
|
buildCliFlagsSummary,
|
package/dist/chain-health.js
CHANGED
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
DEFAULT_WINDOW_BLOCKS,
|
|
4
4
|
MAX_SPANS_PER_SAMPLER,
|
|
5
5
|
endpointHost
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-NTJRL6TA.js";
|
|
7
|
+
import "./chunk-KXYSKT5U.js";
|
|
8
|
+
import "./chunk-BMUDRQYV.js";
|
|
9
9
|
import "./chunk-SH2LG52Z.js";
|
|
10
10
|
export {
|
|
11
11
|
ChainHealthSampler,
|
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
isTestnetSpecName,
|
|
10
10
|
testnetFromNetworkField
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-OFR4K7P3.js";
|
|
12
12
|
import {
|
|
13
13
|
getWsProvider,
|
|
14
14
|
parseRpcFrame
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-FUU5U5GB.js";
|
|
16
16
|
import {
|
|
17
17
|
HIGHEST_VERIFIED_DOTNS_RELEASE,
|
|
18
18
|
POP_CONTROLLER_PROBE_ABI,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
} from "./chunk-3NR3T7US.js";
|
|
28
28
|
import {
|
|
29
29
|
ChainHealthSampler
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-NTJRL6TA.js";
|
|
31
31
|
import {
|
|
32
32
|
captureWarning,
|
|
33
33
|
markCodePath,
|
|
@@ -35,13 +35,13 @@ import {
|
|
|
35
35
|
setDeploySentryTag,
|
|
36
36
|
truncateAddress,
|
|
37
37
|
withSpan
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-KXYSKT5U.js";
|
|
39
39
|
import {
|
|
40
40
|
FALLBACK_MAX_COMMITMENT_AGE_SECONDS,
|
|
41
41
|
clearCommitmentRecord,
|
|
42
42
|
loadCommitmentRecord,
|
|
43
43
|
writeCommitmentRecord
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-BMUDRQYV.js";
|
|
45
45
|
import {
|
|
46
46
|
NonRetryableError
|
|
47
47
|
} from "./chunk-SH2LG52Z.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
verifyEmbeddedAppManifests
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-EHAL4CJM.js";
|
|
4
4
|
import {
|
|
5
5
|
pessimisticSizePreflight
|
|
6
6
|
} from "./chunk-YTRNJMI4.js";
|
|
@@ -19,13 +19,13 @@ import {
|
|
|
19
19
|
setBulletinEndpoints,
|
|
20
20
|
storeDirectory,
|
|
21
21
|
storeFile
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-LTUECTW2.js";
|
|
23
23
|
import {
|
|
24
24
|
DEFAULT_TLD,
|
|
25
25
|
DotNS,
|
|
26
26
|
parseDomainName,
|
|
27
27
|
stripTldSuffix
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-4FAL7DFB.js";
|
|
29
29
|
import {
|
|
30
30
|
DEFAULT_ENV_ID,
|
|
31
31
|
getPopSelfServeConfig,
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
setDeployAttribute,
|
|
37
37
|
withManifestSpan,
|
|
38
38
|
withSpan
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-KXYSKT5U.js";
|
|
40
40
|
import {
|
|
41
41
|
NonRetryableError
|
|
42
42
|
} from "./chunk-SH2LG52Z.js";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
endpointHost
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NTJRL6TA.js";
|
|
4
4
|
import {
|
|
5
5
|
captureWarning
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-KXYSKT5U.js";
|
|
7
7
|
|
|
8
8
|
// src/ws.ts
|
|
9
9
|
import { getWsProvider as papiGetWsProvider } from "polkadot-api/ws";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
package_default,
|
|
3
3
|
writeRunState
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BMUDRQYV.js";
|
|
5
5
|
import {
|
|
6
6
|
FALLBACK_CONFIG_ORIGIN,
|
|
7
7
|
SHIPPED_CONFIG_ORIGIN
|
|
@@ -131,6 +131,11 @@ function setVersionFreshness(status) {
|
|
|
131
131
|
versionFreshness = status;
|
|
132
132
|
}
|
|
133
133
|
async function closeTelemetry(timeoutMs) {
|
|
134
|
+
if (deployRootSpan) {
|
|
135
|
+
if (deployRootSpan === deploySpan) deployRootSpan.setAttribute("deploy.outcome", computeDeployOutcome(currentErrorCategory, currentDeploySad, currentSadReason));
|
|
136
|
+
deployRootSpan.end();
|
|
137
|
+
deployRootSpan = null;
|
|
138
|
+
}
|
|
134
139
|
if (!Sentry) return;
|
|
135
140
|
try {
|
|
136
141
|
await Sentry.close(timeoutMs);
|
|
@@ -152,6 +157,9 @@ function initTelemetry() {
|
|
|
152
157
|
// Sentry Node SDK captures os.hostname() by default, which leaks personal
|
|
153
158
|
// machine names (e.g. "Mac.fritz.box"). Override to something anonymous.
|
|
154
159
|
serverName: process.env.CI ? process.env.RUNNER_NAME ?? "ci" : "local",
|
|
160
|
+
// Library mode registers no uncaughtException listener, so Sentry's fatal
|
|
161
|
+
// handler is what exits the process; report the deploy as failed first.
|
|
162
|
+
integrations: [Sentry.onUncaughtExceptionIntegration({ onFatalError: exitOnFatalError })],
|
|
155
163
|
beforeSend(event) {
|
|
156
164
|
if (event.server_name) event.server_name = process.env.CI ? process.env.RUNNER_NAME ?? "ci" : "local";
|
|
157
165
|
if (event.message) event.message = scrubPaths(event.message);
|
|
@@ -284,6 +292,9 @@ var DEPLOY_SEED_POOL = {
|
|
|
284
292
|
"deploy.pool.nonce_collision_missing": 0,
|
|
285
293
|
"deploy.pool.nonce_collision_reupload_count": 0
|
|
286
294
|
};
|
|
295
|
+
var DEPLOY_SEED_POOL_HEALTH = {
|
|
296
|
+
"deploy.pool.stuck_skipped": "none"
|
|
297
|
+
};
|
|
287
298
|
var DEPLOY_SEED_MANIFEST = {
|
|
288
299
|
"deploy.manifest.fetch_source": "none",
|
|
289
300
|
"deploy.manifest.fetch_attempts": "0",
|
|
@@ -327,6 +338,7 @@ function getDeployAttributes(domain) {
|
|
|
327
338
|
...DEPLOY_SEED_STORAGE,
|
|
328
339
|
...DEPLOY_SEED_PROBE,
|
|
329
340
|
...DEPLOY_SEED_POOL,
|
|
341
|
+
...DEPLOY_SEED_POOL_HEALTH,
|
|
330
342
|
...DEPLOY_SEED_MANIFEST,
|
|
331
343
|
...DEPLOY_SEED_BULLETIN_UPLOAD,
|
|
332
344
|
...DEPLOY_SEED_BULLETIN_AUTH,
|
|
@@ -346,7 +358,12 @@ function getDeployAttributes(domain) {
|
|
|
346
358
|
// #1539: unconditional (both-values rule) so count_if(deploy.is_e2e_fixture,
|
|
347
359
|
// "true") / "false" both work — see isE2eFixtureTag above for the full
|
|
348
360
|
// rationale, and setDeployAttribute below for the options.tag/--tag path.
|
|
349
|
-
"deploy.is_e2e_fixture": String(isE2eFixtureTag(process.env.DEPLOY_TAG))
|
|
361
|
+
"deploy.is_e2e_fixture": String(isE2eFixtureTag(process.env.DEPLOY_TAG)),
|
|
362
|
+
// #1626: the E2E harness sets BULLETIN_E2E_EXPECT_FAIL=1 on a deploy it
|
|
363
|
+
// asserts will fail (S3 owned-elsewhere, governance-reserved, subdomain
|
|
364
|
+
// orphan…), so the E2E dashboard can exclude those deliberate error spans.
|
|
365
|
+
// A tag only: nothing else reads the var. Unconditional (both-values rule).
|
|
366
|
+
"deploy.expected_error": String(process.env.BULLETIN_E2E_EXPECT_FAIL === "1")
|
|
350
367
|
};
|
|
351
368
|
if (hostApp) attrs["deploy.host_app"] = hostApp;
|
|
352
369
|
const hostAppVersion = process.env.BULLETIN_DEPLOY_HOST_APP_VERSION;
|
|
@@ -369,23 +386,19 @@ function cameFromOurConfig(msg) {
|
|
|
369
386
|
const lower = msg.toLowerCase();
|
|
370
387
|
return lower.includes(`came from ${SHIPPED_CONFIG_ORIGIN.toLowerCase()}`) || lower.includes(`came from ${FALLBACK_CONFIG_ORIGIN.toLowerCase()}`);
|
|
371
388
|
}
|
|
372
|
-
|
|
389
|
+
function contractAddressCategory(msg) {
|
|
390
|
+
if (CONTRACT_ADDRESS_FAILURE.test(msg) && /this address came from/i.test(msg) && !cameFromOurConfig(msg)) return "user";
|
|
391
|
+
return /could not determine the DotNS ABI profile/i.test(msg) ? "environment" : "unknown";
|
|
392
|
+
}
|
|
393
|
+
function categoryOf(kind, msg) {
|
|
394
|
+
if (kind === "naming.contract_unavailable" || kind === "naming.contract_function_removed") return contractAddressCategory(msg);
|
|
395
|
+
return ERROR_KIND_CATEGORY[kind];
|
|
396
|
+
}
|
|
373
397
|
function isExpectedError(msg, variant) {
|
|
374
|
-
|
|
375
|
-
if (structuralCategory) return structuralCategory === "user";
|
|
376
|
-
if (GENERIC_USER_ERROR.test(msg)) return true;
|
|
377
|
-
if (CONTRACT_ADDRESS_FAILURE.test(msg)) {
|
|
378
|
-
return /this address came from/i.test(msg) && !cameFromOurConfig(msg);
|
|
379
|
-
}
|
|
380
|
-
return false;
|
|
398
|
+
return classifyDeployError(msg, variant) === "user";
|
|
381
399
|
}
|
|
382
400
|
function classifyDeployError(msg, variant) {
|
|
383
|
-
|
|
384
|
-
if (structuralCategory) return structuralCategory;
|
|
385
|
-
if (isExpectedError(msg)) return "user";
|
|
386
|
-
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|Revive\.call|Utility\.batch_all) timed out after \d+ms|transaction watcher silent for|could not determine the DotNS ABI profile/i.test(msg)) return "environment";
|
|
387
|
-
if (/javascript heap out of memory|allocation failed.*heap|External signer mode is not supported with dotns-cli/i.test(msg)) return "internal";
|
|
388
|
-
return "unknown";
|
|
401
|
+
return structuralCategoryOf(variant) ?? categoryOf(classifyErrorKind(msg, variant), msg);
|
|
389
402
|
}
|
|
390
403
|
function classifySadReason(message) {
|
|
391
404
|
if (/process terminated: SIG/i.test(message)) return "killed";
|
|
@@ -450,8 +463,17 @@ var ERROR_KIND_RULES = [
|
|
|
450
463
|
// Ahead of the generic contract-revert rule: a soulbound refusal is a
|
|
451
464
|
// permanent naming fact, not a transient chain error.
|
|
452
465
|
[/is soulbound and cannot be transferred/i, "naming.soulbound"],
|
|
466
|
+
// Operator-fixable phrasings, above contract-revert so the actionable kind wins over the wrapper.
|
|
467
|
+
// formatUnregistrableReason's phrase (#1185); above the label rules since it can quote the PopError it explains.
|
|
468
|
+
[/cannot register it|base name is \d+ chars|reserved for original/i, "naming.governance_reserved"],
|
|
469
|
+
[/NameNotAvailable/i, "naming.name_unavailable"],
|
|
470
|
+
[/invalid domain label|name must be lowercase/i, "naming.invalid_label"],
|
|
471
|
+
[/insufficient balance|insufficient funds|signer balance .* < estimated fee/i, "funding.insufficient_balance"],
|
|
472
|
+
[/insufficient .* authorization/i, "storage.allowance_insufficient"],
|
|
473
|
+
[/bip39 mnemonic/i, "signer.invalid_mnemonic"],
|
|
474
|
+
[/ipfs cli not installed/i, "tool.ipfs_missing"],
|
|
453
475
|
[/Contract reverted|Contract execution would revert|revert(?:ed|ing)?\s*\(flags=[0-9]+\)|"type"\s*:\s*"ContractReverted"/i, "contract-revert"],
|
|
454
|
-
[/timed out after \d+s waiting for block|Transaction not included after \d+s|Transaction did not settle within|Commitment still too new
|
|
476
|
+
[/timed out after \d+s waiting for block|Transaction not included after \d+s|Transaction did not settle within|Commitment still too new/i, "chain-timeout"],
|
|
455
477
|
[/\bstale\b.*nonce|nonce.*\bstale\b|"type"\s*:\s*"(?:Future|Stale)"|Invalid::Future|tx rejected by pool/i, "nonce-stale"],
|
|
456
478
|
// Invalid::BadProof: the extrinsic's signature didn't verify (wrong genesis
|
|
457
479
|
// hash / mortality window / spec version, or a re-signed payload mismatch).
|
|
@@ -465,6 +487,8 @@ var ERROR_KIND_RULES = [
|
|
|
465
487
|
[/short names are not on sale on|Short names are not for sale/i, "naming.short_names_closed"],
|
|
466
488
|
[/requires ProofOfPersonhood(?:Full|Lite|Light),\s*but this signer is NoStatus/i, "naming.pop_required"],
|
|
467
489
|
[/requires NoStatus,\s*but this signer is ProofOfPersonhood/i, "naming.nostatus_required"],
|
|
490
|
+
// Other personhood phrasings ("Requires Full Personhood verification", "personhood check failed"): after both specific rules above so their kinds win.
|
|
491
|
+
[/personhood/i, "naming.pop_required"],
|
|
468
492
|
// #1345 (2026-09-01 previewnet TLD change, fixed in #1324): checkTldNodeConsistency's
|
|
469
493
|
// safety-net throw (src/dotns.ts). Was 100% of the 48-span 'unknown' majority in the
|
|
470
494
|
// 7d sweep — anchored on the stable prefix, never on the interpolated namehash values.
|
|
@@ -473,6 +497,11 @@ var ERROR_KIND_RULES = [
|
|
|
473
497
|
// Anchored on the stable "DotNS signer ... PAS free; needs ≥" shape, never on the
|
|
474
498
|
// interpolated address/amounts — those vary per signer and per fee floor.
|
|
475
499
|
[/DotNS signer .+ PAS free; needs ≥/i, "funding.insufficient_balance"],
|
|
500
|
+
// Revive's TransferFailed module error, raised by register / finalize-registration
|
|
501
|
+
// (formatDispatchError JSON) when concurrent deploys on one shared signer spent its
|
|
502
|
+
// balance after the preflight check passed. Matches the variant name alone: the
|
|
503
|
+
// enclosing JSON can be cut by truncation, the innermost variant is the tail.
|
|
504
|
+
[/"type"\s*:\s*"TransferFailed"/i, "funding.transfer_failed"],
|
|
476
505
|
[/Cannot decode zero data.*with ABI parameters/i, "dotns.abi_decode_empty"],
|
|
477
506
|
// Issue #1060: contractCall's own empty-`0x`-data guard (src/dotns.ts, #729) throws
|
|
478
507
|
// an actionable wrapper instead of letting the raw viem message above reach a
|
|
@@ -512,33 +541,34 @@ var ERROR_KIND_RULES = [
|
|
|
512
541
|
// coming back with empty data. Genuinely a missing-contract config problem,
|
|
513
542
|
// not a removed-function one — stays naming.contract_unavailable.
|
|
514
543
|
[/Invalid contract address for \w+ in environment/i, "naming.contract_unavailable"],
|
|
515
|
-
[new RegExp(`Domain\\s+\\S+\\.${TLD_FRAGMENT}\\s+is already owned by\\s+0x[a-fA-F0-9]+`, "i"), "naming.already_owned"],
|
|
516
|
-
// #1185: formatUnregistrableReason's distinctive phrase — present in both
|
|
517
|
-
// the unregistered ("...is not registered, and bulletin-deploy cannot
|
|
518
|
-
// register it: ...") and owned-by-another-account ("...is owned by
|
|
519
|
-
// 0x..., and bulletin-deploy cannot register it for a different account:
|
|
520
|
-
// ...") variants, so one rule classifies both. Ordered before
|
|
521
|
-
// naming.subdomain_orphan (a different message shape entirely) and after
|
|
522
|
-
// naming.already_owned (whose "already owned by 0x..." phrasing this rule
|
|
523
|
-
// never produces, so there's no overlap either way).
|
|
524
|
-
[/cannot register it/i, "naming.governance_reserved"],
|
|
525
544
|
[new RegExp(`Cannot deploy\\s+[\\w.-]+\\.${TLD_FRAGMENT}:\\s*parent\\s+[\\w.-]+\\.${TLD_FRAGMENT}\\s+is owned by`, "i"), "naming.subdomain_orphan"],
|
|
545
|
+
// After subdomain_orphan, whose "is owned by" it would otherwise claim.
|
|
546
|
+
[/owner mismatch|\bowned by\b/i, "naming.already_owned"],
|
|
526
547
|
[/Post-deploy verification failed for .+: on-chain contenthash is /i, "verify.contenthash_mismatch"],
|
|
527
548
|
[/Deploy verification failed:\s*DAG-PB root.+not finalised/i, "verify.dagpb_not_finalised"],
|
|
528
549
|
[/Retry budget exhausted:.*recovery attempts/i, "network.recovery_exhausted"],
|
|
529
550
|
[/Account auto-mapping did not take effect on-chain/i, "account.mapping_pending"],
|
|
530
|
-
[/ReviveApi
|
|
531
|
-
[/ReviveApi
|
|
532
|
-
[/transaction watcher silent for
|
|
551
|
+
[/ReviveApi.*timed out/i, "chain.api_timeout"],
|
|
552
|
+
[/ReviveApi.*returned empty result/i, "chain.api_timeout"],
|
|
553
|
+
[/transaction watcher silent for/i, "chain.tx_silent"],
|
|
533
554
|
[/(?:commit|register|setSubnodeOwner|setResolver|setContenthash|setText|Revive\.call|Utility\.batch_all) timed out after \d+ms/i, "chain.tx_timeout"],
|
|
534
555
|
// Prefix, not the full `AncientBirthBlock` variant name: at 17 chars it is
|
|
535
556
|
// long enough to be cut in half by the 100-char truncation both src/deploy.ts
|
|
536
557
|
// producer sites apply to the inner chain error, which sent a live span to
|
|
537
558
|
// `unknown` with the message ending `"type": "AncientBirth`.
|
|
538
559
|
[/AncientBirth/i, "chain.extrinsic_expired"],
|
|
539
|
-
[/
|
|
560
|
+
[/quota exhausted/i, "chain.quota_exhausted"],
|
|
540
561
|
[/Mobile (?:transaction )?signing (?:failed|rejected).*message too big/i, "signer.message_too_large"],
|
|
541
|
-
[/^INVARIANT FAILED:/i, "tool.invariant"]
|
|
562
|
+
[/^INVARIANT FAILED:/i, "tool.invariant"],
|
|
563
|
+
// Broad fallbacks, last.
|
|
564
|
+
[/javascript heap out of memory|allocation failed.*heap/i, "tool.out_of_memory"],
|
|
565
|
+
[/External signer mode is not supported with dotns-cli/i, "tool.external_signer_unsupported"],
|
|
566
|
+
[/All promises were rejected/i, "network.endpoints_failed"],
|
|
567
|
+
[/tx dropped from best chain|chain may have (?:dropped|evicted)/i, "chain.tx_dropped"],
|
|
568
|
+
[/not finalised after \d+s/i, "chain.not_finalised"],
|
|
569
|
+
[/chunk.*failed after.*retr/i, "chain.chunk_failed"],
|
|
570
|
+
[/"type"\s*:\s*"Invalid"/i, "chain.tx_invalid"],
|
|
571
|
+
[/dotns register failed/i, "dotns.register_failed"]
|
|
542
572
|
];
|
|
543
573
|
var INVALID_TRANSACTION_VARIANT_KIND = {
|
|
544
574
|
Future: "nonce-stale",
|
|
@@ -555,6 +585,57 @@ function classifyErrorKind(msg, variant) {
|
|
|
555
585
|
}
|
|
556
586
|
return "unknown";
|
|
557
587
|
}
|
|
588
|
+
var ERROR_KIND_CATEGORY = {
|
|
589
|
+
"contract-revert": "environment",
|
|
590
|
+
"chain-timeout": "environment",
|
|
591
|
+
"nonce-stale": "environment",
|
|
592
|
+
"connection": "environment",
|
|
593
|
+
"naming.pop_required": "user",
|
|
594
|
+
"naming.nostatus_required": "user",
|
|
595
|
+
"naming.contract_unavailable": "unknown",
|
|
596
|
+
// see contractAddressCategory
|
|
597
|
+
"naming.contract_function_removed": "unknown",
|
|
598
|
+
// see contractAddressCategory
|
|
599
|
+
"dotns.abi_decode_empty": "unknown",
|
|
600
|
+
// never attributed; kept visible
|
|
601
|
+
"naming.already_owned": "user",
|
|
602
|
+
"naming.governance_reserved": "user",
|
|
603
|
+
"naming.short_names_closed": "user",
|
|
604
|
+
"naming.soulbound": "user",
|
|
605
|
+
"naming.subdomain_orphan": "user",
|
|
606
|
+
"naming.invalid_label": "user",
|
|
607
|
+
"naming.name_unavailable": "user",
|
|
608
|
+
"naming.tld_mismatch": "environment",
|
|
609
|
+
"funding.insufficient_balance": "user",
|
|
610
|
+
"funding.transfer_failed": "user",
|
|
611
|
+
"verify.contenthash_mismatch": "environment",
|
|
612
|
+
"verify.dagpb_not_finalised": "environment",
|
|
613
|
+
"network.recovery_exhausted": "environment",
|
|
614
|
+
"network.endpoints_failed": "environment",
|
|
615
|
+
"account.mapping_pending": "environment",
|
|
616
|
+
"chain.api_timeout": "environment",
|
|
617
|
+
"chain.tx_timeout": "environment",
|
|
618
|
+
"chain.tx_silent": "environment",
|
|
619
|
+
"chain.extrinsic_expired": "environment",
|
|
620
|
+
"chain.quota_exhausted": "user",
|
|
621
|
+
"chain.bad_proof": "environment",
|
|
622
|
+
"chain.chunk_failed": "environment",
|
|
623
|
+
"chain.tx_dropped": "environment",
|
|
624
|
+
"chain.tx_invalid": "environment",
|
|
625
|
+
"chain.not_finalised": "environment",
|
|
626
|
+
"dotns.register_failed": "environment",
|
|
627
|
+
"signer.message_too_large": "environment",
|
|
628
|
+
"signer.invalid_mnemonic": "user",
|
|
629
|
+
"storage.rejected": "user",
|
|
630
|
+
"storage.allowance_insufficient": "user",
|
|
631
|
+
"user.aborted": "user",
|
|
632
|
+
"signer.phone_confirmation_unavailable": "user",
|
|
633
|
+
"tool.invariant": "internal",
|
|
634
|
+
"tool.ipfs_missing": "user",
|
|
635
|
+
"tool.out_of_memory": "internal",
|
|
636
|
+
"tool.external_signer_unsupported": "internal",
|
|
637
|
+
"unknown": "unknown"
|
|
638
|
+
};
|
|
558
639
|
function chainErrorVariantOf(error) {
|
|
559
640
|
return error?.chainErrorVariant;
|
|
560
641
|
}
|
|
@@ -609,6 +690,7 @@ async function withSpan(op, description, attributes, fn) {
|
|
|
609
690
|
}
|
|
610
691
|
var memoryPeak = null;
|
|
611
692
|
var deployRootSpan = null;
|
|
693
|
+
var deploySpan = null;
|
|
612
694
|
var stageSamples = {};
|
|
613
695
|
var reportContext = {};
|
|
614
696
|
var currentErrorCategory = null;
|
|
@@ -674,6 +756,7 @@ async function withDeploySpan(domain, fn) {
|
|
|
674
756
|
try {
|
|
675
757
|
return await Sentry.startSpan({ op: "deploy", name: `deploy ${domain}`, attributes: attrs }, async (span) => {
|
|
676
758
|
deployRootSpan = span;
|
|
759
|
+
deploySpan = span;
|
|
677
760
|
span.setAttribute("deploy.tool_version", VERSION);
|
|
678
761
|
if (relaunchOomHintShown) {
|
|
679
762
|
span.setAttribute("deploy.relaunch.oom_hint_shown", "true");
|
|
@@ -694,19 +777,7 @@ async function withDeploySpan(domain, fn) {
|
|
|
694
777
|
span.setAttribute("deploy.status", "ok");
|
|
695
778
|
return result;
|
|
696
779
|
} catch (error) {
|
|
697
|
-
|
|
698
|
-
const variant = chainErrorVariantOf(error);
|
|
699
|
-
span.setAttribute("deploy.status", "error");
|
|
700
|
-
setDeployErrorOnSpan(span, msg, variant);
|
|
701
|
-
const errorCategory = classifyDeployError(msg, variant);
|
|
702
|
-
span.setAttribute("deploy.error_category", errorCategory);
|
|
703
|
-
currentErrorCategory = errorCategory;
|
|
704
|
-
const isExpected = isExpectedError(msg, variant);
|
|
705
|
-
span.setAttribute("deploy.expected", isExpected ? "true" : "false");
|
|
706
|
-
span.setAttribute("deploy.sad", isExpected ? "false" : "true");
|
|
707
|
-
if (!isExpected) {
|
|
708
|
-
span.setStatus({ code: 2, message: "internal_error" });
|
|
709
|
-
}
|
|
780
|
+
recordDeployFailure(span, error);
|
|
710
781
|
throw error;
|
|
711
782
|
} finally {
|
|
712
783
|
sampleMemory("end");
|
|
@@ -757,6 +828,7 @@ async function withDeploySpan(domain, fn) {
|
|
|
757
828
|
} finally {
|
|
758
829
|
memoryPeak = null;
|
|
759
830
|
deployRootSpan = null;
|
|
831
|
+
deploySpan = null;
|
|
760
832
|
stageSamples = {};
|
|
761
833
|
reportContext = {};
|
|
762
834
|
currentErrorCategory = null;
|
|
@@ -828,6 +900,29 @@ function setDeployError(msg, variant) {
|
|
|
828
900
|
if (!deployRootSpan) return;
|
|
829
901
|
setDeployErrorOnSpan(deployRootSpan, msg, variant);
|
|
830
902
|
}
|
|
903
|
+
function recordDeployFailure(span, error) {
|
|
904
|
+
const msg = error?.message ?? String(error);
|
|
905
|
+
const variant = chainErrorVariantOf(error);
|
|
906
|
+
span.setAttribute("deploy.status", "error");
|
|
907
|
+
setDeployErrorOnSpan(span, msg, variant);
|
|
908
|
+
const errorCategory = classifyDeployError(msg, variant);
|
|
909
|
+
span.setAttribute("deploy.error_category", errorCategory);
|
|
910
|
+
currentErrorCategory = errorCategory;
|
|
911
|
+
const isExpected = isExpectedError(msg, variant);
|
|
912
|
+
span.setAttribute("deploy.expected", isExpected ? "true" : "false");
|
|
913
|
+
span.setAttribute("deploy.sad", isExpected ? "false" : "true");
|
|
914
|
+
if (!isExpected) {
|
|
915
|
+
span.setStatus({ code: 2, message: "internal_error" });
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
function markDeployFatal(error) {
|
|
919
|
+
if (deployRootSpan && deployRootSpan === deploySpan) recordDeployFailure(deployRootSpan, error);
|
|
920
|
+
}
|
|
921
|
+
function exitOnFatalError(error) {
|
|
922
|
+
console.error(error);
|
|
923
|
+
markDeployFatal(error);
|
|
924
|
+
void closeTelemetry(2e3).finally(() => process.exit(1));
|
|
925
|
+
}
|
|
831
926
|
function __setDeployRootSpanForTest(span) {
|
|
832
927
|
deployRootSpan = span;
|
|
833
928
|
}
|
|
@@ -1035,6 +1130,7 @@ export {
|
|
|
1035
1130
|
computeDeployOutcome,
|
|
1036
1131
|
classifiableErrorKinds,
|
|
1037
1132
|
classifyErrorKind,
|
|
1133
|
+
ERROR_KIND_CATEGORY,
|
|
1038
1134
|
sanitizeErrorMessage,
|
|
1039
1135
|
analyseErrorPattern,
|
|
1040
1136
|
withSpan,
|
|
@@ -1044,6 +1140,7 @@ export {
|
|
|
1044
1140
|
setDeployReportContext,
|
|
1045
1141
|
setDeployAttribute,
|
|
1046
1142
|
setDeployError,
|
|
1143
|
+
markDeployFatal,
|
|
1047
1144
|
__setDeployRootSpanForTest,
|
|
1048
1145
|
__setSentryForTest,
|
|
1049
1146
|
getCurrentSentryTraceId,
|