@bcts/frost-hubert 1.0.0-alpha.22 → 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.
Files changed (174) hide show
  1. package/dist/bin/frost.cjs +347 -75
  2. package/dist/bin/frost.cjs.map +1 -1
  3. package/dist/bin/frost.mjs +347 -75
  4. package/dist/bin/frost.mjs.map +1 -1
  5. package/dist/busy-DkM2jAIZ.mjs +27 -0
  6. package/dist/busy-DkM2jAIZ.mjs.map +1 -0
  7. package/dist/busy-EZU7EKr6.cjs +38 -0
  8. package/dist/busy-EZU7EKr6.cjs.map +1 -0
  9. package/dist/{chunk-uaV2rQ02.cjs → chunk-CZWwpsFl.cjs} +22 -32
  10. package/dist/{chunk-ClPoSABd.mjs → chunk-CjcI7cDX.mjs} +6 -12
  11. package/dist/cmd/index.cjs +46 -43
  12. package/dist/cmd/index.d.cts +2 -4
  13. package/dist/cmd/index.d.mts +2 -4
  14. package/dist/cmd/index.mjs +7 -6
  15. package/dist/cmd-Bw9_i2_f.cjs +130 -0
  16. package/dist/cmd-Bw9_i2_f.cjs.map +1 -0
  17. package/dist/cmd-CS1uJtuD.mjs +113 -0
  18. package/dist/cmd-CS1uJtuD.mjs.map +1 -0
  19. package/dist/common-CvH6dFvQ.mjs +282 -0
  20. package/dist/common-CvH6dFvQ.mjs.map +1 -0
  21. package/dist/common-DUWvtc08.mjs +96 -0
  22. package/dist/common-DUWvtc08.mjs.map +1 -0
  23. package/dist/common-lKP5EzHy.cjs +372 -0
  24. package/dist/common-lKP5EzHy.cjs.map +1 -0
  25. package/dist/common-lThIvJmZ.cjs +114 -0
  26. package/dist/common-lThIvJmZ.cjs.map +1 -0
  27. package/dist/dkg/index.cjs +245 -7
  28. package/dist/dkg/index.cjs.map +1 -0
  29. package/dist/dkg/index.d.cts +2 -2
  30. package/dist/dkg/index.d.mts +2 -2
  31. package/dist/dkg/index.mjs +238 -2
  32. package/dist/dkg/index.mjs.map +1 -0
  33. package/dist/finalize-BRgJK-Xv.cjs +402 -0
  34. package/dist/finalize-BRgJK-Xv.cjs.map +1 -0
  35. package/dist/finalize-BfLgzn8f.cjs +303 -0
  36. package/dist/finalize-BfLgzn8f.cjs.map +1 -0
  37. package/dist/finalize-CNTDj6aS.mjs +389 -0
  38. package/dist/finalize-CNTDj6aS.mjs.map +1 -0
  39. package/dist/finalize-EC3ikHQq.mjs +252 -0
  40. package/dist/finalize-EC3ikHQq.mjs.map +1 -0
  41. package/dist/finalize-IA01t_Qq.mjs +290 -0
  42. package/dist/finalize-IA01t_Qq.mjs.map +1 -0
  43. package/dist/finalize-UPyI1yb1.cjs +265 -0
  44. package/dist/finalize-UPyI1yb1.cjs.map +1 -0
  45. package/dist/frost/index.cjs +8 -9
  46. package/dist/frost/index.cjs.map +1 -1
  47. package/dist/frost/index.mjs +2 -3
  48. package/dist/frost/index.mjs.map +1 -1
  49. package/dist/{group-invite-Dz1Jmiky.d.cts → index-B3c-80VS.d.cts} +25 -2
  50. package/dist/index-B3c-80VS.d.cts.map +1 -0
  51. package/dist/{index-CcvTi5EA.d.cts → index-BgbSGpxn.d.mts} +102 -80
  52. package/dist/index-BgbSGpxn.d.mts.map +1 -0
  53. package/dist/{registry-impl-CE76sTXQ.d.cts → index-C8QeHNwa.d.cts} +46 -2
  54. package/dist/index-C8QeHNwa.d.cts.map +1 -0
  55. package/dist/{group-invite-Wk9CIbHL.d.mts → index-D3QTWkEm.d.mts} +25 -2
  56. package/dist/index-D3QTWkEm.d.mts.map +1 -0
  57. package/dist/{registry-impl-BETn_lEO.d.mts → index-DVbWyOs7.d.mts} +46 -2
  58. package/dist/index-DVbWyOs7.d.mts.map +1 -0
  59. package/dist/{index-DNCPeLNM.d.mts → index-F1iNEAJR.d.cts} +102 -80
  60. package/dist/index-F1iNEAJR.d.cts.map +1 -0
  61. package/dist/index.cjs +72 -68
  62. package/dist/index.cjs.map +1 -1
  63. package/dist/index.d.cts +4 -7
  64. package/dist/index.d.cts.map +1 -1
  65. package/dist/index.d.mts +4 -7
  66. package/dist/index.d.mts.map +1 -1
  67. package/dist/index.mjs +11 -10
  68. package/dist/index.mjs.map +1 -1
  69. package/dist/invite-5277FQVT.cjs +274 -0
  70. package/dist/invite-5277FQVT.cjs.map +1 -0
  71. package/dist/invite-DUTcfTgX.cjs +109 -0
  72. package/dist/invite-DUTcfTgX.cjs.map +1 -0
  73. package/dist/invite-IU4n0dq2.mjs +96 -0
  74. package/dist/invite-IU4n0dq2.mjs.map +1 -0
  75. package/dist/invite-RU-OXTNS.mjs +219 -0
  76. package/dist/invite-RU-OXTNS.mjs.map +1 -0
  77. package/dist/parallel-D1R6ZGlY.cjs +318 -0
  78. package/dist/parallel-D1R6ZGlY.cjs.map +1 -0
  79. package/dist/parallel-D6zc6VW4.mjs +235 -0
  80. package/dist/parallel-D6zc6VW4.mjs.map +1 -0
  81. package/dist/proposed-participant-Dm1Eq6mX.cjs +141 -0
  82. package/dist/proposed-participant-Dm1Eq6mX.cjs.map +1 -0
  83. package/dist/proposed-participant-cWM7iUrO.mjs +129 -0
  84. package/dist/proposed-participant-cWM7iUrO.mjs.map +1 -0
  85. package/dist/receive-CAI-x4II.cjs +213 -0
  86. package/dist/receive-CAI-x4II.cjs.map +1 -0
  87. package/dist/receive-D2Nn68L7.mjs +188 -0
  88. package/dist/receive-D2Nn68L7.mjs.map +1 -0
  89. package/dist/receive-DA_KQEgk.mjs +177 -0
  90. package/dist/receive-DA_KQEgk.mjs.map +1 -0
  91. package/dist/receive-kZMsXhbK.cjs +190 -0
  92. package/dist/receive-kZMsXhbK.cjs.map +1 -0
  93. package/dist/registry/index.cjs +881 -13
  94. package/dist/registry/index.cjs.map +1 -0
  95. package/dist/registry/index.d.cts +1 -1
  96. package/dist/registry/index.d.mts +1 -1
  97. package/dist/registry/index.mjs +867 -2
  98. package/dist/registry/index.mjs.map +1 -0
  99. package/dist/{registry-FMU-ec5K.cjs → registry-9puTaRrD.cjs} +28 -31
  100. package/dist/registry-9puTaRrD.cjs.map +1 -0
  101. package/dist/{registry-BDnNV1Rk.mjs → registry-BpCwtrRt.mjs} +7 -10
  102. package/dist/{registry-BDnNV1Rk.mjs.map → registry-BpCwtrRt.mjs.map} +1 -1
  103. package/dist/round1-4Hyx8w0x.cjs +422 -0
  104. package/dist/round1-4Hyx8w0x.cjs.map +1 -0
  105. package/dist/round1-7v9LlE11.mjs +373 -0
  106. package/dist/round1-7v9LlE11.mjs.map +1 -0
  107. package/dist/round1-BHBjru1m.cjs +465 -0
  108. package/dist/round1-BHBjru1m.cjs.map +1 -0
  109. package/dist/round1-CMLKN2RR.mjs +195 -0
  110. package/dist/round1-CMLKN2RR.mjs.map +1 -0
  111. package/dist/round1-CWSXZx5R.cjs +208 -0
  112. package/dist/round1-CWSXZx5R.cjs.map +1 -0
  113. package/dist/round1-CcQCGlIT.mjs +208 -0
  114. package/dist/round1-CcQCGlIT.mjs.map +1 -0
  115. package/dist/round1-Cgm7j1kI.mjs +452 -0
  116. package/dist/round1-Cgm7j1kI.mjs.map +1 -0
  117. package/dist/round1-DQ0fnc1H.cjs +221 -0
  118. package/dist/round1-DQ0fnc1H.cjs.map +1 -0
  119. package/dist/round2-BWz9SQIi.cjs +305 -0
  120. package/dist/round2-BWz9SQIi.cjs.map +1 -0
  121. package/dist/round2-BkNRCXgS.mjs +292 -0
  122. package/dist/round2-BkNRCXgS.mjs.map +1 -0
  123. package/dist/round2-Bl2uK93U.mjs +450 -0
  124. package/dist/round2-Bl2uK93U.mjs.map +1 -0
  125. package/dist/round2-CdUT-AhH.cjs +499 -0
  126. package/dist/round2-CdUT-AhH.cjs.map +1 -0
  127. package/dist/round2-DOA3rnV-.mjs +280 -0
  128. package/dist/round2-DOA3rnV-.mjs.map +1 -0
  129. package/dist/round2-Dg24w-TU.mjs +397 -0
  130. package/dist/round2-Dg24w-TU.mjs.map +1 -0
  131. package/dist/round2-LylCa84n.cjs +293 -0
  132. package/dist/round2-LylCa84n.cjs.map +1 -0
  133. package/dist/round2-o2Q-GMbX.cjs +410 -0
  134. package/dist/round2-o2Q-GMbX.cjs.map +1 -0
  135. package/dist/storage-B-Gu68-O.cjs +79 -0
  136. package/dist/storage-B-Gu68-O.cjs.map +1 -0
  137. package/dist/storage-Bkkliz0K.mjs +74 -0
  138. package/dist/storage-Bkkliz0K.mjs.map +1 -0
  139. package/package.json +17 -17
  140. package/src/bin/frost.ts +849 -128
  141. package/src/cmd/common.ts +19 -1
  142. package/src/cmd/dkg/common.ts +97 -10
  143. package/src/cmd/dkg/coordinator/invite.ts +5 -2
  144. package/src/cmd/dkg/participant/finalize.ts +52 -18
  145. package/src/cmd/dkg/participant/round1.ts +39 -38
  146. package/src/cmd/dkg/participant/round2.ts +60 -26
  147. package/src/cmd/sign/coordinator/round2.ts +5 -1
  148. package/src/cmd/sign/participant/finalize.ts +6 -2
  149. package/src/cmd/sign/participant/receive.ts +5 -2
  150. package/src/dkg/group-invite.ts +12 -2
  151. package/src/dkg/proposed-participant.ts +33 -5
  152. package/src/frost/index.ts +1 -1
  153. package/src/registry/owner-record.ts +13 -2
  154. package/src/registry/participant-record.ts +36 -4
  155. package/src/registry/registry-impl.ts +74 -18
  156. package/dist/group-invite-CrbOabFL.cjs +0 -368
  157. package/dist/group-invite-CrbOabFL.cjs.map +0 -1
  158. package/dist/group-invite-Dz1Jmiky.d.cts.map +0 -1
  159. package/dist/group-invite-RPElq-fm.mjs +0 -338
  160. package/dist/group-invite-RPElq-fm.mjs.map +0 -1
  161. package/dist/group-invite-Wk9CIbHL.d.mts.map +0 -1
  162. package/dist/index-CcvTi5EA.d.cts.map +0 -1
  163. package/dist/index-DNCPeLNM.d.mts.map +0 -1
  164. package/dist/registry-FMU-ec5K.cjs.map +0 -1
  165. package/dist/registry-impl-BETn_lEO.d.mts.map +0 -1
  166. package/dist/registry-impl-C7w4awTv.cjs +0 -865
  167. package/dist/registry-impl-C7w4awTv.cjs.map +0 -1
  168. package/dist/registry-impl-CE76sTXQ.d.cts.map +0 -1
  169. package/dist/registry-impl-eYXVSPwM.mjs +0 -797
  170. package/dist/registry-impl-eYXVSPwM.mjs.map +0 -1
  171. package/dist/sign-2bOp18Fs.cjs +0 -4875
  172. package/dist/sign-2bOp18Fs.cjs.map +0 -1
  173. package/dist/sign-D8C3HJ4B.mjs +0 -4736
  174. package/dist/sign-D8C3HJ4B.mjs.map +0 -1
