@parity/product-deploy 0.8.3 → 0.9.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -201
- package/README.md +9 -3
- package/assets/environments.json +0 -1
- package/dist/auth/index.d.ts +2 -3
- package/dist/auth/index.js +1 -1
- package/dist/auth/vendor/index.d.ts +2 -3
- package/dist/auth/vendor/index.js +1 -1
- package/dist/auth/vendor/ui/index.d.ts +1 -2
- package/dist/auth-C-Pel0AT.d.ts +235 -0
- package/dist/auth-config.d.ts +30 -8
- package/dist/auth-config.js +14 -6
- package/dist/bug-report.js +4 -4
- package/dist/{chunk-XM5MFMMX.js → chunk-2SR5D4CP.js} +19 -15
- package/dist/{chunk-HK3B5MKA.js → chunk-6NW5M3F5.js} +9 -20
- package/dist/{chunk-2OZVKA3D.js → chunk-DHY2ZXVZ.js} +36 -28
- package/dist/chunk-G56VYTUD.js +75 -0
- package/dist/{chunk-5K3RI5C2.js → chunk-GL3U7K2B.js} +0 -1
- package/dist/{chunk-YUSHBZBX.js → chunk-H4LWILH4.js} +32 -6
- package/dist/chunk-J7CYVTAW.js +43 -0
- package/dist/{chunk-WF2XKCEZ.js → chunk-LCKLYFAZ.js} +1 -1
- package/dist/{chunk-3LNKPUZ7.js → chunk-NP4SLURL.js} +1 -1
- package/dist/{chunk-LRRQP7DH.js → chunk-O2NWQLYB.js} +2 -2
- package/dist/{chunk-DKGCOGRT.js → chunk-RD2QHYTL.js} +144 -37
- package/dist/{chunk-S7S7WENB.js → chunk-WZBAQCA5.js} +2 -2
- package/dist/{chunk-JMHX3M4C.js → chunk-YIKGVALU.js} +3 -3
- package/dist/chunk-probe.js +3 -3
- package/dist/commands/login.d.ts +34 -9
- package/dist/commands/login.js +171 -68
- package/dist/commands/logout.d.ts +1 -2
- package/dist/commands/logout.js +5 -3
- package/dist/commands/whoami.d.ts +1 -2
- package/dist/commands/whoami.js +7 -4
- package/dist/deploy.d.ts +7 -1
- package/dist/deploy.js +12 -9
- package/dist/dotns.js +4 -4
- package/dist/environments.js +1 -1
- package/dist/index.js +11 -10
- package/dist/manifest/publish.js +11 -10
- package/dist/manifest/types.d.ts +1 -1
- package/dist/memory-report.js +2 -2
- package/dist/merkle.js +10 -9
- package/dist/personhood/bootstrap.js +10 -10
- package/dist/personhood/people-client.js +4 -4
- package/dist/run-state.js +1 -1
- package/dist/{signer-CriGqahj.d.ts → signer-vR6KKC7V.d.ts} +1 -1
- package/dist/spinner.d.ts +21 -0
- package/dist/spinner.js +6 -0
- package/dist/sss-allowance.d.ts +29 -0
- package/dist/sss-allowance.js +8 -0
- package/dist/storage-signer.d.ts +94 -2
- package/dist/storage-signer.js +18 -9
- package/dist/telemetry.js +2 -2
- package/dist/version-check.d.ts +0 -3
- package/dist/version-check.js +3 -3
- package/package.json +19 -15
- package/dist/allocations-B65Is4Md.d.ts +0 -97
- package/dist/auth-DkRZBK-T.d.ts +0 -122
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
|
|
5
5
|
// src/auth/vendor/auth.ts
|
|
6
6
|
import { readdir, unlink } from "fs/promises";
|
|
7
|
-
import { homedir } from "os";
|
|
7
|
+
import { homedir, platform, release } from "os";
|
|
8
8
|
import { join } from "path";
|
|
9
9
|
import { deriveH160, ss58Encode } from "@parity/product-sdk-address";
|
|
10
10
|
import {
|
|
@@ -95,22 +95,18 @@ function createSessionSigner(session, ref) {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
// src/auth/vendor/allocations.ts
|
|
98
|
+
import {
|
|
99
|
+
requestResourceAllocation as terminalRequestResourceAllocation
|
|
100
|
+
} from "@parity/product-sdk-terminal/host";
|
|
98
101
|
var DEFAULT_RESOURCES = [
|
|
99
102
|
{ tag: "BulletInAllowance", value: void 0 },
|
|
100
103
|
{ tag: "StatementStoreAllowance", value: void 0 },
|
|
101
104
|
// derivation index 0 = the default product account.
|
|
102
105
|
{ tag: "SmartContractAllowance", value: 0 }
|
|
103
106
|
];
|
|
104
|
-
async function requestResourceAllocation(session,
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
resources,
|
|
108
|
-
onExisting
|
|
109
|
-
});
|
|
110
|
-
if (result.isErr()) {
|
|
111
|
-
throw new Error(`Resource allocation request failed: ${result.error.message}`);
|
|
112
|
-
}
|
|
113
|
-
return result.value;
|
|
107
|
+
async function requestResourceAllocation(session, adapter, resources = DEFAULT_RESOURCES, onExisting = "Ignore") {
|
|
108
|
+
const outcomes = await terminalRequestResourceAllocation(session, adapter, resources, { onExisting });
|
|
109
|
+
return outcomes;
|
|
114
110
|
}
|
|
115
111
|
function summarizeOutcomes(outcomes, resources) {
|
|
116
112
|
const granted = [];
|
|
@@ -133,8 +129,13 @@ function createAuthClient(config) {
|
|
|
133
129
|
function createAdapter() {
|
|
134
130
|
return createTerminalAdapter({
|
|
135
131
|
appId: config.dappId,
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
endpoints: config.peopleEndpoints,
|
|
133
|
+
hostMetadata: {
|
|
134
|
+
hostName: config.hostName,
|
|
135
|
+
hostVersion: config.hostVersion,
|
|
136
|
+
platformType: platform(),
|
|
137
|
+
platformVersion: release()
|
|
138
|
+
}
|
|
138
139
|
});
|
|
139
140
|
}
|
|
140
141
|
function deriveSessionAddresses(session) {
|
|
@@ -166,6 +167,8 @@ function createAuthClient(config) {
|
|
|
166
167
|
const sessions = await waitForSessions(adapter);
|
|
167
168
|
if (sessions.length > 0) {
|
|
168
169
|
const addresses = deriveSessionAddresses(sessions[0]);
|
|
170
|
+
adapter.destroy().catch(() => {
|
|
171
|
+
});
|
|
169
172
|
return { kind: "existing", address: addresses.productAddress, addresses };
|
|
170
173
|
}
|
|
171
174
|
const authPromise = adapter.sso.authenticate();
|
|
@@ -214,7 +217,7 @@ function createAuthClient(config) {
|
|
|
214
217
|
}
|
|
215
218
|
});
|
|
216
219
|
let authenticated = false;
|
|
217
|
-
let
|
|
220
|
+
let handle = null;
|
|
218
221
|
try {
|
|
219
222
|
const result = await authPromise;
|
|
220
223
|
result.match(
|
|
@@ -230,8 +233,8 @@ function createAuthClient(config) {
|
|
|
230
233
|
if (authenticated) {
|
|
231
234
|
const sessions = await waitForSessions(adapter, 3e3);
|
|
232
235
|
if (sessions.length > 0) {
|
|
233
|
-
|
|
234
|
-
address =
|
|
236
|
+
handle = buildSessionHandle(adapter, sessions[0]);
|
|
237
|
+
const { address, addresses } = handle;
|
|
235
238
|
onStatus({ step: "success", address, addresses });
|
|
236
239
|
} else {
|
|
237
240
|
onStatus({
|
|
@@ -243,17 +246,9 @@ function createAuthClient(config) {
|
|
|
243
246
|
} finally {
|
|
244
247
|
unsubPairing();
|
|
245
248
|
}
|
|
246
|
-
return
|
|
249
|
+
return handle;
|
|
247
250
|
}
|
|
248
|
-
|
|
249
|
-
const adapter = createAdapter();
|
|
250
|
-
const sessions = await waitForSessions(adapter, 3e3);
|
|
251
|
-
if (sessions.length === 0) {
|
|
252
|
-
adapter.destroy().catch(() => {
|
|
253
|
-
});
|
|
254
|
-
return null;
|
|
255
|
-
}
|
|
256
|
-
const session = sessions[0];
|
|
251
|
+
function buildSessionHandle(adapter, session) {
|
|
257
252
|
const signer = createSigner(session);
|
|
258
253
|
const addresses = deriveSessionAddresses(session);
|
|
259
254
|
let destroyed = false;
|
|
@@ -268,11 +263,22 @@ function createAuthClient(config) {
|
|
|
268
263
|
addresses,
|
|
269
264
|
signer,
|
|
270
265
|
userSession: session,
|
|
266
|
+
adapter,
|
|
271
267
|
destroy
|
|
272
268
|
};
|
|
273
269
|
}
|
|
274
|
-
async function
|
|
275
|
-
|
|
270
|
+
async function getSessionSigner() {
|
|
271
|
+
const adapter = createAdapter();
|
|
272
|
+
const sessions = await waitForSessions(adapter, 3e3);
|
|
273
|
+
if (sessions.length === 0) {
|
|
274
|
+
adapter.destroy().catch(() => {
|
|
275
|
+
});
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
return buildSessionHandle(adapter, sessions[0]);
|
|
279
|
+
}
|
|
280
|
+
async function requestAllocation(session, adapter, resources = DEFAULT_RESOURCES, onExisting = "Ignore") {
|
|
281
|
+
return requestResourceAllocation(session, adapter, resources, onExisting);
|
|
276
282
|
}
|
|
277
283
|
async function findSession() {
|
|
278
284
|
const adapter = createAdapter();
|
|
@@ -292,6 +298,8 @@ function createAuthClient(config) {
|
|
|
292
298
|
const { adapter, address, session } = handle;
|
|
293
299
|
try {
|
|
294
300
|
onStatus({ step: "disconnecting", address });
|
|
301
|
+
await Promise.resolve(session.abortPendingRequests()).catch(() => {
|
|
302
|
+
});
|
|
295
303
|
const result = await adapter.sessions.disconnect(session);
|
|
296
304
|
if (result.isOk()) {
|
|
297
305
|
await clearLocalAppStorage();
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// src/sss-allowance.ts
|
|
2
|
+
import WebSocket from "ws";
|
|
3
|
+
var SSS_PREFIX = new TextEncoder().encode(":statement_allowance:");
|
|
4
|
+
function sssStorageKey(pubkey) {
|
|
5
|
+
if (pubkey.length !== 32) {
|
|
6
|
+
throw new Error(`SSS storage key requires a 32-byte public key, got ${pubkey.length} bytes`);
|
|
7
|
+
}
|
|
8
|
+
const full = new Uint8Array(SSS_PREFIX.length + pubkey.length);
|
|
9
|
+
full.set(SSS_PREFIX, 0);
|
|
10
|
+
full.set(pubkey, SSS_PREFIX.length);
|
|
11
|
+
return "0x" + Buffer.from(full).toString("hex");
|
|
12
|
+
}
|
|
13
|
+
function checkSSSAllowance(pubkey, peopleEndpoints, timeoutMs = 5e3) {
|
|
14
|
+
return new Promise((resolve) => {
|
|
15
|
+
const endpoint = peopleEndpoints[0];
|
|
16
|
+
if (!endpoint) {
|
|
17
|
+
resolve(null);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
let settled = false;
|
|
21
|
+
let timer = null;
|
|
22
|
+
function done(value) {
|
|
23
|
+
if (settled) return;
|
|
24
|
+
settled = true;
|
|
25
|
+
if (timer !== null) clearTimeout(timer);
|
|
26
|
+
try {
|
|
27
|
+
ws.terminate();
|
|
28
|
+
} catch {
|
|
29
|
+
}
|
|
30
|
+
resolve(value);
|
|
31
|
+
}
|
|
32
|
+
let ws;
|
|
33
|
+
try {
|
|
34
|
+
ws = new WebSocket(endpoint);
|
|
35
|
+
} catch {
|
|
36
|
+
resolve(null);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
timer = setTimeout(() => done(null), timeoutMs);
|
|
40
|
+
ws.on("error", () => done(null));
|
|
41
|
+
ws.on("open", () => {
|
|
42
|
+
let storageKey;
|
|
43
|
+
try {
|
|
44
|
+
storageKey = sssStorageKey(pubkey);
|
|
45
|
+
} catch {
|
|
46
|
+
done(null);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const request = JSON.stringify({
|
|
50
|
+
jsonrpc: "2.0",
|
|
51
|
+
id: 1,
|
|
52
|
+
method: "state_getStorage",
|
|
53
|
+
params: [storageKey]
|
|
54
|
+
});
|
|
55
|
+
ws.send(request, (err) => {
|
|
56
|
+
if (err) done(null);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
ws.on("message", (data) => {
|
|
60
|
+
try {
|
|
61
|
+
const msg = JSON.parse(data.toString());
|
|
62
|
+
const result = msg.result;
|
|
63
|
+
const present = result != null && result !== "0x";
|
|
64
|
+
done(present);
|
|
65
|
+
} catch {
|
|
66
|
+
done(null);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
sssStorageKey,
|
|
74
|
+
checkSSSAllowance
|
|
75
|
+
};
|
|
@@ -108,7 +108,6 @@ var environments_default = {
|
|
|
108
108
|
e2eEligible: true,
|
|
109
109
|
backend: "https://identity-backend-next.parity-testnet.parity.io",
|
|
110
110
|
ipfs: "https://paseo-bulletin-next-ipfs.polkadot.io",
|
|
111
|
-
docsUrl: "https://sre.teleport.parity.io/environments/paseo-next/",
|
|
112
111
|
autoAccountMapping: true,
|
|
113
112
|
nativeToEthRatio: 1e8,
|
|
114
113
|
registerStorageDeposit: 2e12,
|
|
@@ -1,17 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VERSION
|
|
3
|
+
} from "./chunk-LCKLYFAZ.js";
|
|
1
4
|
import {
|
|
2
5
|
loadEnvironments
|
|
3
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-GL3U7K2B.js";
|
|
4
7
|
|
|
5
8
|
// src/auth-config.ts
|
|
6
|
-
import { existsSync } from "fs";
|
|
9
|
+
import { existsSync, readdirSync } from "fs";
|
|
7
10
|
import { homedir } from "os";
|
|
8
11
|
import { join } from "path";
|
|
9
12
|
var DOT_DAPP_ID = "dot-cli";
|
|
10
13
|
var DOT_PRODUCT_ID = "playground.dot";
|
|
11
14
|
var DOT_DERIVATION_INDEX = 0;
|
|
12
|
-
var
|
|
15
|
+
var DOT_HOST_NAME = "bulletin-deploy";
|
|
16
|
+
var STALE_SESSION_MESSAGE = 'Stored login session could not be read \u2014 it may have been written by an older version. Run "bulletin-deploy logout", then "bulletin-deploy login" to pair again.';
|
|
13
17
|
function hasPersistedSession() {
|
|
14
|
-
|
|
18
|
+
const dir = join(homedir(), ".polkadot-apps");
|
|
19
|
+
if (!existsSync(dir)) return false;
|
|
20
|
+
const prefix = `${DOT_DAPP_ID}_SsoSessions`;
|
|
21
|
+
try {
|
|
22
|
+
return readdirSync(dir).some((f) => f.startsWith(prefix) && f.endsWith(".json"));
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
15
26
|
}
|
|
16
27
|
function buildAuthConfig(doc, envId) {
|
|
17
28
|
const peopleChain = doc.chains.find((c) => c.id === "people");
|
|
@@ -31,10 +42,22 @@ function buildAuthConfig(doc, envId) {
|
|
|
31
42
|
dappId: DOT_DAPP_ID,
|
|
32
43
|
productId: DOT_PRODUCT_ID,
|
|
33
44
|
derivationIndex: DOT_DERIVATION_INDEX,
|
|
34
|
-
|
|
45
|
+
hostName: DOT_HOST_NAME,
|
|
46
|
+
hostVersion: VERSION,
|
|
35
47
|
peopleEndpoints
|
|
36
48
|
};
|
|
37
49
|
}
|
|
50
|
+
function resolveBulletinEndpoints(doc, envId) {
|
|
51
|
+
const bulletinChain = doc.chains.find((c) => c.id === "bulletin");
|
|
52
|
+
const endpoint = bulletinChain?.endpoints[envId];
|
|
53
|
+
if (!endpoint) return null;
|
|
54
|
+
return Array.isArray(endpoint.wss) ? endpoint.wss : [endpoint.wss];
|
|
55
|
+
}
|
|
56
|
+
async function getPeopleChainEndpoints(envId) {
|
|
57
|
+
const { doc } = await loadEnvironments();
|
|
58
|
+
const config = buildAuthConfig(doc, envId);
|
|
59
|
+
return config.peopleEndpoints;
|
|
60
|
+
}
|
|
38
61
|
async function getAuthClient(envId) {
|
|
39
62
|
const { createAuthClient } = await import("./auth/index.js");
|
|
40
63
|
const { doc } = await loadEnvironments();
|
|
@@ -45,8 +68,11 @@ export {
|
|
|
45
68
|
DOT_DAPP_ID,
|
|
46
69
|
DOT_PRODUCT_ID,
|
|
47
70
|
DOT_DERIVATION_INDEX,
|
|
48
|
-
|
|
71
|
+
DOT_HOST_NAME,
|
|
72
|
+
STALE_SESSION_MESSAGE,
|
|
49
73
|
hasPersistedSession,
|
|
50
74
|
buildAuthConfig,
|
|
75
|
+
resolveBulletinEndpoints,
|
|
76
|
+
getPeopleChainEndpoints,
|
|
51
77
|
getAuthClient
|
|
52
78
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// src/spinner.ts
|
|
2
|
+
var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3
|
+
var FRAME_MS = 120;
|
|
4
|
+
function startSpinner(label, stream = process.stdout) {
|
|
5
|
+
const start = Date.now();
|
|
6
|
+
if (!stream.isTTY) {
|
|
7
|
+
stream.write(` ${label}\u2026
|
|
8
|
+
`);
|
|
9
|
+
let stopped2 = false;
|
|
10
|
+
return {
|
|
11
|
+
stop(finalLine) {
|
|
12
|
+
if (stopped2) return;
|
|
13
|
+
stopped2 = true;
|
|
14
|
+
if (finalLine) stream.write(`${finalLine}
|
|
15
|
+
`);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
let frame = 0;
|
|
20
|
+
const render = () => {
|
|
21
|
+
const elapsed = Math.round((Date.now() - start) / 1e3);
|
|
22
|
+
stream.write(`\r ${FRAMES[frame % FRAMES.length]} ${label}\u2026 (${elapsed}s)\x1B[K`);
|
|
23
|
+
frame++;
|
|
24
|
+
};
|
|
25
|
+
render();
|
|
26
|
+
const interval = setInterval(render, FRAME_MS);
|
|
27
|
+
interval.unref();
|
|
28
|
+
let stopped = false;
|
|
29
|
+
return {
|
|
30
|
+
stop(finalLine) {
|
|
31
|
+
if (stopped) return;
|
|
32
|
+
stopped = true;
|
|
33
|
+
clearInterval(interval);
|
|
34
|
+
stream.write("\r\x1B[K");
|
|
35
|
+
if (finalLine) stream.write(`${finalLine}
|
|
36
|
+
`);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
startSpinner
|
|
43
|
+
};
|
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
classifyErrorArea,
|
|
3
3
|
isInteractive,
|
|
4
4
|
promptYesNo
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-6NW5M3F5.js";
|
|
6
6
|
import {
|
|
7
7
|
VERSION,
|
|
8
8
|
getCurrentSentryTraceId
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-LCKLYFAZ.js";
|
|
10
10
|
|
|
11
11
|
// src/bug-report.ts
|
|
12
12
|
import { execSync, execFileSync } from "child_process";
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
checkSSSAllowance
|
|
3
|
+
} from "./chunk-G56VYTUD.js";
|
|
1
4
|
import {
|
|
2
5
|
MirrorSkipped,
|
|
3
6
|
mirrorToGitHubPages,
|
|
@@ -24,16 +27,17 @@ import {
|
|
|
24
27
|
parseManifest
|
|
25
28
|
} from "./chunk-S7EM5VMW.js";
|
|
26
29
|
import {
|
|
27
|
-
DOT_DAPP_ID,
|
|
28
30
|
DOT_PRODUCT_ID,
|
|
31
|
+
STALE_SESSION_MESSAGE,
|
|
32
|
+
getPeopleChainEndpoints,
|
|
29
33
|
hasPersistedSession
|
|
30
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-H4LWILH4.js";
|
|
31
35
|
import {
|
|
32
36
|
setDeployContext
|
|
33
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-O2NWQLYB.js";
|
|
34
38
|
import {
|
|
35
39
|
probeChunks
|
|
36
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-NP4SLURL.js";
|
|
37
41
|
import {
|
|
38
42
|
packSection
|
|
39
43
|
} from "./chunk-C2TS5MER.js";
|
|
@@ -46,7 +50,7 @@ import {
|
|
|
46
50
|
parseDomainName,
|
|
47
51
|
popStatusName,
|
|
48
52
|
verifyNonceAdvanced
|
|
49
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-WZBAQCA5.js";
|
|
50
54
|
import {
|
|
51
55
|
derivePoolAccounts,
|
|
52
56
|
detectTestnet,
|
|
@@ -68,13 +72,13 @@ import {
|
|
|
68
72
|
truncateAddress,
|
|
69
73
|
withDeploySpan,
|
|
70
74
|
withSpan
|
|
71
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-LCKLYFAZ.js";
|
|
72
76
|
import {
|
|
73
77
|
DEFAULT_ENV_ID,
|
|
74
78
|
getPopSelfServeConfig,
|
|
75
79
|
loadEnvironments,
|
|
76
80
|
resolveEndpoints
|
|
77
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-GL3U7K2B.js";
|
|
78
82
|
import {
|
|
79
83
|
NonRetryableError
|
|
80
84
|
} from "./chunk-ZOC4GITL.js";
|
|
@@ -253,6 +257,76 @@ function extractBulletinSlotKey(outcomes) {
|
|
|
253
257
|
}
|
|
254
258
|
return null;
|
|
255
259
|
}
|
|
260
|
+
var BulletinSlotAuthError = class extends Error {
|
|
261
|
+
reason;
|
|
262
|
+
/** The on-chain expiration block (only set when reason === "expired"). */
|
|
263
|
+
expiration;
|
|
264
|
+
constructor(reason, ss58, expiration) {
|
|
265
|
+
const detail = reason === "expired" && expiration != null ? `expired at block ${expiration}` : "no on-chain authorization found";
|
|
266
|
+
super(`Slot account ${ss58} not authorized on Bulletin (${detail})`);
|
|
267
|
+
this.reason = reason;
|
|
268
|
+
this.expiration = expiration;
|
|
269
|
+
this.name = "BulletinSlotAuthError";
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
function isBulletinAuthActive(auth, blockNumber) {
|
|
273
|
+
if (auth == null) return { active: false, reason: "missing" };
|
|
274
|
+
const exp = Number(auth.expiration ?? 0);
|
|
275
|
+
if (exp <= blockNumber) return { active: false, reason: "expired", expiration: exp };
|
|
276
|
+
return { active: true, expiration: exp };
|
|
277
|
+
}
|
|
278
|
+
async function pollUntilBulletinAuthorized(queryFn, opts = {}) {
|
|
279
|
+
const { pollMs = 2e3, timeoutMs = 9e4 } = opts;
|
|
280
|
+
const debug = Boolean(process.env.DOT_DEBUG);
|
|
281
|
+
const deadline = Date.now() + timeoutMs;
|
|
282
|
+
while (Date.now() < deadline) {
|
|
283
|
+
try {
|
|
284
|
+
const { auth, blockNumber } = await queryFn();
|
|
285
|
+
const result = isBulletinAuthActive(auth, blockNumber);
|
|
286
|
+
if (result.active) {
|
|
287
|
+
if (debug) console.error(`[auth-poll] active expiration=${result.expiration}`);
|
|
288
|
+
return { authorized: true, expiration: result.expiration };
|
|
289
|
+
}
|
|
290
|
+
if (debug) {
|
|
291
|
+
console.error(
|
|
292
|
+
`[auth-poll] not-active reason=${result.reason}` + (result.expiration != null ? ` expiration=${result.expiration}` : "")
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
} catch (e) {
|
|
296
|
+
if (debug) console.error(`[auth-poll] query-errored: ${e instanceof Error ? e.message : String(e)}`);
|
|
297
|
+
}
|
|
298
|
+
const remaining = deadline - Date.now();
|
|
299
|
+
if (remaining <= 0) break;
|
|
300
|
+
await new Promise((r) => setTimeout(r, Math.min(pollMs, remaining)));
|
|
301
|
+
}
|
|
302
|
+
return { authorized: false, reason: "timeout" };
|
|
303
|
+
}
|
|
304
|
+
async function waitForBulletinAuthorization(ss58, opts = {}) {
|
|
305
|
+
const { quiet, endpoints, ...pollOpts } = opts;
|
|
306
|
+
const eps = endpoints && endpoints.length > 0 ? endpoints : BULLETIN_ENDPOINTS;
|
|
307
|
+
const primary = eps[0];
|
|
308
|
+
const onStatusChanged = quiet ? () => {
|
|
309
|
+
} : makeBulletinStatusHandler(primary);
|
|
310
|
+
const client = createPolkadotClient(getWsProvider(
|
|
311
|
+
eps,
|
|
312
|
+
{ heartbeatTimeout: WS_HEARTBEAT_TIMEOUT_MS, onStatusChanged }
|
|
313
|
+
));
|
|
314
|
+
const unsafeApi = client.getUnsafeApi();
|
|
315
|
+
try {
|
|
316
|
+
return await pollUntilBulletinAuthorized(
|
|
317
|
+
async () => {
|
|
318
|
+
const [auth, block] = await Promise.all([
|
|
319
|
+
unsafeApi.query.TransactionStorage.Authorizations.getValue(Enum("Account", ss58)),
|
|
320
|
+
client.getFinalizedBlock()
|
|
321
|
+
]);
|
|
322
|
+
return { auth, blockNumber: block.number };
|
|
323
|
+
},
|
|
324
|
+
pollOpts
|
|
325
|
+
);
|
|
326
|
+
} finally {
|
|
327
|
+
client.destroy();
|
|
328
|
+
}
|
|
329
|
+
}
|
|
256
330
|
async function getSlotSignerProvider(signer, ss58) {
|
|
257
331
|
const primary = BULLETIN_ENDPOINTS[0];
|
|
258
332
|
console.log(` Connecting to Bulletin (slot signer): ${primary}`);
|
|
@@ -265,12 +339,12 @@ async function getSlotSignerProvider(signer, ss58) {
|
|
|
265
339
|
unsafeApi.query.TransactionStorage.Authorizations.getValue(Enum("Account", ss58)),
|
|
266
340
|
client.getFinalizedBlock()
|
|
267
341
|
]);
|
|
268
|
-
const
|
|
269
|
-
if (!
|
|
342
|
+
const result = isBulletinAuthActive(auth, currentBlock.number);
|
|
343
|
+
if (!result.active) {
|
|
270
344
|
client.destroy();
|
|
271
|
-
throw new
|
|
345
|
+
throw new BulletinSlotAuthError(result.reason, ss58, result.expiration);
|
|
272
346
|
}
|
|
273
|
-
console.log(` Using slot signer: ${ss58} (authorized until block ${
|
|
347
|
+
console.log(` Using slot signer: ${ss58} (authorized until block ${result.expiration})`);
|
|
274
348
|
setDeployAttribute("deploy.signer.mode", "slot");
|
|
275
349
|
setDeployAttribute("deploy.signer.address", truncateAddress(ss58));
|
|
276
350
|
return { client, unsafeApi, signer, ss58 };
|
|
@@ -499,6 +573,10 @@ function chooseSignerInput(opts) {
|
|
|
499
573
|
if (opts.hasSession) return "resolve";
|
|
500
574
|
return "pool";
|
|
501
575
|
}
|
|
576
|
+
function formatStorageSignerLine(slotAddress, failReason) {
|
|
577
|
+
if (slotAddress) return ` Storage signer: allowance slot ${slotAddress}`;
|
|
578
|
+
return ` Storage signer: pool fallback (${failReason ?? "no session"})`;
|
|
579
|
+
}
|
|
502
580
|
function selectStorageReconnect(options) {
|
|
503
581
|
if (options.storageSigner && options.storageSignerAddress) {
|
|
504
582
|
let useSlot = true;
|
|
@@ -506,9 +584,20 @@ function selectStorageReconnect(options) {
|
|
|
506
584
|
if (!useSlot) return getProvider();
|
|
507
585
|
try {
|
|
508
586
|
return await getSlotSignerProvider(options.storageSigner, options.storageSignerAddress);
|
|
509
|
-
} catch {
|
|
587
|
+
} catch (e) {
|
|
510
588
|
useSlot = false;
|
|
511
589
|
setDeployAttribute("deploy.signer.mode", "pool-fallback");
|
|
590
|
+
let reason;
|
|
591
|
+
if (e instanceof BulletinSlotAuthError) {
|
|
592
|
+
reason = e.reason === "expired" && e.expiration != null ? `expired at block ${e.expiration}` : "no on-chain authorization found";
|
|
593
|
+
} else {
|
|
594
|
+
reason = e instanceof Error ? e.message : String(e);
|
|
595
|
+
}
|
|
596
|
+
console.warn(
|
|
597
|
+
`\u26A0 Bulletin allowance slot not usable: ${reason}
|
|
598
|
+
Falling back to the shared pool account for storage (fine on testnet).
|
|
599
|
+
To use your own allowance, run: bulletin-deploy logout && bulletin-deploy login`
|
|
600
|
+
);
|
|
512
601
|
return getProvider();
|
|
513
602
|
}
|
|
514
603
|
};
|
|
@@ -1866,43 +1955,56 @@ async function deploy(content, domainName = null, options = {}) {
|
|
|
1866
1955
|
} catch (e) {
|
|
1867
1956
|
if (options.suri) throw e;
|
|
1868
1957
|
if (e?.name === "SignerNotAvailableError") {
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1958
|
+
if (hasSession) {
|
|
1959
|
+
console.error(STALE_SESSION_MESSAGE);
|
|
1960
|
+
} else {
|
|
1961
|
+
console.log(
|
|
1962
|
+
" Login session unavailable or expired \u2014 falling back to pool. Run `bulletin-deploy login` to use your identity."
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1872
1965
|
} else {
|
|
1873
1966
|
throw e;
|
|
1874
1967
|
}
|
|
1875
1968
|
}
|
|
1876
1969
|
}
|
|
1970
|
+
if (resolvedUserSession && options.signer) {
|
|
1971
|
+
try {
|
|
1972
|
+
const productPubkey = options.signer.publicKey;
|
|
1973
|
+
const peopleEndpoints = await getPeopleChainEndpoints(envId);
|
|
1974
|
+
const allowed = await checkSSSAllowance(productPubkey, peopleEndpoints);
|
|
1975
|
+
if (allowed === false) {
|
|
1976
|
+
throw new NonRetryableError(
|
|
1977
|
+
"Session signing allowance has expired (~2-3 days after login). Run `bulletin-deploy login` to renew."
|
|
1978
|
+
);
|
|
1979
|
+
}
|
|
1980
|
+
} catch (e) {
|
|
1981
|
+
if (e instanceof NonRetryableError) throw e;
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1877
1984
|
if (!options.storageSigner) {
|
|
1985
|
+
let storageLine = null;
|
|
1878
1986
|
try {
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
const
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
resolvedUserSession.userSession,
|
|
1885
|
-
DOT_PRODUCT_ID,
|
|
1886
|
-
// StatementStoreAllowance is required for createTransaction (the session
|
|
1887
|
-
// signer uses it to send signing requests to the phone). Include it here
|
|
1888
|
-
// so a deploy without a prior `login` still works. onExisting:"Ignore"
|
|
1889
|
-
// makes this a no-op if the allowance was already granted by login.
|
|
1890
|
-
[
|
|
1891
|
-
{ tag: "BulletInAllowance", value: void 0 },
|
|
1892
|
-
{ tag: "StatementStoreAllowance", value: void 0 }
|
|
1893
|
-
]
|
|
1987
|
+
if (resolvedUserSession?.userSession && resolvedUserSession?.adapter) {
|
|
1988
|
+
const { ss58Encode } = await import("@parity/product-sdk-address");
|
|
1989
|
+
const signerResult = await resolvedUserSession.adapter.allowance.getBulletinSigner(
|
|
1990
|
+
resolvedUserSession.userSession.id,
|
|
1991
|
+
DOT_PRODUCT_ID
|
|
1894
1992
|
);
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1993
|
+
if (signerResult.isOk()) {
|
|
1994
|
+
const slotSigner = signerResult.value;
|
|
1995
|
+
const slotAddress = ss58Encode(slotSigner.publicKey);
|
|
1996
|
+
options = { ...options, storageSigner: slotSigner, storageSignerAddress: slotAddress };
|
|
1997
|
+
storageLine = formatStorageSignerLine(slotAddress);
|
|
1998
|
+
} else {
|
|
1999
|
+
storageLine = formatStorageSignerLine(null, signerResult.error.reason);
|
|
1899
2000
|
}
|
|
1900
|
-
}
|
|
1901
|
-
|
|
1902
|
-
options = { ...options, storageSigner: slotResult.signer, storageSignerAddress: slotResult.ss58 };
|
|
2001
|
+
} else {
|
|
2002
|
+
storageLine = formatStorageSignerLine(null);
|
|
1903
2003
|
}
|
|
1904
2004
|
} catch {
|
|
2005
|
+
storageLine = formatStorageSignerLine(null, "error");
|
|
1905
2006
|
}
|
|
2007
|
+
if (storageLine) console.log(storageLine);
|
|
1906
2008
|
}
|
|
1907
2009
|
initTelemetry();
|
|
1908
2010
|
const randomSuffix = Math.floor(Math.random() * 100).toString().padStart(2, "0");
|
|
@@ -2718,6 +2820,10 @@ export {
|
|
|
2718
2820
|
readBulletinSlotSigner,
|
|
2719
2821
|
writeBulletinSlotKey,
|
|
2720
2822
|
extractBulletinSlotKey,
|
|
2823
|
+
BulletinSlotAuthError,
|
|
2824
|
+
isBulletinAuthActive,
|
|
2825
|
+
pollUntilBulletinAuthorized,
|
|
2826
|
+
waitForBulletinAuthorization,
|
|
2721
2827
|
getSlotSignerProvider,
|
|
2722
2828
|
friendlyChainError,
|
|
2723
2829
|
DEFAULT_BULLETIN_RPC,
|
|
@@ -2741,6 +2847,7 @@ export {
|
|
|
2741
2847
|
encryptContent,
|
|
2742
2848
|
__selectStorageProviderModeForTest,
|
|
2743
2849
|
chooseSignerInput,
|
|
2850
|
+
formatStorageSignerLine,
|
|
2744
2851
|
storeFile,
|
|
2745
2852
|
__assignDenseNoncesForTest,
|
|
2746
2853
|
storeChunkedContent,
|
|
@@ -8,10 +8,10 @@ import {
|
|
|
8
8
|
setDeploySentryTag,
|
|
9
9
|
truncateAddress,
|
|
10
10
|
withSpan
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-LCKLYFAZ.js";
|
|
12
12
|
import {
|
|
13
13
|
validateContractAddresses
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-GL3U7K2B.js";
|
|
15
15
|
import {
|
|
16
16
|
NonRetryableError
|
|
17
17
|
} from "./chunk-ZOC4GITL.js";
|
|
@@ -6,15 +6,15 @@ import {
|
|
|
6
6
|
resolveDotnsConnectOptions,
|
|
7
7
|
storeDirectory,
|
|
8
8
|
storeFile
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-RD2QHYTL.js";
|
|
10
10
|
import {
|
|
11
11
|
DotNS
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-WZBAQCA5.js";
|
|
13
13
|
import {
|
|
14
14
|
getPopSelfServeConfig,
|
|
15
15
|
loadEnvironments,
|
|
16
16
|
resolveEndpoints
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-GL3U7K2B.js";
|
|
18
18
|
import {
|
|
19
19
|
NonRetryableError
|
|
20
20
|
} from "./chunk-ZOC4GITL.js";
|