bulletin-deploy 0.6.0-rc.9 → 0.6.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 +59 -58
- package/bin/bulletin-deploy +36 -184
- package/cdm.json +60 -22
- package/dist/{chunk-RV7XBIIO.js → chunk-AIHW2WLO.js} +0 -5
- package/dist/{chunk-267OASO2.js → chunk-EMQEE6KJ.js} +63 -71
- package/dist/chunk-JALS3N4S.js +610 -0
- package/dist/{chunk-GVZ2PK6F.js → chunk-S5VOTF3L.js} +11 -23
- package/dist/deploy.d.ts +20 -13
- package/dist/deploy.js +24 -6
- package/dist/dotns.d.ts +10 -14
- package/dist/dotns.js +4 -2
- package/dist/index.d.ts +1 -3
- package/dist/index.js +6 -38
- package/dist/pool.js +1 -1
- package/dist/telemetry.d.ts +2 -7
- package/dist/telemetry.js +3 -3
- package/package.json +2 -3
- package/dist/build.d.ts +0 -43
- package/dist/build.js +0 -25
- package/dist/chunk-MQJEKHMX.js +0 -211
- package/dist/chunk-TN2XSXP4.js +0 -835
- package/dist/chunk-VVUWIM3B.js +0 -150
- package/dist/manifest.d.ts +0 -45
- package/dist/manifest.js +0 -15
package/README.md
CHANGED
|
@@ -6,18 +6,12 @@ Deploy static sites and apps to the Polkadot Triangle network with decentralized
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install -g bulletin-deploy
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
bulletin-deploy auto-detects your framework, runs the build, and deploys. Your site is live at `https://my-app00.dot.li`
|
|
13
|
-
|
|
14
|
-
You can also deploy a pre-built directory:
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npm run build
|
|
9
|
+
# Build your app (e.g. npm run build)
|
|
18
10
|
bulletin-deploy ./dist my-app00.dot
|
|
19
11
|
```
|
|
20
12
|
|
|
13
|
+
Your site is live at `https://my-app00.dot.li`
|
|
14
|
+
|
|
21
15
|
## Prerequisites
|
|
22
16
|
|
|
23
17
|
- **Node.js 22+**
|
|
@@ -38,58 +32,53 @@ ipfs init
|
|
|
38
32
|
## CLI Usage
|
|
39
33
|
|
|
40
34
|
```bash
|
|
41
|
-
bulletin-deploy <domain.dot>
|
|
42
|
-
bulletin-deploy <build-dir> <domain.dot> # Deploy pre-built directory
|
|
43
|
-
bulletin-deploy --build-only # Build only, print output dir
|
|
44
|
-
bulletin-deploy --dry-run <domain.dot> # Show upload plan without deploying
|
|
35
|
+
bulletin-deploy <build-dir> <domain.dot>
|
|
45
36
|
```
|
|
46
37
|
|
|
47
|
-
|
|
38
|
+
Examples:
|
|
48
39
|
|
|
40
|
+
```bash
|
|
41
|
+
# Basic deploy
|
|
42
|
+
bulletin-deploy ./dist my-app00.dot
|
|
43
|
+
|
|
44
|
+
# Custom RPC endpoint
|
|
45
|
+
bulletin-deploy --rpc wss://custom-bulletin.example.com ./dist my-app00.dot
|
|
46
|
+
|
|
47
|
+
# Deploy and publish to the Playground remix registry
|
|
48
|
+
bulletin-deploy --playground ./dist my-app00.dot
|
|
49
49
|
```
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
--
|
|
56
|
-
--
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
--
|
|
60
|
-
--help Show help
|
|
50
|
+
|
|
51
|
+
### All options
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
Options:
|
|
55
|
+
--rpc wss://... Bulletin RPC (or set BULLETIN_RPC env var)
|
|
56
|
+
--mnemonic "..." DotNS owner mnemonic (or set MNEMONIC env var)
|
|
57
|
+
--playground Publish to the Playground remix registry
|
|
58
|
+
--pool-size N Number of pool accounts (default: 10)
|
|
59
|
+
--help Show help
|
|
61
60
|
```
|
|
62
61
|
|
|
63
|
-
###
|
|
62
|
+
### Playground registry
|
|
64
63
|
|
|
65
|
-
|
|
64
|
+
By default, deploys only upload to Bulletin storage and register the DotNS domain. The **Playground remix registry** is an on-chain app directory that makes your deploy visible in [Polkadot Playground](https://playground.polkadot.cloud).
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
2. **Build command**: `Makefile` with `build` target → `make build`, otherwise `package.json` `build` script → `<pm> run build`
|
|
69
|
-
3. **Output directory**: framework config (`vite.config.*` → `dist/`, `next.config.*` → `out/`), or probes `dist/`, `out/`, `build/`
|
|
66
|
+
To publish to it, pass `--playground`:
|
|
70
67
|
|
|
71
|
-
|
|
68
|
+
```bash
|
|
69
|
+
bulletin-deploy --playground ./dist my-app.dot
|
|
70
|
+
```
|
|
72
71
|
|
|
73
|
-
|
|
74
|
-
|------|---------|-----------|
|
|
75
|
-
| 0 | Success | — |
|
|
76
|
-
| 1 | Deploy failure (transient) | Yes |
|
|
77
|
-
| 2 | Build failure | No |
|
|
78
|
-
| 3 | Configuration error | No |
|
|
72
|
+
This requires `cdm.json` in your project root (shipped with bulletin-deploy) and a git remote origin.
|
|
79
73
|
|
|
80
74
|
## GitHub Actions
|
|
81
75
|
|
|
82
76
|
1. Copy `workflows/deploy-on-pr.yml` to your repo's `.github/workflows/` directory
|
|
83
|
-
2.
|
|
84
|
-
3. Push and watch the deploy
|
|
77
|
+
2. Customize the **Build** step for your framework (Vite, Next.js, etc.)
|
|
78
|
+
3. Push and watch the deploy
|
|
85
79
|
|
|
86
80
|
The template workflow:
|
|
87
|
-
- Deploys on push to main and on PRs
|
|
88
|
-
- Auto-detects your framework, package manager, and build output directory
|
|
89
|
-
- Uses three cache layers to speed up repeat deploys:
|
|
90
|
-
- **Node modules cache** via `actions/setup-node` with `cache: 'npm'`
|
|
91
|
-
- **Build artifacts cache** keyed on lockfile hash (paths detected by `--print-cache-paths`)
|
|
92
|
-
- **Deploy manifest cache** (`.bulletin-deploy-cache`) keyed on branch + SHA for incremental uploads
|
|
81
|
+
- Deploys on push to main and on PRs
|
|
93
82
|
- Uses `nick-fields/retry@v3` for automatic retries on transient failures
|
|
94
83
|
- Posts a comment on PRs with the live URL
|
|
95
84
|
- Generates domain names as `<repo>-<branch>00.dot`
|
|
@@ -103,20 +92,41 @@ const result = await deploy("./dist", "my-app00.dot");
|
|
|
103
92
|
console.log(result.cid, result.domainName);
|
|
104
93
|
```
|
|
105
94
|
|
|
95
|
+
## Domain Names and Proof of Personhood
|
|
96
|
+
|
|
97
|
+
DotNS domain names are classified by the PopOracle contract on Asset Hub. The classification determines what level of **Proof of Personhood (PoP)** is required to register:
|
|
98
|
+
|
|
99
|
+
| Domain pattern | Example | Required PoP |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| Name with trailing digits | `my-app00.dot` | **None** — open to all |
|
|
102
|
+
| Base name (no trailing digits) | `my-app.dot` | **Full** — requires `ProofOfPersonhoodFull` |
|
|
103
|
+
|
|
104
|
+
On **testnets** (Paseo, Westend, local devnets), bulletin-deploy automatically self-grants `ProofOfPersonhoodFull` before registration — no configuration needed. Both base names and names with trailing digits just work:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
bulletin-deploy ./dist my-app.dot # base name — auto-grants Full PoP
|
|
108
|
+
bulletin-deploy ./dist my-app00.dot # trailing digits — no PoP needed
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
On **mainnet** (Polkadot Hub, Kusama Hub), PoP cannot be self-granted. You must have a verified account. Set `DOTNS_STATUS=none` explicitly or leave it unset (mainnet defaults to `none`).
|
|
112
|
+
|
|
113
|
+
If you see **"Requires Full Personhood verification"**, the deploy will fail early with an actionable error message before any gas is spent on commitment transactions.
|
|
114
|
+
|
|
106
115
|
## Environment Variables
|
|
107
116
|
|
|
108
117
|
| Variable | Default | Description |
|
|
109
118
|
|---|---|---|
|
|
110
119
|
| `BULLETIN_RPC` | `wss://paseo-bulletin-rpc.polkadot.io` | Bulletin chain WebSocket RPC |
|
|
111
120
|
| `BULLETIN_DEPLOY_TELEMETRY` | `1` (enabled) | Set to `0` to disable Sentry telemetry |
|
|
121
|
+
| `DOTNS_STATUS` | `full` (testnet) / `none` (mainnet) | PoP level to self-grant before registration: `none`, `lite`, or `full` |
|
|
112
122
|
| `IPFS_CID` | _(none)_ | Skip storage, use pre-existing CID |
|
|
113
123
|
|
|
114
124
|
## How It Works
|
|
115
125
|
|
|
116
126
|
```
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
127
|
+
Build output ──> IPFS merkleize ──> CAR file ──> Chunk upload ──> DotNS
|
|
128
|
+
./dist ipfs add .car Bulletin Asset Hub
|
|
129
|
+
Storage Registry
|
|
120
130
|
```
|
|
121
131
|
|
|
122
132
|
1. **Merkleize** your build directory with IPFS to produce a content-addressed CAR file
|
|
@@ -140,16 +150,6 @@ Instead of using a single account for all storage transactions, bulletin-deploy
|
|
|
140
150
|
|
|
141
151
|
When a pool account's authorization drops below thresholds (50 transactions or 50MB), bulletin-deploy automatically tops it up by submitting an `authorize_account` transaction from Alice.
|
|
142
152
|
|
|
143
|
-
## Incremental Upload
|
|
144
|
-
|
|
145
|
-
On repeat deploys, bulletin-deploy only uploads content that changed. A deploy manifest (`.bulletin-deploy-cache`) tracks which files and chunks are already on-chain.
|
|
146
|
-
|
|
147
|
-
- **First deploy**: uploads everything, writes the manifest
|
|
148
|
-
- **Subsequent deploys**: compares file CIDs against the manifest, uploads only new/changed files
|
|
149
|
-
- **Typical savings**: 80-95% reduction in upload size and transactions
|
|
150
|
-
|
|
151
|
-
Use `--dry-run` to preview what would be uploaded before deploying.
|
|
152
|
-
|
|
153
153
|
## Telemetry
|
|
154
154
|
|
|
155
155
|
Sentry telemetry is enabled by default for deploy observability. Set `BULLETIN_DEPLOY_TELEMETRY=0` to disable.
|
|
@@ -167,6 +167,7 @@ Dashboard: https://polkadot-community-foundation.sentry.io/dashboards/92523/
|
|
|
167
167
|
|
|
168
168
|
| Error | Solution |
|
|
169
169
|
|---|---|
|
|
170
|
+
| `Requires Full Personhood verification` | Auto-handled on testnets (v0.5.4+). On mainnet, your account needs verified PoP status. |
|
|
170
171
|
| `Payment` or authorization error | Pool account needs storage authorization — auto-authorization should handle this |
|
|
171
172
|
| `Stale` or dropped from best chain | Bulletin chain reorg. Automatic retry handles this. |
|
|
172
173
|
| `IPFS CLI not installed` | Install Kubo: `brew install ipfs && ipfs init` |
|
package/bin/bulletin-deploy
CHANGED
|
@@ -1,217 +1,69 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// so that --help and --print-cache-paths work without @dotdm/cdm installed.
|
|
6
|
-
import { detectFramework, detectCachePaths } from "../dist/build.js";
|
|
3
|
+
import { deploy, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE } from "../dist/deploy.js";
|
|
4
|
+
import { bootstrapPool } from "../dist/pool.js";
|
|
7
5
|
import * as fs from "fs";
|
|
8
|
-
import * as path from "path";
|
|
9
|
-
import * as os from "os";
|
|
10
6
|
|
|
11
7
|
const args = process.argv.slice(2);
|
|
12
8
|
|
|
13
9
|
const flags = {};
|
|
14
10
|
const positional = [];
|
|
15
11
|
for (let i = 0; i < args.length; i++) {
|
|
16
|
-
|
|
17
|
-
if (
|
|
18
|
-
else if (
|
|
19
|
-
else if (
|
|
20
|
-
else if (
|
|
21
|
-
else if (
|
|
22
|
-
else if (
|
|
23
|
-
else
|
|
24
|
-
else if (arg === "--build-only") { flags.buildOnly = true; }
|
|
25
|
-
else if (arg === "--print-cache-paths") { flags.printCachePaths = true; }
|
|
26
|
-
else if (arg === "--dry-run") { flags.dryRun = true; }
|
|
27
|
-
else if (arg === "--registry") { flags.registry = true; }
|
|
28
|
-
else if (arg === "--help" || arg === "-h") { flags.help = true; }
|
|
29
|
-
else { positional.push(arg); }
|
|
12
|
+
if (args[i] === "--bootstrap") { flags.bootstrap = true; }
|
|
13
|
+
else if (args[i] === "--pool-size") { flags.poolSize = parseInt(args[++i], 10); }
|
|
14
|
+
else if (args[i] === "--mnemonic") { flags.mnemonic = args[++i]; }
|
|
15
|
+
else if (args[i] === "--rpc") { flags.rpc = args[++i]; }
|
|
16
|
+
else if (args[i] === "--password") { flags.password = args[++i]; }
|
|
17
|
+
else if (args[i] === "--playground") { flags.playground = true; }
|
|
18
|
+
else if (args[i] === "--help" || args[i] === "-h") { flags.help = true; }
|
|
19
|
+
else { positional.push(args[i]); }
|
|
30
20
|
}
|
|
31
21
|
|
|
32
|
-
if (flags.help || (positional.length === 0 && !flags.bootstrap
|
|
22
|
+
if (flags.help || (positional.length === 0 && !flags.bootstrap)) {
|
|
33
23
|
console.log(`Usage:
|
|
34
|
-
bulletin-deploy <domain.dot>
|
|
35
|
-
bulletin-deploy <build-dir> <domain.dot> Deploy a pre-built directory
|
|
24
|
+
bulletin-deploy <build-dir> <domain.dot> Deploy an app
|
|
36
25
|
bulletin-deploy --bootstrap Initialize pool accounts
|
|
37
26
|
|
|
38
27
|
Options:
|
|
39
|
-
--build-cmd "..." Override build command
|
|
40
|
-
--build-dir ./out Override output directory
|
|
41
|
-
--no-build Skip the build step (use positional arg as build dir)
|
|
42
|
-
--build-only Build only, print output dir to stdout, then exit
|
|
43
|
-
--print-cache-paths Print detected cache paths and exit
|
|
44
|
-
--dry-run Show upload plan without deploying
|
|
45
|
-
--registry Publish to playground registry (only needed on metadata change)
|
|
46
28
|
--mnemonic "..." DotNS owner mnemonic (or set MNEMONIC env var)
|
|
47
29
|
--rpc wss://... Bulletin RPC (or set BULLETIN_RPC env var)
|
|
48
30
|
--pool-size N Number of pool accounts (default: 10)
|
|
31
|
+
--password "..." Encrypt SPA content (users will be prompted to decrypt)
|
|
32
|
+
--playground Publish to the playground remix registry
|
|
49
33
|
--help Show this help`);
|
|
50
34
|
process.exit(0);
|
|
51
35
|
}
|
|
52
36
|
|
|
53
|
-
if (flags.rpc) process.env.BULLETIN_RPC = flags.rpc;
|
|
54
|
-
if (flags.poolSize) process.env.BULLETIN_POOL_SIZE = String(flags.poolSize);
|
|
55
|
-
if (flags.mnemonic) process.env.MNEMONIC = flags.mnemonic;
|
|
56
|
-
|
|
57
|
-
const projectDir = process.cwd();
|
|
58
|
-
|
|
59
|
-
// --print-cache-paths: detect and print, then exit (no heavy deps needed)
|
|
60
|
-
if (flags.printCachePaths) {
|
|
61
|
-
const framework = detectFramework(projectDir);
|
|
62
|
-
const cachePaths = detectCachePaths(framework);
|
|
63
|
-
for (const p of cachePaths) {
|
|
64
|
-
console.log(p);
|
|
65
|
-
}
|
|
66
|
-
process.exit(0);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Lazy-load heavy modules that require @dotdm/cdm; run in parallel
|
|
70
|
-
const [
|
|
71
|
-
{ deploy, merkleize, chunk, measureBuildOutput },
|
|
72
|
-
{ runBuild },
|
|
73
|
-
{ readManifest, classifyWithManifest, classifyFile, formatDryRunReport },
|
|
74
|
-
{ bootstrapPool },
|
|
75
|
-
] = await Promise.all([
|
|
76
|
-
import("../dist/deploy.js"),
|
|
77
|
-
import("../dist/build.js"),
|
|
78
|
-
import("../dist/manifest.js"),
|
|
79
|
-
import("../dist/pool.js"),
|
|
80
|
-
]);
|
|
81
|
-
|
|
82
37
|
try {
|
|
83
38
|
if (flags.bootstrap) {
|
|
84
|
-
const rpc = process.env.BULLETIN_RPC
|
|
85
|
-
const poolSize = parseInt(process.env.BULLETIN_POOL_SIZE
|
|
86
|
-
await bootstrapPool(rpc, poolSize);
|
|
87
|
-
process.exit(0);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// --build-only: run build, print output dir, exit
|
|
91
|
-
if (flags.buildOnly) {
|
|
92
|
-
const result = await runBuild(projectDir, {
|
|
93
|
-
buildCmd: flags.buildCmd,
|
|
94
|
-
buildDir: flags.buildDir,
|
|
95
|
-
});
|
|
96
|
-
console.log(path.resolve(projectDir, result.outputDir));
|
|
97
|
-
process.exit(0);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Determine build dir and domain from positional args
|
|
101
|
-
let buildDir;
|
|
102
|
-
let domain;
|
|
103
|
-
|
|
104
|
-
const [firstArg, secondArg] = positional;
|
|
105
|
-
|
|
106
|
-
if (firstArg && fs.existsSync(firstArg)) {
|
|
107
|
-
// Backward-compat: first arg is an existing path — treat as build dir
|
|
108
|
-
buildDir = firstArg;
|
|
109
|
-
domain = secondArg;
|
|
39
|
+
const rpc = flags.rpc ?? process.env.BULLETIN_RPC ?? DEFAULT_BULLETIN_RPC;
|
|
40
|
+
const poolSize = flags.poolSize ?? parseInt(process.env.BULLETIN_POOL_SIZE ?? String(DEFAULT_POOL_SIZE), 10);
|
|
41
|
+
await bootstrapPool(rpc, poolSize, flags.mnemonic);
|
|
110
42
|
} else {
|
|
111
|
-
domain =
|
|
112
|
-
buildDir
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (!buildDir && !flags.noBuild) {
|
|
123
|
-
console.log("\nBuilding...");
|
|
124
|
-
const buildResult = await runBuild(projectDir, {
|
|
125
|
-
buildCmd: flags.buildCmd,
|
|
126
|
-
buildDir: flags.buildDir,
|
|
43
|
+
const [buildDir, domain] = positional;
|
|
44
|
+
if (!buildDir) { console.error("Error: build directory required"); process.exit(1); }
|
|
45
|
+
if (!domain) { console.error("Error: domain required (e.g. my-app.dot)"); process.exit(1); }
|
|
46
|
+
if (!fs.existsSync(buildDir)) { console.error(`Error: ${buildDir} does not exist`); process.exit(1); }
|
|
47
|
+
|
|
48
|
+
const result = await deploy(buildDir, domain, {
|
|
49
|
+
playground: flags.playground,
|
|
50
|
+
mnemonic: flags.mnemonic,
|
|
51
|
+
rpc: flags.rpc,
|
|
52
|
+
poolSize: flags.poolSize,
|
|
53
|
+
password: flags.password,
|
|
127
54
|
});
|
|
128
|
-
buildDir = path.resolve(projectDir, buildResult.outputDir);
|
|
129
|
-
detectedFramework = buildResult.framework?.name;
|
|
130
|
-
console.log(` Output: ${buildDir} (${buildResult.durationMs}ms)`);
|
|
131
|
-
} else if (flags.noBuild && !buildDir) {
|
|
132
|
-
if (flags.buildDir) {
|
|
133
|
-
buildDir = flags.buildDir;
|
|
134
|
-
} else {
|
|
135
|
-
console.error("Error: --no-build requires a build directory (pass as first arg or --build-dir)");
|
|
136
|
-
process.exit(3);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (!fs.existsSync(buildDir)) {
|
|
141
|
-
console.error(`Error: build directory not found: ${buildDir}`);
|
|
142
|
-
process.exit(3);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// --dry-run: show upload plan without deploying
|
|
146
|
-
if (flags.dryRun) {
|
|
147
|
-
const { execSync } = await import("child_process");
|
|
148
|
-
const { createCID } = await import("../dist/deploy.js");
|
|
149
|
-
|
|
150
|
-
// Merkleize + get per-file CIDs (matches storeDirectory's flow)
|
|
151
|
-
const ipfsCid = execSync(`ipfs add -Q -r --cid-version=1 --raw-leaves --pin=false "${buildDir}"`, { encoding: "utf-8" }).trim();
|
|
152
|
-
const addOutput = execSync(`ipfs add -rn --cid-version=1 --raw-leaves --pin=false "${buildDir}"`, { encoding: "utf-8" });
|
|
153
|
-
const baseName = path.basename(buildDir);
|
|
154
|
-
const fileCids = new Map();
|
|
155
|
-
for (const line of addOutput.trim().split("\n")) {
|
|
156
|
-
const m = line.match(/^added\s+(\S+)\s+(.+)$/);
|
|
157
|
-
if (!m) continue;
|
|
158
|
-
const rel = m[2].startsWith(baseName + "/") ? m[2].slice(baseName.length + 1) : m[2];
|
|
159
|
-
if (rel !== baseName) fileCids.set(rel, m[1]);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const manifestPath = path.join(path.dirname(buildDir), ".bulletin-deploy-cache");
|
|
163
|
-
const manifest = readManifest(manifestPath);
|
|
164
|
-
const buildOutput = measureBuildOutput(buildDir);
|
|
165
|
-
|
|
166
|
-
const currentFiles = buildOutput.files.map(f => ({ path: f.path, cid: fileCids.get(f.path) || ipfsCid, size: f.size }));
|
|
167
55
|
|
|
168
|
-
|
|
169
|
-
if (
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const stable = currentFiles.filter(f => classifyFile(f.path) === "stable");
|
|
173
|
-
const volatile = currentFiles
|
|
174
|
-
.filter(f => classifyFile(f.path) === "volatile")
|
|
175
|
-
.map(f => ({ ...f, previousCid: null }));
|
|
176
|
-
classification = { stable, volatile, hitRate: stable.length / (currentFiles.length || 1), source: "heuristic" };
|
|
56
|
+
const output = process.env.GITHUB_OUTPUT;
|
|
57
|
+
if (output) {
|
|
58
|
+
fs.appendFileSync(output, `cid=${result.cid}\n`);
|
|
59
|
+
fs.appendFileSync(output, `domain=${result.domainName}\n`);
|
|
177
60
|
}
|
|
178
61
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const totalChunks = Math.ceil(totalBytes / (1024 * 1024));
|
|
182
|
-
const volatileBytes = classification.volatile.reduce((s, f) => s + f.size, 0);
|
|
183
|
-
const newChunks = manifest ? Math.max(1, Math.ceil(volatileBytes / (1024 * 1024))) : totalChunks;
|
|
184
|
-
|
|
185
|
-
const report = formatDryRunReport(classification, {
|
|
186
|
-
manifestPath: manifest ? manifestPath : null,
|
|
187
|
-
lastDeploy: manifest ? manifest.deployed_at : null,
|
|
188
|
-
totalChunks,
|
|
189
|
-
newChunks,
|
|
190
|
-
});
|
|
191
|
-
console.log(report);
|
|
192
|
-
process.exit(0);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const result = await deploy(buildDir, domain, { registry: flags.registry ?? false, framework: detectedFramework });
|
|
196
|
-
|
|
197
|
-
const output = process.env.GITHUB_OUTPUT;
|
|
198
|
-
if (output) {
|
|
199
|
-
fs.appendFileSync(output, `cid=${result.cid}\n`);
|
|
200
|
-
fs.appendFileSync(output, `domain=${result.domainName}\n`);
|
|
62
|
+
console.log(`CID: ${result.cid}`);
|
|
63
|
+
console.log(`Domain: ${result.domainName}`);
|
|
201
64
|
}
|
|
202
|
-
|
|
203
|
-
console.log(`CID: ${result.cid}`);
|
|
204
|
-
console.log(`Domain: ${result.domainName}`);
|
|
205
65
|
process.exit(0);
|
|
206
|
-
|
|
207
66
|
} catch (error) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
console.error("Build failed:", error.message);
|
|
211
|
-
} else if (exitCode === 3) {
|
|
212
|
-
console.error("Config error:", error.message);
|
|
213
|
-
} else {
|
|
214
|
-
console.error("Deployment failed:", error.message);
|
|
215
|
-
}
|
|
216
|
-
process.exit(exitCode);
|
|
67
|
+
console.error("Deployment failed:", error.message);
|
|
68
|
+
process.exit(1);
|
|
217
69
|
}
|
package/cdm.json
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"contracts": {
|
|
14
14
|
"acc2c3b5e912b762": {
|
|
15
15
|
"@example/playground-registry": {
|
|
16
|
-
"version":
|
|
17
|
-
"address": "
|
|
16
|
+
"version": 3,
|
|
17
|
+
"address": "0xF8304E5C17769A53E012f39c6990cC8a7AaBC6A5",
|
|
18
18
|
"abi": [
|
|
19
19
|
{
|
|
20
20
|
"type": "constructor",
|
|
@@ -39,35 +39,58 @@
|
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"type": "function",
|
|
42
|
-
"name": "
|
|
42
|
+
"name": "getAppCount",
|
|
43
|
+
"inputs": [],
|
|
44
|
+
"outputs": [
|
|
45
|
+
{
|
|
46
|
+
"name": "",
|
|
47
|
+
"type": "uint32"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"stateMutability": "view"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"type": "function",
|
|
54
|
+
"name": "getDomainAt",
|
|
43
55
|
"inputs": [
|
|
44
56
|
{
|
|
45
|
-
"name": "
|
|
57
|
+
"name": "index",
|
|
58
|
+
"type": "uint32"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"outputs": [
|
|
62
|
+
{
|
|
63
|
+
"name": "",
|
|
46
64
|
"type": "string"
|
|
47
65
|
}
|
|
48
66
|
],
|
|
67
|
+
"stateMutability": "view"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"type": "function",
|
|
71
|
+
"name": "getOwnerAppCount",
|
|
72
|
+
"inputs": [
|
|
73
|
+
{
|
|
74
|
+
"name": "owner",
|
|
75
|
+
"type": "address"
|
|
76
|
+
}
|
|
77
|
+
],
|
|
49
78
|
"outputs": [
|
|
50
79
|
{
|
|
51
80
|
"name": "",
|
|
52
|
-
"type": "
|
|
53
|
-
"components": [
|
|
54
|
-
{
|
|
55
|
-
"name": "isSome",
|
|
56
|
-
"type": "bool"
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
"name": "value",
|
|
60
|
-
"type": "string"
|
|
61
|
-
}
|
|
62
|
-
]
|
|
81
|
+
"type": "uint32"
|
|
63
82
|
}
|
|
64
83
|
],
|
|
65
84
|
"stateMutability": "view"
|
|
66
85
|
},
|
|
67
86
|
{
|
|
68
87
|
"type": "function",
|
|
69
|
-
"name": "
|
|
88
|
+
"name": "getOwnerDomainAt",
|
|
70
89
|
"inputs": [
|
|
90
|
+
{
|
|
91
|
+
"name": "owner",
|
|
92
|
+
"type": "address"
|
|
93
|
+
},
|
|
71
94
|
{
|
|
72
95
|
"name": "index",
|
|
73
96
|
"type": "uint32"
|
|
@@ -83,7 +106,7 @@
|
|
|
83
106
|
},
|
|
84
107
|
{
|
|
85
108
|
"type": "function",
|
|
86
|
-
"name": "
|
|
109
|
+
"name": "getMetadataUri",
|
|
87
110
|
"inputs": [
|
|
88
111
|
{
|
|
89
112
|
"name": "domain",
|
|
@@ -93,25 +116,40 @@
|
|
|
93
116
|
"outputs": [
|
|
94
117
|
{
|
|
95
118
|
"name": "",
|
|
96
|
-
"type": "
|
|
119
|
+
"type": "tuple",
|
|
120
|
+
"components": [
|
|
121
|
+
{
|
|
122
|
+
"name": "isSome",
|
|
123
|
+
"type": "bool"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"name": "value",
|
|
127
|
+
"type": "string"
|
|
128
|
+
}
|
|
129
|
+
]
|
|
97
130
|
}
|
|
98
131
|
],
|
|
99
132
|
"stateMutability": "view"
|
|
100
133
|
},
|
|
101
134
|
{
|
|
102
135
|
"type": "function",
|
|
103
|
-
"name": "
|
|
104
|
-
"inputs": [
|
|
136
|
+
"name": "getOwner",
|
|
137
|
+
"inputs": [
|
|
138
|
+
{
|
|
139
|
+
"name": "domain",
|
|
140
|
+
"type": "string"
|
|
141
|
+
}
|
|
142
|
+
],
|
|
105
143
|
"outputs": [
|
|
106
144
|
{
|
|
107
145
|
"name": "",
|
|
108
|
-
"type": "
|
|
146
|
+
"type": "address"
|
|
109
147
|
}
|
|
110
148
|
],
|
|
111
149
|
"stateMutability": "view"
|
|
112
150
|
}
|
|
113
151
|
],
|
|
114
|
-
"metadataCid": "
|
|
152
|
+
"metadataCid": "bafk2bzacebkch7cuoi77j5vkrkoplax4urywwga7ijamtd3pntv7xjgabhtgs"
|
|
115
153
|
}
|
|
116
154
|
}
|
|
117
155
|
}
|
|
@@ -70,11 +70,6 @@ async function ensureAuthorized(api, poolAccount, bulletinRpc) {
|
|
|
70
70
|
try {
|
|
71
71
|
const keyring = new Keyring({ type: "sr25519" });
|
|
72
72
|
const alice = keyring.addFromUri("//Alice");
|
|
73
|
-
const aliceAccount = await aliceApi.query.System.Account.getValue(alice.address);
|
|
74
|
-
const aliceBalance = BigInt(aliceAccount.data.free);
|
|
75
|
-
if (aliceBalance < 10000000000n) {
|
|
76
|
-
throw new Error(`Alice has insufficient balance on Bulletin for authorization tx fees. Current: ${(Number(aliceBalance) / 1e12).toFixed(4)} PAS`);
|
|
77
|
-
}
|
|
78
73
|
const aliceSigner = getPolkadotSigner(alice.publicKey, "Sr25519", (data) => alice.sign(data));
|
|
79
74
|
const tx = aliceApi.tx.TransactionStorage.authorize_account({
|
|
80
75
|
who: poolAccount.address,
|