@@ -0,0 +1,373 @@
1
+ import { t as __exportAll } from "./chunk-CjcI7cDX.mjs";
2
+ import { Registry, resolveRegistryPath } from "./registry/index.mjs";
3
+ import { c as parseAridUr, n as isVerbose } from "./common-CvH6dFvQ.mjs";
4
+ import { f as parallelFetch, m as parallelSend } from "./parallel-D6zc6VW4.mjs";
5
+ import { n as signingStateDir } from "./common-DUWvtc08.mjs";
6
+ import { ARID, JSON as JSON$1, XID } from "@bcts/components";
7
+ import { Envelope } from "@bcts/envelope";
8
+ import { SealedRequest, SealedResponse } from "@bcts/gstp";
9
+ import * as fs from "node:fs";
10
+ import * as path from "node:path";
11
+ //#region src/cmd/sign/coordinator/round1.ts
12
+ /**
13
+ * Copyright © 2023-2026 Blockchain Commons, LLC
14
+ * Copyright © 2025-2026 Parity Technologies
15
+ *
16
+ *
17
+ * Sign coordinator round 1 command.
18
+ *
19
+ * Port of cmd/sign/coordinator/round1.rs from frost-hubert-rust.
20
+ *
21
+ * @module
22
+ */
23
+ var round1_exports = /* @__PURE__ */ __exportAll({
24
+ buildShareRequestForParticipant: () => buildShareRequestForParticipant,
25
+ collectCommitmentsParallel: () => collectCommitmentsParallel,
26
+ dispatchShareRequestsParallel: () => dispatchShareRequestsParallel,
27
+ persistCommitments: () => persistCommitments,
28
+ round1: () => round1,
29
+ updatePendingForShare: () => updatePendingForShare,
30
+ validateAndExtractCommitResponse: () => validateAndExtractCommitResponse
31
+ });
32
+ /**
33
+ * Load the start state for a signing session.
34
+ *
35
+ * Port of `load_start_state()` from cmd/sign/coordinator/round1.rs.
36
+ */
37
+ function loadStartState(registryPath, sessionId, groupHint) {
38
+ const base = path.dirname(registryPath);
39
+ const groupStateDir = path.join(base, "group-state");
40
+ const candidatePaths = [];
41
+ let groupDirs;
42
+ if (groupHint !== void 0) groupDirs = [[groupHint, path.join(groupStateDir, groupHint.hex())]];
43
+ else {
44
+ groupDirs = [];
45
+ if (fs.existsSync(groupStateDir)) {
46
+ for (const entry of fs.readdirSync(groupStateDir, { withFileTypes: true })) if (entry.isDirectory()) {
47
+ const dirName = entry.name;
48
+ if (dirName.length === 64 && /^[0-9a-fA-F]+$/.test(dirName)) {
49
+ const groupId = ARID.fromHex(dirName);
50
+ groupDirs.push([groupId, path.join(groupStateDir, dirName)]);
51
+ }
52
+ }
53
+ }
54
+ }
55
+ for (const [groupId, groupDir] of groupDirs) {
56
+ const candidate = path.join(groupDir, "signing", sessionId.hex(), "start.json");
57
+ if (fs.existsSync(candidate)) candidatePaths.push([groupId, candidate]);
58
+ }
59
+ if (candidatePaths.length === 0) throw new Error("No sign start state found; run `frost sign coordinator start` first");
60
+ if (candidatePaths.length > 1) throw new Error("Multiple signing sessions found; specify --group to disambiguate");
61
+ const [groupId, statePath] = candidatePaths[0];
62
+ const raw = JSON.parse(fs.readFileSync(statePath, "utf-8"));
63
+ const getStr = (key) => {
64
+ const value = raw[key];
65
+ if (typeof value !== "string") throw new Error(`Missing or invalid ${key} in start.json`);
66
+ return value;
67
+ };
68
+ const sessionInState = parseAridUr(getStr("session_id"));
69
+ const groupInState = parseAridUr(getStr("group"));
70
+ if (sessionInState.hex() !== sessionId.hex()) throw new Error(`start.json session ${sessionInState.urString()} does not match requested session ${sessionId.urString()}`);
71
+ if (groupInState.hex() !== groupId.hex()) throw new Error(`start.json group ${groupInState.urString()} does not match directory group ${groupId.urString()}`);
72
+ const targetUr = getStr("target");
73
+ const participantsVal = raw["participants"];
74
+ if (participantsVal === void 0 || typeof participantsVal !== "object") throw new Error("Missing participants in start.json");
75
+ const participants = /* @__PURE__ */ new Map();
76
+ for (const [xidStr, value] of Object.entries(participantsVal)) {
77
+ const xid = XID.fromURString(xidStr);
78
+ if (typeof value !== "object" || value === null) throw new Error("Participant entry is not an object in start.json");
79
+ const commitAridStr = value["commit_arid"];
80
+ const shareAridStr = value["share_arid"];
81
+ if (typeof commitAridStr !== "string") throw new Error("Missing commit_arid in start.json");
82
+ if (typeof shareAridStr !== "string") throw new Error("Missing share_arid in start.json");
83
+ participants.set(xid.urString(), {
84
+ commitArid: parseAridUr(commitAridStr),
85
+ shareArid: parseAridUr(shareAridStr)
86
+ });
87
+ }
88
+ return {
89
+ groupId,
90
+ targetUr,
91
+ participants
92
+ };
93
+ }
94
+ /**
95
+ * Validate and extract data from a sign commit response.
96
+ *
97
+ * Port of `validate_and_extract_sign_round1_response()` from cmd/sign/coordinator/round1.rs.
98
+ */
99
+ function validateAndExtractCommitResponse(envelope, coordinatorKeys, expectedSender, expectedSessionId) {
100
+ const now = /* @__PURE__ */ new Date();
101
+ const sealedResponse = SealedResponse.tryFromEncryptedEnvelope(envelope, void 0, now, coordinatorKeys);
102
+ if (!sealedResponse.sender().xid().equals(expectedSender)) throw new Error(`Unexpected response sender: ${sealedResponse.sender().xid().urString()} (expected ${expectedSender.urString()})`);
103
+ if (sealedResponse.isErr()) {
104
+ const errorEnvelope = sealedResponse.error();
105
+ let reason = "unknown reason";
106
+ try {
107
+ const reasonEnv = errorEnvelope.objectForPredicate("reason");
108
+ if (reasonEnv !== void 0) reason = reasonEnv.extractString();
109
+ } catch {}
110
+ throw new Error(`Participant rejected signInvite: ${reason}`);
111
+ }
112
+ const result = sealedResponse.result();
113
+ result.checkSubjectUnit();
114
+ result.checkType("signRound1Response");
115
+ const responseSession = result.tryObjectForPredicate("session", (cbor) => ARID.fromTaggedCbor(cbor));
116
+ if (responseSession.hex() !== expectedSessionId.hex()) throw new Error(`Response session ${responseSession.urString()} does not match expected ${expectedSessionId.urString()}`);
117
+ const commitmentsJson = result.tryObjectForPredicate("commitments", (cbor) => JSON$1.fromTaggedCbor(cbor));
118
+ return {
119
+ commitments: JSON.parse(new TextDecoder().decode(commitmentsJson.toData())),
120
+ nextRequestArid: result.tryObjectForPredicate("response_arid", (cbor) => ARID.fromTaggedCbor(cbor))
121
+ };
122
+ }
123
+ /**
124
+ * Collect signing commitments in parallel.
125
+ *
126
+ * Port of `collect_sign_round1_parallel()` from cmd/sign/coordinator/round1.rs.
127
+ */
128
+ async function collectCommitmentsParallel(client, registry, startState, coordinator, sessionId, timeout) {
129
+ const requests = [];
130
+ for (const [xidStr, state] of startState.participants) {
131
+ const xid = XID.fromURString(xidStr);
132
+ const name = registry.participant(xid)?.petName() ?? xid.urString();
133
+ requests.push([
134
+ xid,
135
+ state.commitArid,
136
+ name
137
+ ]);
138
+ }
139
+ const coordinatorKeys = coordinator.inceptionPrivateKeys();
140
+ if (coordinatorKeys === void 0) throw new Error("Missing coordinator private keys");
141
+ return parallelFetch(client, requests, (envelope, xid) => {
142
+ try {
143
+ return validateAndExtractCommitResponse(envelope, coordinatorKeys, xid, sessionId);
144
+ } catch (e) {
145
+ return { rejected: e instanceof Error ? e.message : String(e) };
146
+ }
147
+ }, { timeoutSeconds: timeout });
148
+ }
149
+ /**
150
+ * Build a sign share request for a participant.
151
+ *
152
+ * Port of `build_sign_share_request()` from cmd/sign/coordinator/round1.rs.
153
+ */
154
+ function buildShareRequestForParticipant(sender, _groupId, sessionId, responseArid, commitments) {
155
+ let request = SealedRequest.new("signRound2", sessionId, sender).withParameter("session", sessionId).withParameter("response_arid", responseArid);
156
+ for (const [xidStr, commits] of commitments) {
157
+ const xid = XID.fromURString(xidStr);
158
+ const commitsJson = JSON$1.fromData(new TextEncoder().encode(JSON.stringify(commits)));
159
+ const entry = Envelope.new(xid).addAssertion("commitments", commitsJson.taggedCborData());
160
+ request = request.withParameter("commitment", entry);
161
+ }
162
+ return request;
163
+ }
164
+ /**
165
+ * Dispatch share requests to participants in parallel.
166
+ *
167
+ * Port of parallel dispatch logic from cmd/sign/coordinator/round1.rs.
168
+ */
169
+ async function dispatchShareRequestsParallel(client, registry, owner, startState, sessionId, collection, commitments, previewShare, verbose) {
170
+ const signerKeys = owner.xidDocument().inceptionPrivateKeys();
171
+ if (signerKeys === void 0) throw new Error("Coordinator XID document has no signing keys");
172
+ const validUntil = new Date(Date.now() + 3600 * 1e3);
173
+ const messages = [];
174
+ let previewPrinted = false;
175
+ for (const [xid, data] of collection.successes) {
176
+ const xidStr = xid.urString();
177
+ const participantState = startState.participants.get(xidStr);
178
+ if (participantState === void 0) throw new Error(`Participant ${xidStr} not found in start state`);
179
+ const participantName = registry.participant(xid)?.petName() ?? xidStr;
180
+ let recipientDoc;
181
+ if (xid.urString() === owner.xid().urString()) recipientDoc = owner.xidDocument();
182
+ else {
183
+ const record = registry.participant(xid);
184
+ if (record === void 0) throw new Error(`Participant ${xidStr} not found in registry`);
185
+ recipientDoc = record.xidDocument();
186
+ }
187
+ const request = buildShareRequestForParticipant(owner.xidDocument(), startState.groupId, sessionId, participantState.shareArid, commitments);
188
+ if (previewShare === true && !previewPrinted) {
189
+ const preview = request.toEnvelope(validUntil, signerKeys, void 0);
190
+ console.log(`# signRound2 preview for ${xidStr}`);
191
+ console.log(preview.format());
192
+ previewPrinted = true;
193
+ }
194
+ const sealedEnvelope = request.toEnvelopeForRecipients(validUntil, signerKeys, [recipientDoc]);
195
+ messages.push([
196
+ xid,
197
+ data.nextRequestArid,
198
+ sealedEnvelope,
199
+ participantName
200
+ ]);
201
+ }
202
+ console.error();
203
+ return parallelSend(client, messages, verbose);
204
+ }
205
+ /**
206
+ * Persist collected commitments to disk.
207
+ *
208
+ * Port of commitments persistence logic from cmd/sign/coordinator/round1.rs.
209
+ */
210
+ function persistCommitments(registryPath, groupId, sessionId, startState, commitments) {
211
+ const signingDir = signingStateDir(registryPath, groupId.hex(), sessionId.hex());
212
+ fs.mkdirSync(signingDir, { recursive: true });
213
+ const commitmentsPath = path.join(signingDir, "commitments.json");
214
+ const commitmentsJson = {};
215
+ for (const [xidStr, commits] of commitments) {
216
+ const participantState = startState.participants.get(xidStr);
217
+ if (participantState === void 0) throw new Error(`Participant ${xidStr} not found in start state`);
218
+ commitmentsJson[xidStr] = {
219
+ commitments: commits,
220
+ share_arid: participantState.shareArid.urString()
221
+ };
222
+ }
223
+ const root = {
224
+ group: groupId.urString(),
225
+ session: sessionId.urString(),
226
+ target: startState.targetUr,
227
+ commitments: commitmentsJson
228
+ };
229
+ fs.writeFileSync(commitmentsPath, JSON.stringify(root, null, 2));
230
+ return commitmentsPath;
231
+ }
232
+ /**
233
+ * Update pending requests in the registry for share phase.
234
+ *
235
+ * Note: In the Rust implementation, the registry doesn't track pending ARIDs
236
+ * directly on participant records. The pending state is managed through the
237
+ * start.json and commitments.json files in the signing state directory.
238
+ *
239
+ * This function is provided for API compatibility but currently does nothing.
240
+ */
241
+ function updatePendingForShare(_registry, _collection, _startState) {}
242
+ /**
243
+ * Execute the sign coordinator round 1 command.
244
+ *
245
+ * Collects signing commitments from participants.
246
+ *
247
+ * Port of `round1()` from cmd/sign/coordinator/round1.rs.
248
+ */
249
+ async function round1(client, options, cwd) {
250
+ const registryPath = resolveRegistryPath(options.registryPath, cwd);
251
+ const registry = Registry.load(registryPath);
252
+ const owner = registry.owner();
253
+ if (owner === void 0) throw new Error("Registry owner is required");
254
+ const sessionId = parseAridUr(options.sessionId);
255
+ const startState = loadStartState(registryPath, sessionId, options.groupId !== void 0 ? parseAridUr(options.groupId) : void 0);
256
+ const groupId = startState.groupId;
257
+ const groupRecord = registry.group(groupId);
258
+ if (groupRecord === void 0) throw new Error("Group not found in registry");
259
+ if (groupRecord.coordinator().xid().urString() !== owner.xid().urString()) throw new Error(`Only the coordinator can collect signInvite responses. Coordinator: ${groupRecord.coordinator().xid().urString()}, Owner: ${owner.xid().urString()}`);
260
+ if (options.parallel === true) {
261
+ const collection = await collectCommitmentsParallel(client, registry, startState, owner.xidDocument(), sessionId, options.timeoutSeconds);
262
+ if (collection.rejections.length > 0) {
263
+ console.error();
264
+ console.error("Rejections:");
265
+ for (const [xid, reason] of collection.rejections) console.error(` ${xid.urString()}: ${reason}`);
266
+ }
267
+ if (collection.errors.length > 0) {
268
+ console.error();
269
+ console.error("Errors:");
270
+ for (const [xid, error] of collection.errors) console.error(` ${xid.urString()}: ${error}`);
271
+ }
272
+ if (collection.timeouts.length > 0) {
273
+ console.error();
274
+ console.error("Timeouts:");
275
+ for (const xid of collection.timeouts) console.error(` ${xid.urString()}`);
276
+ }
277
+ if (!collection.allSucceeded()) throw new Error(`Sign commit collection incomplete: ${collection.successes.length} succeeded, ${collection.rejections.length} rejected, ${collection.errors.length} errors, ${collection.timeouts.length} timeouts`);
278
+ const commitments = /* @__PURE__ */ new Map();
279
+ for (const [xid, data] of collection.successes) commitments.set(xid.urString(), data.commitments);
280
+ const commitmentsPath = persistCommitments(registryPath, groupId, sessionId, startState, commitments);
281
+ const failures = (await dispatchShareRequestsParallel(client, registry, owner, startState, sessionId, collection, commitments, options.previewShare, options.verbose)).filter(([_, err]) => err !== null);
282
+ if (failures.length > 0) {
283
+ for (const [xid, error] of failures) if (error !== null) console.error(`Failed to send to ${xid.urString()}: ${error.message}`);
284
+ throw new Error(`Failed to send signRound2 requests to ${failures.length} participants`);
285
+ }
286
+ const displayPath = path.relative(cwd, commitmentsPath) || commitmentsPath;
287
+ if (isVerbose() || options.verbose === true) {
288
+ console.error();
289
+ console.error(`Collected ${collection.successes.length} signInvite responses. Saved to ${displayPath}`);
290
+ console.error(`Dispatched ${collection.successes.length} signRound2 requests.`);
291
+ }
292
+ return {
293
+ accepted: collection.successes.length,
294
+ rejected: collection.rejections.length,
295
+ errors: collection.errors.length,
296
+ timeouts: collection.timeouts.length
297
+ };
298
+ } else {
299
+ if (isVerbose() || options.verbose === true) console.error(`Collecting signInvite responses for session ${sessionId.urString()} from ${startState.participants.size} participants...`);
300
+ const commitments = /* @__PURE__ */ new Map();
301
+ const sendToArids = /* @__PURE__ */ new Map();
302
+ const errors = [];
303
+ const coordinatorKeys = owner.xidDocument().inceptionPrivateKeys();
304
+ if (coordinatorKeys === void 0) throw new Error("Coordinator XID document has no inception private keys");
305
+ for (const [xidStr, participantState] of startState.participants) {
306
+ const xid = XID.fromURString(xidStr);
307
+ const participantName = registry.participant(xid)?.petName() ?? xidStr;
308
+ try {
309
+ const envelope = await client.get(participantState.commitArid, options.timeoutSeconds);
310
+ if (envelope === void 0) throw new Error("Response not found in Hubert storage");
311
+ const data = validateAndExtractCommitResponse(envelope, coordinatorKeys, xid, sessionId);
312
+ commitments.set(xidStr, data.commitments);
313
+ sendToArids.set(xidStr, data.nextRequestArid);
314
+ if (isVerbose() || options.verbose === true) console.error(` ✓ ${participantName}`);
315
+ } catch (e) {
316
+ errors.push([xid, e instanceof Error ? e.message : String(e)]);
317
+ if (isVerbose() || options.verbose === true) console.error(` ✗ ${participantName}: ${e instanceof Error ? e.message : String(e)}`);
318
+ }
319
+ }
320
+ if (errors.length > 0) throw new Error(`Sign commit collection incomplete: ${errors.length} of ${startState.participants.size} responses failed`);
321
+ if (commitments.size !== startState.participants.size) {
322
+ const missing = [];
323
+ for (const xidStr of startState.participants.keys()) if (!commitments.has(xidStr)) missing.push(xidStr);
324
+ throw new Error(`Missing signInvite responses from: ${missing.join(", ")}`);
325
+ }
326
+ const commitmentsPath = persistCommitments(registryPath, groupId, sessionId, startState, commitments);
327
+ const signerKeys = owner.xidDocument().inceptionPrivateKeys();
328
+ if (signerKeys === void 0) throw new Error("Owner XID document has no inception private keys");
329
+ const validUntil = new Date(Date.now() + 3600 * 1e3);
330
+ if (isVerbose() || options.verbose === true) console.error(`Dispatching signRound2 requests to ${sendToArids.size} participants...`);
331
+ else console.error();
332
+ let previewPrinted = false;
333
+ for (const [xidStr, sendToArid] of sendToArids) {
334
+ const xid = XID.fromURString(xidStr);
335
+ const participantState = startState.participants.get(xidStr);
336
+ if (participantState === void 0) throw new Error(`Participant state not found for ${xidStr}`);
337
+ const participantName = registry.participant(xid)?.petName() ?? xidStr;
338
+ let recipientDoc;
339
+ if (xidStr === owner.xid().urString()) recipientDoc = owner.xidDocument();
340
+ else {
341
+ const record = registry.participant(xid);
342
+ if (record === void 0) throw new Error(`Participant ${xidStr} not found in registry`);
343
+ recipientDoc = record.xidDocument();
344
+ }
345
+ const request = buildShareRequestForParticipant(owner.xidDocument(), groupId, sessionId, participantState.shareArid, commitments);
346
+ if (options.previewShare === true && !previewPrinted) {
347
+ const preview = request.toEnvelope(validUntil, signerKeys, void 0);
348
+ console.log(`# signRound2 preview for ${xidStr}`);
349
+ console.log(preview.format());
350
+ previewPrinted = true;
351
+ }
352
+ const sealedEnvelope = request.toEnvelopeForRecipients(validUntil, signerKeys, [recipientDoc]);
353
+ await client.put(sendToArid, sealedEnvelope);
354
+ if (isVerbose() || options.verbose === true) console.error(` ✓ ${participantName}`);
355
+ }
356
+ const displayPath = path.relative(cwd, commitmentsPath) || commitmentsPath;
357
+ if (isVerbose() || options.verbose === true) {
358
+ console.error();
359
+ console.error(`Collected ${commitments.size} signInvite responses. Saved to ${displayPath}`);
360
+ console.error(`Dispatched ${commitments.size} signRound2 requests.`);
361
+ }
362
+ return {
363
+ accepted: commitments.size,
364
+ rejected: 0,
365
+ errors: errors.length,
366
+ timeouts: 0
367
+ };
368
+ }
369
+ }
370
+ //#endregion
371
+ export { round1 as a, validateAndExtractCommitResponse as c, persistCommitments as i, collectCommitmentsParallel as n, round1_exports as o, dispatchShareRequestsParallel as r, updatePendingForShare as s, buildShareRequestForParticipant as t };
372
+
373
+ //# sourceMappingURL=round1-7v9LlE11.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"round1-7v9LlE11.mjs","names":["ARIDClass","XIDClass","JSONClass"],"sources":["../src/cmd/sign/coordinator/round1.ts"],"sourcesContent":["/**\n * Copyright © 2023-2026 Blockchain Commons, LLC\n * Copyright © 2025-2026 Parity Technologies\n *\n *\n * Sign coordinator round 1 command.\n *\n * Port of cmd/sign/coordinator/round1.rs from frost-hubert-rust.\n *\n * @module\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport {\n type ARID,\n type XID,\n ARID as ARIDClass,\n XID as XIDClass,\n JSON as JSONClass,\n type PrivateKeys,\n} from \"@bcts/components\";\nimport { Envelope } from \"@bcts/envelope\";\nimport { SealedRequest, SealedResponse } from \"@bcts/gstp\";\nimport { type XIDDocument } from \"@bcts/xid\";\n\nimport { Registry, resolveRegistryPath, type OwnerRecord } from \"../../../registry/index.js\";\nimport {\n parallelFetch,\n parallelSend,\n type CollectionResult,\n type ParallelFetchConfig,\n} from \"../../parallel.js\";\nimport { type StorageClient } from \"../../storage.js\";\nimport { parseAridUr } from \"../../dkg/common.js\";\nimport { signingStateDir } from \"../common.js\";\nimport { isVerbose } from \"../../common.js\";\n\n/**\n * Options for the sign round1 command.\n */\nexport interface SignRound1Options {\n registryPath?: string;\n groupId?: string;\n sessionId: string;\n parallel?: boolean;\n timeoutSeconds?: number;\n verbose?: boolean;\n previewShare?: boolean;\n}\n\n/**\n * Result of the sign round1 command.\n */\nexport interface SignRound1Result {\n accepted: number;\n rejected: number;\n errors: number;\n timeouts: number;\n}\n\n/**\n * Data extracted from a successful sign round1 response.\n *\n * Port of `struct SignRound1ResponseData` from cmd/sign/coordinator/round1.rs.\n */\nexport interface SignRound1ResponseData {\n /** The signing commitments from this participant */\n commitments: unknown; // frost::round1::SigningCommitments equivalent\n /** The ARID where the participant expects the next request */\n nextRequestArid: ARID;\n}\n\n/**\n * State for a participant in the signing session.\n *\n * Port of `struct StartParticipant` from cmd/sign/coordinator/round1.rs.\n */\nexport interface StartParticipant {\n commitArid: ARID;\n shareArid: ARID;\n}\n\n/**\n * Start state for a signing session.\n *\n * Port of `struct StartState` from cmd/sign/coordinator/round1.rs.\n */\nexport interface StartState {\n groupId: ARID;\n targetUr: string;\n participants: Map<string, StartParticipant>; // Map by XID UR string\n}\n\n/**\n * Load the start state for a signing session.\n *\n * Port of `load_start_state()` from cmd/sign/coordinator/round1.rs.\n */\nfunction loadStartState(registryPath: string, sessionId: ARID, groupHint?: ARID): StartState {\n const base = path.dirname(registryPath);\n const groupStateDir = path.join(base, \"group-state\");\n\n const candidatePaths: [ARID, string][] = [];\n let groupDirs: [ARID, string][];\n\n if (groupHint !== undefined) {\n groupDirs = [[groupHint, path.join(groupStateDir, groupHint.hex())]];\n } else {\n groupDirs = [];\n if (fs.existsSync(groupStateDir)) {\n for (const entry of fs.readdirSync(groupStateDir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n const dirName = entry.name;\n if (dirName.length === 64 && /^[0-9a-fA-F]+$/.test(dirName)) {\n const groupId = ARIDClass.fromHex(dirName);\n groupDirs.push([groupId, path.join(groupStateDir, dirName)]);\n }\n }\n }\n }\n }\n\n for (const [groupId, groupDir] of groupDirs) {\n const candidate = path.join(groupDir, \"signing\", sessionId.hex(), \"start.json\");\n if (fs.existsSync(candidate)) {\n candidatePaths.push([groupId, candidate]);\n }\n }\n\n if (candidatePaths.length === 0) {\n throw new Error(\"No sign start state found; run `frost sign coordinator start` first\");\n }\n if (candidatePaths.length > 1) {\n throw new Error(\"Multiple signing sessions found; specify --group to disambiguate\");\n }\n\n const [groupId, statePath] = candidatePaths[0];\n const raw = JSON.parse(fs.readFileSync(statePath, \"utf-8\")) as Record<string, unknown>;\n\n const getStr = (key: string): string => {\n const value = raw[key];\n if (typeof value !== \"string\") {\n throw new Error(`Missing or invalid ${key} in start.json`);\n }\n return value;\n };\n\n const sessionInState = parseAridUr(getStr(\"session_id\"));\n const groupInState = parseAridUr(getStr(\"group\"));\n\n if (sessionInState.hex() !== sessionId.hex()) {\n throw new Error(\n `start.json session ${sessionInState.urString()} does not match requested session ${sessionId.urString()}`,\n );\n }\n if (groupInState.hex() !== groupId.hex()) {\n throw new Error(\n `start.json group ${groupInState.urString()} does not match directory group ${groupId.urString()}`,\n );\n }\n\n const targetUr = getStr(\"target\");\n\n const participantsVal = raw[\"participants\"] as Record<string, Record<string, string>> | undefined;\n if (participantsVal === undefined || typeof participantsVal !== \"object\") {\n throw new Error(\"Missing participants in start.json\");\n }\n\n const participants = new Map<string, StartParticipant>();\n for (const [xidStr, value] of Object.entries(participantsVal)) {\n const xid = XIDClass.fromURString(xidStr);\n if (typeof value !== \"object\" || value === null) {\n throw new Error(\"Participant entry is not an object in start.json\");\n }\n\n const commitAridStr = value[\"commit_arid\"];\n const shareAridStr = value[\"share_arid\"];\n\n if (typeof commitAridStr !== \"string\") {\n throw new Error(\"Missing commit_arid in start.json\");\n }\n if (typeof shareAridStr !== \"string\") {\n throw new Error(\"Missing share_arid in start.json\");\n }\n\n participants.set(xid.urString(), {\n commitArid: parseAridUr(commitAridStr),\n shareArid: parseAridUr(shareAridStr),\n });\n }\n\n return { groupId, targetUr, participants };\n}\n\n/**\n * Validate and extract data from a sign commit response.\n *\n * Port of `validate_and_extract_sign_round1_response()` from cmd/sign/coordinator/round1.rs.\n */\nexport function validateAndExtractCommitResponse(\n envelope: Envelope,\n coordinatorKeys: PrivateKeys,\n expectedSender: XID,\n expectedSessionId: ARID,\n): SignRound1ResponseData {\n const now = new Date();\n const sealedResponse = SealedResponse.tryFromEncryptedEnvelope(\n envelope,\n undefined,\n now,\n coordinatorKeys,\n );\n\n if (!sealedResponse.sender().xid().equals(expectedSender)) {\n throw new Error(\n `Unexpected response sender: ${sealedResponse.sender().xid().urString()} (expected ${expectedSender.urString()})`,\n );\n }\n\n if (sealedResponse.isErr()) {\n const errorEnvelope = sealedResponse.error();\n let reason = \"unknown reason\";\n try {\n const reasonEnv = errorEnvelope.objectForPredicate(\"reason\");\n if (reasonEnv !== undefined) {\n reason = reasonEnv.extractString();\n }\n } catch {\n // Keep default reason\n }\n throw new Error(`Participant rejected signInvite: ${reason}`);\n }\n\n const result = sealedResponse.result();\n\n result.checkSubjectUnit();\n result.checkType(\"signRound1Response\");\n\n const responseSession = result.tryObjectForPredicate(\"session\", (cbor) =>\n ARIDClass.fromTaggedCbor(cbor),\n );\n if (responseSession.hex() !== expectedSessionId.hex()) {\n throw new Error(\n `Response session ${responseSession.urString()} does not match expected ${expectedSessionId.urString()}`,\n );\n }\n\n const commitmentsJson = result.tryObjectForPredicate(\"commitments\", (cbor) =>\n JSONClass.fromTaggedCbor(cbor),\n );\n const commitments = JSON.parse(new TextDecoder().decode(commitmentsJson.toData())) as Record<\n string,\n unknown\n >;\n\n const nextRequestArid = result.tryObjectForPredicate(\"response_arid\", (cbor) =>\n ARIDClass.fromTaggedCbor(cbor),\n );\n\n return { commitments, nextRequestArid };\n}\n\n/**\n * Collect signing commitments in parallel.\n *\n * Port of `collect_sign_round1_parallel()` from cmd/sign/coordinator/round1.rs.\n */\nexport async function collectCommitmentsParallel(\n client: StorageClient,\n registry: Registry,\n startState: StartState,\n coordinator: XIDDocument,\n sessionId: ARID,\n timeout?: number,\n): Promise<CollectionResult<SignRound1ResponseData>> {\n const requests: [XID, ARID, string][] = [];\n\n for (const [xidStr, state] of startState.participants) {\n const xid = XIDClass.fromURString(xidStr);\n const participant = registry.participant(xid);\n const name = participant?.petName() ?? xid.urString();\n requests.push([xid, state.commitArid, name]);\n }\n\n const coordinatorKeys = coordinator.inceptionPrivateKeys();\n if (coordinatorKeys === undefined) {\n throw new Error(\"Missing coordinator private keys\");\n }\n\n const config: ParallelFetchConfig = { timeoutSeconds: timeout };\n\n return parallelFetch(\n client,\n requests,\n (envelope: Envelope, xid: XID) => {\n try {\n return validateAndExtractCommitResponse(envelope, coordinatorKeys, xid, sessionId);\n } catch (e) {\n return { rejected: e instanceof Error ? e.message : String(e) };\n }\n },\n config,\n );\n}\n\n/**\n * Build a sign share request for a participant.\n *\n * Port of `build_sign_share_request()` from cmd/sign/coordinator/round1.rs.\n */\nexport function buildShareRequestForParticipant(\n sender: XIDDocument,\n _groupId: ARID,\n sessionId: ARID,\n responseArid: ARID,\n commitments: Map<string, unknown>, // Map<XID UR string, commitments>\n): SealedRequest {\n let request = SealedRequest.new(\"signRound2\", sessionId, sender)\n .withParameter(\"session\", sessionId)\n .withParameter(\"response_arid\", responseArid);\n\n for (const [xidStr, commits] of commitments) {\n const xid = XIDClass.fromURString(xidStr);\n const commitsJson = JSONClass.fromData(new TextEncoder().encode(JSON.stringify(commits)));\n // Create envelope with xid as subject, then add commitments assertion with JSON CBOR data\n const entry = Envelope.new(xid).addAssertion(\"commitments\", commitsJson.taggedCborData());\n request = request.withParameter(\"commitment\", entry);\n }\n\n return request;\n}\n\n/**\n * Dispatch share requests to participants in parallel.\n *\n * Port of parallel dispatch logic from cmd/sign/coordinator/round1.rs.\n */\nexport async function dispatchShareRequestsParallel(\n client: StorageClient,\n registry: Registry,\n owner: OwnerRecord,\n startState: StartState,\n sessionId: ARID,\n collection: CollectionResult<SignRound1ResponseData>,\n commitments: Map<string, unknown>,\n previewShare?: boolean,\n verbose?: boolean,\n): Promise<[XID, Error | null][]> {\n const signerKeys = owner.xidDocument().inceptionPrivateKeys();\n if (signerKeys === undefined) {\n throw new Error(\"Coordinator XID document has no signing keys\");\n }\n\n const validUntil = new Date(Date.now() + 60 * 60 * 1000); // 1 hour from now\n\n const messages: [XID, ARID, Envelope, string][] = [];\n let previewPrinted = false;\n\n for (const [xid, data] of collection.successes) {\n const xidStr = xid.urString();\n const participantState = startState.participants.get(xidStr);\n if (participantState === undefined) {\n throw new Error(`Participant ${xidStr} not found in start state`);\n }\n\n const participant = registry.participant(xid);\n const participantName = participant?.petName() ?? xidStr;\n\n let recipientDoc: XIDDocument;\n if (xid.urString() === owner.xid().urString()) {\n recipientDoc = owner.xidDocument();\n } else {\n const record = registry.participant(xid);\n if (record === undefined) {\n throw new Error(`Participant ${xidStr} not found in registry`);\n }\n recipientDoc = record.xidDocument();\n }\n\n const request = buildShareRequestForParticipant(\n owner.xidDocument(),\n startState.groupId,\n sessionId,\n participantState.shareArid,\n commitments,\n );\n\n if (previewShare === true && !previewPrinted) {\n const preview = request.toEnvelope(validUntil, signerKeys, undefined);\n console.log(`# signRound2 preview for ${xidStr}`);\n console.log(preview.format());\n previewPrinted = true;\n }\n\n const sealedEnvelope = request.toEnvelopeForRecipients(validUntil, signerKeys, [recipientDoc]);\n\n messages.push([xid, data.nextRequestArid, sealedEnvelope, participantName]);\n }\n\n // Blank line to separate get phase from put phase\n console.error();\n\n return parallelSend(client, messages, verbose);\n}\n\n/**\n * Persist collected commitments to disk.\n *\n * Port of commitments persistence logic from cmd/sign/coordinator/round1.rs.\n */\nexport function persistCommitments(\n registryPath: string,\n groupId: ARID,\n sessionId: ARID,\n startState: StartState,\n commitments: Map<string, unknown>,\n): string {\n const signingDir = signingStateDir(registryPath, groupId.hex(), sessionId.hex());\n fs.mkdirSync(signingDir, { recursive: true });\n\n const commitmentsPath = path.join(signingDir, \"commitments.json\");\n const commitmentsJson: Record<string, unknown> = {};\n\n for (const [xidStr, commits] of commitments) {\n const participantState = startState.participants.get(xidStr);\n if (participantState === undefined) {\n throw new Error(`Participant ${xidStr} not found in start state`);\n }\n\n commitmentsJson[xidStr] = {\n commitments: commits,\n share_arid: participantState.shareArid.urString(),\n };\n }\n\n const root = {\n group: groupId.urString(),\n session: sessionId.urString(),\n target: startState.targetUr,\n commitments: commitmentsJson,\n };\n\n fs.writeFileSync(commitmentsPath, JSON.stringify(root, null, 2));\n\n return commitmentsPath;\n}\n\n/**\n * Update pending requests in the registry for share phase.\n *\n * Note: In the Rust implementation, the registry doesn't track pending ARIDs\n * directly on participant records. The pending state is managed through the\n * start.json and commitments.json files in the signing state directory.\n *\n * This function is provided for API compatibility but currently does nothing.\n */\nexport function updatePendingForShare(\n _registry: Registry,\n _collection: CollectionResult<SignRound1ResponseData>,\n _startState: StartState,\n): void {\n // No-op: The Rust implementation manages pending state through files,\n // not through the registry. The share_arid values are already stored\n // in commitments.json and will be used for round 2 collection.\n}\n\n/**\n * Execute the sign coordinator round 1 command.\n *\n * Collects signing commitments from participants.\n *\n * Port of `round1()` from cmd/sign/coordinator/round1.rs.\n */\nexport async function round1(\n client: StorageClient,\n options: SignRound1Options,\n cwd: string,\n): Promise<SignRound1Result> {\n const registryPath = resolveRegistryPath(options.registryPath, cwd);\n const registry = Registry.load(registryPath);\n\n const owner = registry.owner();\n if (owner === undefined) {\n throw new Error(\"Registry owner is required\");\n }\n\n const sessionId = parseAridUr(options.sessionId);\n const groupHint = options.groupId !== undefined ? parseAridUr(options.groupId) : undefined;\n\n const startState = loadStartState(registryPath, sessionId, groupHint);\n const groupId = startState.groupId;\n const groupRecord = registry.group(groupId);\n\n if (groupRecord === undefined) {\n throw new Error(\"Group not found in registry\");\n }\n\n if (groupRecord.coordinator().xid().urString() !== owner.xid().urString()) {\n throw new Error(\n `Only the coordinator can collect signInvite responses. ` +\n `Coordinator: ${groupRecord.coordinator().xid().urString()}, ` +\n `Owner: ${owner.xid().urString()}`,\n );\n }\n\n if (options.parallel === true) {\n // Parallel path with progress display\n const collection = await collectCommitmentsParallel(\n client,\n registry,\n startState,\n owner.xidDocument(),\n sessionId,\n options.timeoutSeconds,\n );\n\n // Report any failures\n if (collection.rejections.length > 0) {\n console.error();\n console.error(\"Rejections:\");\n for (const [xid, reason] of collection.rejections) {\n console.error(` ${xid.urString()}: ${reason}`);\n }\n }\n if (collection.errors.length > 0) {\n console.error();\n console.error(\"Errors:\");\n for (const [xid, error] of collection.errors) {\n console.error(` ${xid.urString()}: ${error}`);\n }\n }\n if (collection.timeouts.length > 0) {\n console.error();\n console.error(\"Timeouts:\");\n for (const xid of collection.timeouts) {\n console.error(` ${xid.urString()}`);\n }\n }\n\n if (!collection.allSucceeded()) {\n throw new Error(\n `Sign commit collection incomplete: ${collection.successes.length} succeeded, ` +\n `${collection.rejections.length} rejected, ${collection.errors.length} errors, ` +\n `${collection.timeouts.length} timeouts`,\n );\n }\n\n // Build commitments map\n const commitments = new Map<string, unknown>();\n for (const [xid, data] of collection.successes) {\n commitments.set(xid.urString(), data.commitments);\n }\n\n // Persist aggregated commitments\n const commitmentsPath = persistCommitments(\n registryPath,\n groupId,\n sessionId,\n startState,\n commitments,\n );\n\n // Dispatch share requests in parallel\n const sendResults = await dispatchShareRequestsParallel(\n client,\n registry,\n owner,\n startState,\n sessionId,\n collection,\n commitments,\n options.previewShare,\n options.verbose,\n );\n\n // Check for send failures\n const failures = sendResults.filter(([_, err]) => err !== null);\n if (failures.length > 0) {\n for (const [xid, error] of failures) {\n if (error !== null) {\n console.error(`Failed to send to ${xid.urString()}: ${error.message}`);\n }\n }\n throw new Error(`Failed to send signRound2 requests to ${failures.length} participants`);\n }\n\n // Update registry pending requests\n updatePendingForShare(registry, collection, startState);\n\n const displayPath = path.relative(cwd, commitmentsPath) || commitmentsPath;\n\n if (isVerbose() || options.verbose === true) {\n console.error();\n console.error(\n `Collected ${collection.successes.length} signInvite responses. Saved to ${displayPath}`,\n );\n console.error(`Dispatched ${collection.successes.length} signRound2 requests.`);\n }\n\n return {\n accepted: collection.successes.length,\n rejected: collection.rejections.length,\n errors: collection.errors.length,\n timeouts: collection.timeouts.length,\n };\n } else {\n // Sequential path (original behavior)\n if (isVerbose() || options.verbose === true) {\n console.error(\n `Collecting signInvite responses for session ${sessionId.urString()} ` +\n `from ${startState.participants.size} participants...`,\n );\n }\n\n const commitments = new Map<string, unknown>();\n const sendToArids = new Map<string, ARID>();\n const errors: [XID, string][] = [];\n\n const coordinatorKeys = owner.xidDocument().inceptionPrivateKeys();\n if (coordinatorKeys === undefined) {\n throw new Error(\"Coordinator XID document has no inception private keys\");\n }\n\n for (const [xidStr, participantState] of startState.participants) {\n const xid = XIDClass.fromURString(xidStr);\n const participant = registry.participant(xid);\n const participantName = participant?.petName() ?? xidStr;\n\n try {\n const envelope = await client.get(participantState.commitArid, options.timeoutSeconds);\n\n if (envelope === undefined) {\n throw new Error(\"Response not found in Hubert storage\");\n }\n\n const data = validateAndExtractCommitResponse(envelope, coordinatorKeys, xid, sessionId);\n\n commitments.set(xidStr, data.commitments);\n sendToArids.set(xidStr, data.nextRequestArid);\n\n if (isVerbose() || options.verbose === true) {\n console.error(` ✓ ${participantName}`);\n }\n } catch (e) {\n errors.push([xid, e instanceof Error ? e.message : String(e)]);\n if (isVerbose() || options.verbose === true) {\n console.error(` ✗ ${participantName}: ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n }\n\n if (errors.length > 0) {\n throw new Error(\n `Sign commit collection incomplete: ${errors.length} of ${startState.participants.size} responses failed`,\n );\n }\n\n if (commitments.size !== startState.participants.size) {\n const missing: string[] = [];\n for (const xidStr of startState.participants.keys()) {\n if (!commitments.has(xidStr)) {\n missing.push(xidStr);\n }\n }\n throw new Error(`Missing signInvite responses from: ${missing.join(\", \")}`);\n }\n\n // Persist aggregated commitments\n const commitmentsPath = persistCommitments(\n registryPath,\n groupId,\n sessionId,\n startState,\n commitments,\n );\n\n // Build and send signRound2 requests\n const signerKeys = owner.xidDocument().inceptionPrivateKeys();\n if (signerKeys === undefined) {\n throw new Error(\"Owner XID document has no inception private keys\");\n }\n const validUntil = new Date(Date.now() + 60 * 60 * 1000);\n\n if (isVerbose() || options.verbose === true) {\n console.error(`Dispatching signRound2 requests to ${sendToArids.size} participants...`);\n } else {\n // Blank line to separate get phase from put phase\n console.error();\n }\n\n let previewPrinted = false;\n for (const [xidStr, sendToArid] of sendToArids) {\n const xid = XIDClass.fromURString(xidStr);\n const participantState = startState.participants.get(xidStr);\n if (participantState === undefined) {\n throw new Error(`Participant state not found for ${xidStr}`);\n }\n const participant = registry.participant(xid);\n const participantName = participant?.petName() ?? xidStr;\n\n let recipientDoc: XIDDocument;\n if (xidStr === owner.xid().urString()) {\n recipientDoc = owner.xidDocument();\n } else {\n const record = registry.participant(xid);\n if (record === undefined) {\n throw new Error(`Participant ${xidStr} not found in registry`);\n }\n recipientDoc = record.xidDocument();\n }\n\n const request = buildShareRequestForParticipant(\n owner.xidDocument(),\n groupId,\n sessionId,\n participantState.shareArid,\n commitments,\n );\n\n if (options.previewShare === true && !previewPrinted) {\n const preview = request.toEnvelope(validUntil, signerKeys, undefined);\n console.log(`# signRound2 preview for ${xidStr}`);\n console.log(preview.format());\n previewPrinted = true;\n }\n\n const sealedEnvelope = request.toEnvelopeForRecipients(validUntil, signerKeys, [\n recipientDoc,\n ]);\n\n await client.put(sendToArid, sealedEnvelope);\n\n if (isVerbose() || options.verbose === true) {\n console.error(` ✓ ${participantName}`);\n }\n }\n\n const displayPath = path.relative(cwd, commitmentsPath) || commitmentsPath;\n\n if (isVerbose() || options.verbose === true) {\n console.error();\n console.error(`Collected ${commitments.size} signInvite responses. Saved to ${displayPath}`);\n console.error(`Dispatched ${commitments.size} signRound2 requests.`);\n }\n\n return {\n accepted: commitments.size,\n rejected: 0,\n errors: errors.length,\n timeouts: 0,\n };\n }\n}\n"],"mappings":"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"}