@bcts/frost-hubert 1.0.0-alpha.23 → 1.0.0-beta.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/dist/bin/frost.cjs +345 -71
- package/dist/bin/frost.cjs.map +1 -1
- package/dist/bin/frost.mjs +345 -71
- package/dist/bin/frost.mjs.map +1 -1
- package/dist/busy-DkM2jAIZ.mjs +27 -0
- package/dist/busy-DkM2jAIZ.mjs.map +1 -0
- package/dist/busy-EZU7EKr6.cjs +38 -0
- package/dist/busy-EZU7EKr6.cjs.map +1 -0
- package/dist/cmd/index.cjs +28 -22
- package/dist/cmd/index.d.cts +2 -2
- package/dist/cmd/index.d.mts +2 -2
- package/dist/cmd/index.mjs +7 -3
- package/dist/cmd-Bw9_i2_f.cjs +130 -0
- package/dist/cmd-Bw9_i2_f.cjs.map +1 -0
- package/dist/cmd-CS1uJtuD.mjs +113 -0
- package/dist/cmd-CS1uJtuD.mjs.map +1 -0
- package/dist/common-CvH6dFvQ.mjs +282 -0
- package/dist/common-CvH6dFvQ.mjs.map +1 -0
- package/dist/common-DUWvtc08.mjs +96 -0
- package/dist/common-DUWvtc08.mjs.map +1 -0
- package/dist/common-lKP5EzHy.cjs +372 -0
- package/dist/common-lKP5EzHy.cjs.map +1 -0
- package/dist/common-lThIvJmZ.cjs +114 -0
- package/dist/common-lThIvJmZ.cjs.map +1 -0
- package/dist/dkg/index.cjs +6 -102
- package/dist/dkg/index.cjs.map +1 -1
- package/dist/dkg/index.d.cts +2 -2
- package/dist/dkg/index.d.mts +2 -2
- package/dist/dkg/index.mjs +4 -101
- package/dist/dkg/index.mjs.map +1 -1
- package/dist/finalize-BRgJK-Xv.cjs +402 -0
- package/dist/finalize-BRgJK-Xv.cjs.map +1 -0
- package/dist/finalize-BfLgzn8f.cjs +303 -0
- package/dist/finalize-BfLgzn8f.cjs.map +1 -0
- package/dist/finalize-CNTDj6aS.mjs +389 -0
- package/dist/finalize-CNTDj6aS.mjs.map +1 -0
- package/dist/finalize-EC3ikHQq.mjs +252 -0
- package/dist/finalize-EC3ikHQq.mjs.map +1 -0
- package/dist/finalize-IA01t_Qq.mjs +290 -0
- package/dist/finalize-IA01t_Qq.mjs.map +1 -0
- package/dist/finalize-UPyI1yb1.cjs +265 -0
- package/dist/finalize-UPyI1yb1.cjs.map +1 -0
- package/dist/{index-BkqLimZT.d.mts → index-B3c-80VS.d.cts} +26 -3
- package/dist/index-B3c-80VS.d.cts.map +1 -0
- package/dist/{index-BJlwbPYu.d.cts → index-BgbSGpxn.d.mts} +102 -80
- package/dist/index-BgbSGpxn.d.mts.map +1 -0
- package/dist/{index-BMbPgH0W.d.cts → index-C8QeHNwa.d.cts} +46 -2
- package/dist/{index-BMbPgH0W.d.cts.map → index-C8QeHNwa.d.cts.map} +1 -1
- package/dist/{index-DmxfT59Y.d.cts → index-D3QTWkEm.d.mts} +26 -3
- package/dist/index-D3QTWkEm.d.mts.map +1 -0
- package/dist/{index-DoV5HFvV.d.mts → index-DVbWyOs7.d.mts} +46 -2
- package/dist/{index-DoV5HFvV.d.mts.map → index-DVbWyOs7.d.mts.map} +1 -1
- package/dist/{index-Dzm1v4_4.d.mts → index-F1iNEAJR.d.cts} +102 -80
- package/dist/index-F1iNEAJR.d.cts.map +1 -0
- package/dist/index.cjs +31 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +9 -4
- package/dist/index.mjs.map +1 -1
- package/dist/invite-5277FQVT.cjs +274 -0
- package/dist/invite-5277FQVT.cjs.map +1 -0
- package/dist/invite-DUTcfTgX.cjs +109 -0
- package/dist/invite-DUTcfTgX.cjs.map +1 -0
- package/dist/invite-IU4n0dq2.mjs +96 -0
- package/dist/invite-IU4n0dq2.mjs.map +1 -0
- package/dist/invite-RU-OXTNS.mjs +219 -0
- package/dist/invite-RU-OXTNS.mjs.map +1 -0
- package/dist/parallel-D1R6ZGlY.cjs +318 -0
- package/dist/parallel-D1R6ZGlY.cjs.map +1 -0
- package/dist/parallel-D6zc6VW4.mjs +235 -0
- package/dist/parallel-D6zc6VW4.mjs.map +1 -0
- package/dist/proposed-participant-Dm1Eq6mX.cjs +141 -0
- package/dist/proposed-participant-Dm1Eq6mX.cjs.map +1 -0
- package/dist/proposed-participant-cWM7iUrO.mjs +129 -0
- package/dist/proposed-participant-cWM7iUrO.mjs.map +1 -0
- package/dist/receive-CAI-x4II.cjs +213 -0
- package/dist/receive-CAI-x4II.cjs.map +1 -0
- package/dist/receive-D2Nn68L7.mjs +188 -0
- package/dist/receive-D2Nn68L7.mjs.map +1 -0
- package/dist/receive-DA_KQEgk.mjs +177 -0
- package/dist/receive-DA_KQEgk.mjs.map +1 -0
- package/dist/receive-kZMsXhbK.cjs +190 -0
- package/dist/receive-kZMsXhbK.cjs.map +1 -0
- package/dist/registry/index.cjs +85 -10
- package/dist/registry/index.cjs.map +1 -1
- package/dist/registry/index.d.cts +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +85 -10
- package/dist/registry/index.mjs.map +1 -1
- package/dist/{registry-loI1_Mh1.cjs → registry-9puTaRrD.cjs} +1 -1
- package/dist/{registry-loI1_Mh1.cjs.map → registry-9puTaRrD.cjs.map} +1 -1
- package/dist/{registry-CgrCZ4En.mjs → registry-BpCwtrRt.mjs} +1 -1
- package/dist/{registry-CgrCZ4En.mjs.map → registry-BpCwtrRt.mjs.map} +1 -1
- package/dist/round1-4Hyx8w0x.cjs +422 -0
- package/dist/round1-4Hyx8w0x.cjs.map +1 -0
- package/dist/round1-7v9LlE11.mjs +373 -0
- package/dist/round1-7v9LlE11.mjs.map +1 -0
- package/dist/round1-BHBjru1m.cjs +465 -0
- package/dist/round1-BHBjru1m.cjs.map +1 -0
- package/dist/round1-CMLKN2RR.mjs +195 -0
- package/dist/round1-CMLKN2RR.mjs.map +1 -0
- package/dist/round1-CWSXZx5R.cjs +208 -0
- package/dist/round1-CWSXZx5R.cjs.map +1 -0
- package/dist/round1-CcQCGlIT.mjs +208 -0
- package/dist/round1-CcQCGlIT.mjs.map +1 -0
- package/dist/round1-Cgm7j1kI.mjs +452 -0
- package/dist/round1-Cgm7j1kI.mjs.map +1 -0
- package/dist/round1-DQ0fnc1H.cjs +221 -0
- package/dist/round1-DQ0fnc1H.cjs.map +1 -0
- package/dist/round2-BWz9SQIi.cjs +305 -0
- package/dist/round2-BWz9SQIi.cjs.map +1 -0
- package/dist/round2-BkNRCXgS.mjs +292 -0
- package/dist/round2-BkNRCXgS.mjs.map +1 -0
- package/dist/round2-Bl2uK93U.mjs +450 -0
- package/dist/round2-Bl2uK93U.mjs.map +1 -0
- package/dist/round2-CdUT-AhH.cjs +499 -0
- package/dist/round2-CdUT-AhH.cjs.map +1 -0
- package/dist/round2-DOA3rnV-.mjs +280 -0
- package/dist/round2-DOA3rnV-.mjs.map +1 -0
- package/dist/round2-Dg24w-TU.mjs +397 -0
- package/dist/round2-Dg24w-TU.mjs.map +1 -0
- package/dist/round2-LylCa84n.cjs +293 -0
- package/dist/round2-LylCa84n.cjs.map +1 -0
- package/dist/round2-o2Q-GMbX.cjs +410 -0
- package/dist/round2-o2Q-GMbX.cjs.map +1 -0
- package/dist/storage-B-Gu68-O.cjs +79 -0
- package/dist/storage-B-Gu68-O.cjs.map +1 -0
- package/dist/storage-Bkkliz0K.mjs +74 -0
- package/dist/storage-Bkkliz0K.mjs.map +1 -0
- package/package.json +10 -10
- package/src/bin/frost.ts +849 -128
- package/src/cmd/common.ts +19 -1
- package/src/cmd/dkg/common.ts +97 -10
- package/src/cmd/dkg/coordinator/invite.ts +5 -2
- package/src/cmd/dkg/participant/finalize.ts +51 -17
- package/src/cmd/dkg/participant/round1.ts +39 -38
- package/src/cmd/dkg/participant/round2.ts +60 -26
- package/src/cmd/sign/coordinator/round2.ts +5 -1
- package/src/cmd/sign/participant/finalize.ts +6 -2
- package/src/cmd/sign/participant/receive.ts +5 -2
- package/src/dkg/group-invite.ts +12 -2
- package/src/dkg/proposed-participant.ts +32 -3
- package/src/registry/owner-record.ts +12 -0
- package/src/registry/participant-record.ts +35 -2
- package/src/registry/registry-impl.ts +74 -18
- package/dist/cmd-5yLeC_QL.mjs +0 -4708
- package/dist/cmd-5yLeC_QL.mjs.map +0 -1
- package/dist/cmd-BfZjC3Uh.cjs +0 -4847
- package/dist/cmd-BfZjC3Uh.cjs.map +0 -1
- package/dist/index-BJlwbPYu.d.cts.map +0 -1
- package/dist/index-BkqLimZT.d.mts.map +0 -1
- package/dist/index-DmxfT59Y.d.cts.map +0 -1
- package/dist/index-Dzm1v4_4.d.mts.map +0 -1
package/src/bin/frost.ts
CHANGED
|
@@ -3,12 +3,18 @@
|
|
|
3
3
|
* Copyright © 2023-2026 Blockchain Commons, LLC
|
|
4
4
|
* Copyright © 2025-2026 Parity Technologies
|
|
5
5
|
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/**
|
|
6
|
+
*
|
|
9
7
|
* FROST CLI binary entry point.
|
|
10
8
|
*
|
|
11
|
-
* Port of main.rs and
|
|
9
|
+
* Port of `frost-hubert-rust/src/main.rs` and the per-subcommand
|
|
10
|
+
* `clap::Parser` definitions in
|
|
11
|
+
* `frost-hubert-rust/src/cmd/{registry,dkg,sign}/...`.
|
|
12
|
+
*
|
|
13
|
+
* Each subcommand is a thin wrapper that:
|
|
14
|
+
* 1. parses CLI args into the matching `*Options` interface,
|
|
15
|
+
* 2. constructs a `StorageClient` if a backend is requested,
|
|
16
|
+
* 3. delegates to the library function in `src/cmd/...`,
|
|
17
|
+
* 4. prints the same single-line output Rust prints.
|
|
12
18
|
*
|
|
13
19
|
* @module
|
|
14
20
|
*/
|
|
@@ -17,13 +23,48 @@ import { program } from "commander";
|
|
|
17
23
|
|
|
18
24
|
import { ownerSet } from "../cmd/registry/owner/set.js";
|
|
19
25
|
import { participantAdd } from "../cmd/registry/participant/add.js";
|
|
26
|
+
import { type StorageClient, type StorageSelection, createStorageClient } from "../cmd/storage.js";
|
|
27
|
+
|
|
28
|
+
// DKG / sign command modules transitively load `@frosts/core`, whose
|
|
29
|
+
// published dist auto-imports `vitest` as a side-effect (a known
|
|
30
|
+
// upstream packaging bug). Importing them at module-load time would
|
|
31
|
+
// crash the registry-only CLI, so we lazy-import them inside the
|
|
32
|
+
// command handlers below. Once `@frosts/core` ships a clean dist this
|
|
33
|
+
// can be flipped back to static imports.
|
|
34
|
+
const lazyDkgCoord = {
|
|
35
|
+
invite: () => import("../cmd/dkg/coordinator/invite.js").then((m) => m.invite),
|
|
36
|
+
round1: () => import("../cmd/dkg/coordinator/round1.js").then((m) => m.round1),
|
|
37
|
+
round2: () => import("../cmd/dkg/coordinator/round2.js").then((m) => m.round2),
|
|
38
|
+
finalize: () => import("../cmd/dkg/coordinator/finalize.js").then((m) => m.finalize),
|
|
39
|
+
};
|
|
40
|
+
const lazyDkgPart = {
|
|
41
|
+
receive: () => import("../cmd/dkg/participant/receive.js").then((m) => m.receive),
|
|
42
|
+
round1: () => import("../cmd/dkg/participant/round1.js").then((m) => m.round1),
|
|
43
|
+
round2: () => import("../cmd/dkg/participant/round2.js").then((m) => m.round2),
|
|
44
|
+
finalize: () => import("../cmd/dkg/participant/finalize.js").then((m) => m.finalize),
|
|
45
|
+
};
|
|
46
|
+
const lazySignCoord = {
|
|
47
|
+
invite: () => import("../cmd/sign/coordinator/invite.js").then((m) => m.invite),
|
|
48
|
+
round1: () => import("../cmd/sign/coordinator/round1.js").then((m) => m.round1),
|
|
49
|
+
round2: () => import("../cmd/sign/coordinator/round2.js").then((m) => m.round2),
|
|
50
|
+
};
|
|
51
|
+
const lazySignPart = {
|
|
52
|
+
receive: () => import("../cmd/sign/participant/receive.js").then((m) => m.receive),
|
|
53
|
+
round1: () => import("../cmd/sign/participant/round1.js").then((m) => m.round1),
|
|
54
|
+
round2: () => import("../cmd/sign/participant/round2.js").then((m) => m.round2),
|
|
55
|
+
finalize: () => import("../cmd/sign/participant/finalize.js").then((m) => m.finalize),
|
|
56
|
+
};
|
|
20
57
|
|
|
21
58
|
// Type for modules that may have registerTags
|
|
22
59
|
interface TagModule {
|
|
23
60
|
registerTags?: () => void;
|
|
24
61
|
}
|
|
25
62
|
|
|
26
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Initialize the global CBOR tag registry. Mirrors the
|
|
65
|
+
* Rust `lib.rs::run` initialization step (`bc_components::register_tags();`
|
|
66
|
+
* `bc_envelope::register_tags();` `provenance_mark::register_tags();`).
|
|
67
|
+
*/
|
|
27
68
|
async function registerTags(): Promise<void> {
|
|
28
69
|
try {
|
|
29
70
|
const components = (await import("@bcts/components")) as TagModule;
|
|
@@ -44,40 +85,145 @@ async function registerTags(): Promise<void> {
|
|
|
44
85
|
}
|
|
45
86
|
}
|
|
46
87
|
|
|
47
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Storage-related CLI options shared across most subcommands.
|
|
90
|
+
*
|
|
91
|
+
* Mirrors Rust `OptionalStorageSelector` (clap-flatten) — the user can
|
|
92
|
+
* pass exactly one of `--storage server|mainline|ipfs|hybrid` to enable
|
|
93
|
+
* a Hubert backend. When omitted, the subcommand runs in local-only
|
|
94
|
+
* preview/state mode.
|
|
95
|
+
*/
|
|
96
|
+
interface StorageOpts {
|
|
97
|
+
storage?: StorageSelection;
|
|
98
|
+
host?: string;
|
|
99
|
+
port?: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function isStorageSelection(value: string): value is StorageSelection {
|
|
103
|
+
return value === "server" || value === "mainline" || value === "ipfs" || value === "hybrid";
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function parseStorageSelection(opts: StorageOpts): StorageSelection | undefined {
|
|
107
|
+
const value = opts.storage;
|
|
108
|
+
if (value === undefined) return undefined;
|
|
109
|
+
if (!isStorageSelection(value)) {
|
|
110
|
+
throw new Error(`Unknown --storage value: ${String(value)}`);
|
|
111
|
+
}
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function buildClient(opts: StorageOpts): Promise<StorageClient | undefined> {
|
|
116
|
+
const selection = parseStorageSelection(opts);
|
|
117
|
+
if (selection === undefined) return undefined;
|
|
118
|
+
const serverUrl =
|
|
119
|
+
opts.host !== undefined && opts.port !== undefined
|
|
120
|
+
? `http://${opts.host}:${opts.port}`
|
|
121
|
+
: opts.host;
|
|
122
|
+
return createStorageClient(selection, serverUrl);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Convert a comma-separated, repeated-flag, or positional list. */
|
|
126
|
+
function asStringArray(value: unknown): string[] {
|
|
127
|
+
if (Array.isArray(value)) return value as string[];
|
|
128
|
+
if (typeof value === "string") return [value];
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function asNumber(value: unknown): number | undefined {
|
|
133
|
+
if (value === undefined || value === null) return undefined;
|
|
134
|
+
if (typeof value !== "string" && typeof value !== "number") {
|
|
135
|
+
throw new Error(`Expected a number, got: ${typeof value}`);
|
|
136
|
+
}
|
|
137
|
+
const n = Number(value);
|
|
138
|
+
if (Number.isNaN(n)) throw new Error(`Expected a number, got: ${value as string}`);
|
|
139
|
+
return n;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Build an object containing only the keys whose values are defined.
|
|
144
|
+
*
|
|
145
|
+
* The frost-hubert library types use `exactOptionalPropertyTypes: true`,
|
|
146
|
+
* which means `{ foo?: string }` rejects `{ foo: undefined }` — only
|
|
147
|
+
* `{ foo: "x" }` or `{}` is allowed. Spreading this helper's return
|
|
148
|
+
* value into an options object preserves that contract: at runtime we
|
|
149
|
+
* filter out the `undefined` keys, and we strip `undefined` from the
|
|
150
|
+
* value type so the spread satisfies `exactOptionalPropertyTypes`.
|
|
151
|
+
*/
|
|
152
|
+
type DefinedValues<T> = { [K in keyof T]?: Exclude<T[K], undefined> };
|
|
153
|
+
function defined<T extends Record<string, unknown>>(obj: T): DefinedValues<T> {
|
|
154
|
+
const out: Record<string, unknown> = {};
|
|
155
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
156
|
+
if (value !== undefined) out[key] = value;
|
|
157
|
+
}
|
|
158
|
+
return out as DefinedValues<T>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Wrap a CLI action handler so any thrown error prints to stderr and
|
|
163
|
+
* exits with code 1. Mirrors Rust's `anyhow::Result<()>` propagation.
|
|
164
|
+
*/
|
|
165
|
+
function runAsync<TArgs extends unknown[]>(
|
|
166
|
+
handler: (...args: TArgs) => Promise<void>,
|
|
167
|
+
): (...args: TArgs) => void {
|
|
168
|
+
return (...args: TArgs): void => {
|
|
169
|
+
handler(...args).catch((err: unknown) => {
|
|
170
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
171
|
+
process.exit(1);
|
|
172
|
+
});
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function runSync<TArgs extends unknown[]>(
|
|
177
|
+
handler: (...args: TArgs) => void,
|
|
178
|
+
): (...args: TArgs) => void {
|
|
179
|
+
return (...args: TArgs): void => {
|
|
180
|
+
try {
|
|
181
|
+
handler(...args);
|
|
182
|
+
} catch (err) {
|
|
183
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Common option attachers — keep the per-subcommand definitions short.
|
|
190
|
+
const addStorageOpts = (cmd: ReturnType<typeof program.command>): typeof cmd =>
|
|
191
|
+
cmd
|
|
192
|
+
.option("--storage <selection>", "Storage backend (server|mainline|ipfs|hybrid)")
|
|
193
|
+
.option("--host <host>", "Server host (server backend only)")
|
|
194
|
+
.option("--port <port>", "Server port (server backend only)");
|
|
195
|
+
|
|
196
|
+
const addRegistryOpt = (cmd: ReturnType<typeof program.command>): typeof cmd =>
|
|
197
|
+
cmd.option("-r, --registry <path>", "Registry path or filename override");
|
|
198
|
+
|
|
199
|
+
const addTimeoutOpt = (cmd: ReturnType<typeof program.command>): typeof cmd =>
|
|
200
|
+
cmd.option("--timeout <seconds>", "Wait up to this many seconds");
|
|
201
|
+
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
// CLI definition
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
|
|
48
206
|
async function main(): Promise<void> {
|
|
49
|
-
// Initialize tags before CLI runs
|
|
50
207
|
await registerTags();
|
|
51
208
|
|
|
52
209
|
program.name("frost").description("FROST threshold signing CLI").version("1.0.0");
|
|
53
210
|
|
|
54
|
-
// Registry
|
|
211
|
+
// ─── Registry ──────────────────────────────────────────────────────────
|
|
55
212
|
const registryCmd = program.command("registry").description("Manage the registry");
|
|
56
|
-
|
|
57
|
-
// Registry owner commands
|
|
58
213
|
const ownerCmd = registryCmd.command("owner").description("Manage the registry owner");
|
|
59
214
|
|
|
60
215
|
ownerCmd
|
|
61
216
|
.command("set <xid-document> [pet-name]")
|
|
62
217
|
.description("Set the registry owner using an ur:xid document that includes private keys")
|
|
63
218
|
.option("-r, --registry <path>", "Registry path or filename override")
|
|
64
|
-
.action(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
{
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
},
|
|
72
|
-
process.cwd(),
|
|
73
|
-
);
|
|
74
|
-
} catch (error) {
|
|
75
|
-
console.error((error as Error).message);
|
|
76
|
-
process.exit(1);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
219
|
+
.action(
|
|
220
|
+
runSync(
|
|
221
|
+
(xidDocument: string, petName: string | undefined, options: { registry?: string }) => {
|
|
222
|
+
ownerSet({ xidDocument, petName, registryPath: options.registry }, process.cwd());
|
|
223
|
+
},
|
|
224
|
+
),
|
|
225
|
+
);
|
|
79
226
|
|
|
80
|
-
// Registry participant commands
|
|
81
227
|
const participantCmd = registryCmd
|
|
82
228
|
.command("participant")
|
|
83
229
|
.description("Manage registry participants");
|
|
@@ -86,138 +232,713 @@ async function main(): Promise<void> {
|
|
|
86
232
|
.command("add <xid-document> [pet-name]")
|
|
87
233
|
.description("Add a participant using an ur:xid document")
|
|
88
234
|
.option("-r, --registry <path>", "Registry path or filename override")
|
|
89
|
-
.action(
|
|
90
|
-
|
|
91
|
-
|
|
235
|
+
.action(
|
|
236
|
+
runSync(
|
|
237
|
+
(xidDocument: string, petName: string | undefined, options: { registry?: string }) => {
|
|
238
|
+
participantAdd({ xidDocument, petName, registryPath: options.registry }, process.cwd());
|
|
239
|
+
},
|
|
240
|
+
),
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
// ─── DKG ──────────────────────────────────────────────────────────────
|
|
244
|
+
const dkgCmd = program.command("dkg").description("Distributed Key Generation commands");
|
|
245
|
+
const dkgCoordinatorCmd = dkgCmd.command("coordinator").description("DKG coordinator commands");
|
|
246
|
+
|
|
247
|
+
// dkg coordinator invite
|
|
248
|
+
addStorageOpts(
|
|
249
|
+
addRegistryOpt(
|
|
250
|
+
dkgCoordinatorCmd
|
|
251
|
+
.command("invite <participants...>")
|
|
252
|
+
.description("Compose or send a DKG invite")
|
|
253
|
+
.option("--min-signers <n>", "Minimum signers required; defaults to participant count")
|
|
254
|
+
.option("--charter <string>", "Charter statement for the DKG group", "")
|
|
255
|
+
.option("--valid-days <days>", "Days the invite is valid for", "30")
|
|
256
|
+
.option("--preview", "Print the preview invite envelope UR instead of the sealed envelope"),
|
|
257
|
+
),
|
|
258
|
+
).action(
|
|
259
|
+
runAsync(
|
|
260
|
+
async (
|
|
261
|
+
participants: string[],
|
|
262
|
+
opts: StorageOpts & {
|
|
263
|
+
registry?: string;
|
|
264
|
+
minSigners?: string;
|
|
265
|
+
charter?: string;
|
|
266
|
+
validDays?: string;
|
|
267
|
+
preview?: boolean;
|
|
268
|
+
},
|
|
269
|
+
) => {
|
|
270
|
+
const selection = parseStorageSelection(opts);
|
|
271
|
+
if (selection !== undefined && opts.preview === true) {
|
|
272
|
+
throw new Error("--preview cannot be used with Hubert storage options");
|
|
273
|
+
}
|
|
274
|
+
const client = await buildClient(opts);
|
|
275
|
+
const fn = await lazyDkgCoord.invite();
|
|
276
|
+
const result = await fn(
|
|
277
|
+
// dkgCoordInvite requires a defined client; for preview the
|
|
278
|
+
// invite is built but not posted, so we pass a no-op client.
|
|
279
|
+
client ?? noOpClient(),
|
|
92
280
|
{
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
281
|
+
charter: opts.charter ?? "",
|
|
282
|
+
validDays: asNumber(opts.validDays) ?? 30,
|
|
283
|
+
participantNames: asStringArray(participants),
|
|
284
|
+
...defined({
|
|
285
|
+
registryPath: opts.registry,
|
|
286
|
+
minSigners: asNumber(opts.minSigners),
|
|
287
|
+
}),
|
|
96
288
|
},
|
|
97
289
|
process.cwd(),
|
|
98
290
|
);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// DKG commands (placeholder)
|
|
106
|
-
const dkgCmd = program.command("dkg").description("Distributed Key Generation commands");
|
|
291
|
+
console.log(result.envelopeUr);
|
|
292
|
+
},
|
|
293
|
+
),
|
|
294
|
+
);
|
|
107
295
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
296
|
+
// dkg coordinator round1
|
|
297
|
+
addStorageOpts(
|
|
298
|
+
addTimeoutOpt(
|
|
299
|
+
addRegistryOpt(
|
|
300
|
+
dkgCoordinatorCmd
|
|
301
|
+
.command("round1 <group-id>")
|
|
302
|
+
.description("Collect round 1 responses")
|
|
303
|
+
.option("--preview", "Preview one of the round 2 requests while sending")
|
|
304
|
+
.option("--parallel", "Use parallel fetch/send"),
|
|
305
|
+
),
|
|
306
|
+
),
|
|
307
|
+
).action(
|
|
308
|
+
runAsync(
|
|
309
|
+
async (
|
|
310
|
+
groupId: string,
|
|
311
|
+
opts: StorageOpts & {
|
|
312
|
+
registry?: string;
|
|
313
|
+
timeout?: string;
|
|
314
|
+
preview?: boolean;
|
|
315
|
+
parallel?: boolean;
|
|
316
|
+
},
|
|
317
|
+
) => {
|
|
318
|
+
const client = await buildClient(opts);
|
|
319
|
+
if (client === undefined) {
|
|
320
|
+
throw new Error("dkg coordinator round1 requires --storage");
|
|
321
|
+
}
|
|
322
|
+
const fn = await lazyDkgCoord.round1();
|
|
323
|
+
const result = await fn(
|
|
324
|
+
client,
|
|
325
|
+
{
|
|
326
|
+
groupId,
|
|
327
|
+
...defined({
|
|
328
|
+
registryPath: opts.registry,
|
|
329
|
+
timeoutSeconds: asNumber(opts.timeout),
|
|
330
|
+
preview: opts.preview,
|
|
331
|
+
parallel: opts.parallel,
|
|
332
|
+
}),
|
|
333
|
+
},
|
|
334
|
+
process.cwd(),
|
|
335
|
+
);
|
|
336
|
+
console.log(JSON.stringify(result));
|
|
337
|
+
},
|
|
338
|
+
),
|
|
339
|
+
);
|
|
115
340
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
341
|
+
// dkg coordinator round2
|
|
342
|
+
addStorageOpts(
|
|
343
|
+
addTimeoutOpt(
|
|
344
|
+
addRegistryOpt(
|
|
345
|
+
dkgCoordinatorCmd
|
|
346
|
+
.command("round2 <group-id>")
|
|
347
|
+
.description("Collect round 2 responses")
|
|
348
|
+
.option("--preview", "Preview one of the finalize requests while sending")
|
|
349
|
+
.option("--parallel", "Use parallel fetch/send"),
|
|
350
|
+
),
|
|
351
|
+
),
|
|
352
|
+
).action(
|
|
353
|
+
runAsync(
|
|
354
|
+
async (
|
|
355
|
+
groupId: string,
|
|
356
|
+
opts: StorageOpts & {
|
|
357
|
+
registry?: string;
|
|
358
|
+
timeout?: string;
|
|
359
|
+
preview?: boolean;
|
|
360
|
+
parallel?: boolean;
|
|
361
|
+
},
|
|
362
|
+
) => {
|
|
363
|
+
const client = await buildClient(opts);
|
|
364
|
+
if (client === undefined) {
|
|
365
|
+
throw new Error("dkg coordinator round2 requires --storage");
|
|
366
|
+
}
|
|
367
|
+
const fn = await lazyDkgCoord.round2();
|
|
368
|
+
const result = await fn(
|
|
369
|
+
client,
|
|
370
|
+
{
|
|
371
|
+
groupId,
|
|
372
|
+
...defined({
|
|
373
|
+
registryPath: opts.registry,
|
|
374
|
+
timeoutSeconds: asNumber(opts.timeout),
|
|
375
|
+
preview: opts.preview,
|
|
376
|
+
parallel: opts.parallel,
|
|
377
|
+
}),
|
|
378
|
+
},
|
|
379
|
+
process.cwd(),
|
|
380
|
+
);
|
|
381
|
+
console.log(JSON.stringify(result));
|
|
382
|
+
},
|
|
383
|
+
),
|
|
384
|
+
);
|
|
122
385
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
386
|
+
// dkg coordinator finalize
|
|
387
|
+
addStorageOpts(
|
|
388
|
+
addTimeoutOpt(
|
|
389
|
+
addRegistryOpt(
|
|
390
|
+
dkgCoordinatorCmd
|
|
391
|
+
.command("finalize <group-id>")
|
|
392
|
+
.description("Collect finalize responses")
|
|
393
|
+
.option("--parallel", "Use parallel fetch"),
|
|
394
|
+
),
|
|
395
|
+
),
|
|
396
|
+
).action(
|
|
397
|
+
runAsync(
|
|
398
|
+
async (
|
|
399
|
+
groupId: string,
|
|
400
|
+
opts: StorageOpts & {
|
|
401
|
+
registry?: string;
|
|
402
|
+
timeout?: string;
|
|
403
|
+
parallel?: boolean;
|
|
404
|
+
},
|
|
405
|
+
) => {
|
|
406
|
+
const client = await buildClient(opts);
|
|
407
|
+
if (client === undefined) {
|
|
408
|
+
throw new Error("dkg coordinator finalize requires --storage");
|
|
409
|
+
}
|
|
410
|
+
const fn = await lazyDkgCoord.finalize();
|
|
411
|
+
const result = await fn(
|
|
412
|
+
client,
|
|
413
|
+
{
|
|
414
|
+
groupId,
|
|
415
|
+
...defined({
|
|
416
|
+
registryPath: opts.registry,
|
|
417
|
+
timeoutSeconds: asNumber(opts.timeout),
|
|
418
|
+
parallel: opts.parallel,
|
|
419
|
+
}),
|
|
420
|
+
},
|
|
421
|
+
process.cwd(),
|
|
422
|
+
);
|
|
423
|
+
console.log(result.verifyingKey);
|
|
424
|
+
},
|
|
425
|
+
),
|
|
426
|
+
);
|
|
129
427
|
|
|
428
|
+
// ─── DKG participant ───────────────────────────────────────────────────
|
|
130
429
|
const dkgParticipantCmd = dkgCmd.command("participant").description("DKG participant commands");
|
|
131
|
-
dkgParticipantCmd
|
|
132
|
-
.command("receive")
|
|
133
|
-
.description("Receive DKG invite")
|
|
134
|
-
.action(() => {
|
|
135
|
-
console.log("DKG participant receive command not yet implemented");
|
|
136
|
-
});
|
|
137
430
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
431
|
+
// dkg participant receive
|
|
432
|
+
addStorageOpts(
|
|
433
|
+
addTimeoutOpt(
|
|
434
|
+
addRegistryOpt(
|
|
435
|
+
dkgParticipantCmd
|
|
436
|
+
.command("receive <invite>")
|
|
437
|
+
.description("Receive a DKG invite (ur:arid or ur:envelope)")
|
|
438
|
+
.option("--no-envelope", "Suppress printing the invite envelope UR")
|
|
439
|
+
.option("--info", "Show invite details")
|
|
440
|
+
.option("--sender <sender>", "Require the invite to come from this sender"),
|
|
441
|
+
),
|
|
442
|
+
),
|
|
443
|
+
).action(
|
|
444
|
+
runAsync(
|
|
445
|
+
async (
|
|
446
|
+
invite: string,
|
|
447
|
+
opts: StorageOpts & {
|
|
448
|
+
registry?: string;
|
|
449
|
+
timeout?: string;
|
|
450
|
+
envelope?: boolean;
|
|
451
|
+
info?: boolean;
|
|
452
|
+
sender?: string;
|
|
453
|
+
},
|
|
454
|
+
) => {
|
|
455
|
+
const selection = parseStorageSelection(opts);
|
|
456
|
+
const client = await buildClient(opts);
|
|
457
|
+
const fn = await lazyDkgPart.receive();
|
|
458
|
+
const result = await fn(
|
|
459
|
+
client,
|
|
460
|
+
{
|
|
461
|
+
invite,
|
|
462
|
+
// commander auto-negates `--no-envelope` into `envelope: false`.
|
|
463
|
+
noEnvelope: opts.envelope === false,
|
|
464
|
+
...defined({
|
|
465
|
+
registryPath: opts.registry,
|
|
466
|
+
timeoutSeconds: asNumber(opts.timeout),
|
|
467
|
+
info: opts.info,
|
|
468
|
+
sender: opts.sender,
|
|
469
|
+
storageSelection: selection,
|
|
470
|
+
}),
|
|
471
|
+
},
|
|
472
|
+
process.cwd(),
|
|
473
|
+
);
|
|
474
|
+
if (result.envelopeUr !== undefined) console.log(result.envelopeUr);
|
|
475
|
+
},
|
|
476
|
+
),
|
|
477
|
+
);
|
|
144
478
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
479
|
+
// dkg participant round1
|
|
480
|
+
addStorageOpts(
|
|
481
|
+
addTimeoutOpt(
|
|
482
|
+
addRegistryOpt(
|
|
483
|
+
dkgParticipantCmd
|
|
484
|
+
.command("round1 <invite>")
|
|
485
|
+
.description("Send round 1 response")
|
|
486
|
+
.option("--response-arid <ur>", "Optional ARID for the next response")
|
|
487
|
+
.option("--preview", "Print the preview response envelope UR instead")
|
|
488
|
+
.option("--reject <reason>", "Reject the invite with the provided reason")
|
|
489
|
+
.option("--sender <sender>", "Require the invite to come from this sender"),
|
|
490
|
+
),
|
|
491
|
+
),
|
|
492
|
+
).action(
|
|
493
|
+
runAsync(
|
|
494
|
+
async (
|
|
495
|
+
invite: string,
|
|
496
|
+
opts: StorageOpts & {
|
|
497
|
+
registry?: string;
|
|
498
|
+
timeout?: string;
|
|
499
|
+
responseArid?: string;
|
|
500
|
+
preview?: boolean;
|
|
501
|
+
reject?: string;
|
|
502
|
+
sender?: string;
|
|
503
|
+
},
|
|
504
|
+
) => {
|
|
505
|
+
const selection = parseStorageSelection(opts);
|
|
506
|
+
const client = await buildClient(opts);
|
|
507
|
+
const fn = await lazyDkgPart.round1();
|
|
508
|
+
const result = await fn(
|
|
509
|
+
client,
|
|
510
|
+
{
|
|
511
|
+
invite,
|
|
512
|
+
...defined({
|
|
513
|
+
registryPath: opts.registry,
|
|
514
|
+
timeoutSeconds: asNumber(opts.timeout),
|
|
515
|
+
responseArid: opts.responseArid,
|
|
516
|
+
preview: opts.preview,
|
|
517
|
+
rejectReason: opts.reject,
|
|
518
|
+
sender: opts.sender,
|
|
519
|
+
storageSelection: selection,
|
|
520
|
+
}),
|
|
521
|
+
},
|
|
522
|
+
process.cwd(),
|
|
523
|
+
);
|
|
524
|
+
if (result.envelopeUr !== undefined) console.log(result.envelopeUr);
|
|
525
|
+
else if (result.listeningArid !== undefined) console.log(result.listeningArid);
|
|
526
|
+
},
|
|
527
|
+
),
|
|
528
|
+
);
|
|
151
529
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
530
|
+
// dkg participant round2
|
|
531
|
+
addStorageOpts(
|
|
532
|
+
addTimeoutOpt(
|
|
533
|
+
addRegistryOpt(
|
|
534
|
+
dkgParticipantCmd
|
|
535
|
+
.command("round2 <group-id>")
|
|
536
|
+
.description("Send round 2 response")
|
|
537
|
+
.option("--preview", "Also print the preview response envelope"),
|
|
538
|
+
),
|
|
539
|
+
),
|
|
540
|
+
).action(
|
|
541
|
+
runAsync(
|
|
542
|
+
async (
|
|
543
|
+
groupId: string,
|
|
544
|
+
opts: StorageOpts & { registry?: string; timeout?: string; preview?: boolean },
|
|
545
|
+
) => {
|
|
546
|
+
const selection = parseStorageSelection(opts);
|
|
547
|
+
const client = await buildClient(opts);
|
|
548
|
+
const fn = await lazyDkgPart.round2();
|
|
549
|
+
const result = await fn(
|
|
550
|
+
client,
|
|
551
|
+
{
|
|
552
|
+
groupId,
|
|
553
|
+
...defined({
|
|
554
|
+
registryPath: opts.registry,
|
|
555
|
+
timeoutSeconds: asNumber(opts.timeout),
|
|
556
|
+
preview: opts.preview,
|
|
557
|
+
storageSelection: selection,
|
|
558
|
+
}),
|
|
559
|
+
},
|
|
560
|
+
process.cwd(),
|
|
561
|
+
);
|
|
562
|
+
if (result.envelopeUr !== undefined) console.log(result.envelopeUr);
|
|
563
|
+
else console.log(result.listeningArid);
|
|
564
|
+
},
|
|
565
|
+
),
|
|
566
|
+
);
|
|
158
567
|
|
|
159
|
-
//
|
|
160
|
-
|
|
568
|
+
// dkg participant finalize
|
|
569
|
+
addStorageOpts(
|
|
570
|
+
addTimeoutOpt(
|
|
571
|
+
addRegistryOpt(
|
|
572
|
+
dkgParticipantCmd
|
|
573
|
+
.command("finalize <group-id>")
|
|
574
|
+
.description("Receive finalize package")
|
|
575
|
+
.option("--preview", "Also print the preview response envelope"),
|
|
576
|
+
),
|
|
577
|
+
),
|
|
578
|
+
).action(
|
|
579
|
+
runAsync(
|
|
580
|
+
async (
|
|
581
|
+
groupId: string,
|
|
582
|
+
opts: StorageOpts & { registry?: string; timeout?: string; preview?: boolean },
|
|
583
|
+
) => {
|
|
584
|
+
const selection = parseStorageSelection(opts);
|
|
585
|
+
const client = await buildClient(opts);
|
|
586
|
+
const fn = await lazyDkgPart.finalize();
|
|
587
|
+
const result = await fn(
|
|
588
|
+
client,
|
|
589
|
+
{
|
|
590
|
+
groupId,
|
|
591
|
+
...defined({
|
|
592
|
+
registryPath: opts.registry,
|
|
593
|
+
timeoutSeconds: asNumber(opts.timeout),
|
|
594
|
+
preview: opts.preview,
|
|
595
|
+
storageSelection: selection,
|
|
596
|
+
}),
|
|
597
|
+
},
|
|
598
|
+
process.cwd(),
|
|
599
|
+
);
|
|
600
|
+
console.log(result.verifyingKey);
|
|
601
|
+
},
|
|
602
|
+
),
|
|
603
|
+
);
|
|
161
604
|
|
|
605
|
+
// ─── Sign ──────────────────────────────────────────────────────────────
|
|
606
|
+
const signCmd = program.command("sign").description("Threshold signing commands");
|
|
162
607
|
const signCoordinatorCmd = signCmd
|
|
163
608
|
.command("coordinator")
|
|
164
609
|
.description("Sign coordinator commands");
|
|
165
|
-
signCoordinatorCmd
|
|
166
|
-
.command("invite")
|
|
167
|
-
.description("Send sign invite to participants")
|
|
168
|
-
.action(() => {
|
|
169
|
-
console.log("Sign coordinator invite command not yet implemented");
|
|
170
|
-
});
|
|
171
610
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
611
|
+
// sign coordinator invite
|
|
612
|
+
addStorageOpts(
|
|
613
|
+
addRegistryOpt(
|
|
614
|
+
signCoordinatorCmd
|
|
615
|
+
.command("invite <group-id>")
|
|
616
|
+
.description("Send sign invite to participants")
|
|
617
|
+
.requiredOption("--target <path>", "Path to a file containing the target envelope UR")
|
|
618
|
+
.option("--preview", "Print the preview request envelope UR instead of sending"),
|
|
619
|
+
),
|
|
620
|
+
).action(
|
|
621
|
+
runAsync(
|
|
622
|
+
async (
|
|
623
|
+
groupId: string,
|
|
624
|
+
opts: StorageOpts & { registry?: string; target: string; preview?: boolean },
|
|
625
|
+
) => {
|
|
626
|
+
const client = await buildClient(opts);
|
|
627
|
+
const fn = await lazySignCoord.invite();
|
|
628
|
+
const result = await fn(
|
|
629
|
+
client,
|
|
630
|
+
{
|
|
631
|
+
groupId,
|
|
632
|
+
targetFile: opts.target,
|
|
633
|
+
...defined({
|
|
634
|
+
registryPath: opts.registry,
|
|
635
|
+
preview: opts.preview,
|
|
636
|
+
}),
|
|
637
|
+
},
|
|
638
|
+
process.cwd(),
|
|
639
|
+
);
|
|
640
|
+
console.log(result.startArid);
|
|
641
|
+
},
|
|
642
|
+
),
|
|
643
|
+
);
|
|
178
644
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
645
|
+
// sign coordinator round1
|
|
646
|
+
addStorageOpts(
|
|
647
|
+
addTimeoutOpt(
|
|
648
|
+
addRegistryOpt(
|
|
649
|
+
signCoordinatorCmd
|
|
650
|
+
.command("round1 <session-id>")
|
|
651
|
+
.description("Collect round 1 (commitment) responses")
|
|
652
|
+
.option("--group <ur:arid>", "Optional group ID hint")
|
|
653
|
+
.option("--preview-share", "Print a sample unsealed signRound2 request")
|
|
654
|
+
.option("--parallel", "Use parallel fetch/send"),
|
|
655
|
+
),
|
|
656
|
+
),
|
|
657
|
+
).action(
|
|
658
|
+
runAsync(
|
|
659
|
+
async (
|
|
660
|
+
sessionId: string,
|
|
661
|
+
opts: StorageOpts & {
|
|
662
|
+
registry?: string;
|
|
663
|
+
timeout?: string;
|
|
664
|
+
group?: string;
|
|
665
|
+
previewShare?: boolean;
|
|
666
|
+
parallel?: boolean;
|
|
667
|
+
},
|
|
668
|
+
) => {
|
|
669
|
+
const client = await buildClient(opts);
|
|
670
|
+
if (client === undefined) {
|
|
671
|
+
throw new Error("sign coordinator round1 requires --storage");
|
|
672
|
+
}
|
|
673
|
+
const fn = await lazySignCoord.round1();
|
|
674
|
+
const result = await fn(
|
|
675
|
+
client,
|
|
676
|
+
{
|
|
677
|
+
sessionId,
|
|
678
|
+
...defined({
|
|
679
|
+
registryPath: opts.registry,
|
|
680
|
+
groupId: opts.group,
|
|
681
|
+
timeoutSeconds: asNumber(opts.timeout),
|
|
682
|
+
previewShare: opts.previewShare,
|
|
683
|
+
parallel: opts.parallel,
|
|
684
|
+
}),
|
|
685
|
+
},
|
|
686
|
+
process.cwd(),
|
|
687
|
+
);
|
|
688
|
+
console.log(JSON.stringify(result));
|
|
689
|
+
},
|
|
690
|
+
),
|
|
691
|
+
);
|
|
185
692
|
|
|
693
|
+
// sign coordinator round2
|
|
694
|
+
addStorageOpts(
|
|
695
|
+
addTimeoutOpt(
|
|
696
|
+
addRegistryOpt(
|
|
697
|
+
signCoordinatorCmd
|
|
698
|
+
.command("round2 <session-id>")
|
|
699
|
+
.description("Collect round 2 responses and finalize signature")
|
|
700
|
+
.option("--group <ur:arid>", "Optional group ID hint")
|
|
701
|
+
.option("--preview-finalize", "Print a sample unsealed finalize package")
|
|
702
|
+
.option("--parallel", "Use parallel fetch/send"),
|
|
703
|
+
),
|
|
704
|
+
),
|
|
705
|
+
).action(
|
|
706
|
+
runAsync(
|
|
707
|
+
async (
|
|
708
|
+
sessionId: string,
|
|
709
|
+
opts: StorageOpts & {
|
|
710
|
+
registry?: string;
|
|
711
|
+
timeout?: string;
|
|
712
|
+
group?: string;
|
|
713
|
+
previewFinalize?: boolean;
|
|
714
|
+
parallel?: boolean;
|
|
715
|
+
},
|
|
716
|
+
) => {
|
|
717
|
+
const client = await buildClient(opts);
|
|
718
|
+
if (client === undefined) {
|
|
719
|
+
throw new Error("sign coordinator round2 requires --storage");
|
|
720
|
+
}
|
|
721
|
+
const fn = await lazySignCoord.round2();
|
|
722
|
+
const result = await fn(
|
|
723
|
+
client,
|
|
724
|
+
{
|
|
725
|
+
sessionId,
|
|
726
|
+
...defined({
|
|
727
|
+
registryPath: opts.registry,
|
|
728
|
+
groupId: opts.group,
|
|
729
|
+
timeoutSeconds: asNumber(opts.timeout),
|
|
730
|
+
previewFinalize: opts.previewFinalize,
|
|
731
|
+
parallel: opts.parallel,
|
|
732
|
+
}),
|
|
733
|
+
},
|
|
734
|
+
process.cwd(),
|
|
735
|
+
);
|
|
736
|
+
console.log(result.signedEnvelope);
|
|
737
|
+
},
|
|
738
|
+
),
|
|
739
|
+
);
|
|
740
|
+
|
|
741
|
+
// ─── Sign participant ──────────────────────────────────────────────────
|
|
186
742
|
const signParticipantCmd = signCmd
|
|
187
743
|
.command("participant")
|
|
188
744
|
.description("Sign participant commands");
|
|
189
|
-
signParticipantCmd
|
|
190
|
-
.command("receive")
|
|
191
|
-
.description("Receive sign invite")
|
|
192
|
-
.action(() => {
|
|
193
|
-
console.log("Sign participant receive command not yet implemented");
|
|
194
|
-
});
|
|
195
745
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
746
|
+
// sign participant receive
|
|
747
|
+
addStorageOpts(
|
|
748
|
+
addTimeoutOpt(
|
|
749
|
+
addRegistryOpt(
|
|
750
|
+
signParticipantCmd
|
|
751
|
+
.command("receive <request>")
|
|
752
|
+
.description("Receive a signInvite request (ur:arid or ur:envelope)")
|
|
753
|
+
.option("--info", "Show request details")
|
|
754
|
+
.option("--sender <sender>", "Require the request to come from this sender"),
|
|
755
|
+
),
|
|
756
|
+
),
|
|
757
|
+
).action(
|
|
758
|
+
runAsync(
|
|
759
|
+
async (
|
|
760
|
+
request: string,
|
|
761
|
+
opts: StorageOpts & {
|
|
762
|
+
registry?: string;
|
|
763
|
+
timeout?: string;
|
|
764
|
+
info?: boolean;
|
|
765
|
+
sender?: string;
|
|
766
|
+
},
|
|
767
|
+
) => {
|
|
768
|
+
const selection = parseStorageSelection(opts);
|
|
769
|
+
const client = await buildClient(opts);
|
|
770
|
+
const fn = await lazySignPart.receive();
|
|
771
|
+
const result = await fn(
|
|
772
|
+
client,
|
|
773
|
+
selection,
|
|
774
|
+
{
|
|
775
|
+
request,
|
|
776
|
+
...defined({
|
|
777
|
+
registryPath: opts.registry,
|
|
778
|
+
timeoutSeconds: asNumber(opts.timeout),
|
|
779
|
+
info: opts.info,
|
|
780
|
+
sender: opts.sender,
|
|
781
|
+
}),
|
|
782
|
+
},
|
|
783
|
+
process.cwd(),
|
|
784
|
+
);
|
|
785
|
+
console.log(JSON.stringify(result));
|
|
786
|
+
},
|
|
787
|
+
),
|
|
788
|
+
);
|
|
202
789
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
790
|
+
// sign participant round1
|
|
791
|
+
addStorageOpts(
|
|
792
|
+
addRegistryOpt(
|
|
793
|
+
signParticipantCmd
|
|
794
|
+
.command("round1 <session-id>")
|
|
795
|
+
.description("Send commitment")
|
|
796
|
+
.option("--preview", "Print the preview response envelope UR instead of sending")
|
|
797
|
+
.option("--reject <reason>", "Reject the signInvite request with the provided reason")
|
|
798
|
+
.option("--group <ur:arid>", "Optional group ID hint"),
|
|
799
|
+
),
|
|
800
|
+
).action(
|
|
801
|
+
runAsync(
|
|
802
|
+
async (
|
|
803
|
+
sessionId: string,
|
|
804
|
+
opts: StorageOpts & {
|
|
805
|
+
registry?: string;
|
|
806
|
+
preview?: boolean;
|
|
807
|
+
reject?: string;
|
|
808
|
+
group?: string;
|
|
809
|
+
},
|
|
810
|
+
) => {
|
|
811
|
+
const selection = parseStorageSelection(opts);
|
|
812
|
+
const client = await buildClient(opts);
|
|
813
|
+
const fn = await lazySignPart.round1();
|
|
814
|
+
const result = await fn(
|
|
815
|
+
client,
|
|
816
|
+
{
|
|
817
|
+
sessionId,
|
|
818
|
+
...defined({
|
|
819
|
+
registryPath: opts.registry,
|
|
820
|
+
groupId: opts.group,
|
|
821
|
+
preview: opts.preview,
|
|
822
|
+
rejectReason: opts.reject,
|
|
823
|
+
storageSelection: selection,
|
|
824
|
+
}),
|
|
825
|
+
},
|
|
826
|
+
process.cwd(),
|
|
827
|
+
);
|
|
828
|
+
if (result.envelopeUr !== undefined) console.log(result.envelopeUr);
|
|
829
|
+
else if (result.listeningArid !== undefined) console.log(result.listeningArid);
|
|
830
|
+
},
|
|
831
|
+
),
|
|
832
|
+
);
|
|
209
833
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
834
|
+
// sign participant round2
|
|
835
|
+
addStorageOpts(
|
|
836
|
+
addTimeoutOpt(
|
|
837
|
+
addRegistryOpt(
|
|
838
|
+
signParticipantCmd
|
|
839
|
+
.command("round2 <session-id>")
|
|
840
|
+
.description("Send signature share")
|
|
841
|
+
.option("--preview", "Print the unsealed response envelope UR instead of sending")
|
|
842
|
+
.option("--group <ur:arid>", "Optional group ID hint"),
|
|
843
|
+
),
|
|
844
|
+
),
|
|
845
|
+
).action(
|
|
846
|
+
runAsync(
|
|
847
|
+
async (
|
|
848
|
+
sessionId: string,
|
|
849
|
+
opts: StorageOpts & {
|
|
850
|
+
registry?: string;
|
|
851
|
+
timeout?: string;
|
|
852
|
+
preview?: boolean;
|
|
853
|
+
group?: string;
|
|
854
|
+
},
|
|
855
|
+
) => {
|
|
856
|
+
const client = await buildClient(opts);
|
|
857
|
+
if (client === undefined) {
|
|
858
|
+
throw new Error("sign participant round2 requires --storage");
|
|
859
|
+
}
|
|
860
|
+
const fn = await lazySignPart.round2();
|
|
861
|
+
const result = await fn(
|
|
862
|
+
client,
|
|
863
|
+
{
|
|
864
|
+
sessionId,
|
|
865
|
+
...defined({
|
|
866
|
+
registryPath: opts.registry,
|
|
867
|
+
groupId: opts.group,
|
|
868
|
+
timeoutSeconds: asNumber(opts.timeout),
|
|
869
|
+
preview: opts.preview,
|
|
870
|
+
}),
|
|
871
|
+
},
|
|
872
|
+
process.cwd(),
|
|
873
|
+
);
|
|
874
|
+
console.log(result.listeningArid);
|
|
875
|
+
},
|
|
876
|
+
),
|
|
877
|
+
);
|
|
878
|
+
|
|
879
|
+
// sign participant finalize
|
|
880
|
+
addStorageOpts(
|
|
881
|
+
addTimeoutOpt(
|
|
882
|
+
addRegistryOpt(
|
|
883
|
+
signParticipantCmd
|
|
884
|
+
.command("finalize <session-id>")
|
|
885
|
+
.description("Receive finalize event")
|
|
886
|
+
.option("--group <ur:arid>", "Optional group ID hint"),
|
|
887
|
+
),
|
|
888
|
+
),
|
|
889
|
+
).action(
|
|
890
|
+
runAsync(
|
|
891
|
+
async (
|
|
892
|
+
sessionId: string,
|
|
893
|
+
opts: StorageOpts & {
|
|
894
|
+
registry?: string;
|
|
895
|
+
timeout?: string;
|
|
896
|
+
group?: string;
|
|
897
|
+
},
|
|
898
|
+
) => {
|
|
899
|
+
const client = await buildClient(opts);
|
|
900
|
+
if (client === undefined) {
|
|
901
|
+
throw new Error("sign participant finalize requires --storage");
|
|
902
|
+
}
|
|
903
|
+
const fn = await lazySignPart.finalize();
|
|
904
|
+
const result = await fn(
|
|
905
|
+
client,
|
|
906
|
+
{
|
|
907
|
+
sessionId,
|
|
908
|
+
...defined({
|
|
909
|
+
registryPath: opts.registry,
|
|
910
|
+
groupId: opts.group,
|
|
911
|
+
timeoutSeconds: asNumber(opts.timeout),
|
|
912
|
+
}),
|
|
913
|
+
},
|
|
914
|
+
process.cwd(),
|
|
915
|
+
);
|
|
916
|
+
console.log(result.signature);
|
|
917
|
+
},
|
|
918
|
+
),
|
|
919
|
+
);
|
|
216
920
|
|
|
217
921
|
program.parse();
|
|
218
922
|
}
|
|
219
923
|
|
|
924
|
+
/**
|
|
925
|
+
* Build a no-op StorageClient for preview-only paths (the
|
|
926
|
+
* coordinator-invite library expects a defined client even when no
|
|
927
|
+
* envelope is sent, because it threads through some helpers).
|
|
928
|
+
*
|
|
929
|
+
* Mirrors Rust's behaviour: `--preview` skips the
|
|
930
|
+
* `StorageClient::from_selection` call entirely, but the underlying
|
|
931
|
+
* library still walks through the same code path with a stub.
|
|
932
|
+
*/
|
|
933
|
+
function noOpClient(): StorageClient {
|
|
934
|
+
return {
|
|
935
|
+
put: () => Promise.reject(new Error("no-op storage client used in preview mode")),
|
|
936
|
+
get: () => Promise.reject(new Error("no-op storage client used in preview mode")),
|
|
937
|
+
exists: () => Promise.resolve(false),
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
|
|
220
941
|
main().catch((error: unknown) => {
|
|
221
|
-
console.error(
|
|
942
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
222
943
|
process.exit(1);
|
|
223
944
|
});
|