@parity/product-deploy 0.8.3-rc.6 → 0.8.3-rc.8
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-22CE57IY.js → chunk-3OWKSL7K.js} +1 -1
- package/dist/chunk-7DGFJC6E.js +379 -0
- package/dist/{chunk-3TOFKDMY.js → chunk-EGNMZHMR.js} +1 -1
- package/dist/chunk-JQKKMUCT.js +0 -0
- package/dist/{chunk-L5Z3TJD7.js → chunk-OCKCB72S.js} +6 -6
- package/dist/{chunk-YUIBBHS2.js → chunk-OFVBJOFB.js} +1 -1
- package/dist/chunk-RIRDBSBG.js +36 -0
- package/dist/{chunk-Y7F57J2T.js → chunk-RPU72Z4B.js} +606 -384
- package/dist/{chunk-6XDIJYDO.js → chunk-T4PAK4YK.js} +2 -2
- package/dist/{chunk-M6DM2NUT.js → chunk-WHMNBSG7.js} +8 -2
- package/dist/{chunk-3ASTLJSZ.js → chunk-YOQLRCQV.js} +2 -2
- package/dist/{chunk-LX77LVIM.js → chunk-YXGNQZZF.js} +17 -3
- 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-T4PAK4YK.js";
|
|
24
34
|
import {
|
|
25
35
|
probeChunks
|
|
26
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-3OWKSL7K.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-EGNMZHMR.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-WHMNBSG7.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,416 @@ 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);
|
|
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
|
+
let resolvedUserSession = void 0;
|
|
1820
|
+
if (signerChoice === "resolve") {
|
|
1821
|
+
const { resolveSigner: resolveSignerFn } = await import("./auth/index.js");
|
|
1822
|
+
const { getAuthClient } = await import("./auth-config.js");
|
|
1823
|
+
const authClient = await getAuthClient(envId);
|
|
1824
|
+
try {
|
|
1825
|
+
const resolved = await resolveSignerFn(authClient, { suri: options.suri });
|
|
1826
|
+
options = { ...options, signer: resolved.signer, signerAddress: resolved.address };
|
|
1827
|
+
sessionCleanup = resolved.destroy.bind(resolved);
|
|
1828
|
+
console.log(` Using ${resolved.source} signer: ${resolved.address}`);
|
|
1829
|
+
if (resolved.source === "session") resolvedUserSession = resolved;
|
|
1830
|
+
} catch (e) {
|
|
1831
|
+
if (options.suri) throw e;
|
|
1832
|
+
if (e?.name === "SignerNotAvailableError") {
|
|
1833
|
+
console.log(
|
|
1834
|
+
" Login session unavailable or expired \u2014 falling back to pool. Run `bulletin-deploy login` to use your identity."
|
|
1835
|
+
);
|
|
1836
|
+
} else {
|
|
1837
|
+
throw e;
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
if (!options.storageSigner) {
|
|
1842
|
+
try {
|
|
1843
|
+
let slotResult = await readBulletinSlotSigner(DOT_DAPP_ID);
|
|
1844
|
+
if (!slotResult && resolvedUserSession?.userSession) {
|
|
1845
|
+
const { requestResourceAllocation } = await import("./auth/index.js");
|
|
1846
|
+
console.log("Requesting Bulletin storage allowance \u2014 check your phone to approve");
|
|
1847
|
+
const outcomes = await requestResourceAllocation(
|
|
1848
|
+
resolvedUserSession.userSession,
|
|
1849
|
+
DOT_PRODUCT_ID,
|
|
1850
|
+
[{ tag: "BulletInAllowance", value: void 0 }]
|
|
1851
|
+
);
|
|
1852
|
+
const hexKey = extractBulletinSlotKey(outcomes);
|
|
1853
|
+
if (hexKey) {
|
|
1854
|
+
await writeBulletinSlotKey(DOT_DAPP_ID, hexKey);
|
|
1855
|
+
slotResult = await readBulletinSlotSigner(DOT_DAPP_ID);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
if (slotResult) {
|
|
1859
|
+
options = { ...options, storageSigner: slotResult.signer, storageSignerAddress: slotResult.ss58 };
|
|
1860
|
+
}
|
|
1861
|
+
} catch {
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1657
1864
|
initTelemetry();
|
|
1658
1865
|
const randomSuffix = Math.floor(Math.random() * 100).toString().padStart(2, "0");
|
|
1659
1866
|
const parsed = domainName ? parseDomainName(domainName) : null;
|
|
1660
1867
|
const name = parsed ? parsed.label : `test-domain-${Date.now().toString(36)}${randomSuffix}`;
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
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;
|
|
1689
|
-
try {
|
|
1868
|
+
try {
|
|
1869
|
+
return await withDeploySpan(name, async () => {
|
|
1870
|
+
const deployTag = options.tag ?? process.env.DEPLOY_TAG;
|
|
1871
|
+
if (deployTag) {
|
|
1872
|
+
setDeployAttribute("deploy.tag", deployTag);
|
|
1873
|
+
setDeploySentryTag("deploy.tag", deployTag);
|
|
1874
|
+
}
|
|
1875
|
+
setDeployAttribute("deploy.env", envId);
|
|
1876
|
+
setDeployAttribute("deploy.label", parsed?.label ?? name);
|
|
1877
|
+
setDeployAttribute("deploy.subdomain", String(parsed?.isSubdomain ?? false));
|
|
1878
|
+
if (envNetwork) setDeployAttribute("deploy.network", envNetwork);
|
|
1879
|
+
if (envSource) setDeployAttribute("deploy.environments_source", envSource);
|
|
1880
|
+
let cid;
|
|
1881
|
+
let ipfsCid;
|
|
1882
|
+
let mirrorPromise = Promise.resolve(null);
|
|
1690
1883
|
console.log("\n" + "=".repeat(60));
|
|
1691
|
-
console.log(
|
|
1884
|
+
console.log(`DEPLOYING TO TESTNET v${VERSION}`);
|
|
1692
1885
|
console.log("=".repeat(60));
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
if (
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1886
|
+
if (envName) console.log(` Environment: ${envName}`);
|
|
1887
|
+
console.log(` Domain: ${name}.dot`);
|
|
1888
|
+
if (deployTag) console.log(` Tag: ${deployTag}`);
|
|
1889
|
+
if (options.inputCar) console.log(` Input CAR: ${path.resolve(options.inputCar)}`);
|
|
1890
|
+
else if (typeof content === "string") console.log(` Build dir: ${path.resolve(content)}`);
|
|
1891
|
+
if (process.env.CI) console.log(` Runner: ${resolveRunner()} (${resolveRunnerType()})`);
|
|
1892
|
+
if (options.password) console.log(` Encrypted: yes`);
|
|
1893
|
+
let provider;
|
|
1894
|
+
const reconnect = selectStorageReconnect(options);
|
|
1895
|
+
let dotnsPreflight = null;
|
|
1896
|
+
let previousContenthashCid = null;
|
|
1897
|
+
try {
|
|
1898
|
+
console.log("\n" + "=".repeat(60));
|
|
1899
|
+
console.log("Preflight");
|
|
1900
|
+
console.log("=".repeat(60));
|
|
1901
|
+
const preflight = new DotNS();
|
|
1902
|
+
await preflight.connect(resolveDotnsConnectOptions(options, envAssetHub, envAutoAccountMapping, envContracts, envNativeToEthRatio, envId, envPopSelfServe, envRegisterStorageDeposit));
|
|
1903
|
+
if (parsed?.isSubdomain) {
|
|
1904
|
+
try {
|
|
1905
|
+
const subResult = await preflight.checkSubdomainOwnership(parsed.sublabel, parsed.parentLabel);
|
|
1906
|
+
assertSubdomainOwnerMatchesSigner(subResult, preflight.evmAddress, parsed.sublabel, parsed.parentLabel);
|
|
1907
|
+
if (!subResult.owned) {
|
|
1908
|
+
const { owned: parentOwned, owner: parentOwner } = await preflight.checkOwnership(parsed.parentLabel);
|
|
1909
|
+
if (!parentOwned) {
|
|
1910
|
+
throw new NonRetryableError(
|
|
1911
|
+
`Cannot deploy ${parsed.fullName}: parent ${parsed.parentLabel}.dot is owned by ${parentOwner ?? "no one"}, not by this signer.`
|
|
1912
|
+
);
|
|
1913
|
+
}
|
|
1705
1914
|
}
|
|
1915
|
+
previousContenthashCid = await readPreviousContenthashSafe(preflight, parsed.fullName);
|
|
1916
|
+
setDeployAttribute("deploy.incremental", previousContenthashCid ? "true" : "false");
|
|
1917
|
+
} finally {
|
|
1918
|
+
preflight.disconnect();
|
|
1919
|
+
}
|
|
1920
|
+
console.log(` Mode: subdomain (parent ${parsed.parentLabel}.dot owned by signer)`);
|
|
1921
|
+
} else {
|
|
1922
|
+
try {
|
|
1923
|
+
dotnsPreflight = await preflight.preflight(name);
|
|
1924
|
+
previousContenthashCid = await readPreviousContenthashSafe(preflight, name);
|
|
1925
|
+
setDeployAttribute("deploy.incremental", previousContenthashCid ? "true" : "false");
|
|
1926
|
+
} finally {
|
|
1927
|
+
preflight.disconnect();
|
|
1928
|
+
}
|
|
1929
|
+
if (dotnsPreflight) {
|
|
1930
|
+
setDeployAttribute("deploy.dotns.preflight.action", dotnsPreflight.plannedAction);
|
|
1931
|
+
setDeployAttribute("deploy.dotns.preflight.classification", popStatusName(dotnsPreflight.classification.status));
|
|
1932
|
+
}
|
|
1933
|
+
const alreadyOwned = dotnsPreflight.plannedAction === "already-owned-by-us";
|
|
1934
|
+
const reqSuffix = alreadyOwned ? " (already owned, requirement not enforced)" : "";
|
|
1935
|
+
console.log(` DotNS: ${name}.dot requires ${popStatusName(dotnsPreflight.classification.status)}${reqSuffix}`);
|
|
1936
|
+
if (dotnsPreflight.canProceed) {
|
|
1937
|
+
const fromName = popStatusName(dotnsPreflight.userStatus);
|
|
1938
|
+
console.log(` Your PoP: ${fromName}`);
|
|
1939
|
+
console.log(` Domain: ${dotnsPreflight.plannedAction === "already-owned-by-us" ? "owned by you" : "available"}`);
|
|
1940
|
+
}
|
|
1941
|
+
if (!dotnsPreflight.canProceed) {
|
|
1942
|
+
throw new NonRetryableError(
|
|
1943
|
+
dotnsPreflight.reason ?? "DotNS preflight rejected the deploy; please check the label and signer."
|
|
1944
|
+
);
|
|
1706
1945
|
}
|
|
1707
|
-
previousContenthashCid = await readPreviousContenthashSafe(preflight, parsed.fullName);
|
|
1708
|
-
setDeployAttribute("deploy.incremental", previousContenthashCid ? "true" : "false");
|
|
1709
|
-
} finally {
|
|
1710
|
-
preflight.disconnect();
|
|
1711
|
-
}
|
|
1712
|
-
console.log(` Mode: subdomain (parent ${parsed.parentLabel}.dot owned by signer)`);
|
|
1713
|
-
} else {
|
|
1714
|
-
try {
|
|
1715
|
-
dotnsPreflight = await preflight.preflight(name);
|
|
1716
|
-
previousContenthashCid = await readPreviousContenthashSafe(preflight, name);
|
|
1717
|
-
setDeployAttribute("deploy.incremental", previousContenthashCid ? "true" : "false");
|
|
1718
|
-
} finally {
|
|
1719
|
-
preflight.disconnect();
|
|
1720
|
-
}
|
|
1721
|
-
if (dotnsPreflight) {
|
|
1722
|
-
setDeployAttribute("deploy.dotns.preflight.action", dotnsPreflight.plannedAction);
|
|
1723
|
-
setDeployAttribute("deploy.dotns.preflight.classification", popStatusName(dotnsPreflight.classification.status));
|
|
1724
|
-
}
|
|
1725
|
-
const alreadyOwned = dotnsPreflight.plannedAction === "already-owned-by-us";
|
|
1726
|
-
const reqSuffix = alreadyOwned ? " (already owned, requirement not enforced)" : "";
|
|
1727
|
-
console.log(` DotNS: ${name}.dot requires ${popStatusName(dotnsPreflight.classification.status)}${reqSuffix}`);
|
|
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
1946
|
}
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
console.log(`
|
|
1947
|
+
provider = await reconnect();
|
|
1948
|
+
const providerWithReconnect = { ...provider, reconnect };
|
|
1949
|
+
const isTestnet = await detectTestnet(provider.unsafeApi);
|
|
1950
|
+
setDeployAttribute("deploy.is_testnet", isTestnet ? "true" : "false");
|
|
1951
|
+
console.log("\n" + "=".repeat(60));
|
|
1952
|
+
console.log("Storage");
|
|
1953
|
+
console.log("=".repeat(60));
|
|
1954
|
+
setDeployAttribute("deploy.content_type", "unknown");
|
|
1955
|
+
setDeployAttribute("deploy.encrypted", "false");
|
|
1956
|
+
await withSpan("deploy.storage", "1. storage", {}, async () => {
|
|
1957
|
+
if (options.inputCar) {
|
|
1958
|
+
setDeployAttribute("deploy.content_type", "inputCar");
|
|
1959
|
+
const carPath = path.resolve(options.inputCar);
|
|
1960
|
+
if (!fs.existsSync(carPath)) throw new Error(`CAR file not found: ${carPath}`);
|
|
1961
|
+
console.log(`
|
|
1754
1962
|
Mode: Pre-built CAR`);
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1963
|
+
console.log(` Path: ${carPath}`);
|
|
1964
|
+
let carContent = fs.readFileSync(carPath);
|
|
1965
|
+
console.log(` Size: ${(carContent.length / 1024 / 1024).toFixed(2)} MB`);
|
|
1966
|
+
const reader = await CarReader.fromBytes(carContent);
|
|
1967
|
+
const roots = await reader.getRoots();
|
|
1968
|
+
if (roots.length === 0) throw new Error("CAR file has no roots");
|
|
1969
|
+
ipfsCid = roots[0].toString();
|
|
1970
|
+
console.log(` Root CID: ${ipfsCid}`);
|
|
1971
|
+
if (options.password) {
|
|
1972
|
+
setDeployAttribute("deploy.encrypted", "true");
|
|
1973
|
+
console.log(` Encrypting CAR file...`);
|
|
1974
|
+
carContent = await encryptContent(carContent, options.password);
|
|
1975
|
+
console.log(` Encrypted: ${(carContent.length / 1024 / 1024).toFixed(2)} MB`);
|
|
1976
|
+
}
|
|
1977
|
+
let carChunks;
|
|
1978
|
+
if (options.password) {
|
|
1979
|
+
carChunks = chunk(carContent, CHUNK_SIZE);
|
|
1980
|
+
} else {
|
|
1981
|
+
try {
|
|
1982
|
+
let prevStableOrder = [];
|
|
1983
|
+
const manifestBytes = await extractManifestFromCar(carContent);
|
|
1984
|
+
if (manifestBytes) {
|
|
1985
|
+
const parsed2 = parseManifest(Buffer.from(manifestBytes).toString("utf8"));
|
|
1986
|
+
if (parsed2.ok) prevStableOrder = parsed2.manifest.stableBlockOrder;
|
|
1987
|
+
}
|
|
1988
|
+
const rebuilt = await rebuildOrderedCarFromBytes(carContent, prevStableOrder);
|
|
1989
|
+
if (Buffer.compare(Buffer.from(rebuilt.carBytes), Buffer.from(carContent)) === 0) {
|
|
1990
|
+
carChunks = rebuilt.chunks;
|
|
1991
|
+
} else {
|
|
1992
|
+
captureWarning("input CAR ordered rechunk drift; falling back to size chunking", {
|
|
1993
|
+
rootCid: ipfsCid
|
|
1994
|
+
});
|
|
1995
|
+
carChunks = chunk(carContent, CHUNK_SIZE);
|
|
1996
|
+
}
|
|
1997
|
+
} catch (err) {
|
|
1998
|
+
captureWarning("input CAR ordered rechunk failed; falling back to size chunking", {
|
|
1999
|
+
rootCid: ipfsCid,
|
|
2000
|
+
reason: err?.message ?? String(err)
|
|
1786
2001
|
});
|
|
1787
2002
|
carChunks = chunk(carContent, CHUNK_SIZE);
|
|
1788
2003
|
}
|
|
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
2004
|
}
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
console.log(`
|
|
2005
|
+
const predictedStorageCid = computeStorageCid(carChunks);
|
|
2006
|
+
if (options.ghPagesMirror) {
|
|
2007
|
+
mirrorPromise = mirrorToGitHubPages({
|
|
2008
|
+
domain: name,
|
|
2009
|
+
carBytes: carContent,
|
|
2010
|
+
cid: predictedStorageCid,
|
|
2011
|
+
toolVersion: VERSION,
|
|
2012
|
+
bulletinRpc: BULLETIN_ENDPOINTS[0],
|
|
2013
|
+
encrypted: Boolean(options.password)
|
|
2014
|
+
}).catch((err) => err instanceof Error ? err : new Error(String(err)));
|
|
2015
|
+
}
|
|
2016
|
+
cid = (await storeChunkedContent(carChunks, providerWithReconnect)).storageCid;
|
|
2017
|
+
} else if (process.env.IPFS_CID) {
|
|
2018
|
+
setDeployAttribute("deploy.content_type", "ipfsCid");
|
|
2019
|
+
if (options.password) {
|
|
2020
|
+
throw new Error(
|
|
2021
|
+
"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."
|
|
2022
|
+
);
|
|
2023
|
+
}
|
|
2024
|
+
cid = process.env.IPFS_CID;
|
|
2025
|
+
ipfsCid = cid;
|
|
2026
|
+
console.log(`
|
|
1819
2027
|
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");
|
|
2028
|
+
} else if (Array.isArray(content)) {
|
|
2029
|
+
setDeployAttribute("deploy.content_type", "multiChunk");
|
|
1840
2030
|
console.log(`
|
|
2031
|
+
Mode: Multi-chunk (${content.length} chunks)`);
|
|
2032
|
+
let contentChunks = content;
|
|
2033
|
+
if (options.password) {
|
|
2034
|
+
setDeployAttribute("deploy.encrypted", "true");
|
|
2035
|
+
console.log(` Encrypting...`);
|
|
2036
|
+
const encrypted = await encryptContent(Buffer.concat(content), options.password);
|
|
2037
|
+
console.log(` Encrypted: ${(encrypted.length / 1024).toFixed(1)} KB`);
|
|
2038
|
+
contentChunks = chunk(encrypted);
|
|
2039
|
+
}
|
|
2040
|
+
cid = (await storeChunkedContent(contentChunks, providerWithReconnect)).storageCid;
|
|
2041
|
+
} else if (typeof content === "string") {
|
|
2042
|
+
setDeployAttribute("deploy.content_type", "path");
|
|
2043
|
+
const contentPath = path.resolve(content);
|
|
2044
|
+
if (!fs.existsSync(contentPath)) throw new Error(`Path not found: ${contentPath}`);
|
|
2045
|
+
const stats = fs.statSync(contentPath);
|
|
2046
|
+
if (stats.isDirectory()) {
|
|
2047
|
+
setDeployAttribute("deploy.content_type", "directory");
|
|
2048
|
+
console.log(`
|
|
1841
2049
|
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
|
-
|
|
2050
|
+
console.log(` Path: ${contentPath}`);
|
|
2051
|
+
if (previousContenthashCid) console.log(` Incremental: previous contenthash ${previousContenthashCid}`);
|
|
2052
|
+
else console.log(` Incremental: first deploy (no previous contenthash)`);
|
|
2053
|
+
if (options.password) setDeployAttribute("deploy.encrypted", "true");
|
|
2054
|
+
const storeFn = options.password ? storeDirectory : storeDirectoryV2;
|
|
2055
|
+
const { storageCid: sCid, ipfsCid: iCid } = await storeFn(contentPath, {
|
|
2056
|
+
provider: providerWithReconnect,
|
|
2057
|
+
password: options.password,
|
|
2058
|
+
jsMerkle: options.jsMerkle,
|
|
2059
|
+
previousContenthash: previousContenthashCid,
|
|
2060
|
+
allowLargeDeploy: options.allowLargeDeploy,
|
|
2061
|
+
reproducibleSource: options.reproducibleSource,
|
|
2062
|
+
domain: name,
|
|
2063
|
+
gateway: envIpfs,
|
|
2064
|
+
dumpCar: options.dumpCar,
|
|
2065
|
+
onCarReady: (carBytes, predictedCid) => {
|
|
2066
|
+
if (options.ghPagesMirror) {
|
|
2067
|
+
mirrorPromise = mirrorToGitHubPages({
|
|
2068
|
+
domain: name,
|
|
2069
|
+
carBytes,
|
|
2070
|
+
cid: predictedCid,
|
|
2071
|
+
toolVersion: VERSION,
|
|
2072
|
+
bulletinRpc: BULLETIN_ENDPOINTS[0],
|
|
2073
|
+
encrypted: Boolean(options.password)
|
|
2074
|
+
}).catch((err) => err instanceof Error ? err : new Error(String(err)));
|
|
2075
|
+
}
|
|
1867
2076
|
}
|
|
2077
|
+
});
|
|
2078
|
+
cid = sCid;
|
|
2079
|
+
ipfsCid = iCid;
|
|
2080
|
+
} else {
|
|
2081
|
+
setDeployAttribute("deploy.content_type", "file");
|
|
2082
|
+
console.log(`
|
|
2083
|
+
Mode: File`);
|
|
2084
|
+
console.log(` Path: ${contentPath}`);
|
|
2085
|
+
let fileContent = fs.readFileSync(contentPath);
|
|
2086
|
+
if (options.password) {
|
|
2087
|
+
setDeployAttribute("deploy.encrypted", "true");
|
|
2088
|
+
console.log(` Encrypting...`);
|
|
2089
|
+
fileContent = await encryptContent(fileContent, options.password);
|
|
2090
|
+
console.log(` Encrypted: ${(fileContent.length / 1024).toFixed(1)} KB`);
|
|
1868
2091
|
}
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
2092
|
+
if (fileContent.length > MAX_FILE_SIZE) {
|
|
2093
|
+
console.log(` Exceeds 8MB, chunking...`);
|
|
2094
|
+
cid = (await storeChunkedContent(chunk(fileContent), providerWithReconnect)).storageCid;
|
|
2095
|
+
} else {
|
|
2096
|
+
cid = await storeFile(fileContent, providerWithReconnect);
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
} else if (content instanceof Uint8Array) {
|
|
2100
|
+
setDeployAttribute("deploy.content_type", "multiChunk");
|
|
1874
2101
|
console.log(`
|
|
1875
|
-
Mode:
|
|
1876
|
-
|
|
1877
|
-
let fileContent = fs.readFileSync(contentPath);
|
|
2102
|
+
Mode: Bytes`);
|
|
2103
|
+
let bytesContent = content;
|
|
1878
2104
|
if (options.password) {
|
|
1879
2105
|
setDeployAttribute("deploy.encrypted", "true");
|
|
1880
2106
|
console.log(` Encrypting...`);
|
|
1881
|
-
|
|
1882
|
-
console.log(` Encrypted: ${(
|
|
2107
|
+
bytesContent = await encryptContent(bytesContent, options.password);
|
|
2108
|
+
console.log(` Encrypted: ${(bytesContent.length / 1024).toFixed(1)} KB`);
|
|
1883
2109
|
}
|
|
1884
|
-
if (
|
|
2110
|
+
if (bytesContent.length > MAX_FILE_SIZE) {
|
|
1885
2111
|
console.log(` Exceeds 8MB, chunking...`);
|
|
1886
|
-
cid = (await storeChunkedContent(chunk(
|
|
2112
|
+
cid = (await storeChunkedContent(chunk(bytesContent), providerWithReconnect)).storageCid;
|
|
1887
2113
|
} else {
|
|
1888
|
-
cid = await storeFile(
|
|
2114
|
+
cid = await storeFile(bytesContent, providerWithReconnect);
|
|
1889
2115
|
}
|
|
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
2116
|
} else {
|
|
1906
|
-
|
|
2117
|
+
throw new Error("Invalid content: must be path, Uint8Array, or Array<Uint8Array>");
|
|
1907
2118
|
}
|
|
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);
|
|
2119
|
+
});
|
|
2120
|
+
setDeployAttribute("deploy.cid", cid);
|
|
2121
|
+
if (options.attributes) {
|
|
2122
|
+
for (const [key, value] of Object.entries(options.attributes)) {
|
|
2123
|
+
setDeployAttribute(key, value);
|
|
1943
2124
|
}
|
|
1944
2125
|
}
|
|
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
2126
|
console.log("\n" + "=".repeat(60));
|
|
1965
|
-
console.log("
|
|
2127
|
+
console.log("DotNS");
|
|
1966
2128
|
console.log("=".repeat(60));
|
|
1967
|
-
await withSpan("deploy.
|
|
1968
|
-
const
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
2129
|
+
await withSpan("deploy.dotns", "2. dotns", { "deploy.domain": name, "deploy.subdomain": String(parsed?.isSubdomain ?? false) }, async () => {
|
|
2130
|
+
const dotns = new DotNS();
|
|
2131
|
+
await dotns.connect(resolveDotnsConnectOptions(options, envAssetHub, envAutoAccountMapping, envContracts, envNativeToEthRatio, envId, envPopSelfServe, envRegisterStorageDeposit));
|
|
2132
|
+
if (parsed?.isSubdomain) {
|
|
2133
|
+
const { owned, owner } = await dotns.checkSubdomainOwnership(parsed.sublabel, parsed.parentLabel);
|
|
2134
|
+
if (owned) {
|
|
2135
|
+
console.log(` Status: Already owned`);
|
|
2136
|
+
} else if (owner) {
|
|
2137
|
+
throw new Error(`Subdomain ${parsed.fullName} is owned by ${owner}, not ${dotns.evmAddress}`);
|
|
2138
|
+
} else {
|
|
2139
|
+
const parentOwnership = await dotns.checkOwnership(parsed.parentLabel);
|
|
2140
|
+
if (!parentOwnership.owned) throw new Error(`You must own ${parsed.parentLabel}.dot to register subdomains under it`);
|
|
2141
|
+
console.log(` Status: Registering subdomain...`);
|
|
2142
|
+
await dotns.registerSubdomain(parsed.sublabel, parsed.parentLabel);
|
|
2143
|
+
}
|
|
2144
|
+
} else {
|
|
2145
|
+
const { owned } = await dotns.checkOwnership(name);
|
|
2146
|
+
if (owned) {
|
|
2147
|
+
console.log(` Status: Already owned`);
|
|
2148
|
+
} else {
|
|
2149
|
+
console.log(` Status: Registering...`);
|
|
2150
|
+
await dotns.register(name);
|
|
2151
|
+
}
|
|
1976
2152
|
}
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2153
|
+
const contenthashHex = `0x${encodeContenthash(cid)}`;
|
|
2154
|
+
await dotns.setContenthash(name, contenthashHex);
|
|
2155
|
+
if (options.publish && parsed) {
|
|
2156
|
+
await publish(dotns, parsed, options.failOnPublishError);
|
|
1981
2157
|
}
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2158
|
+
dotns.disconnect();
|
|
2159
|
+
});
|
|
2160
|
+
await withSpan("deploy.p2p-check", "3. p2p-check", { "deploy.domain": name }, async () => {
|
|
2161
|
+
const probe = await probeP2pRetrieval(provider.client, cid);
|
|
2162
|
+
setDeployAttribute("deploy.p2p.retrievable", probe.retrievable ? "true" : "false");
|
|
2163
|
+
setDeployAttribute("deploy.p2p.check_ms", String(probe.durationMs));
|
|
2164
|
+
setDeployAttribute("deploy.p2p.error_variant", probe.errorVariant);
|
|
2165
|
+
if (probe.retrievable) {
|
|
2166
|
+
console.log(` P2P retrieval: \u2713 (${probe.durationMs}ms)`);
|
|
1990
2167
|
} 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");
|
|
2168
|
+
console.log(` P2P retrieval: \u26A0 not yet retrievable (${probe.errorVariant}, ${probe.durationMs}ms)`);
|
|
1994
2169
|
}
|
|
1995
2170
|
});
|
|
2171
|
+
if (options.ghPagesMirror) {
|
|
2172
|
+
console.log("\n" + "=".repeat(60));
|
|
2173
|
+
console.log("Final checks");
|
|
2174
|
+
console.log("=".repeat(60));
|
|
2175
|
+
await withSpan("deploy.gh-pages-mirror", "4. gh-pages-mirror", { "deploy.domain": name }, async () => {
|
|
2176
|
+
const mirror = await mirrorPromise;
|
|
2177
|
+
if (mirror === null) {
|
|
2178
|
+
console.log(" GitHub Pages mirror: skipped (only directory deploys produce a CAR suitable for mirroring).");
|
|
2179
|
+
return;
|
|
2180
|
+
}
|
|
2181
|
+
if (mirror instanceof MirrorSkipped) {
|
|
2182
|
+
console.log(` GitHub Pages mirror: skipped \u2014 ${mirror.message}`);
|
|
2183
|
+
return;
|
|
2184
|
+
}
|
|
2185
|
+
if (mirror instanceof Error) {
|
|
2186
|
+
console.log(` GitHub Pages mirror: failed (non-fatal) \u2014 ${mirror.message}`);
|
|
2187
|
+
captureWarning("gh-pages mirror failed", { error: mirror.message.slice(0, 200) });
|
|
2188
|
+
return;
|
|
2189
|
+
}
|
|
2190
|
+
console.log(` Mirror: ${mirror.url}`);
|
|
2191
|
+
console.log(` Manifest: https://${mirror.owner}.github.io/${mirror.repo}/${mirror.manifestPath}`);
|
|
2192
|
+
setDeployAttribute("deploy.gh_pages_url", mirror.url);
|
|
2193
|
+
process.stdout.write(" Verifying Pages serves this deploy's CAR... ");
|
|
2194
|
+
const freshness = await pollMirrorFreshness(mirror.url, cid, { timeoutMs: 3 * 60 * 1e3, intervalMs: 1e4 });
|
|
2195
|
+
if (freshness.verified) {
|
|
2196
|
+
console.log(`ok (${freshness.attempts} attempt${freshness.attempts === 1 ? "" : "s"}, ${(freshness.durationMs / 1e3).toFixed(0)}s).`);
|
|
2197
|
+
setDeployAttribute("deploy.gh_pages_freshness_verified", "true");
|
|
2198
|
+
} else {
|
|
2199
|
+
console.log(`timed out.`);
|
|
2200
|
+
console.log(` GitHub Pages last served cid=${freshness.lastCid ?? "n/a"} (expected ${cid}); it should catch up shortly. Non-fatal.`);
|
|
2201
|
+
setDeployAttribute("deploy.gh_pages_freshness_verified", "false");
|
|
2202
|
+
}
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2205
|
+
console.log("\n" + "=".repeat(60));
|
|
2206
|
+
console.log("DEPLOYMENT COMPLETE!");
|
|
2207
|
+
console.log("=".repeat(60));
|
|
2208
|
+
console.log("\n\u{1F53A} Polkadot Triangle");
|
|
2209
|
+
console.log(` - Polkadot Desktop: ${name}.dot`);
|
|
2210
|
+
console.log(` - Polkadot Browser: ${browserUrlFor(name, envId)}`);
|
|
2211
|
+
console.log("\n" + "=".repeat(60) + "\n");
|
|
2212
|
+
return { domainName: name, fullDomain: `${name}.dot`, cid, ipfsCid };
|
|
2213
|
+
} finally {
|
|
2214
|
+
if (_deployRpcFailedOver) setDeployAttribute("deploy.rpc.failed_over", "true");
|
|
2215
|
+
provider?.client.destroy();
|
|
1996
2216
|
}
|
|
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
|
-
});
|
|
2217
|
+
});
|
|
2218
|
+
} finally {
|
|
2219
|
+
sessionCleanup?.();
|
|
2220
|
+
}
|
|
2010
2221
|
}
|
|
2011
2222
|
|
|
2012
2223
|
// src/merkle.ts
|
|
@@ -2183,12 +2394,13 @@ async function merkleizeKuboBackend(directoryPath) {
|
|
|
2183
2394
|
const { fileBlocks, fileCids, rootBlockCids, subdirCids } = walkFileBlocks(cidStr, blocks);
|
|
2184
2395
|
return { rootCid: cidStr, blocks, fileBlocks, fileCids, rootBlockCids, subdirCids };
|
|
2185
2396
|
}
|
|
2186
|
-
async function merkleizeBackend(directoryPath, useKubo) {
|
|
2397
|
+
async function merkleizeBackend(directoryPath, useKubo, phase) {
|
|
2398
|
+
const tag = phase ? ` \u2014 ${phase}` : "";
|
|
2187
2399
|
if (useKubo) {
|
|
2188
|
-
console.log(` Merkleizing (Kubo): ${directoryPath}`);
|
|
2400
|
+
console.log(` Merkleizing (Kubo${tag}): ${directoryPath}`);
|
|
2189
2401
|
return merkleizeKuboBackend(directoryPath);
|
|
2190
2402
|
}
|
|
2191
|
-
console.log(` Merkleizing (JS): ${directoryPath}`);
|
|
2403
|
+
console.log(` Merkleizing (JS${tag}): ${directoryPath}`);
|
|
2192
2404
|
return merkleizeJSBackend(directoryPath);
|
|
2193
2405
|
}
|
|
2194
2406
|
function encodeCarFrame(cid, payload) {
|
|
@@ -2237,6 +2449,7 @@ function frameBlockCid(frame) {
|
|
|
2237
2449
|
async function buildOrderedCar(options) {
|
|
2238
2450
|
const { output, prevStableOrder = [] } = options;
|
|
2239
2451
|
const clsFn = options.classifyFn ?? ((p) => classifyFile(p));
|
|
2452
|
+
const tag = options.phase ? ` \u2014 ${options.phase}` : "";
|
|
2240
2453
|
const MANIFEST_PATH_LITERAL = ".bulletin-deploy/manifest.json";
|
|
2241
2454
|
const stableFiles = [];
|
|
2242
2455
|
const volatileFiles = [];
|
|
@@ -2321,7 +2534,7 @@ async function buildOrderedCar(options) {
|
|
|
2321
2534
|
const s1Bytes = section1Chunks.reduce((s, b) => s + b.length, 0);
|
|
2322
2535
|
const s2Bytes = section2Chunks.reduce((s, b) => s + b.length, 0);
|
|
2323
2536
|
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)`
|
|
2537
|
+
` 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
2538
|
);
|
|
2326
2539
|
return {
|
|
2327
2540
|
carBytes,
|
|
@@ -2358,8 +2571,9 @@ async function rebuildOrderedCarFromBytes(carBytes, prevStableOrder = []) {
|
|
|
2358
2571
|
}
|
|
2359
2572
|
async function merkleizeWithStableOrder(directoryPath, prevStableOrder, options) {
|
|
2360
2573
|
const useKubo = options?.useKubo ?? false;
|
|
2361
|
-
const
|
|
2362
|
-
|
|
2574
|
+
const phase = options?.phase;
|
|
2575
|
+
const output = await merkleizeBackend(directoryPath, useKubo, phase);
|
|
2576
|
+
return buildOrderedCar({ output, classifyFn: options?.classifyFn, prevStableOrder, phase });
|
|
2363
2577
|
}
|
|
2364
2578
|
async function merkleizeJS(directoryPath) {
|
|
2365
2579
|
console.log(` Merkleizing (JS): ${directoryPath}`);
|
|
@@ -2403,11 +2617,18 @@ export {
|
|
|
2403
2617
|
rebuildOrderedCarFromBytes,
|
|
2404
2618
|
merkleizeWithStableOrder,
|
|
2405
2619
|
merkleizeJS,
|
|
2620
|
+
readBulletinSlotSigner,
|
|
2621
|
+
writeBulletinSlotKey,
|
|
2622
|
+
extractBulletinSlotKey,
|
|
2623
|
+
getSlotSignerProvider,
|
|
2406
2624
|
friendlyChainError,
|
|
2407
2625
|
DEFAULT_BULLETIN_RPC,
|
|
2408
2626
|
DEFAULT_POOL_SIZE,
|
|
2627
|
+
BULLETIN_ENDPOINTS,
|
|
2409
2628
|
setWsHaltCallback,
|
|
2629
|
+
makeBulletinStatusHandler,
|
|
2410
2630
|
CHUNK_MORTALITY_PERIOD,
|
|
2631
|
+
WS_HEARTBEAT_TIMEOUT_MS,
|
|
2411
2632
|
retryBudgetExhausted,
|
|
2412
2633
|
isConnectionError,
|
|
2413
2634
|
deriveRootSigner,
|
|
@@ -2421,6 +2642,7 @@ export {
|
|
|
2421
2642
|
ENCRYPT_PBKDF2_ITERATIONS,
|
|
2422
2643
|
encryptContent,
|
|
2423
2644
|
__selectStorageProviderModeForTest,
|
|
2645
|
+
chooseSignerInput,
|
|
2424
2646
|
storeFile,
|
|
2425
2647
|
__assignDenseNoncesForTest,
|
|
2426
2648
|
storeChunkedContent,
|