@parity/product-deploy 0.8.3-rc.6 → 0.8.3-rc.7
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 +33 -7
- package/dist/allocations-B65Is4Md.d.ts +97 -0
- package/dist/auth/index.d.ts +7 -0
- package/dist/auth/index.js +25 -0
- package/dist/auth/vendor/index.d.ts +32 -0
- package/dist/auth/vendor/index.js +26 -0
- package/dist/auth/vendor/ui/index.d.ts +15 -0
- package/dist/auth/vendor/ui/index.js +10 -0
- package/dist/auth-DkRZBK-T.d.ts +122 -0
- package/dist/auth-config.d.ts +39 -0
- package/dist/auth-config.js +20 -0
- package/dist/bug-report.js +4 -4
- package/dist/chunk-327NAPBD.js +52 -0
- package/dist/chunk-7DGFJC6E.js +379 -0
- package/dist/{chunk-6XDIJYDO.js → chunk-BI5SDZMM.js} +2 -2
- package/dist/{chunk-22CE57IY.js → chunk-C2DA2PRC.js} +1 -1
- package/dist/{chunk-YUIBBHS2.js → chunk-HEKCOME3.js} +1 -1
- package/dist/chunk-JQKKMUCT.js +0 -0
- package/dist/{chunk-3TOFKDMY.js → chunk-OBCWAZQE.js} +1 -1
- package/dist/{chunk-L5Z3TJD7.js → chunk-OCKCB72S.js} +6 -6
- package/dist/{chunk-LX77LVIM.js → chunk-OPMGKRYY.js} +17 -3
- package/dist/chunk-RIRDBSBG.js +36 -0
- package/dist/{chunk-Y7F57J2T.js → chunk-TDPH6Y3G.js} +602 -383
- package/dist/{chunk-M6DM2NUT.js → chunk-W4MILLXD.js} +8 -2
- package/dist/{chunk-3ASTLJSZ.js → chunk-XYBMCFIX.js} +2 -2
- package/dist/chunk-probe.js +3 -3
- package/dist/commands/login.d.ts +28 -0
- package/dist/commands/login.js +63 -0
- package/dist/commands/logout.d.ts +21 -0
- package/dist/commands/logout.js +37 -0
- package/dist/commands/whoami.d.ts +22 -0
- package/dist/commands/whoami.js +47 -0
- package/dist/deploy.d.ts +40 -3
- package/dist/deploy.js +17 -8
- package/dist/dotns.js +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +13 -12
- package/dist/manifest/publish.js +10 -9
- package/dist/memory-report.js +2 -2
- package/dist/merkle.d.ts +3 -1
- package/dist/merkle.js +9 -8
- package/dist/personhood/bind-paid-alias.js +3 -3
- package/dist/personhood/bind-personal-id.js +2 -2
- package/dist/personhood/bootstrap.js +16 -16
- package/dist/personhood/claim-pgas.js +2 -2
- package/dist/personhood/people-client.js +3 -3
- package/dist/personhood/proof-validity.js +2 -2
- package/dist/personhood/reprove.js +5 -5
- package/dist/run-state.js +1 -1
- package/dist/signer-CriGqahj.d.ts +35 -0
- package/dist/storage-signer.d.ts +38 -0
- package/dist/storage-signer.js +28 -0
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.js +2 -2
- package/dist/version-check.js +3 -3
- package/package.json +17 -3
- package/dist/{chunk-LHLCPDGL.js → chunk-7URNKK6J.js} +3 -3
- package/dist/{chunk-7Y7RDOGT.js → chunk-EATOPQFR.js} +5 -5
- package/dist/{chunk-SLE4P6MO.js → chunk-EJI3MX4G.js} +3 -3
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MirrorSkipped,
|
|
3
|
+
mirrorToGitHubPages,
|
|
4
|
+
pollMirrorFreshness
|
|
5
|
+
} from "./chunk-HOTQDYHD.js";
|
|
1
6
|
import {
|
|
2
7
|
computeStats,
|
|
3
8
|
renderSummary,
|
|
@@ -18,12 +23,17 @@ import {
|
|
|
18
23
|
classifyFile,
|
|
19
24
|
parseManifest
|
|
20
25
|
} from "./chunk-S7EM5VMW.js";
|
|
26
|
+
import {
|
|
27
|
+
DOT_DAPP_ID,
|
|
28
|
+
DOT_PRODUCT_ID,
|
|
29
|
+
hasPersistedSession
|
|
30
|
+
} from "./chunk-327NAPBD.js";
|
|
21
31
|
import {
|
|
22
32
|
setDeployContext
|
|
23
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-BI5SDZMM.js";
|
|
24
34
|
import {
|
|
25
35
|
probeChunks
|
|
26
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-C2DA2PRC.js";
|
|
27
37
|
import {
|
|
28
38
|
packSection
|
|
29
39
|
} from "./chunk-C2TS5MER.js";
|
|
@@ -35,7 +45,7 @@ import {
|
|
|
35
45
|
parseDomainName,
|
|
36
46
|
popStatusName,
|
|
37
47
|
verifyNonceAdvanced
|
|
38
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-OBCWAZQE.js";
|
|
39
49
|
import {
|
|
40
50
|
derivePoolAccounts,
|
|
41
51
|
detectTestnet,
|
|
@@ -57,7 +67,7 @@ import {
|
|
|
57
67
|
truncateAddress,
|
|
58
68
|
withDeploySpan,
|
|
59
69
|
withSpan
|
|
60
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-W4MILLXD.js";
|
|
61
71
|
import {
|
|
62
72
|
DEFAULT_ENV_ID,
|
|
63
73
|
getPopSelfServeConfig,
|
|
@@ -67,11 +77,6 @@ import {
|
|
|
67
77
|
import {
|
|
68
78
|
NonRetryableError
|
|
69
79
|
} from "./chunk-ZOC4GITL.js";
|
|
70
|
-
import {
|
|
71
|
-
MirrorSkipped,
|
|
72
|
-
mirrorToGitHubPages,
|
|
73
|
-
pollMirrorFreshness
|
|
74
|
-
} from "./chunk-HOTQDYHD.js";
|
|
75
80
|
|
|
76
81
|
// src/merkle.ts
|
|
77
82
|
import * as fs2 from "fs";
|
|
@@ -91,8 +96,8 @@ import * as path from "path";
|
|
|
91
96
|
import { execSync } from "child_process";
|
|
92
97
|
import { sha256 } from "@noble/hashes/sha256";
|
|
93
98
|
import { blake2b } from "@noble/hashes/blake2b";
|
|
94
|
-
import { createClient as
|
|
95
|
-
import { getWsProvider, WsEvent } from "polkadot-api/ws";
|
|
99
|
+
import { createClient as createPolkadotClient2, Enum as Enum2 } from "polkadot-api";
|
|
100
|
+
import { getWsProvider as getWsProvider2, WsEvent } from "polkadot-api/ws";
|
|
96
101
|
import { CID } from "multiformats/cid";
|
|
97
102
|
import { create as createMultihash } from "multiformats/hashes/digest";
|
|
98
103
|
import { base32 } from "multiformats/bases/base32";
|
|
@@ -100,10 +105,176 @@ import { base58btc } from "multiformats/bases/base58";
|
|
|
100
105
|
import * as dagPB from "@ipld/dag-pb";
|
|
101
106
|
import { UnixFS } from "ipfs-unixfs";
|
|
102
107
|
import { cryptoWaitReady } from "@polkadot/util-crypto";
|
|
103
|
-
import { getPolkadotSigner } from "polkadot-api/signer";
|
|
104
|
-
import { sr25519CreateDerive } from "@polkadot-labs/hdkd";
|
|
105
|
-
import { mnemonicToEntropy, entropyToMiniSecret, ss58Address } from "@polkadot-labs/hdkd-helpers";
|
|
108
|
+
import { getPolkadotSigner as getPolkadotSigner2 } from "polkadot-api/signer";
|
|
109
|
+
import { sr25519CreateDerive as sr25519CreateDerive2 } from "@polkadot-labs/hdkd";
|
|
110
|
+
import { mnemonicToEntropy, entropyToMiniSecret, ss58Address as ss58Address2 } from "@polkadot-labs/hdkd-helpers";
|
|
106
111
|
import { CarReader } from "@ipld/car/reader";
|
|
112
|
+
|
|
113
|
+
// src/storage-signer.ts
|
|
114
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
115
|
+
import { homedir } from "os";
|
|
116
|
+
import { join, dirname } from "path";
|
|
117
|
+
|
|
118
|
+
// node_modules/@polkadot-api/utils/dist/hex.js
|
|
119
|
+
var HEX_STR = "0123456789abcdef";
|
|
120
|
+
function toHex(bytes) {
|
|
121
|
+
const result = new Array(bytes.length + 1);
|
|
122
|
+
result[0] = "0x";
|
|
123
|
+
for (let i = 0; i < bytes.length; ) {
|
|
124
|
+
const b = bytes[i++];
|
|
125
|
+
result[i] = HEX_STR[b >> 4] + HEX_STR[b & 15];
|
|
126
|
+
}
|
|
127
|
+
return result.join("");
|
|
128
|
+
}
|
|
129
|
+
var HEX_MAP = {
|
|
130
|
+
0: 0,
|
|
131
|
+
1: 1,
|
|
132
|
+
2: 2,
|
|
133
|
+
3: 3,
|
|
134
|
+
4: 4,
|
|
135
|
+
5: 5,
|
|
136
|
+
6: 6,
|
|
137
|
+
7: 7,
|
|
138
|
+
8: 8,
|
|
139
|
+
9: 9,
|
|
140
|
+
a: 10,
|
|
141
|
+
b: 11,
|
|
142
|
+
c: 12,
|
|
143
|
+
d: 13,
|
|
144
|
+
e: 14,
|
|
145
|
+
f: 15,
|
|
146
|
+
A: 10,
|
|
147
|
+
B: 11,
|
|
148
|
+
C: 12,
|
|
149
|
+
D: 13,
|
|
150
|
+
E: 14,
|
|
151
|
+
F: 15
|
|
152
|
+
};
|
|
153
|
+
function fromHex(hexString) {
|
|
154
|
+
const isOdd = hexString.length % 2;
|
|
155
|
+
const base = (hexString[1] === "x" ? 2 : 0) + isOdd;
|
|
156
|
+
const nBytes = (hexString.length - base) / 2 + isOdd;
|
|
157
|
+
const bytes = new Uint8Array(nBytes);
|
|
158
|
+
if (isOdd) bytes[0] = 0 | HEX_MAP[hexString[2]];
|
|
159
|
+
for (let i = 0; i < nBytes; ) {
|
|
160
|
+
const idx = base + i * 2;
|
|
161
|
+
const a = HEX_MAP[hexString[idx]];
|
|
162
|
+
const b = HEX_MAP[hexString[idx + 1]];
|
|
163
|
+
bytes[isOdd + i++] = a << 4 | b;
|
|
164
|
+
}
|
|
165
|
+
return bytes;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/storage-signer.ts
|
|
169
|
+
import { sr25519CreateDerive } from "@polkadot-labs/hdkd";
|
|
170
|
+
import { sr25519, ss58Address } from "@polkadot-labs/hdkd-helpers";
|
|
171
|
+
import { createClient as createPolkadotClient, Enum } from "polkadot-api";
|
|
172
|
+
import { getPolkadotSigner } from "polkadot-api/signer";
|
|
173
|
+
import { getWsProvider } from "polkadot-api/ws";
|
|
174
|
+
function sanitize(appId) {
|
|
175
|
+
return appId.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
176
|
+
}
|
|
177
|
+
function cacheFilePath(appId, storageDir) {
|
|
178
|
+
return join(storageDir ?? homedir(), ".polkadot-apps", `${sanitize(appId)}_AllowanceKeys.json`);
|
|
179
|
+
}
|
|
180
|
+
function normalizeSchnorrkelKey(key) {
|
|
181
|
+
if (key.length !== 64) return key;
|
|
182
|
+
const out = new Uint8Array(key);
|
|
183
|
+
let carry = 0;
|
|
184
|
+
for (let i = 0; i < 32; i++) {
|
|
185
|
+
const v = key[i] * 8 + carry;
|
|
186
|
+
out[i] = v & 255;
|
|
187
|
+
carry = v >> 8;
|
|
188
|
+
}
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
function signerFromSecret(secret) {
|
|
192
|
+
if (secret.length === 32) {
|
|
193
|
+
const kp = sr25519CreateDerive(secret)("");
|
|
194
|
+
return getPolkadotSigner(kp.publicKey, "Sr25519", async (d) => kp.sign(d));
|
|
195
|
+
}
|
|
196
|
+
if (secret.length === 64) {
|
|
197
|
+
const normalized = normalizeSchnorrkelKey(secret);
|
|
198
|
+
const pub = sr25519.getPublicKey(normalized);
|
|
199
|
+
return getPolkadotSigner(pub, "Sr25519", async (d) => sr25519.sign(d, normalized));
|
|
200
|
+
}
|
|
201
|
+
throw new Error(
|
|
202
|
+
`BulletInAllowance slot key: unexpected length ${secret.length} (expected 32 or 64)`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
async function readBulletinSlotSigner(appId, storageDir) {
|
|
206
|
+
let raw;
|
|
207
|
+
try {
|
|
208
|
+
raw = await readFile(cacheFilePath(appId, storageDir), "utf-8");
|
|
209
|
+
} catch (e) {
|
|
210
|
+
if (e?.code === "ENOENT") return null;
|
|
211
|
+
throw e;
|
|
212
|
+
}
|
|
213
|
+
let cache;
|
|
214
|
+
try {
|
|
215
|
+
cache = JSON.parse(raw);
|
|
216
|
+
} catch {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const entry = cache?.entries?.BulletInAllowance;
|
|
220
|
+
if (!entry?.slotAccountKey) return null;
|
|
221
|
+
let secret;
|
|
222
|
+
try {
|
|
223
|
+
secret = fromHex(entry.slotAccountKey);
|
|
224
|
+
} catch {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
const signer = signerFromSecret(secret);
|
|
228
|
+
return { signer, ss58: ss58Address(signer.publicKey) };
|
|
229
|
+
}
|
|
230
|
+
async function writeBulletinSlotKey(appId, hexKey, storageDir) {
|
|
231
|
+
const path3 = cacheFilePath(appId, storageDir);
|
|
232
|
+
await mkdir(dirname(path3), { recursive: true, mode: 448 });
|
|
233
|
+
let existing = { version: 1, entries: {} };
|
|
234
|
+
try {
|
|
235
|
+
existing = JSON.parse(await readFile(path3, "utf-8"));
|
|
236
|
+
} catch {
|
|
237
|
+
}
|
|
238
|
+
existing.entries ??= {};
|
|
239
|
+
existing.entries.BulletInAllowance = { tag: "BulletInAllowance", slotAccountKey: hexKey };
|
|
240
|
+
await writeFile(path3, `${JSON.stringify(existing, null, 2)}
|
|
241
|
+
`, { mode: 384 });
|
|
242
|
+
}
|
|
243
|
+
function extractBulletinSlotKey(outcomes) {
|
|
244
|
+
for (const outcome of outcomes) {
|
|
245
|
+
if (outcome.tag !== "Allocated") continue;
|
|
246
|
+
const allocated = outcome.value;
|
|
247
|
+
if (allocated?.tag !== "BulletInAllowance") continue;
|
|
248
|
+
const key = allocated.value?.slotAccountKey;
|
|
249
|
+
if (!(key instanceof Uint8Array)) continue;
|
|
250
|
+
return toHex(normalizeSchnorrkelKey(key));
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
async function getSlotSignerProvider(signer, ss58) {
|
|
255
|
+
const primary = BULLETIN_ENDPOINTS[0];
|
|
256
|
+
console.log(` Connecting to Bulletin (slot signer): ${primary}`);
|
|
257
|
+
const client = createPolkadotClient(getWsProvider(
|
|
258
|
+
BULLETIN_ENDPOINTS,
|
|
259
|
+
{ heartbeatTimeout: WS_HEARTBEAT_TIMEOUT_MS, onStatusChanged: makeBulletinStatusHandler(primary) }
|
|
260
|
+
));
|
|
261
|
+
const unsafeApi = client.getUnsafeApi();
|
|
262
|
+
const [auth, currentBlock] = await Promise.all([
|
|
263
|
+
unsafeApi.query.TransactionStorage.Authorizations.getValue(Enum("Account", ss58)),
|
|
264
|
+
client.getFinalizedBlock()
|
|
265
|
+
]);
|
|
266
|
+
const now = currentBlock.number;
|
|
267
|
+
if (!auth || Number(auth.expiration ?? 0) <= now) {
|
|
268
|
+
client.destroy();
|
|
269
|
+
throw new Error(`Slot account ${ss58} not authorized on Bulletin`);
|
|
270
|
+
}
|
|
271
|
+
console.log(` Using slot signer: ${ss58} (authorized until block ${Number(auth?.expiration ?? 0)})`);
|
|
272
|
+
setDeployAttribute("deploy.signer.mode", "slot");
|
|
273
|
+
setDeployAttribute("deploy.signer.address", truncateAddress(ss58));
|
|
274
|
+
return { client, unsafeApi, signer, ss58 };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// src/deploy.ts
|
|
107
278
|
function friendlyChainError(msg) {
|
|
108
279
|
if (/"type":\s*"Invalid"[\s\S]*?"type":\s*"Payment"/i.test(msg)) {
|
|
109
280
|
return "Bulletin quota exhausted (signed extension rejected the tx \u2014 signer is out of allowed txs or bytes; grant quota on-chain)";
|
|
@@ -166,10 +337,10 @@ var CID_CONFIG = { version: 1, codec: 85, hashCode: 18, hashLength: 32 };
|
|
|
166
337
|
function deriveRootSigner(mnemonic, path3 = "") {
|
|
167
338
|
const entropy = mnemonicToEntropy(mnemonic);
|
|
168
339
|
const miniSecret = entropyToMiniSecret(entropy);
|
|
169
|
-
const derive =
|
|
340
|
+
const derive = sr25519CreateDerive2(miniSecret);
|
|
170
341
|
const keyPair = derive(path3);
|
|
171
|
-
const signer =
|
|
172
|
-
return { signer, ss58:
|
|
342
|
+
const signer = getPolkadotSigner2(keyPair.publicKey, "Sr25519", keyPair.sign);
|
|
343
|
+
return { signer, ss58: ss58Address2(keyPair.publicKey) };
|
|
173
344
|
}
|
|
174
345
|
function createCID(data, codec = CID_CONFIG.codec, hashCode = CID_CONFIG.hashCode) {
|
|
175
346
|
let hash;
|
|
@@ -223,7 +394,7 @@ function toHashingEnum(mhCode) {
|
|
|
223
394
|
async function getProvider() {
|
|
224
395
|
const primary = BULLETIN_ENDPOINTS[0];
|
|
225
396
|
console.log(` Connecting to Bulletin: ${primary}`);
|
|
226
|
-
const client =
|
|
397
|
+
const client = createPolkadotClient2(getWsProvider2(
|
|
227
398
|
BULLETIN_ENDPOINTS,
|
|
228
399
|
{ heartbeatTimeout: WS_HEARTBEAT_TIMEOUT_MS, onStatusChanged: makeBulletinStatusHandler(primary) }
|
|
229
400
|
));
|
|
@@ -251,7 +422,7 @@ async function getProvider() {
|
|
|
251
422
|
async function getDirectProvider(mnemonic, derivationPath = "") {
|
|
252
423
|
const primary = BULLETIN_ENDPOINTS[0];
|
|
253
424
|
console.log(` Connecting to Bulletin: ${primary}`);
|
|
254
|
-
const client =
|
|
425
|
+
const client = createPolkadotClient2(getWsProvider2(
|
|
255
426
|
BULLETIN_ENDPOINTS,
|
|
256
427
|
{ heartbeatTimeout: WS_HEARTBEAT_TIMEOUT_MS, onStatusChanged: makeBulletinStatusHandler(primary) }
|
|
257
428
|
));
|
|
@@ -259,7 +430,7 @@ async function getDirectProvider(mnemonic, derivationPath = "") {
|
|
|
259
430
|
const { signer, ss58 } = deriveRootSigner(mnemonic, derivationPath);
|
|
260
431
|
console.log(` Using direct signer: ${ss58}${derivationPath ? ` (path: ${derivationPath})` : ""}`);
|
|
261
432
|
let [auth, currentBlock] = await Promise.all([
|
|
262
|
-
unsafeApi.query.TransactionStorage.Authorizations.getValue(
|
|
433
|
+
unsafeApi.query.TransactionStorage.Authorizations.getValue(Enum2("Account", ss58)),
|
|
263
434
|
client.getFinalizedBlock()
|
|
264
435
|
]);
|
|
265
436
|
let now = currentBlock.number;
|
|
@@ -267,7 +438,7 @@ async function getDirectProvider(mnemonic, derivationPath = "") {
|
|
|
267
438
|
try {
|
|
268
439
|
await ensureAuthorized(unsafeApi, ss58, "direct signer");
|
|
269
440
|
[auth, currentBlock] = await Promise.all([
|
|
270
|
-
unsafeApi.query.TransactionStorage.Authorizations.getValue(
|
|
441
|
+
unsafeApi.query.TransactionStorage.Authorizations.getValue(Enum2("Account", ss58)),
|
|
271
442
|
client.getFinalizedBlock()
|
|
272
443
|
]);
|
|
273
444
|
now = currentBlock.number;
|
|
@@ -281,52 +452,35 @@ async function getDirectProvider(mnemonic, derivationPath = "") {
|
|
|
281
452
|
setDeployAttribute("deploy.signer.address", truncateAddress(ss58));
|
|
282
453
|
return { client, unsafeApi, signer, ss58 };
|
|
283
454
|
}
|
|
284
|
-
async function getSignerProvider(signer, ss58) {
|
|
285
|
-
const primary = BULLETIN_ENDPOINTS[0];
|
|
286
|
-
console.log(` Connecting to Bulletin: ${primary}`);
|
|
287
|
-
const client = createPolkadotClient(getWsProvider(
|
|
288
|
-
BULLETIN_ENDPOINTS,
|
|
289
|
-
{ heartbeatTimeout: WS_HEARTBEAT_TIMEOUT_MS, onStatusChanged: makeBulletinStatusHandler(primary) }
|
|
290
|
-
));
|
|
291
|
-
const unsafeApi = client.getUnsafeApi();
|
|
292
|
-
console.log(` Using external signer: ${ss58}`);
|
|
293
|
-
let [auth, currentBlock] = await Promise.all([
|
|
294
|
-
unsafeApi.query.TransactionStorage.Authorizations.getValue(Enum("Account", ss58)),
|
|
295
|
-
client.getFinalizedBlock()
|
|
296
|
-
]);
|
|
297
|
-
let now = currentBlock.number;
|
|
298
|
-
if (!auth || Number(auth.expiration ?? 0) <= now) {
|
|
299
|
-
try {
|
|
300
|
-
await ensureAuthorized(unsafeApi, ss58, "external signer");
|
|
301
|
-
[auth, currentBlock] = await Promise.all([
|
|
302
|
-
unsafeApi.query.TransactionStorage.Authorizations.getValue(Enum("Account", ss58)),
|
|
303
|
-
client.getFinalizedBlock()
|
|
304
|
-
]);
|
|
305
|
-
now = currentBlock.number;
|
|
306
|
-
} catch (e) {
|
|
307
|
-
client.destroy();
|
|
308
|
-
throw new NonRetryableError(`Account ${ss58} is not authorized for Bulletin storage and auto-authorization failed: ${e.message}`);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
console.log(` Authorization: expires at block ${Number(auth?.expiration ?? 0)} (current: ${now})`);
|
|
312
|
-
setDeployAttribute("deploy.signer.mode", "external");
|
|
313
|
-
setDeployAttribute("deploy.signer.address", truncateAddress(ss58));
|
|
314
|
-
return { client, unsafeApi, signer, ss58 };
|
|
315
|
-
}
|
|
316
455
|
function __selectStorageProviderModeForTest(options) {
|
|
317
|
-
if (options.
|
|
456
|
+
if (options.storageSigner && options.storageSignerAddress) return "storageSigner";
|
|
318
457
|
if (options.mnemonic) return "direct";
|
|
319
458
|
return "pool";
|
|
320
459
|
}
|
|
460
|
+
function chooseSignerInput(opts) {
|
|
461
|
+
if (opts.mnemonic) return "mnemonic";
|
|
462
|
+
if (opts.hasInjectedSigner) return "injected";
|
|
463
|
+
if (opts.suri) return "resolve";
|
|
464
|
+
if (opts.hasSession) return "resolve";
|
|
465
|
+
return "pool";
|
|
466
|
+
}
|
|
321
467
|
function selectStorageReconnect(options) {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
468
|
+
if (options.storageSigner && options.storageSignerAddress) {
|
|
469
|
+
let useSlot = true;
|
|
470
|
+
return async () => {
|
|
471
|
+
if (!useSlot) return getProvider();
|
|
472
|
+
try {
|
|
473
|
+
return await getSlotSignerProvider(options.storageSigner, options.storageSignerAddress);
|
|
474
|
+
} catch {
|
|
475
|
+
useSlot = false;
|
|
476
|
+
setDeployAttribute("deploy.signer.mode", "pool-fallback");
|
|
477
|
+
return getProvider();
|
|
478
|
+
}
|
|
479
|
+
};
|
|
329
480
|
}
|
|
481
|
+
if (options.mnemonic)
|
|
482
|
+
return () => getDirectProvider(options.mnemonic, options.derivationPath);
|
|
483
|
+
return () => getProvider();
|
|
330
484
|
}
|
|
331
485
|
function watchTransaction(tx, signer, txOpts, onSuccess, { label = "transaction", rpc, senderSS58, expectedNonce, timeoutMs, fetchNonce: fetchNonceOverride } = {}) {
|
|
332
486
|
const timeout = timeoutMs ?? TX_TIMEOUT_MS;
|
|
@@ -491,7 +645,7 @@ async function storeChunkedContent(chunks, { client: existingClient, unsafeApi:
|
|
|
491
645
|
}
|
|
492
646
|
}
|
|
493
647
|
const readUploadAuthorization = () => Promise.all([
|
|
494
|
-
unsafeApi.query.TransactionStorage.Authorizations.getValue(
|
|
648
|
+
unsafeApi.query.TransactionStorage.Authorizations.getValue(Enum2("Account", ss58)),
|
|
495
649
|
unsafeApi.query.System.Number.getValue()
|
|
496
650
|
]);
|
|
497
651
|
let uploadAuth;
|
|
@@ -1120,7 +1274,7 @@ async function storeDirectoryV2(directoryPath, opts = {}) {
|
|
|
1120
1274
|
useKubo = hasIPFS();
|
|
1121
1275
|
}
|
|
1122
1276
|
const phaseA = await withSpan("deploy.merkleize", `1a. merkleize (${useKubo ? "kubo" : "js"}, stable)`, { "deploy.directory": dirBasename, "deploy.merkle": useKubo ? "kubo" : "js" }, async () => {
|
|
1123
|
-
const r = await merkleizeWithStableOrder(directoryPath, prevManifest?.stableBlockOrder, { useKubo });
|
|
1277
|
+
const r = await merkleizeWithStableOrder(directoryPath, prevManifest?.stableBlockOrder, { useKubo, phase: "Phase A" });
|
|
1124
1278
|
sampleMemory("merkleize_end");
|
|
1125
1279
|
return r;
|
|
1126
1280
|
});
|
|
@@ -1239,7 +1393,7 @@ async function storeDirectoryV2(directoryPath, opts = {}) {
|
|
|
1239
1393
|
carChunksA.length = 0;
|
|
1240
1394
|
phaseA.carBytes = new Uint8Array(0);
|
|
1241
1395
|
const phaseB = await withSpan("deploy.merkleize", "1c. merkleize (js, finalise)", { "deploy.directory": dirBasename }, async () => {
|
|
1242
|
-
const r = await merkleizeWithStableOrder(directoryPath, phaseA.stableOrder, { useKubo });
|
|
1396
|
+
const r = await merkleizeWithStableOrder(directoryPath, phaseA.stableOrder, { useKubo, phase: "Phase B" });
|
|
1243
1397
|
sampleMemory("merkleize_finalise_end");
|
|
1244
1398
|
return r;
|
|
1245
1399
|
});
|
|
@@ -1654,359 +1808,413 @@ async function deploy(content, domainName = null, options = {}) {
|
|
|
1654
1808
|
BULLETIN_ENDPOINTS = userRpc ? [userRpc, ...envBulletin.filter((e) => e !== userRpc)] : envBulletin;
|
|
1655
1809
|
_deployRpcFailedOver = false;
|
|
1656
1810
|
POOL_SIZE = options.poolSize ?? parseInt(process.env.BULLETIN_POOL_SIZE ?? String(DEFAULT_POOL_SIZE), 10);
|
|
1657
|
-
|
|
1658
|
-
const
|
|
1659
|
-
const
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
setDeployAttribute("deploy.subdomain", String(parsed?.isSubdomain ?? false));
|
|
1670
|
-
if (envNetwork) setDeployAttribute("deploy.network", envNetwork);
|
|
1671
|
-
if (envSource) setDeployAttribute("deploy.environments_source", envSource);
|
|
1672
|
-
let cid;
|
|
1673
|
-
let ipfsCid;
|
|
1674
|
-
let mirrorPromise = Promise.resolve(null);
|
|
1675
|
-
console.log("\n" + "=".repeat(60));
|
|
1676
|
-
console.log(`DEPLOYING TO TESTNET v${VERSION}`);
|
|
1677
|
-
console.log("=".repeat(60));
|
|
1678
|
-
if (envName) console.log(` Environment: ${envName}`);
|
|
1679
|
-
console.log(` Domain: ${name}.dot`);
|
|
1680
|
-
if (deployTag) console.log(` Tag: ${deployTag}`);
|
|
1681
|
-
if (options.inputCar) console.log(` Input CAR: ${path.resolve(options.inputCar)}`);
|
|
1682
|
-
else if (typeof content === "string") console.log(` Build dir: ${path.resolve(content)}`);
|
|
1683
|
-
if (process.env.CI) console.log(` Runner: ${resolveRunner()} (${resolveRunnerType()})`);
|
|
1684
|
-
if (options.password) console.log(` Encrypted: yes`);
|
|
1685
|
-
let provider;
|
|
1686
|
-
const reconnect = selectStorageReconnect(options);
|
|
1687
|
-
let dotnsPreflight = null;
|
|
1688
|
-
let previousContenthashCid = null;
|
|
1811
|
+
let sessionCleanup;
|
|
1812
|
+
const hasSession = hasPersistedSession();
|
|
1813
|
+
const signerChoice = chooseSignerInput({
|
|
1814
|
+
mnemonic: options.mnemonic,
|
|
1815
|
+
suri: options.suri,
|
|
1816
|
+
hasInjectedSigner: !!(options.signer && options.signerAddress),
|
|
1817
|
+
hasSession
|
|
1818
|
+
});
|
|
1819
|
+
if (signerChoice === "resolve") {
|
|
1820
|
+
const { resolveSigner: resolveSignerFn, requestResourceAllocation } = await import("./auth/index.js");
|
|
1821
|
+
const { getAuthClient } = await import("./auth-config.js");
|
|
1822
|
+
const authClient = await getAuthClient(envId);
|
|
1689
1823
|
try {
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
if (parsed?.isSubdomain) {
|
|
1824
|
+
const resolved = await resolveSignerFn(authClient, { suri: options.suri });
|
|
1825
|
+
options = { ...options, signer: resolved.signer, signerAddress: resolved.address };
|
|
1826
|
+
sessionCleanup = resolved.destroy.bind(resolved);
|
|
1827
|
+
console.log(` Using ${resolved.source} signer: ${resolved.address}`);
|
|
1828
|
+
if (resolved.source === "session") {
|
|
1696
1829
|
try {
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
const
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1830
|
+
let slotResult = await readBulletinSlotSigner(DOT_DAPP_ID);
|
|
1831
|
+
if (!slotResult && resolved.userSession) {
|
|
1832
|
+
console.log("Requesting Bulletin storage allowance \u2014 check your phone to approve");
|
|
1833
|
+
const outcomes = await requestResourceAllocation(
|
|
1834
|
+
resolved.userSession,
|
|
1835
|
+
DOT_PRODUCT_ID,
|
|
1836
|
+
[{ tag: "BulletInAllowance", value: void 0 }]
|
|
1837
|
+
);
|
|
1838
|
+
const hexKey = extractBulletinSlotKey(outcomes);
|
|
1839
|
+
if (hexKey) {
|
|
1840
|
+
await writeBulletinSlotKey(DOT_DAPP_ID, hexKey);
|
|
1841
|
+
slotResult = await readBulletinSlotSigner(DOT_DAPP_ID);
|
|
1705
1842
|
}
|
|
1706
1843
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1844
|
+
if (slotResult) {
|
|
1845
|
+
options = { ...options, storageSigner: slotResult.signer, storageSignerAddress: slotResult.ss58 };
|
|
1846
|
+
}
|
|
1847
|
+
} catch {
|
|
1711
1848
|
}
|
|
1712
|
-
|
|
1849
|
+
}
|
|
1850
|
+
} catch (e) {
|
|
1851
|
+
if (options.suri) throw e;
|
|
1852
|
+
if (e?.name === "SignerNotAvailableError") {
|
|
1853
|
+
console.log(
|
|
1854
|
+
" Login session unavailable or expired \u2014 falling back to pool. Run `bulletin-deploy login` to use your identity."
|
|
1855
|
+
);
|
|
1713
1856
|
} else {
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
if (dotnsPreflight.canProceed) {
|
|
1729
|
-
const fromName = popStatusName(dotnsPreflight.userStatus);
|
|
1730
|
-
console.log(` Your PoP: ${fromName}`);
|
|
1731
|
-
console.log(` Domain: ${dotnsPreflight.plannedAction === "already-owned-by-us" ? "owned by you" : "available"}`);
|
|
1732
|
-
}
|
|
1733
|
-
if (!dotnsPreflight.canProceed) {
|
|
1734
|
-
throw new NonRetryableError(
|
|
1735
|
-
dotnsPreflight.reason ?? "DotNS preflight rejected the deploy; please check the label and signer."
|
|
1736
|
-
);
|
|
1737
|
-
}
|
|
1857
|
+
throw e;
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
initTelemetry();
|
|
1862
|
+
const randomSuffix = Math.floor(Math.random() * 100).toString().padStart(2, "0");
|
|
1863
|
+
const parsed = domainName ? parseDomainName(domainName) : null;
|
|
1864
|
+
const name = parsed ? parsed.label : `test-domain-${Date.now().toString(36)}${randomSuffix}`;
|
|
1865
|
+
try {
|
|
1866
|
+
return await withDeploySpan(name, async () => {
|
|
1867
|
+
const deployTag = options.tag ?? process.env.DEPLOY_TAG;
|
|
1868
|
+
if (deployTag) {
|
|
1869
|
+
setDeployAttribute("deploy.tag", deployTag);
|
|
1870
|
+
setDeploySentryTag("deploy.tag", deployTag);
|
|
1738
1871
|
}
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
setDeployAttribute("deploy.
|
|
1872
|
+
setDeployAttribute("deploy.env", envId);
|
|
1873
|
+
setDeployAttribute("deploy.label", parsed?.label ?? name);
|
|
1874
|
+
setDeployAttribute("deploy.subdomain", String(parsed?.isSubdomain ?? false));
|
|
1875
|
+
if (envNetwork) setDeployAttribute("deploy.network", envNetwork);
|
|
1876
|
+
if (envSource) setDeployAttribute("deploy.environments_source", envSource);
|
|
1877
|
+
let cid;
|
|
1878
|
+
let ipfsCid;
|
|
1879
|
+
let mirrorPromise = Promise.resolve(null);
|
|
1743
1880
|
console.log("\n" + "=".repeat(60));
|
|
1744
|
-
console.log(
|
|
1881
|
+
console.log(`DEPLOYING TO TESTNET v${VERSION}`);
|
|
1745
1882
|
console.log("=".repeat(60));
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
try {
|
|
1774
|
-
let prevStableOrder = [];
|
|
1775
|
-
const manifestBytes = await extractManifestFromCar(carContent);
|
|
1776
|
-
if (manifestBytes) {
|
|
1777
|
-
const parsed2 = parseManifest(Buffer.from(manifestBytes).toString("utf8"));
|
|
1778
|
-
if (parsed2.ok) prevStableOrder = parsed2.manifest.stableBlockOrder;
|
|
1779
|
-
}
|
|
1780
|
-
const rebuilt = await rebuildOrderedCarFromBytes(carContent, prevStableOrder);
|
|
1781
|
-
if (Buffer.compare(Buffer.from(rebuilt.carBytes), Buffer.from(carContent)) === 0) {
|
|
1782
|
-
carChunks = rebuilt.chunks;
|
|
1783
|
-
} else {
|
|
1784
|
-
captureWarning("input CAR ordered rechunk drift; falling back to size chunking", {
|
|
1785
|
-
rootCid: ipfsCid
|
|
1786
|
-
});
|
|
1787
|
-
carChunks = chunk(carContent, CHUNK_SIZE);
|
|
1883
|
+
if (envName) console.log(` Environment: ${envName}`);
|
|
1884
|
+
console.log(` Domain: ${name}.dot`);
|
|
1885
|
+
if (deployTag) console.log(` Tag: ${deployTag}`);
|
|
1886
|
+
if (options.inputCar) console.log(` Input CAR: ${path.resolve(options.inputCar)}`);
|
|
1887
|
+
else if (typeof content === "string") console.log(` Build dir: ${path.resolve(content)}`);
|
|
1888
|
+
if (process.env.CI) console.log(` Runner: ${resolveRunner()} (${resolveRunnerType()})`);
|
|
1889
|
+
if (options.password) console.log(` Encrypted: yes`);
|
|
1890
|
+
let provider;
|
|
1891
|
+
const reconnect = selectStorageReconnect(options);
|
|
1892
|
+
let dotnsPreflight = null;
|
|
1893
|
+
let previousContenthashCid = null;
|
|
1894
|
+
try {
|
|
1895
|
+
console.log("\n" + "=".repeat(60));
|
|
1896
|
+
console.log("Preflight");
|
|
1897
|
+
console.log("=".repeat(60));
|
|
1898
|
+
const preflight = new DotNS();
|
|
1899
|
+
await preflight.connect(resolveDotnsConnectOptions(options, envAssetHub, envAutoAccountMapping, envContracts, envNativeToEthRatio, envId, envPopSelfServe, envRegisterStorageDeposit));
|
|
1900
|
+
if (parsed?.isSubdomain) {
|
|
1901
|
+
try {
|
|
1902
|
+
const subResult = await preflight.checkSubdomainOwnership(parsed.sublabel, parsed.parentLabel);
|
|
1903
|
+
assertSubdomainOwnerMatchesSigner(subResult, preflight.evmAddress, parsed.sublabel, parsed.parentLabel);
|
|
1904
|
+
if (!subResult.owned) {
|
|
1905
|
+
const { owned: parentOwned, owner: parentOwner } = await preflight.checkOwnership(parsed.parentLabel);
|
|
1906
|
+
if (!parentOwned) {
|
|
1907
|
+
throw new NonRetryableError(
|
|
1908
|
+
`Cannot deploy ${parsed.fullName}: parent ${parsed.parentLabel}.dot is owned by ${parentOwner ?? "no one"}, not by this signer.`
|
|
1909
|
+
);
|
|
1788
1910
|
}
|
|
1789
|
-
} catch (err) {
|
|
1790
|
-
captureWarning("input CAR ordered rechunk failed; falling back to size chunking", {
|
|
1791
|
-
rootCid: ipfsCid,
|
|
1792
|
-
reason: err?.message ?? String(err)
|
|
1793
|
-
});
|
|
1794
|
-
carChunks = chunk(carContent, CHUNK_SIZE);
|
|
1795
1911
|
}
|
|
1912
|
+
previousContenthashCid = await readPreviousContenthashSafe(preflight, parsed.fullName);
|
|
1913
|
+
setDeployAttribute("deploy.incremental", previousContenthashCid ? "true" : "false");
|
|
1914
|
+
} finally {
|
|
1915
|
+
preflight.disconnect();
|
|
1916
|
+
}
|
|
1917
|
+
console.log(` Mode: subdomain (parent ${parsed.parentLabel}.dot owned by signer)`);
|
|
1918
|
+
} else {
|
|
1919
|
+
try {
|
|
1920
|
+
dotnsPreflight = await preflight.preflight(name);
|
|
1921
|
+
previousContenthashCid = await readPreviousContenthashSafe(preflight, name);
|
|
1922
|
+
setDeployAttribute("deploy.incremental", previousContenthashCid ? "true" : "false");
|
|
1923
|
+
} finally {
|
|
1924
|
+
preflight.disconnect();
|
|
1796
1925
|
}
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
domain: name,
|
|
1801
|
-
carBytes: carContent,
|
|
1802
|
-
cid: predictedStorageCid,
|
|
1803
|
-
toolVersion: VERSION,
|
|
1804
|
-
bulletinRpc: BULLETIN_ENDPOINTS[0],
|
|
1805
|
-
encrypted: Boolean(options.password)
|
|
1806
|
-
}).catch((err) => err instanceof Error ? err : new Error(String(err)));
|
|
1926
|
+
if (dotnsPreflight) {
|
|
1927
|
+
setDeployAttribute("deploy.dotns.preflight.action", dotnsPreflight.plannedAction);
|
|
1928
|
+
setDeployAttribute("deploy.dotns.preflight.classification", popStatusName(dotnsPreflight.classification.status));
|
|
1807
1929
|
}
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
if (
|
|
1812
|
-
|
|
1813
|
-
|
|
1930
|
+
const alreadyOwned = dotnsPreflight.plannedAction === "already-owned-by-us";
|
|
1931
|
+
const reqSuffix = alreadyOwned ? " (already owned, requirement not enforced)" : "";
|
|
1932
|
+
console.log(` DotNS: ${name}.dot requires ${popStatusName(dotnsPreflight.classification.status)}${reqSuffix}`);
|
|
1933
|
+
if (dotnsPreflight.canProceed) {
|
|
1934
|
+
const fromName = popStatusName(dotnsPreflight.userStatus);
|
|
1935
|
+
console.log(` Your PoP: ${fromName}`);
|
|
1936
|
+
console.log(` Domain: ${dotnsPreflight.plannedAction === "already-owned-by-us" ? "owned by you" : "available"}`);
|
|
1937
|
+
}
|
|
1938
|
+
if (!dotnsPreflight.canProceed) {
|
|
1939
|
+
throw new NonRetryableError(
|
|
1940
|
+
dotnsPreflight.reason ?? "DotNS preflight rejected the deploy; please check the label and signer."
|
|
1814
1941
|
);
|
|
1815
1942
|
}
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1943
|
+
}
|
|
1944
|
+
provider = await reconnect();
|
|
1945
|
+
const providerWithReconnect = { ...provider, reconnect };
|
|
1946
|
+
const isTestnet = await detectTestnet(provider.unsafeApi);
|
|
1947
|
+
setDeployAttribute("deploy.is_testnet", isTestnet ? "true" : "false");
|
|
1948
|
+
console.log("\n" + "=".repeat(60));
|
|
1949
|
+
console.log("Storage");
|
|
1950
|
+
console.log("=".repeat(60));
|
|
1951
|
+
setDeployAttribute("deploy.content_type", "unknown");
|
|
1952
|
+
setDeployAttribute("deploy.encrypted", "false");
|
|
1953
|
+
await withSpan("deploy.storage", "1. storage", {}, async () => {
|
|
1954
|
+
if (options.inputCar) {
|
|
1955
|
+
setDeployAttribute("deploy.content_type", "inputCar");
|
|
1956
|
+
const carPath = path.resolve(options.inputCar);
|
|
1957
|
+
if (!fs.existsSync(carPath)) throw new Error(`CAR file not found: ${carPath}`);
|
|
1958
|
+
console.log(`
|
|
1959
|
+
Mode: Pre-built CAR`);
|
|
1960
|
+
console.log(` Path: ${carPath}`);
|
|
1961
|
+
let carContent = fs.readFileSync(carPath);
|
|
1962
|
+
console.log(` Size: ${(carContent.length / 1024 / 1024).toFixed(2)} MB`);
|
|
1963
|
+
const reader = await CarReader.fromBytes(carContent);
|
|
1964
|
+
const roots = await reader.getRoots();
|
|
1965
|
+
if (roots.length === 0) throw new Error("CAR file has no roots");
|
|
1966
|
+
ipfsCid = roots[0].toString();
|
|
1967
|
+
console.log(` Root CID: ${ipfsCid}`);
|
|
1968
|
+
if (options.password) {
|
|
1969
|
+
setDeployAttribute("deploy.encrypted", "true");
|
|
1970
|
+
console.log(` Encrypting CAR file...`);
|
|
1971
|
+
carContent = await encryptContent(carContent, options.password);
|
|
1972
|
+
console.log(` Encrypted: ${(carContent.length / 1024 / 1024).toFixed(2)} MB`);
|
|
1973
|
+
}
|
|
1974
|
+
let carChunks;
|
|
1975
|
+
if (options.password) {
|
|
1976
|
+
carChunks = chunk(carContent, CHUNK_SIZE);
|
|
1977
|
+
} else {
|
|
1978
|
+
try {
|
|
1979
|
+
let prevStableOrder = [];
|
|
1980
|
+
const manifestBytes = await extractManifestFromCar(carContent);
|
|
1981
|
+
if (manifestBytes) {
|
|
1982
|
+
const parsed2 = parseManifest(Buffer.from(manifestBytes).toString("utf8"));
|
|
1983
|
+
if (parsed2.ok) prevStableOrder = parsed2.manifest.stableBlockOrder;
|
|
1984
|
+
}
|
|
1985
|
+
const rebuilt = await rebuildOrderedCarFromBytes(carContent, prevStableOrder);
|
|
1986
|
+
if (Buffer.compare(Buffer.from(rebuilt.carBytes), Buffer.from(carContent)) === 0) {
|
|
1987
|
+
carChunks = rebuilt.chunks;
|
|
1988
|
+
} else {
|
|
1989
|
+
captureWarning("input CAR ordered rechunk drift; falling back to size chunking", {
|
|
1990
|
+
rootCid: ipfsCid
|
|
1991
|
+
});
|
|
1992
|
+
carChunks = chunk(carContent, CHUNK_SIZE);
|
|
1993
|
+
}
|
|
1994
|
+
} catch (err) {
|
|
1995
|
+
captureWarning("input CAR ordered rechunk failed; falling back to size chunking", {
|
|
1996
|
+
rootCid: ipfsCid,
|
|
1997
|
+
reason: err?.message ?? String(err)
|
|
1998
|
+
});
|
|
1999
|
+
carChunks = chunk(carContent, CHUNK_SIZE);
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
const predictedStorageCid = computeStorageCid(carChunks);
|
|
2003
|
+
if (options.ghPagesMirror) {
|
|
2004
|
+
mirrorPromise = mirrorToGitHubPages({
|
|
2005
|
+
domain: name,
|
|
2006
|
+
carBytes: carContent,
|
|
2007
|
+
cid: predictedStorageCid,
|
|
2008
|
+
toolVersion: VERSION,
|
|
2009
|
+
bulletinRpc: BULLETIN_ENDPOINTS[0],
|
|
2010
|
+
encrypted: Boolean(options.password)
|
|
2011
|
+
}).catch((err) => err instanceof Error ? err : new Error(String(err)));
|
|
2012
|
+
}
|
|
2013
|
+
cid = (await storeChunkedContent(carChunks, providerWithReconnect)).storageCid;
|
|
2014
|
+
} else if (process.env.IPFS_CID) {
|
|
2015
|
+
setDeployAttribute("deploy.content_type", "ipfsCid");
|
|
2016
|
+
if (options.password) {
|
|
2017
|
+
throw new Error(
|
|
2018
|
+
"IPFS_CID and --password are mutually exclusive: IPFS_CID skips the upload step, so there is nothing to encrypt. Either unset IPFS_CID to upload and encrypt fresh content, or remove --password to reuse the existing CID as-is."
|
|
2019
|
+
);
|
|
2020
|
+
}
|
|
2021
|
+
cid = process.env.IPFS_CID;
|
|
2022
|
+
ipfsCid = cid;
|
|
2023
|
+
console.log(`
|
|
1819
2024
|
Using CID: ${cid}`);
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
console.log(`
|
|
1823
|
-
Mode: Multi-chunk (${content.length} chunks)`);
|
|
1824
|
-
let contentChunks = content;
|
|
1825
|
-
if (options.password) {
|
|
1826
|
-
setDeployAttribute("deploy.encrypted", "true");
|
|
1827
|
-
console.log(` Encrypting...`);
|
|
1828
|
-
const encrypted = await encryptContent(Buffer.concat(content), options.password);
|
|
1829
|
-
console.log(` Encrypted: ${(encrypted.length / 1024).toFixed(1)} KB`);
|
|
1830
|
-
contentChunks = chunk(encrypted);
|
|
1831
|
-
}
|
|
1832
|
-
cid = (await storeChunkedContent(contentChunks, providerWithReconnect)).storageCid;
|
|
1833
|
-
} else if (typeof content === "string") {
|
|
1834
|
-
setDeployAttribute("deploy.content_type", "path");
|
|
1835
|
-
const contentPath = path.resolve(content);
|
|
1836
|
-
if (!fs.existsSync(contentPath)) throw new Error(`Path not found: ${contentPath}`);
|
|
1837
|
-
const stats = fs.statSync(contentPath);
|
|
1838
|
-
if (stats.isDirectory()) {
|
|
1839
|
-
setDeployAttribute("deploy.content_type", "directory");
|
|
2025
|
+
} else if (Array.isArray(content)) {
|
|
2026
|
+
setDeployAttribute("deploy.content_type", "multiChunk");
|
|
1840
2027
|
console.log(`
|
|
2028
|
+
Mode: Multi-chunk (${content.length} chunks)`);
|
|
2029
|
+
let contentChunks = content;
|
|
2030
|
+
if (options.password) {
|
|
2031
|
+
setDeployAttribute("deploy.encrypted", "true");
|
|
2032
|
+
console.log(` Encrypting...`);
|
|
2033
|
+
const encrypted = await encryptContent(Buffer.concat(content), options.password);
|
|
2034
|
+
console.log(` Encrypted: ${(encrypted.length / 1024).toFixed(1)} KB`);
|
|
2035
|
+
contentChunks = chunk(encrypted);
|
|
2036
|
+
}
|
|
2037
|
+
cid = (await storeChunkedContent(contentChunks, providerWithReconnect)).storageCid;
|
|
2038
|
+
} else if (typeof content === "string") {
|
|
2039
|
+
setDeployAttribute("deploy.content_type", "path");
|
|
2040
|
+
const contentPath = path.resolve(content);
|
|
2041
|
+
if (!fs.existsSync(contentPath)) throw new Error(`Path not found: ${contentPath}`);
|
|
2042
|
+
const stats = fs.statSync(contentPath);
|
|
2043
|
+
if (stats.isDirectory()) {
|
|
2044
|
+
setDeployAttribute("deploy.content_type", "directory");
|
|
2045
|
+
console.log(`
|
|
1841
2046
|
Mode: Directory`);
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
2047
|
+
console.log(` Path: ${contentPath}`);
|
|
2048
|
+
if (previousContenthashCid) console.log(` Incremental: previous contenthash ${previousContenthashCid}`);
|
|
2049
|
+
else console.log(` Incremental: first deploy (no previous contenthash)`);
|
|
2050
|
+
if (options.password) setDeployAttribute("deploy.encrypted", "true");
|
|
2051
|
+
const storeFn = options.password ? storeDirectory : storeDirectoryV2;
|
|
2052
|
+
const { storageCid: sCid, ipfsCid: iCid } = await storeFn(contentPath, {
|
|
2053
|
+
provider: providerWithReconnect,
|
|
2054
|
+
password: options.password,
|
|
2055
|
+
jsMerkle: options.jsMerkle,
|
|
2056
|
+
previousContenthash: previousContenthashCid,
|
|
2057
|
+
allowLargeDeploy: options.allowLargeDeploy,
|
|
2058
|
+
reproducibleSource: options.reproducibleSource,
|
|
2059
|
+
domain: name,
|
|
2060
|
+
gateway: envIpfs,
|
|
2061
|
+
dumpCar: options.dumpCar,
|
|
2062
|
+
onCarReady: (carBytes, predictedCid) => {
|
|
2063
|
+
if (options.ghPagesMirror) {
|
|
2064
|
+
mirrorPromise = mirrorToGitHubPages({
|
|
2065
|
+
domain: name,
|
|
2066
|
+
carBytes,
|
|
2067
|
+
cid: predictedCid,
|
|
2068
|
+
toolVersion: VERSION,
|
|
2069
|
+
bulletinRpc: BULLETIN_ENDPOINTS[0],
|
|
2070
|
+
encrypted: Boolean(options.password)
|
|
2071
|
+
}).catch((err) => err instanceof Error ? err : new Error(String(err)));
|
|
2072
|
+
}
|
|
1867
2073
|
}
|
|
2074
|
+
});
|
|
2075
|
+
cid = sCid;
|
|
2076
|
+
ipfsCid = iCid;
|
|
2077
|
+
} else {
|
|
2078
|
+
setDeployAttribute("deploy.content_type", "file");
|
|
2079
|
+
console.log(`
|
|
2080
|
+
Mode: File`);
|
|
2081
|
+
console.log(` Path: ${contentPath}`);
|
|
2082
|
+
let fileContent = fs.readFileSync(contentPath);
|
|
2083
|
+
if (options.password) {
|
|
2084
|
+
setDeployAttribute("deploy.encrypted", "true");
|
|
2085
|
+
console.log(` Encrypting...`);
|
|
2086
|
+
fileContent = await encryptContent(fileContent, options.password);
|
|
2087
|
+
console.log(` Encrypted: ${(fileContent.length / 1024).toFixed(1)} KB`);
|
|
1868
2088
|
}
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
2089
|
+
if (fileContent.length > MAX_FILE_SIZE) {
|
|
2090
|
+
console.log(` Exceeds 8MB, chunking...`);
|
|
2091
|
+
cid = (await storeChunkedContent(chunk(fileContent), providerWithReconnect)).storageCid;
|
|
2092
|
+
} else {
|
|
2093
|
+
cid = await storeFile(fileContent, providerWithReconnect);
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
} else if (content instanceof Uint8Array) {
|
|
2097
|
+
setDeployAttribute("deploy.content_type", "multiChunk");
|
|
1874
2098
|
console.log(`
|
|
1875
|
-
Mode:
|
|
1876
|
-
|
|
1877
|
-
let fileContent = fs.readFileSync(contentPath);
|
|
2099
|
+
Mode: Bytes`);
|
|
2100
|
+
let bytesContent = content;
|
|
1878
2101
|
if (options.password) {
|
|
1879
2102
|
setDeployAttribute("deploy.encrypted", "true");
|
|
1880
2103
|
console.log(` Encrypting...`);
|
|
1881
|
-
|
|
1882
|
-
console.log(` Encrypted: ${(
|
|
2104
|
+
bytesContent = await encryptContent(bytesContent, options.password);
|
|
2105
|
+
console.log(` Encrypted: ${(bytesContent.length / 1024).toFixed(1)} KB`);
|
|
1883
2106
|
}
|
|
1884
|
-
if (
|
|
2107
|
+
if (bytesContent.length > MAX_FILE_SIZE) {
|
|
1885
2108
|
console.log(` Exceeds 8MB, chunking...`);
|
|
1886
|
-
cid = (await storeChunkedContent(chunk(
|
|
2109
|
+
cid = (await storeChunkedContent(chunk(bytesContent), providerWithReconnect)).storageCid;
|
|
1887
2110
|
} else {
|
|
1888
|
-
cid = await storeFile(
|
|
2111
|
+
cid = await storeFile(bytesContent, providerWithReconnect);
|
|
1889
2112
|
}
|
|
1890
|
-
}
|
|
1891
|
-
} else if (content instanceof Uint8Array) {
|
|
1892
|
-
setDeployAttribute("deploy.content_type", "multiChunk");
|
|
1893
|
-
console.log(`
|
|
1894
|
-
Mode: Bytes`);
|
|
1895
|
-
let bytesContent = content;
|
|
1896
|
-
if (options.password) {
|
|
1897
|
-
setDeployAttribute("deploy.encrypted", "true");
|
|
1898
|
-
console.log(` Encrypting...`);
|
|
1899
|
-
bytesContent = await encryptContent(bytesContent, options.password);
|
|
1900
|
-
console.log(` Encrypted: ${(bytesContent.length / 1024).toFixed(1)} KB`);
|
|
1901
|
-
}
|
|
1902
|
-
if (bytesContent.length > MAX_FILE_SIZE) {
|
|
1903
|
-
console.log(` Exceeds 8MB, chunking...`);
|
|
1904
|
-
cid = (await storeChunkedContent(chunk(bytesContent), providerWithReconnect)).storageCid;
|
|
1905
2113
|
} else {
|
|
1906
|
-
|
|
2114
|
+
throw new Error("Invalid content: must be path, Uint8Array, or Array<Uint8Array>");
|
|
1907
2115
|
}
|
|
1908
|
-
}
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
if (options.attributes) {
|
|
1914
|
-
for (const [key, value] of Object.entries(options.attributes)) {
|
|
1915
|
-
setDeployAttribute(key, value);
|
|
1916
|
-
}
|
|
1917
|
-
}
|
|
1918
|
-
console.log("\n" + "=".repeat(60));
|
|
1919
|
-
console.log("DotNS");
|
|
1920
|
-
console.log("=".repeat(60));
|
|
1921
|
-
await withSpan("deploy.dotns", "2. dotns", { "deploy.domain": name, "deploy.subdomain": String(parsed?.isSubdomain ?? false) }, async () => {
|
|
1922
|
-
const dotns = new DotNS();
|
|
1923
|
-
await dotns.connect(resolveDotnsConnectOptions(options, envAssetHub, envAutoAccountMapping, envContracts, envNativeToEthRatio, envId, envPopSelfServe, envRegisterStorageDeposit));
|
|
1924
|
-
if (parsed?.isSubdomain) {
|
|
1925
|
-
const { owned, owner } = await dotns.checkSubdomainOwnership(parsed.sublabel, parsed.parentLabel);
|
|
1926
|
-
if (owned) {
|
|
1927
|
-
console.log(` Status: Already owned`);
|
|
1928
|
-
} else if (owner) {
|
|
1929
|
-
throw new Error(`Subdomain ${parsed.fullName} is owned by ${owner}, not ${dotns.evmAddress}`);
|
|
1930
|
-
} else {
|
|
1931
|
-
const parentOwnership = await dotns.checkOwnership(parsed.parentLabel);
|
|
1932
|
-
if (!parentOwnership.owned) throw new Error(`You must own ${parsed.parentLabel}.dot to register subdomains under it`);
|
|
1933
|
-
console.log(` Status: Registering subdomain...`);
|
|
1934
|
-
await dotns.registerSubdomain(parsed.sublabel, parsed.parentLabel);
|
|
1935
|
-
}
|
|
1936
|
-
} else {
|
|
1937
|
-
const { owned } = await dotns.checkOwnership(name);
|
|
1938
|
-
if (owned) {
|
|
1939
|
-
console.log(` Status: Already owned`);
|
|
1940
|
-
} else {
|
|
1941
|
-
console.log(` Status: Registering...`);
|
|
1942
|
-
await dotns.register(name);
|
|
2116
|
+
});
|
|
2117
|
+
setDeployAttribute("deploy.cid", cid);
|
|
2118
|
+
if (options.attributes) {
|
|
2119
|
+
for (const [key, value] of Object.entries(options.attributes)) {
|
|
2120
|
+
setDeployAttribute(key, value);
|
|
1943
2121
|
}
|
|
1944
2122
|
}
|
|
1945
|
-
const contenthashHex = `0x${encodeContenthash(cid)}`;
|
|
1946
|
-
await dotns.setContenthash(name, contenthashHex);
|
|
1947
|
-
if (options.publish && parsed) {
|
|
1948
|
-
await publish(dotns, parsed, options.failOnPublishError);
|
|
1949
|
-
}
|
|
1950
|
-
dotns.disconnect();
|
|
1951
|
-
});
|
|
1952
|
-
await withSpan("deploy.p2p-check", "3. p2p-check", { "deploy.domain": name }, async () => {
|
|
1953
|
-
const probe = await probeP2pRetrieval(provider.client, cid);
|
|
1954
|
-
setDeployAttribute("deploy.p2p.retrievable", probe.retrievable ? "true" : "false");
|
|
1955
|
-
setDeployAttribute("deploy.p2p.check_ms", String(probe.durationMs));
|
|
1956
|
-
setDeployAttribute("deploy.p2p.error_variant", probe.errorVariant);
|
|
1957
|
-
if (probe.retrievable) {
|
|
1958
|
-
console.log(` P2P retrieval: \u2713 (${probe.durationMs}ms)`);
|
|
1959
|
-
} else {
|
|
1960
|
-
console.log(` P2P retrieval: \u26A0 not yet retrievable (${probe.errorVariant}, ${probe.durationMs}ms)`);
|
|
1961
|
-
}
|
|
1962
|
-
});
|
|
1963
|
-
if (options.ghPagesMirror) {
|
|
1964
2123
|
console.log("\n" + "=".repeat(60));
|
|
1965
|
-
console.log("
|
|
2124
|
+
console.log("DotNS");
|
|
1966
2125
|
console.log("=".repeat(60));
|
|
1967
|
-
await withSpan("deploy.
|
|
1968
|
-
const
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
2126
|
+
await withSpan("deploy.dotns", "2. dotns", { "deploy.domain": name, "deploy.subdomain": String(parsed?.isSubdomain ?? false) }, async () => {
|
|
2127
|
+
const dotns = new DotNS();
|
|
2128
|
+
await dotns.connect(resolveDotnsConnectOptions(options, envAssetHub, envAutoAccountMapping, envContracts, envNativeToEthRatio, envId, envPopSelfServe, envRegisterStorageDeposit));
|
|
2129
|
+
if (parsed?.isSubdomain) {
|
|
2130
|
+
const { owned, owner } = await dotns.checkSubdomainOwnership(parsed.sublabel, parsed.parentLabel);
|
|
2131
|
+
if (owned) {
|
|
2132
|
+
console.log(` Status: Already owned`);
|
|
2133
|
+
} else if (owner) {
|
|
2134
|
+
throw new Error(`Subdomain ${parsed.fullName} is owned by ${owner}, not ${dotns.evmAddress}`);
|
|
2135
|
+
} else {
|
|
2136
|
+
const parentOwnership = await dotns.checkOwnership(parsed.parentLabel);
|
|
2137
|
+
if (!parentOwnership.owned) throw new Error(`You must own ${parsed.parentLabel}.dot to register subdomains under it`);
|
|
2138
|
+
console.log(` Status: Registering subdomain...`);
|
|
2139
|
+
await dotns.registerSubdomain(parsed.sublabel, parsed.parentLabel);
|
|
2140
|
+
}
|
|
2141
|
+
} else {
|
|
2142
|
+
const { owned } = await dotns.checkOwnership(name);
|
|
2143
|
+
if (owned) {
|
|
2144
|
+
console.log(` Status: Already owned`);
|
|
2145
|
+
} else {
|
|
2146
|
+
console.log(` Status: Registering...`);
|
|
2147
|
+
await dotns.register(name);
|
|
2148
|
+
}
|
|
1976
2149
|
}
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2150
|
+
const contenthashHex = `0x${encodeContenthash(cid)}`;
|
|
2151
|
+
await dotns.setContenthash(name, contenthashHex);
|
|
2152
|
+
if (options.publish && parsed) {
|
|
2153
|
+
await publish(dotns, parsed, options.failOnPublishError);
|
|
1981
2154
|
}
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2155
|
+
dotns.disconnect();
|
|
2156
|
+
});
|
|
2157
|
+
await withSpan("deploy.p2p-check", "3. p2p-check", { "deploy.domain": name }, async () => {
|
|
2158
|
+
const probe = await probeP2pRetrieval(provider.client, cid);
|
|
2159
|
+
setDeployAttribute("deploy.p2p.retrievable", probe.retrievable ? "true" : "false");
|
|
2160
|
+
setDeployAttribute("deploy.p2p.check_ms", String(probe.durationMs));
|
|
2161
|
+
setDeployAttribute("deploy.p2p.error_variant", probe.errorVariant);
|
|
2162
|
+
if (probe.retrievable) {
|
|
2163
|
+
console.log(` P2P retrieval: \u2713 (${probe.durationMs}ms)`);
|
|
1990
2164
|
} else {
|
|
1991
|
-
console.log(`
|
|
1992
|
-
console.log(` GitHub Pages last served cid=${freshness.lastCid ?? "n/a"} (expected ${cid}); it should catch up shortly. Non-fatal.`);
|
|
1993
|
-
setDeployAttribute("deploy.gh_pages_freshness_verified", "false");
|
|
2165
|
+
console.log(` P2P retrieval: \u26A0 not yet retrievable (${probe.errorVariant}, ${probe.durationMs}ms)`);
|
|
1994
2166
|
}
|
|
1995
2167
|
});
|
|
2168
|
+
if (options.ghPagesMirror) {
|
|
2169
|
+
console.log("\n" + "=".repeat(60));
|
|
2170
|
+
console.log("Final checks");
|
|
2171
|
+
console.log("=".repeat(60));
|
|
2172
|
+
await withSpan("deploy.gh-pages-mirror", "4. gh-pages-mirror", { "deploy.domain": name }, async () => {
|
|
2173
|
+
const mirror = await mirrorPromise;
|
|
2174
|
+
if (mirror === null) {
|
|
2175
|
+
console.log(" GitHub Pages mirror: skipped (only directory deploys produce a CAR suitable for mirroring).");
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
2178
|
+
if (mirror instanceof MirrorSkipped) {
|
|
2179
|
+
console.log(` GitHub Pages mirror: skipped \u2014 ${mirror.message}`);
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2182
|
+
if (mirror instanceof Error) {
|
|
2183
|
+
console.log(` GitHub Pages mirror: failed (non-fatal) \u2014 ${mirror.message}`);
|
|
2184
|
+
captureWarning("gh-pages mirror failed", { error: mirror.message.slice(0, 200) });
|
|
2185
|
+
return;
|
|
2186
|
+
}
|
|
2187
|
+
console.log(` Mirror: ${mirror.url}`);
|
|
2188
|
+
console.log(` Manifest: https://${mirror.owner}.github.io/${mirror.repo}/${mirror.manifestPath}`);
|
|
2189
|
+
setDeployAttribute("deploy.gh_pages_url", mirror.url);
|
|
2190
|
+
process.stdout.write(" Verifying Pages serves this deploy's CAR... ");
|
|
2191
|
+
const freshness = await pollMirrorFreshness(mirror.url, cid, { timeoutMs: 3 * 60 * 1e3, intervalMs: 1e4 });
|
|
2192
|
+
if (freshness.verified) {
|
|
2193
|
+
console.log(`ok (${freshness.attempts} attempt${freshness.attempts === 1 ? "" : "s"}, ${(freshness.durationMs / 1e3).toFixed(0)}s).`);
|
|
2194
|
+
setDeployAttribute("deploy.gh_pages_freshness_verified", "true");
|
|
2195
|
+
} else {
|
|
2196
|
+
console.log(`timed out.`);
|
|
2197
|
+
console.log(` GitHub Pages last served cid=${freshness.lastCid ?? "n/a"} (expected ${cid}); it should catch up shortly. Non-fatal.`);
|
|
2198
|
+
setDeployAttribute("deploy.gh_pages_freshness_verified", "false");
|
|
2199
|
+
}
|
|
2200
|
+
});
|
|
2201
|
+
}
|
|
2202
|
+
console.log("\n" + "=".repeat(60));
|
|
2203
|
+
console.log("DEPLOYMENT COMPLETE!");
|
|
2204
|
+
console.log("=".repeat(60));
|
|
2205
|
+
console.log("\n\u{1F53A} Polkadot Triangle");
|
|
2206
|
+
console.log(` - Polkadot Desktop: ${name}.dot`);
|
|
2207
|
+
console.log(` - Polkadot Browser: ${browserUrlFor(name, envId)}`);
|
|
2208
|
+
console.log("\n" + "=".repeat(60) + "\n");
|
|
2209
|
+
return { domainName: name, fullDomain: `${name}.dot`, cid, ipfsCid };
|
|
2210
|
+
} finally {
|
|
2211
|
+
if (_deployRpcFailedOver) setDeployAttribute("deploy.rpc.failed_over", "true");
|
|
2212
|
+
provider?.client.destroy();
|
|
1996
2213
|
}
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
console.log(` - Polkadot Desktop: ${name}.dot`);
|
|
2002
|
-
console.log(` - Polkadot Browser: ${browserUrlFor(name, envId)}`);
|
|
2003
|
-
console.log("\n" + "=".repeat(60) + "\n");
|
|
2004
|
-
return { domainName: name, fullDomain: `${name}.dot`, cid, ipfsCid };
|
|
2005
|
-
} finally {
|
|
2006
|
-
if (_deployRpcFailedOver) setDeployAttribute("deploy.rpc.failed_over", "true");
|
|
2007
|
-
provider?.client.destroy();
|
|
2008
|
-
}
|
|
2009
|
-
});
|
|
2214
|
+
});
|
|
2215
|
+
} finally {
|
|
2216
|
+
sessionCleanup?.();
|
|
2217
|
+
}
|
|
2010
2218
|
}
|
|
2011
2219
|
|
|
2012
2220
|
// src/merkle.ts
|
|
@@ -2183,12 +2391,13 @@ async function merkleizeKuboBackend(directoryPath) {
|
|
|
2183
2391
|
const { fileBlocks, fileCids, rootBlockCids, subdirCids } = walkFileBlocks(cidStr, blocks);
|
|
2184
2392
|
return { rootCid: cidStr, blocks, fileBlocks, fileCids, rootBlockCids, subdirCids };
|
|
2185
2393
|
}
|
|
2186
|
-
async function merkleizeBackend(directoryPath, useKubo) {
|
|
2394
|
+
async function merkleizeBackend(directoryPath, useKubo, phase) {
|
|
2395
|
+
const tag = phase ? ` \u2014 ${phase}` : "";
|
|
2187
2396
|
if (useKubo) {
|
|
2188
|
-
console.log(` Merkleizing (Kubo): ${directoryPath}`);
|
|
2397
|
+
console.log(` Merkleizing (Kubo${tag}): ${directoryPath}`);
|
|
2189
2398
|
return merkleizeKuboBackend(directoryPath);
|
|
2190
2399
|
}
|
|
2191
|
-
console.log(` Merkleizing (JS): ${directoryPath}`);
|
|
2400
|
+
console.log(` Merkleizing (JS${tag}): ${directoryPath}`);
|
|
2192
2401
|
return merkleizeJSBackend(directoryPath);
|
|
2193
2402
|
}
|
|
2194
2403
|
function encodeCarFrame(cid, payload) {
|
|
@@ -2237,6 +2446,7 @@ function frameBlockCid(frame) {
|
|
|
2237
2446
|
async function buildOrderedCar(options) {
|
|
2238
2447
|
const { output, prevStableOrder = [] } = options;
|
|
2239
2448
|
const clsFn = options.classifyFn ?? ((p) => classifyFile(p));
|
|
2449
|
+
const tag = options.phase ? ` \u2014 ${options.phase}` : "";
|
|
2240
2450
|
const MANIFEST_PATH_LITERAL = ".bulletin-deploy/manifest.json";
|
|
2241
2451
|
const stableFiles = [];
|
|
2242
2452
|
const volatileFiles = [];
|
|
@@ -2321,7 +2531,7 @@ async function buildOrderedCar(options) {
|
|
|
2321
2531
|
const s1Bytes = section1Chunks.reduce((s, b) => s + b.length, 0);
|
|
2322
2532
|
const s2Bytes = section2Chunks.reduce((s, b) => s + b.length, 0);
|
|
2323
2533
|
console.log(
|
|
2324
|
-
` CAR (3-section): ${(carBytes.length / 1024 / 1024).toFixed(2)} MB (s0=${section0Bytes.length}B s1=${s1Bytes}B s2=${s2Bytes}B), ${allChunks.length} frames (${section0Chunks.length} header + ${section1Chunks.length} data + ${section2Chunks.length} manifest)`
|
|
2534
|
+
` CAR (3-section${tag}): ${(carBytes.length / 1024 / 1024).toFixed(2)} MB (s0=${section0Bytes.length}B s1=${s1Bytes}B s2=${s2Bytes}B), ${allChunks.length} frames (${section0Chunks.length} header + ${section1Chunks.length} data + ${section2Chunks.length} manifest)`
|
|
2325
2535
|
);
|
|
2326
2536
|
return {
|
|
2327
2537
|
carBytes,
|
|
@@ -2358,8 +2568,9 @@ async function rebuildOrderedCarFromBytes(carBytes, prevStableOrder = []) {
|
|
|
2358
2568
|
}
|
|
2359
2569
|
async function merkleizeWithStableOrder(directoryPath, prevStableOrder, options) {
|
|
2360
2570
|
const useKubo = options?.useKubo ?? false;
|
|
2361
|
-
const
|
|
2362
|
-
|
|
2571
|
+
const phase = options?.phase;
|
|
2572
|
+
const output = await merkleizeBackend(directoryPath, useKubo, phase);
|
|
2573
|
+
return buildOrderedCar({ output, classifyFn: options?.classifyFn, prevStableOrder, phase });
|
|
2363
2574
|
}
|
|
2364
2575
|
async function merkleizeJS(directoryPath) {
|
|
2365
2576
|
console.log(` Merkleizing (JS): ${directoryPath}`);
|
|
@@ -2403,11 +2614,18 @@ export {
|
|
|
2403
2614
|
rebuildOrderedCarFromBytes,
|
|
2404
2615
|
merkleizeWithStableOrder,
|
|
2405
2616
|
merkleizeJS,
|
|
2617
|
+
readBulletinSlotSigner,
|
|
2618
|
+
writeBulletinSlotKey,
|
|
2619
|
+
extractBulletinSlotKey,
|
|
2620
|
+
getSlotSignerProvider,
|
|
2406
2621
|
friendlyChainError,
|
|
2407
2622
|
DEFAULT_BULLETIN_RPC,
|
|
2408
2623
|
DEFAULT_POOL_SIZE,
|
|
2624
|
+
BULLETIN_ENDPOINTS,
|
|
2409
2625
|
setWsHaltCallback,
|
|
2626
|
+
makeBulletinStatusHandler,
|
|
2410
2627
|
CHUNK_MORTALITY_PERIOD,
|
|
2628
|
+
WS_HEARTBEAT_TIMEOUT_MS,
|
|
2411
2629
|
retryBudgetExhausted,
|
|
2412
2630
|
isConnectionError,
|
|
2413
2631
|
deriveRootSigner,
|
|
@@ -2421,6 +2639,7 @@ export {
|
|
|
2421
2639
|
ENCRYPT_PBKDF2_ITERATIONS,
|
|
2422
2640
|
encryptContent,
|
|
2423
2641
|
__selectStorageProviderModeForTest,
|
|
2642
|
+
chooseSignerInput,
|
|
2424
2643
|
storeFile,
|
|
2425
2644
|
__assignDenseNoncesForTest,
|
|
2426
2645
|
storeChunkedContent,
|