@parity/product-deploy 0.8.1-rc.1 → 0.8.2-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -230
- package/bin/bulletin-deploy +15 -1
- package/dist/bug-report.js +4 -4
- package/dist/{chunk-67LJSVIF.js → chunk-4Y4ZBN45.js} +1 -1
- package/dist/{chunk-KVWIZYYV.js → chunk-5EJ247OO.js} +88 -77
- package/dist/{chunk-EGPPGZXB.js → chunk-7GYCJPFI.js} +128 -22
- package/dist/{chunk-5QX6RJWD.js → chunk-CSDXTU3G.js} +2 -2
- package/dist/{chunk-L2SKSKB6.js → chunk-J3NIXHZZ.js} +108 -0
- package/dist/{chunk-RZQQLSF4.js → chunk-JQ5X3VMP.js} +15 -102
- package/dist/{chunk-XOQ7IJOQ.js → chunk-N27JUWU2.js} +6 -3
- package/dist/{chunk-IT2RZLUT.js → chunk-PIGHAAM2.js} +3 -3
- package/dist/{chunk-KBZXNQOT.js → chunk-R2ORPNZC.js} +1 -1
- package/dist/{chunk-VCOYLHNE.js → chunk-RRYHCOOJ.js} +75 -33
- package/dist/{chunk-CNPB4VAM.js → chunk-XFX4VODU.js} +65 -0
- package/dist/chunk-probe.js +3 -3
- package/dist/deploy.d.ts +38 -1
- package/dist/deploy.js +16 -10
- package/dist/dotns.d.ts +33 -2
- package/dist/dotns.js +9 -5
- package/dist/environments.d.ts +15 -2
- package/dist/environments.js +3 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +13 -11
- package/dist/manifest/publish.js +11 -11
- package/dist/manifest-fetch.d.ts +22 -1
- package/dist/manifest-fetch.js +7 -1
- package/dist/manifest-roundtrip.js +1 -1
- package/dist/memory-report.js +2 -2
- package/dist/merkle.js +10 -10
- package/dist/personhood/bootstrap.js +5 -5
- package/dist/personhood/people-client.js +5 -5
- package/dist/pool.d.ts +2 -12
- package/dist/pool.js +3 -11
- package/dist/run-state.js +1 -1
- package/dist/telemetry.js +2 -2
- package/dist/version-check.js +3 -3
- package/docs/bootstrap.md +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -1,233 +1,5 @@
|
|
|
1
1
|
# bulletin-deploy
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Early alpha code, stay tuned.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Quick Start
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install -g bulletin-deploy
|
|
11
|
-
|
|
12
|
-
# Build your app first, then deploy it.
|
|
13
|
-
bulletin-deploy ./dist my-app00.dot
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
On success, the CLI prints the CID and the `.dot` domain that now serves your app.
|
|
17
|
-
|
|
18
|
-
## Installation
|
|
19
|
-
|
|
20
|
-
- **Node.js 22+**
|
|
21
|
-
- **IPFS Kubo** if you want the default merkleization path
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
# macOS
|
|
25
|
-
brew install ipfs
|
|
26
|
-
ipfs init
|
|
27
|
-
|
|
28
|
-
# Linux
|
|
29
|
-
wget https://dist.ipfs.tech/kubo/v0.33.0/kubo_v0.33.0_linux-amd64.tar.gz
|
|
30
|
-
tar -xvzf kubo_v0.33.0_linux-amd64.tar.gz
|
|
31
|
-
sudo bash kubo/install.sh
|
|
32
|
-
ipfs init
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
If you do not want a Kubo dependency, pass `--js-merkle`.
|
|
36
|
-
|
|
37
|
-
Stable installs:
|
|
38
|
-
|
|
39
|
-
- `npm install -g bulletin-deploy`
|
|
40
|
-
- `npm install -g bulletin-deploy@latest`
|
|
41
|
-
|
|
42
|
-
Release candidates:
|
|
43
|
-
|
|
44
|
-
- `npm install -g bulletin-deploy@rc`
|
|
45
|
-
- `npm install -g bulletin-deploy@<exact-version>`
|
|
46
|
-
|
|
47
|
-
## CLI Usage
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
bulletin-deploy <build-dir> <domain.dot>
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Examples:
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
# Basic deploy (defaults to --env paseo-next-v2)
|
|
57
|
-
bulletin-deploy ./dist my-app00.dot
|
|
58
|
-
|
|
59
|
-
# Pick a different environment
|
|
60
|
-
bulletin-deploy ./dist my-app00.dot --env paseo-review
|
|
61
|
-
|
|
62
|
-
# List supported environments
|
|
63
|
-
bulletin-deploy --list-environments
|
|
64
|
-
|
|
65
|
-
# Refresh the environments cache before deploying
|
|
66
|
-
bulletin-deploy ./dist my-app00.dot --refresh-environments --env paseo-next-v2
|
|
67
|
-
|
|
68
|
-
# Direct signer deploy
|
|
69
|
-
bulletin-deploy ./dist my-app00.dot --mnemonic "..."
|
|
70
|
-
|
|
71
|
-
# Custom Bulletin RPC override (asset-hub still comes from --env)
|
|
72
|
-
bulletin-deploy ./dist my-app00.dot --rpc wss://custom-bulletin.example.com
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### Selecting an environment
|
|
76
|
-
|
|
77
|
-
`--env <id>` selects a target environment by id. The list of environments and their RPC endpoints is sourced dynamically from [`paritytech/bulletin-deploy/assets/environments.json`](./assets/environments.json), which mirrors [`paritytech/triangle-status/environments.json`](https://github.com/paritytech/triangle-status/blob/main/environments.json) (the latter is private; bulletin-deploy serves as the public mirror).
|
|
78
|
-
|
|
79
|
-
| Env id | Network | Bulletin available? |
|
|
80
|
-
|---|---|---|
|
|
81
|
-
| `paseo-next-v2` (default) | testnet | yes |
|
|
82
|
-
| `paseo-next` | testnet | yes |
|
|
83
|
-
| `paseo-review` | testnet | yes |
|
|
84
|
-
| `previewnet` | testnet | yes |
|
|
85
|
-
| `polkadot` | mainnet | not yet |
|
|
86
|
-
| `kusama` | mainnet | not yet |
|
|
87
|
-
|
|
88
|
-
A single env id drives both the bulletin RPC and the asset-hub RPC used internally for DotNS, so they cannot drift. When you pass `--rpc`, it overrides only the bulletin endpoint within the chosen env; the asset-hub endpoint still comes from `--env`.
|
|
89
|
-
|
|
90
|
-
The runtime uses a 24-hour cache at `${XDG_CACHE_HOME:-~/.cache}/bulletin-deploy/environments.json`; `--refresh-environments` busts it and re-fetches. The npm tarball ships a bundled snapshot that is used when the live URL is unreachable.
|
|
91
|
-
|
|
92
|
-
### Options
|
|
93
|
-
|
|
94
|
-
| Flag | What it does |
|
|
95
|
-
|---|---|
|
|
96
|
-
| `--env <id>` | Target environment. Default: `paseo-next-v2`. See `--list-environments` for valid ids. |
|
|
97
|
-
| `--list-environments` | Print the environments table and exit. |
|
|
98
|
-
| `--refresh-environments` | Bust the cache and re-fetch environments.json. Composes with `--env` (refresh-then-deploy) or runs solo. |
|
|
99
|
-
| `--rpc wss://...` | Override the Bulletin RPC endpoint within the chosen `--env`. Also readable from `BULLETIN_RPC`. |
|
|
100
|
-
| `--mnemonic "..."` | Use a specific mnemonic as the direct signer for Bulletin uploads and DotNS updates. Also readable from `MNEMONIC`. |
|
|
101
|
-
| `--derivation-path "..."` | Apply a Substrate derivation path to `--mnemonic`, for example `//deploy/3`. |
|
|
102
|
-
| `--pool-size N` | Change the number of derived pool accounts available for pool-mode Bulletin uploads. Default: `10`. |
|
|
103
|
-
| `--password "..."` | Encrypt SPA content before upload. Consumers must provide the password to decrypt it. |
|
|
104
|
-
| `--js-merkle` | Use pure-JS merkleization instead of the Kubo binary. |
|
|
105
|
-
| `--tag "..."` | Attach a free-form telemetry label. Also readable from `DEPLOY_TAG`. |
|
|
106
|
-
| `--gh-pages-mirror` | After a successful deploy, push the generated CAR to the current repo's `gh-pages` branch as an HTTP mirror. |
|
|
107
|
-
| `--input-car <path>` | Deploy from a pre-built CAR file instead of a build directory. Skips merkleization; reads the root CID from the CAR header. Usage: `bulletin-deploy --input-car site.car my-app.dot` |
|
|
108
|
-
| `--version` | Print the CLI version. |
|
|
109
|
-
| `--help` | Show help. |
|
|
110
|
-
|
|
111
|
-
## Concepts
|
|
112
|
-
|
|
113
|
-
- `Bulletin`: the chain that stores the app payload in chunked transaction storage.
|
|
114
|
-
- `.dot domain`: the DotNS name that points at the deployed content.
|
|
115
|
-
- `CAR`: the content-addressed archive produced from your build output before upload.
|
|
116
|
-
- `merkleization`: turning a directory into a content-addressed DAG and CAR file.
|
|
117
|
-
- `pool accounts`: derived Bulletin uploader accounts used to spread nonce and authorization load.
|
|
118
|
-
- `PoP`: Proof of Personhood, which some `.dot` names require before registration.
|
|
119
|
-
|
|
120
|
-
## Incremental Upload
|
|
121
|
-
|
|
122
|
-
After the first deploy of a `.dot` domain, every subsequent deploy automatically reuses chunks already stored on Bulletin instead of re-uploading them. There is no flag to enable; it just runs.
|
|
123
|
-
|
|
124
|
-
How it works:
|
|
125
|
-
|
|
126
|
-
1. The previous deploy embeds a manifest at `.bulletin-deploy/manifest.json` inside the deployed content (file classification, block ordering, chunk metadata).
|
|
127
|
-
2. The new deploy fetches the previous contenthash from DotNS, then fetches that manifest via the Bulletin IPFS gateway.
|
|
128
|
-
3. The new build's CAR is sliced into chunks; each chunk's CID is HEAD-probed against the gateway. Chunks already present are skipped.
|
|
129
|
-
4. Only the chunks that actually changed (typically: the manifest itself and any modified content) are uploaded.
|
|
130
|
-
|
|
131
|
-
The summary line at the end of a deploy shows the savings:
|
|
132
|
-
|
|
133
|
-
```
|
|
134
|
-
Cache:
|
|
135
|
-
Manifest: embedded (1 attempt)
|
|
136
|
-
Probed: 18 chunks → 15 cached, 2 to upload, 1 probe-failed
|
|
137
|
-
Recycled: 3 CIDs found on-chain that weren't in the previous manifest
|
|
138
|
-
Saved: ~52s and 14.3 MB upload
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
CI runners benefit identically — no `actions/cache` wiring required, because the manifest travels with the deployed content rather than living on the runner's disk.
|
|
142
|
-
|
|
143
|
-
**Encrypted deploys** (`--password`) bypass the incremental path. Encryption produces non-deterministic CAR bytes per run, so chunk-level dedup can't apply.
|
|
144
|
-
|
|
145
|
-
**Force a full re-upload** by deleting `.bulletin-deploy/` from your build output (or changing one byte in any non-volatile file) before deploying. The classifier treats `.bulletin-deploy/` paths as volatile, so removing the manifest forces the next deploy to fall back to the heuristic classifier.
|
|
146
|
-
|
|
147
|
-
## Domain Rules
|
|
148
|
-
|
|
149
|
-
DotNS classifies labels on-chain and may require a specific Proof of Personhood level before registration.
|
|
150
|
-
|
|
151
|
-
Typical cases:
|
|
152
|
-
|
|
153
|
-
| Domain pattern | Typical classification |
|
|
154
|
-
|---|---|
|
|
155
|
-
| Base name, for example `my-app.dot` | `ProofOfPersonhoodFull` |
|
|
156
|
-
| Name with trailing digits, for example `my-app00.dot` | often `NoStatus`, but not guaranteed |
|
|
157
|
-
|
|
158
|
-
Do not rely on the string shape alone. The on-chain classifier is authoritative.
|
|
159
|
-
|
|
160
|
-
On testnets, `bulletin-deploy` self-grants PoP only when the classifier says it is needed. On mainnet, PoP cannot be self-granted.
|
|
161
|
-
|
|
162
|
-
## GitHub Pages Mirror
|
|
163
|
-
|
|
164
|
-
`--gh-pages-mirror` is an opt-in cache path for hosts that want an HTTP fetch path in addition to Bulletin.
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
bulletin-deploy ./dist my-app.dot --gh-pages-mirror
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
After a successful deploy, the CLI pushes:
|
|
171
|
-
|
|
172
|
-
- `bulletin/<domain>.dot.car`
|
|
173
|
-
- `bulletin/<domain>.dot.json`
|
|
174
|
-
|
|
175
|
-
to the current repo's `gh-pages` branch and prints the Pages URL.
|
|
176
|
-
|
|
177
|
-
Use it when you want to validate or consume the mirror feature. The source of truth remains Bulletin plus DotNS.
|
|
178
|
-
|
|
179
|
-
## Programmatic API
|
|
180
|
-
|
|
181
|
-
```js
|
|
182
|
-
import { deploy } from "bulletin-deploy";
|
|
183
|
-
|
|
184
|
-
const result = await deploy("./dist", "my-app00.dot");
|
|
185
|
-
console.log(result.cid, result.domainName);
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
For environments without Kubo:
|
|
189
|
-
|
|
190
|
-
```js
|
|
191
|
-
await deploy("./dist", "my-app00.dot", { jsMerkle: true });
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
## Environment Variables
|
|
195
|
-
|
|
196
|
-
| Variable | Default | Description |
|
|
197
|
-
|---|---|---|
|
|
198
|
-
| `BULLETIN_RPC` | `wss://paseo-bulletin-rpc.polkadot.io` | Override the Bulletin chain WebSocket RPC for the chosen `--env`. |
|
|
199
|
-
| `BULLETIN_ENVIRONMENTS_URL` | bulletin-deploy public mirror | Override the runtime URL for environments.json. Internal teams point this at a fork or local proxy. |
|
|
200
|
-
| `BULLETIN_DEPLOY_TELEMETRY` | off for external users, on for internal users | `1` to opt in, `0` to force off |
|
|
201
|
-
| `BULLETIN_DEPLOY_UPDATE_CHECK` | `1` | Set to `0` to disable version checks on failure |
|
|
202
|
-
| `IPFS_CID` | unset | Skip storage and reuse an existing CID |
|
|
203
|
-
| `DEPLOY_TAG` | unset | Telemetry label equivalent to `--tag` |
|
|
204
|
-
| `BULLETIN_DEPLOY_HOST_APP` | unset | Name of the host app embedding bulletin-deploy (e.g. `playground-cli`). Sets `deploy.host_app` on telemetry spans. |
|
|
205
|
-
| `BULLETIN_DEPLOY_HOST_APP_VERSION` | unset | Version of the host app. Sets `deploy.host_app_version` on telemetry spans when `BULLETIN_DEPLOY_HOST_APP` is also set. |
|
|
206
|
-
|
|
207
|
-
## Troubleshooting
|
|
208
|
-
|
|
209
|
-
| Error | What to check |
|
|
210
|
-
|---|---|
|
|
211
|
-
| `Requires Full Personhood verification` | The chosen label needs a higher PoP level. |
|
|
212
|
-
| `Domain ... is owned by a different account` | The `.dot` name is already owned by the account indicated. Use that account as parameter or transfer the domain from that account to the new account you want to use |
|
|
213
|
-
| `Account ... is not authorized for Bulletin storage` | The uploader account is not authorized on Bulletin yet. For operator-managed pools, see [`bulletin-bootstrap`](docs/bootstrap.md). |
|
|
214
|
-
| `fetchNonce timed out` or connection errors | The Bulletin RPC may be unhealthy. Try another endpoint. |
|
|
215
|
-
| `IPFS CLI not installed` | Install Kubo or switch to `--js-merkle`. |
|
|
216
|
-
| Previous deploy did not exit cleanly / OOM hint | Retry with a larger Node heap, for example `NODE_OPTIONS='--max-old-space-size=8192'`. |
|
|
217
|
-
|
|
218
|
-
## Contributing
|
|
219
|
-
|
|
220
|
-
New to the codebase? Start with **[ONBOARDING.md](ONBOARDING.md)** — it covers install, the mental model, the first task, and the working conventions for this repo (worktree-per-branch, squash-merge policy, never-delete-tests, where the per-directory rules live).
|
|
221
|
-
|
|
222
|
-
The team uses Claude Code as a primary tool. The repo ships team-shared Claude configuration: `.claude/skills/` (project-specific commands like `/e2e-local`, `/dotns-diagnose`, `/sentry-query`), `.claude/settings.json` (Bash allowlist), and per-directory `CLAUDE.md` files in `src/`, `sentry/`, `test/`, `tools/` that load on demand. Running `claude` inside this repo picks all of that up automatically.
|
|
223
|
-
|
|
224
|
-
Already have Claude Code installed? Clone, `npm install`, open `ONBOARDING.md`. New to Claude Code itself? The same doc covers install.
|
|
225
|
-
|
|
226
|
-
For maintainers and engineers familiar with the release flow, the canonical procedures live in the root [`CLAUDE.md`](CLAUDE.md): change workflow, dual-stage RC → stable release, post-release Sentry monitoring, and the squash-merge convention that satisfies branch protection without per-commit GPG signing.
|
|
227
|
-
|
|
228
|
-
## More Docs
|
|
229
|
-
|
|
230
|
-
- [Bootstrap and operator setup](docs/bootstrap.md)
|
|
231
|
-
- [Testing](docs/testing.md)
|
|
232
|
-
- [Telemetry](docs/telemetry.md)
|
|
233
|
-
- [E2E one-time setup](docs/e2e-bootstrap.md)
|
|
5
|
+
Full documentation and contributing guide: [docs-internal/README.dev.md](docs-internal/README.dev.md)
|
package/bin/bulletin-deploy
CHANGED
|
@@ -42,6 +42,7 @@ for (let i = 0; i < args.length; i++) {
|
|
|
42
42
|
}
|
|
43
43
|
(flags.contracts ??= {})[kv.slice(0, eq)] = kv.slice(eq + 1);
|
|
44
44
|
}
|
|
45
|
+
else if (args[i] === "--environment-file") { flags.environmentFile = args[++i]; }
|
|
45
46
|
else if (args[i] === "--list-environments") { flags.listEnvironments = true; }
|
|
46
47
|
else if (args[i] === "--password") { flags.password = args[++i]; }
|
|
47
48
|
else if (args[i] === "--js-merkle") { flags.jsMerkle = true; }
|
|
@@ -67,6 +68,12 @@ if (flags.publish && flags.unpublish) {
|
|
|
67
68
|
process.exit(1);
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
// --environment-file: propagate to the env var so all internal loadEnvironments()
|
|
72
|
+
// call sites (deploy.ts, manifest/publish.ts, personhood) honor the override.
|
|
73
|
+
if (flags.environmentFile) {
|
|
74
|
+
process.env.BULLETIN_DEPLOY_ENV_FILE = flags.environmentFile;
|
|
75
|
+
}
|
|
76
|
+
|
|
70
77
|
if (flags.version) {
|
|
71
78
|
console.log(`bulletin-deploy v${VERSION}`);
|
|
72
79
|
process.exit(0);
|
|
@@ -81,7 +88,7 @@ if (flags.removedBootstrap) {
|
|
|
81
88
|
// nothing else (deploy positional args are ignored).
|
|
82
89
|
if (flags.listEnvironments) {
|
|
83
90
|
try {
|
|
84
|
-
const { doc } = await loadEnvironments();
|
|
91
|
+
const { doc } = await loadEnvironments({ userFilePath: flags.environmentFile ?? process.env.BULLETIN_DEPLOY_ENV_FILE });
|
|
85
92
|
console.log(formatEnvironmentTable(listEnvironments(doc)));
|
|
86
93
|
process.exit(0);
|
|
87
94
|
} catch (e) {
|
|
@@ -169,6 +176,13 @@ Options:
|
|
|
169
176
|
--env <id> Target environment from environments.json (default: paseo-next-v2).
|
|
170
177
|
Drives both the bulletin RPC and the asset-hub RPC used
|
|
171
178
|
by DotNS. See --list-environments for valid ids.
|
|
179
|
+
--environment-file <path>
|
|
180
|
+
Path to a JSON file deep-merged over the bundled
|
|
181
|
+
environments.json. Override only the fields you need
|
|
182
|
+
(e.g. contract addresses after a chain reset); unspecified
|
|
183
|
+
fields fall through to the bundled values. Also honored
|
|
184
|
+
via BULLETIN_DEPLOY_ENV_FILE env var.
|
|
185
|
+
Warning: values are not validated against chain.
|
|
172
186
|
--list-environments Print the environments table and exit.
|
|
173
187
|
--contract <KEY>=<addr> Supply/override a DotNS contract address (repeatable).
|
|
174
188
|
Merged over the chosen --env's contracts map; required
|
package/dist/bug-report.js
CHANGED
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
offerBugReport,
|
|
10
10
|
scrubSecrets,
|
|
11
11
|
setDeployContext
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-CSDXTU3G.js";
|
|
13
|
+
import "./chunk-R2ORPNZC.js";
|
|
14
|
+
import "./chunk-5EJ247OO.js";
|
|
15
|
+
import "./chunk-N27JUWU2.js";
|
|
16
16
|
export {
|
|
17
17
|
buildCliFlagsSummary,
|
|
18
18
|
buildLabels,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
package_default,
|
|
3
3
|
writeRunState
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-N27JUWU2.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"]
|