@did-btcr2/method 0.35.0 → 0.36.1

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 (55) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/browser.js +460 -223
  3. package/dist/browser.mjs +460 -223
  4. package/dist/cjs/index.js +461 -223
  5. package/dist/esm/core/aggregation/cohort.js +3 -1
  6. package/dist/esm/core/aggregation/cohort.js.map +1 -1
  7. package/dist/esm/core/aggregation/conditions.js +75 -0
  8. package/dist/esm/core/aggregation/conditions.js.map +1 -0
  9. package/dist/esm/core/aggregation/messages/base.js.map +1 -1
  10. package/dist/esm/core/aggregation/messages/bodies.js +16 -2
  11. package/dist/esm/core/aggregation/messages/bodies.js.map +1 -1
  12. package/dist/esm/core/aggregation/messages/factories.js.map +1 -1
  13. package/dist/esm/core/aggregation/participant.js +20 -7
  14. package/dist/esm/core/aggregation/participant.js.map +1 -1
  15. package/dist/esm/core/aggregation/runner/participant-runner.js +37 -2
  16. package/dist/esm/core/aggregation/runner/participant-runner.js.map +1 -1
  17. package/dist/esm/core/aggregation/runner/service-runner.js +323 -189
  18. package/dist/esm/core/aggregation/runner/service-runner.js.map +1 -1
  19. package/dist/esm/core/aggregation/service.js +23 -3
  20. package/dist/esm/core/aggregation/service.js.map +1 -1
  21. package/dist/esm/index.js +1 -0
  22. package/dist/esm/index.js.map +1 -1
  23. package/dist/types/core/aggregation/cohort.d.ts.map +1 -1
  24. package/dist/types/core/aggregation/conditions.d.ts +58 -0
  25. package/dist/types/core/aggregation/conditions.d.ts.map +1 -0
  26. package/dist/types/core/aggregation/messages/base.d.ts +2 -3
  27. package/dist/types/core/aggregation/messages/base.d.ts.map +1 -1
  28. package/dist/types/core/aggregation/messages/bodies.d.ts +2 -3
  29. package/dist/types/core/aggregation/messages/bodies.d.ts.map +1 -1
  30. package/dist/types/core/aggregation/messages/factories.d.ts +2 -3
  31. package/dist/types/core/aggregation/messages/factories.d.ts.map +1 -1
  32. package/dist/types/core/aggregation/participant.d.ts +16 -4
  33. package/dist/types/core/aggregation/participant.d.ts.map +1 -1
  34. package/dist/types/core/aggregation/runner/events.d.ts +22 -11
  35. package/dist/types/core/aggregation/runner/events.d.ts.map +1 -1
  36. package/dist/types/core/aggregation/runner/participant-runner.d.ts +21 -12
  37. package/dist/types/core/aggregation/runner/participant-runner.d.ts.map +1 -1
  38. package/dist/types/core/aggregation/runner/service-runner.d.ts +76 -22
  39. package/dist/types/core/aggregation/runner/service-runner.d.ts.map +1 -1
  40. package/dist/types/core/aggregation/service.d.ts +8 -4
  41. package/dist/types/core/aggregation/service.d.ts.map +1 -1
  42. package/dist/types/index.d.ts +1 -0
  43. package/dist/types/index.d.ts.map +1 -1
  44. package/package.json +4 -4
  45. package/src/core/aggregation/cohort.ts +3 -1
  46. package/src/core/aggregation/conditions.ts +116 -0
  47. package/src/core/aggregation/messages/base.ts +6 -3
  48. package/src/core/aggregation/messages/bodies.ts +18 -6
  49. package/src/core/aggregation/messages/factories.ts +2 -3
  50. package/src/core/aggregation/participant.ts +28 -11
  51. package/src/core/aggregation/runner/events.ts +23 -14
  52. package/src/core/aggregation/runner/participant-runner.ts +43 -13
  53. package/src/core/aggregation/runner/service-runner.ts +375 -195
  54. package/src/core/aggregation/service.ts +39 -7
  55. package/src/index.ts +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"participant-runner.d.ts","sourceRoot":"","sources":["../../../../../src/core/aggregation/runner/participant-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAUzD,OAAO,KAAK,EACV,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EAAC,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EACL,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,yEAAyE;AACzE,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpE,wEAAwE;AACxE,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAEjC,4DAA4D;AAC5D,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEzF,oDAAoD;AACpD,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,qBAAqB,KAAK,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAE/F,MAAM,WAAW,mCAAmC;IAClD,4BAA4B;IAC5B,SAAS,EAAE,SAAS,CAAC;IAErB,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,cAAc,CAAC;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IAExB;;;OAGG;IACH,eAAe,EAAE,eAAe,CAAC;IAEjC;;;OAGG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,qBAAa,4BAA6B,SAAQ,iBAAiB,CAAC,4BAA4B,CAAC;;IAC/F,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;gBAY7B,OAAO,EAAE,mCAAmC;IAexD;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,8EAA8E;IAC9E,IAAI,IAAI,IAAI;IA4BZ;;;OAGG;WACU,SAAS,CACpB,OAAO,EAAE,mCAAmC,GAC3C,OAAO,CAAC;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,mEAAmE;QACnE,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzC,0FAA0F;QAC1F,QAAQ,CAAC,EAAE,kBAAkB,CAAC;KAC/B,CAAC;CAwNH"}
1
+ {"version":3,"file":"participant-runner.d.ts","sourceRoot":"","sources":["../../../../../src/core/aggregation/runner/participant-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAUzD,OAAO,KAAK,EACV,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EAAC,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EACL,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,4BAA4B,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,yEAAyE;AACzE,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpE,wEAAwE;AACxE,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAEjC,4DAA4D;AAC5D,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEzF,oDAAoD;AACpD,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,qBAAqB,KAAK,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAE/F,MAAM,WAAW,mCAAmC;IAClD,4BAA4B;IAC5B,SAAS,EAAE,SAAS,CAAC;IAErB,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,cAAc,CAAC;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IAExB;;;OAGG;IACH,eAAe,EAAE,eAAe,CAAC;IAEjC;;;OAGG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,qBAAa,4BAA6B,SAAQ,iBAAiB,CAAC,4BAA4B,CAAC;;IAC/F,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;gBAY7B,OAAO,EAAE,mCAAmC;IAexD;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,8EAA8E;IAC9E,IAAI,IAAI,IAAI;IA4BZ;;;;OAIG;WACU,SAAS,CACpB,OAAO,EAAE,mCAAmC,GAC3C,OAAO,CAAC,kBAAkB,CAAC;IAY9B;;;;;;;;;;;;;;;OAeG;WACU,YAAY,CACvB,OAAO,EAAE,mCAAmC,EAC5C,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,kBAAkB,EAAE,CAAC;CA+NjC"}
@@ -27,8 +27,13 @@ export interface AggregationServiceRunnerOptions {
27
27
  /** This service's identity. */
28
28
  did: string;
29
29
  keys: SchnorrKeyPair;
30
- /** Cohort configuration. */
31
- config: CohortConfig;
30
+ /**
31
+ * Default cohort configuration for the {@link AggregationServiceRunner.run}
32
+ * convenience path. Optional: omit it when driving the runner with
33
+ * {@link AggregationServiceRunner.advertiseCohort}, which takes a per-cohort
34
+ * config and can be called many times on one runner.
35
+ */
36
+ config?: CohortConfig;
32
37
  /**
33
38
  * Decide whether to accept a participant's opt-in.
34
39
  * Default: auto-accept all opt-ins.
@@ -52,24 +57,26 @@ export interface AggregationServiceRunnerOptions {
52
57
  */
53
58
  maxUpdateSizeBytes?: number;
54
59
  /**
55
- * Overall wall-clock budget for the cohort, from run() to signing-complete.
56
- * On expiry the cohort is dropped, `cohort-failed` is emitted, and run()
57
- * rejects with a timeout error. Leave undefined to disable.
60
+ * Overall wall-clock budget for each cohort, from advertise to
61
+ * signing-complete. On expiry the cohort is dropped, `cohort-failed` is
62
+ * emitted, and that cohort's completion rejects with a timeout error. Other
63
+ * cohorts on the same runner are unaffected. Leave undefined to disable.
58
64
  */
59
65
  cohortTtlMs?: number;
60
66
  /**
61
- * Maximum time allowed between phase transitions. Protects against stalled
62
- * cohorts (e.g. a participant vanishing mid-protocol). Reset automatically
63
- * on every observed phase change. Leave undefined to disable.
67
+ * Maximum time allowed between phase transitions for a cohort. Protects
68
+ * against stalled cohorts (e.g. a participant vanishing mid-protocol). Reset
69
+ * automatically on every observed phase change. Applied per cohort. Leave
70
+ * undefined to disable.
64
71
  */
65
72
  phaseTimeoutMs?: number;
66
73
  /**
67
- * Re-publish COHORT_ADVERT on this interval until keygen is finalized.
68
- * Works around relays that don't backfill historical events to late
69
- * subscribers — a republish gives late joiners a window to discover the
74
+ * Re-publish COHORT_ADVERT on this interval until a cohort's keygen is
75
+ * finalized. Works around relays that don't backfill historical events to
76
+ * late subscribers — a republish gives late joiners a window to discover the
70
77
  * advert without protocol changes. The first publish is immediate;
71
- * subsequent publishes fire every `advertRepeatIntervalMs` until
72
- * keygen-complete, fail, or stop(). Defaults to
78
+ * subsequent publishes fire every `advertRepeatIntervalMs` until that
79
+ * cohort's keygen completes, fails, or is stopped. Defaults to
73
80
  * {@link DEFAULT_ADVERT_REPEAT_INTERVAL_MS} (60 s). Set to 0 to publish
74
81
  * once and never retry.
75
82
  */
@@ -84,6 +91,14 @@ export declare const DEFAULT_ADVERT_REPEAT_INTERVAL_MS = 60000;
84
91
  * encapsulating message handler registration, outgoing message dispatch,
85
92
  * and decision callback orchestration.
86
93
  *
94
+ * A single runner is a long-lived multiplexer: it advertises and drives many
95
+ * cohorts concurrently over one transport. Each advertised cohort owns an
96
+ * independent completion promise and fails in isolation — a stalled or failed
97
+ * cohort never settles its siblings (see ADR 040). Use
98
+ * {@link AggregationServiceRunner.advertiseCohort} for the multi-cohort path;
99
+ * {@link AggregationServiceRunner.run} is a thin single-cohort convenience over
100
+ * it.
101
+ *
87
102
  * @example
88
103
  * ```typescript
89
104
  * const transport = new NostrTransport({ relays: [RELAY] });
@@ -93,16 +108,21 @@ export declare const DEFAULT_ADVERT_REPEAT_INTERVAL_MS = 60000;
93
108
  * transport,
94
109
  * did: serviceDid,
95
110
  * keys: serviceKeys,
96
- * config: { minParticipants: 2, network: 'mutinynet', beaconType: 'CASBeacon' },
97
- * onProvideTxData: async ({ beaconAddress, signalBytes }) => {
111
+ * onProvideTxData: async ({ cohortId, beaconAddress, signalBytes }) => {
98
112
  * return await buildBeaconTransaction(beaconAddress, signalBytes, bitcoin);
99
113
  * },
100
114
  * });
101
115
  *
102
- * runner.on('keygen-complete', ({ beaconAddress }) => console.log(beaconAddress));
103
- * runner.on('signing-complete', ({ signature }) => console.log('done'));
116
+ * runner.on('keygen-complete', ({ cohortId, beaconAddress }) => console.log(beaconAddress));
117
+ * runner.on('signing-complete', ({ cohortId, signature }) => console.log('done', cohortId));
104
118
  *
105
- * const result = await runner.run();
119
+ * // Multi-cohort: advertise several cohorts; each completion resolves independently.
120
+ * const a = runner.advertiseCohort({ minParticipants: 2, network: 'mutinynet', beaconType: 'CASBeacon' });
121
+ * const b = runner.advertiseCohort({ minParticipants: 3, network: 'mutinynet', beaconType: 'SMTBeacon' });
122
+ * const [ra, rb] = await Promise.all([a.completion, b.completion]);
123
+ *
124
+ * // Single-cohort convenience (requires `config` in the options):
125
+ * // const result = await runner.run();
106
126
  * ```
107
127
  *
108
128
  * For full manual control, drop down to the underlying state machine via
@@ -117,15 +137,49 @@ export declare class AggregationServiceRunner extends TypedEventEmitter<Aggregat
117
137
  readonly session: AggregationService;
118
138
  constructor(options: AggregationServiceRunnerOptions);
119
139
  /**
120
- * Run the protocol to completion. Resolves with the final aggregation result
121
- * (signature + signed transaction) once signing is complete.
140
+ * Advertise a new cohort and begin driving it to completion. Callable many
141
+ * times on one runner; each cohort runs concurrently and independently.
142
+ *
143
+ * @param config Per-cohort conditions + network (see {@link CohortConfig}).
144
+ * @returns The new cohort's id and a `completion` promise that resolves with
145
+ * that cohort's {@link AggregationResult} (or rejects if it fails/stalls).
146
+ * @throws If the runner has been stopped, or the config is invalid
147
+ * (fail-fast via `createCohort`).
148
+ */
149
+ advertiseCohort(config: CohortConfig): {
150
+ cohortId: string;
151
+ completion: Promise<AggregationResult>;
152
+ };
153
+ /**
154
+ * Run a single cohort to completion using the `config` supplied in the
155
+ * runner options. Thin convenience over {@link advertiseCohort} for the
156
+ * single-cohort case (and the path {@link AggregationRunner.solo} rides).
122
157
  *
123
158
  * @returns {Promise<AggregationResult>} The final result with signature and signed tx.
124
159
  */
125
160
  run(): Promise<AggregationResult>;
126
161
  /**
127
- * Stop the runner early. Marks the runner stopped and detaches transport
128
- * handlers so a restart or a new runner doesn't inherit stale dispatch.
162
+ * Wait for every currently-outstanding cohort to settle and return the
163
+ * successful results. Dynamic drain: cohorts advertised while this is pending
164
+ * are included, and it resolves only once no cohorts remain. Failed cohorts
165
+ * are surfaced via `error` / `cohort-failed` events and their rejected
166
+ * `completion` promises; they are omitted from the returned array (this
167
+ * method does not throw). Bound long-running cohorts with `cohortTtlMs` /
168
+ * `phaseTimeoutMs` or this may never resolve.
169
+ *
170
+ * @returns {Promise<AggregationResult[]>} Results of the cohorts that completed.
171
+ */
172
+ runAll(): Promise<AggregationResult[]>;
173
+ /**
174
+ * Stop a single cohort early without affecting the rest of the runner. Drops
175
+ * the cohort's state machine state; its `completion` promise rejects with a
176
+ * stopped error.
177
+ */
178
+ stopCohort(cohortId: string): void;
179
+ /**
180
+ * Stop the whole runner. Fails every outstanding cohort, then detaches the
181
+ * shared transport handlers so a restart or a new runner doesn't inherit
182
+ * stale dispatch. Safe to call repeatedly.
129
183
  */
130
184
  stop(): void;
131
185
  }
@@ -1 +1 @@
1
- {"version":3,"file":"service-runner.d.ts","sourceRoot":"","sources":["../../../../../src/core/aggregation/runner/service-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAUzD,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,aAAa,EAAC,MAAM,eAAe,CAAC;AACtC,OAAO,EACL,kBAAkB,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,kEAAkE;AAClE,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEtF,6EAA6E;AAC7E,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB,KAAK,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAErC,mEAAmE;AACnE,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,UAAU,CAAC;CACzB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;AAE7B,MAAM,WAAW,+BAA+B;IAC9C,kEAAkE;IAClE,SAAS,EAAE,SAAS,CAAC;IAErB,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,cAAc,CAAC;IAErB,4BAA4B;IAC5B,MAAM,EAAE,YAAY,CAAC;IAErB;;;OAGG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAEtC;;;OAGG;IACH,eAAe,EAAE,eAAe,CAAC;IAEjC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;;;;;;OASG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,0FAA0F;AAC1F,eAAO,MAAM,iCAAiC,QAAS,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,wBAAyB,SAAQ,iBAAiB,CAAC,wBAAwB,CAAC;;IACvF,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;gBA8BzB,OAAO,EAAE,+BAA+B;IAoCpD;;;;;OAKG;IACH,GAAG,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAiGjC;;;OAGG;IACH,IAAI,IAAI,IAAI;CAqQb"}
1
+ {"version":3,"file":"service-runner.d.ts","sourceRoot":"","sources":["../../../../../src/core/aggregation/runner/service-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAWzD,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,aAAa,EAAC,MAAM,eAAe,CAAC;AACtC,OAAO,EACL,kBAAkB,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,kEAAkE;AAClE,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEtF,6EAA6E;AAC7E,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB,KAAK,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAErC,mEAAmE;AACnE,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,UAAU,CAAC;CACzB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;AAE7B,MAAM,WAAW,+BAA+B;IAC9C,kEAAkE;IAClE,SAAS,EAAE,SAAS,CAAC;IAErB,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,cAAc,CAAC;IAErB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IAEtB;;;OAGG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAEtC;;;OAGG;IACH,eAAe,EAAE,eAAe,CAAC;IAEjC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;;;;;;OASG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,0FAA0F;AAC1F,eAAO,MAAM,iCAAiC,QAAS,CAAC;AAqCxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,qBAAa,wBAAyB,SAAQ,iBAAiB,CAAC,wBAAwB,CAAC;;IACvF,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;gBAiBzB,OAAO,EAAE,+BAA+B;IAyCpD;;;;;;;;;OASG;IACH,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAA;KAAE;IA6CnG;;;;;;OAMG;IACH,GAAG,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAcjC;;;;;;;;;;OAUG;IACG,MAAM,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAiI5C;;;;OAIG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IASlC;;;;OAIG;IACH,IAAI,IAAI,IAAI;CAyQb"}
@@ -2,13 +2,17 @@ import type { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
2
2
  import type { CompressedSecp256k1PublicKey } from '@did-btcr2/keypair';
3
3
  import type { Transaction } from '@scure/btc-signer';
4
4
  import { AggregationCohort } from './cohort.js';
5
+ import { type CohortConditions } from './conditions.js';
5
6
  import type { BaseMessage } from './messages/base.js';
6
7
  import type { ServiceCohortPhaseType } from './phases.js';
7
- /** Cohort configuration set by the service operator. */
8
- export interface CohortConfig {
9
- minParticipants: number;
8
+ /**
9
+ * Cohort configuration set by the service operator: the advertised cohort
10
+ * {@link CohortConditions} plus the Bitcoin network. `beaconType` and
11
+ * `minParticipants` are required; the other conditions are optional (absent =
12
+ * unconstrained). See ADR 039.
13
+ */
14
+ export interface CohortConfig extends CohortConditions {
10
15
  network: string;
11
- beaconType: string;
12
16
  }
13
17
  /** Pending opt-in awaiting service operator approval. */
14
18
  export interface PendingOptIn {
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../../src/core/aggregation/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../../src/core/aggregation/service.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  export * from './core/aggregation/service.js';
2
2
  export * from './core/aggregation/participant.js';
3
3
  export * from './core/aggregation/signer.js';
4
+ export * from './core/aggregation/conditions.js';
4
5
  export * from './core/aggregation/cohort.js';
5
6
  export * from './core/aggregation/signing-session.js';
6
7
  export * from './core/aggregation/phases.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AAGnD,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AAGvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AAGxC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AAGnD,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AAGvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AAGxC,cAAc,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@did-btcr2/method",
3
- "version": "0.35.0",
3
+ "version": "0.36.1",
4
4
  "type": "module",
5
5
  "description": "Reference implementation for the did:btcr2 DID method written in TypeScript and JavaScript. did:btcr2 is a censorship resistant DID Method using the Bitcoin blockchain as a Verifiable Data Registry to announce changes to the DID document. This is the core method implementation for the did-btcr2-js monorepo.",
6
6
  "main": "./dist/cjs/index.js",
@@ -80,11 +80,11 @@
80
80
  "helia": "^5.5.1",
81
81
  "multiformats": "^13.4.2",
82
82
  "nostr-tools": "^2.23.3",
83
- "@did-btcr2/common": "^9.1.0",
84
83
  "@did-btcr2/bitcoin": "^0.6.0",
85
- "@did-btcr2/cryptosuite": "^8.0.0",
84
+ "@did-btcr2/keypair": "^0.13.1",
86
85
  "@did-btcr2/smt": "^0.3.0",
87
- "@did-btcr2/keypair": "^0.13.1"
86
+ "@did-btcr2/common": "^9.1.0",
87
+ "@did-btcr2/cryptosuite": "^8.0.0"
88
88
  },
89
89
  "devDependencies": {
90
90
  "@eslint/js": "^9.39.4",
@@ -91,7 +91,9 @@ export class AggregationCohort {
91
91
 
92
92
  constructor({ id, minParticipants, serviceDid, network, beaconType }: AggregationCohortParams) {
93
93
  this.id = id || crypto.randomUUID();
94
- this.minParticipants = minParticipants || 2;
94
+ // `?? 2` (not `|| 2`) so a deliberately-passed 0 is preserved rather than
95
+ // silently coerced; the service rejects an invalid count at createCohort.
96
+ this.minParticipants = minParticipants ?? 2;
95
97
  this.serviceDid = serviceDid || '';
96
98
  this.network = network;
97
99
  this.beaconType = beaconType || 'CASBeacon';
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Cohort conditions: the constraints an Aggregation Service advertises for a
3
+ * cohort (did:btcr2 spec, "Step 1: Create Aggregation Cohort"). See ADR 039.
4
+ *
5
+ * The spec frames these as an optional menu ("the Aggregation Service can define
6
+ * conditions such as ..."), so only `beaconType` and `minParticipants` are
7
+ * required here; every other condition is optional and, when absent, means
8
+ * unconstrained.
9
+ *
10
+ * Enforcement is staged (ADR 039): `beaconType` and the participant bounds are
11
+ * enforced by the state machine now; DIDs-per-participant, timing/cadence, and
12
+ * the pending-update trigger are modeled and advertised here but enforced when
13
+ * the multi-cohort (AGG-4) and non-inclusion (AGG-5) tracks land. The two cost
14
+ * conditions are advertised metadata only - the protocol performs no payment or
15
+ * settlement (consistent with ADR 008).
16
+ */
17
+
18
+ /** Beacon types that support aggregation (singleton is single-party only, per ADR 037). */
19
+ export const KNOWN_BEACON_TYPES = ['CASBeacon', 'SMTBeacon'] as const;
20
+
21
+ /**
22
+ * An advertised price. `unit` is operator-defined (the spec does not specify a
23
+ * currency); `basis` distinguishes a per-DID from a per-participant charge for
24
+ * "cost per announcement". Advertised only - never settled by the protocol.
25
+ */
26
+ export interface CohortCost {
27
+ amount: number;
28
+ unit: string;
29
+ basis?: 'per-did' | 'per-participant';
30
+ }
31
+
32
+ /** The seven spec cohort conditions. Only beaconType + minParticipants are required. */
33
+ export interface CohortConditions {
34
+ /** 1. Beacon mechanism: 'CASBeacon' or 'SMTBeacon'. Enforced. */
35
+ beaconType: string;
36
+ /** 2. Lower bound on cohort size. Enforced (finalize floor). */
37
+ minParticipants: number;
38
+ /** 2. Upper bound on cohort size. Enforced (accept/finalize ceiling). */
39
+ maxParticipants?: number;
40
+ /** 3. Lower bound on DIDs a participant may register. Advertised; enforcement staged (AGG-5). */
41
+ minDidsPerParticipant?: number;
42
+ /** 3. Upper bound on DIDs a participant may register. Advertised; enforcement staged (AGG-5). */
43
+ maxDidsPerParticipant?: number;
44
+ /** 4. One-time enrollment price. Advertised only - no settlement. */
45
+ costOfEnrollment?: CohortCost;
46
+ /** 5. Recurring per-announcement price. Advertised only - no settlement. */
47
+ costPerAnnouncement?: CohortCost;
48
+ /** 6. Floor on time between announcements (seconds). Advertised; enforcement staged (AGG-4/5). */
49
+ minSecondsBetweenAnnouncements?: number;
50
+ /** 6. Ceiling on time between announcements (seconds). Advertised; enforcement staged - generalizes the ADR 027 Cohort TTL. */
51
+ maxSecondsBetweenAnnouncements?: number;
52
+ /** 7. Pending-update count that triggers an announcement. Advertised; enforcement staged (AGG-5) - generalizes hasAllUpdates(). */
53
+ pendingUpdateTrigger?: number;
54
+ }
55
+
56
+ /** Validate an optional [min, max] integer pair. */
57
+ function checkPair(problems: string[], label: string, min?: number, max?: number): void {
58
+ if(min !== undefined && (!Number.isInteger(min) || min < 0)) {
59
+ problems.push(`min${label} must be an integer >= 0`);
60
+ }
61
+ if(max !== undefined && (!Number.isInteger(max) || max < 0)) {
62
+ problems.push(`max${label} must be an integer >= 0`);
63
+ }
64
+ if(min !== undefined && max !== undefined && Number.isInteger(min) && Number.isInteger(max) && max < min) {
65
+ problems.push(`max${label} must be >= min${label}`);
66
+ }
67
+ }
68
+
69
+ /** Validate an optional advertised cost. */
70
+ function checkCost(problems: string[], label: string, cost?: CohortCost): void {
71
+ if(cost === undefined) return;
72
+ if(typeof cost.amount !== 'number' || !Number.isFinite(cost.amount) || cost.amount < 0) {
73
+ problems.push(`${label}.amount must be a finite number >= 0`);
74
+ }
75
+ if(typeof cost.unit !== 'string' || cost.unit.length === 0) {
76
+ problems.push(`${label}.unit must be a non-empty string`);
77
+ }
78
+ if(cost.basis !== undefined && cost.basis !== 'per-did' && cost.basis !== 'per-participant') {
79
+ problems.push(`${label}.basis must be 'per-did' or 'per-participant'`);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Validate a set of cohort conditions. Returns a list of human-readable problems
85
+ * (empty when valid) so the caller can decide how to surface them. Used by
86
+ * `createCohort()` to fail fast instead of discovering invalidity at finalize.
87
+ */
88
+ export function validateCohortConditions(c: CohortConditions): string[] {
89
+ const problems: string[] = [];
90
+
91
+ if(!(KNOWN_BEACON_TYPES as readonly string[]).includes(c.beaconType)) {
92
+ problems.push(`beaconType must be one of ${KNOWN_BEACON_TYPES.join(', ')}`);
93
+ }
94
+ if(!Number.isInteger(c.minParticipants) || c.minParticipants < 1) {
95
+ problems.push('minParticipants must be an integer >= 1');
96
+ }
97
+ if(c.maxParticipants !== undefined) {
98
+ if(!Number.isInteger(c.maxParticipants) || c.maxParticipants < 1) {
99
+ problems.push('maxParticipants must be an integer >= 1');
100
+ } else if(Number.isInteger(c.minParticipants) && c.maxParticipants < c.minParticipants) {
101
+ problems.push('maxParticipants must be >= minParticipants');
102
+ }
103
+ }
104
+
105
+ checkPair(problems, 'DidsPerParticipant', c.minDidsPerParticipant, c.maxDidsPerParticipant);
106
+ checkPair(problems, 'SecondsBetweenAnnouncements', c.minSecondsBetweenAnnouncements, c.maxSecondsBetweenAnnouncements);
107
+
108
+ if(c.pendingUpdateTrigger !== undefined && (!Number.isInteger(c.pendingUpdateTrigger) || c.pendingUpdateTrigger < 1)) {
109
+ problems.push('pendingUpdateTrigger must be an integer >= 1');
110
+ }
111
+
112
+ checkCost(problems, 'costOfEnrollment', c.costOfEnrollment);
113
+ checkCost(problems, 'costPerAnnouncement', c.costPerAnnouncement);
114
+
115
+ return problems;
116
+ }
@@ -1,3 +1,5 @@
1
+ import type { CohortConditions } from '../conditions.js';
2
+
1
3
  /**
2
4
  * Current on-the-wire protocol version.
3
5
  *
@@ -7,9 +9,11 @@
7
9
  */
8
10
  export const AGGREGATION_WIRE_VERSION = 1;
9
11
 
10
- export type BaseBody = {
12
+ // Cohort conditions (beaconType, minParticipants, maxParticipants, ...) ride on
13
+ // the wire as flat optional body fields, supplied via `Partial<CohortConditions>`
14
+ // below so the bag stays a single source of truth for the advertised conditions.
15
+ export type BaseBody = Partial<CohortConditions> & {
11
16
  cohortId: string;
12
- cohortSize?: number;
13
17
  network?: string;
14
18
  participantPk?: Uint8Array;
15
19
  beaconAddress?: string;
@@ -23,7 +27,6 @@ export type BaseBody = {
23
27
  prevOutScriptHex?: string;
24
28
  prevOutValue?: string;
25
29
  communicationPk?: Uint8Array;
26
- beaconType?: string;
27
30
  data?: string;
28
31
  signedUpdate?: Record<string, unknown>;
29
32
  casAnnouncement?: Record<string, string>;
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  import type { SerializedSMTProof } from '@did-btcr2/smt';
15
+ import type { CohortConditions } from '../conditions.js';
15
16
  import type { BaseMessage } from './base.js';
16
17
  import {
17
18
  AGGREGATED_NONCE,
@@ -29,10 +30,8 @@ import {
29
30
 
30
31
  // ── Cohort formation (Step 1) ─────────────────────────────────────────────
31
32
 
32
- export interface CohortAdvertBody {
33
+ export interface CohortAdvertBody extends CohortConditions {
33
34
  cohortId: string;
34
- cohortSize: number;
35
- beaconType: string;
36
35
  network: string;
37
36
  communicationPk: Uint8Array;
38
37
  }
@@ -135,8 +134,16 @@ export type AggregationMessage =
135
134
 
136
135
  const hasStr = (b: unknown, k: string): boolean =>
137
136
  !!b && typeof (b as Record<string, unknown>)[k] === 'string';
138
- const hasNum = (b: unknown, k: string): boolean =>
139
- !!b && typeof (b as Record<string, unknown>)[k] === 'number';
137
+ /** Present, an integer, and >= min. */
138
+ const hasIntMin = (b: unknown, k: string, min: number): boolean => {
139
+ const v = b ? (b as Record<string, unknown>)[k] : undefined;
140
+ return typeof v === 'number' && Number.isInteger(v) && v >= min;
141
+ };
142
+ /** Absent, or present as an integer >= min. */
143
+ const optIntMin = (b: unknown, k: string, min: number): boolean => {
144
+ const v = b ? (b as Record<string, unknown>)[k] : undefined;
145
+ return v === undefined || (typeof v === 'number' && Number.isInteger(v) && v >= min);
146
+ };
140
147
  const hasBool = (b: unknown, k: string): boolean =>
141
148
  !!b && typeof (b as Record<string, unknown>)[k] === 'boolean';
142
149
  const hasBytes = (b: unknown, k: string): boolean =>
@@ -147,9 +154,14 @@ const hasBytesArray = (b: unknown, k: string): boolean => {
147
154
  };
148
155
 
149
156
  export function isCohortAdvertMessage(m: BaseMessage): m is CohortAdvertMessage {
157
+ // Range-check the participant bounds so a malformed advert (missing or
158
+ // zero/negative minParticipants) is rejected rather than silently accepted as
159
+ // a zero-floor cohort. The service does the full cross-field validation at
160
+ // createCohort (see validateCohortConditions); here we guard the wire shape.
150
161
  return m.type === COHORT_ADVERT
151
162
  && hasStr(m.body, 'cohortId')
152
- && hasNum(m.body, 'cohortSize')
163
+ && hasIntMin(m.body, 'minParticipants', 1)
164
+ && optIntMin(m.body, 'maxParticipants', 1)
153
165
  && hasStr(m.body, 'beaconType')
154
166
  && hasStr(m.body, 'network')
155
167
  && hasBytes(m.body, 'communicationPk');
@@ -1,3 +1,4 @@
1
+ import type { CohortConditions } from '../conditions.js';
1
2
  import { BaseMessage } from './base.js';
2
3
  import {
3
4
  AGGREGATED_NONCE,
@@ -18,11 +19,9 @@ import {
18
19
  * Factory functions for creating messages related to the cohort formation step, where cohorts are
19
20
  * formed and participants opt in to join the cohort.
20
21
  */
21
- type CohortAdvertMessage = {
22
+ type CohortAdvertMessage = CohortConditions & {
22
23
  from: string;
23
24
  cohortId: string;
24
- cohortSize: number;
25
- beaconType: string;
26
25
  network: string;
27
26
  communicationPk: Uint8Array;
28
27
  };
@@ -5,8 +5,10 @@ import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
5
5
  import { Transaction } from '@scure/btc-signer';
6
6
  import { getBeaconStrategy } from './beacon-strategy.js';
7
7
  import { AggregationCohort } from './cohort.js';
8
+ import type { CohortConditions } from './conditions.js';
8
9
  import { AggregationParticipantError } from './errors.js';
9
10
  import type { BaseMessage } from './messages/base.js';
11
+ import { isCohortAdvertMessage } from './messages/bodies.js';
10
12
  import { AGGREGATION_WIRE_VERSION } from './messages/base.js';
11
13
  import {
12
14
  AGGREGATED_NONCE,
@@ -28,13 +30,15 @@ import { ParticipantCohortPhase } from './phases.js';
28
30
  import type { AggregationSigner } from './signer.js';
29
31
  import { BeaconSigningSession } from './signing-session.js';
30
32
 
31
- /** Cohort advert as discovered by the participant (UI: list of joinable cohorts). */
32
- export interface CohortAdvert {
33
+ /**
34
+ * Cohort advert as discovered by the participant (UI: list of joinable cohorts).
35
+ * Carries the advertised {@link CohortConditions} (beaconType, minParticipants,
36
+ * maxParticipants, costs, ...) so a `shouldJoin` decision can inspect them.
37
+ */
38
+ export interface CohortAdvert extends CohortConditions {
33
39
  cohortId: string;
34
40
  serviceDid: string;
35
- cohortSize: number;
36
41
  network: string;
37
- beaconType: string;
38
42
  serviceCommunicationPk: Uint8Array;
39
43
  }
40
44
 
@@ -168,17 +172,18 @@ export class AggregationParticipant {
168
172
  }
169
173
 
170
174
  #handleCohortAdvert(message: BaseMessage): void {
171
- const cohortId = message.body?.cohortId;
172
- if(!cohortId) return;
175
+ // Validate the wire shape (incl. minParticipants range) before trusting it,
176
+ // rather than reading fields with `?? 0` fallbacks (see ADR 039).
177
+ if(!isCohortAdvertMessage(message)) return;
178
+ const { cohortId, network, communicationPk, ...conditions } = message.body;
173
179
  if(this.#cohortStates.has(cohortId)) return; // Already known
174
180
 
175
181
  const advert: CohortAdvert = {
176
182
  cohortId,
177
183
  serviceDid : message.from,
178
- cohortSize : message.body?.cohortSize ?? 0,
179
- network : message.body?.network ?? '',
180
- beaconType : message.body?.beaconType ?? 'CASBeacon',
181
- serviceCommunicationPk : message.body?.communicationPk ?? new Uint8Array(),
184
+ network,
185
+ serviceCommunicationPk : communicationPk,
186
+ ...conditions,
182
187
  };
183
188
 
184
189
  this.#cohortStates.set(cohortId, {
@@ -206,7 +211,7 @@ export class AggregationParticipant {
206
211
  const cohort = new AggregationCohort({
207
212
  id : cohortId,
208
213
  serviceDid : state.serviceDid,
209
- minParticipants : state.advert!.cohortSize,
214
+ minParticipants : state.advert!.minParticipants,
210
215
  network : state.advert!.network,
211
216
  beaconType : state.advert!.beaconType,
212
217
  });
@@ -302,6 +307,18 @@ export class AggregationParticipant {
302
307
  return map;
303
308
  }
304
309
 
310
+ /**
311
+ * The validated aggregated data retained for a cohort, regardless of phase.
312
+ * Unlike {@link pendingValidations} (which lists only cohorts still awaiting
313
+ * the validate decision), this returns the stored validation — including the
314
+ * participant's sidecar (the CAS Announcement map or its SMT inclusion proof)
315
+ * — so it is still readable once the cohort reaches Complete. Returns
316
+ * undefined before aggregated data has been received.
317
+ */
318
+ public getValidation(cohortId: string): PendingValidation | undefined {
319
+ return this.#cohortStates.get(cohortId)?.validation;
320
+ }
321
+
305
322
  #handleDistributeAggregatedData(message: BaseMessage): void {
306
323
  const cohortId = message.body?.cohortId;
307
324
  if(!cohortId) return;
@@ -2,6 +2,23 @@ import type { SerializedSMTProof } from '@did-btcr2/smt';
2
2
  import type { CohortAdvert, PendingSigningRequest, PendingValidation } from '../participant.js';
3
3
  import type { AggregationResult, PendingOptIn, Rejection } from '../service.js';
4
4
 
5
+ /**
6
+ * Sidecar data a participant keeps when a cohort completes from its
7
+ * perspective: the cohort's beacon coordinates plus the off-chain artifact it
8
+ * needs for future DID resolution (the CAS Announcement map for CAS beacons, or
9
+ * the SMT inclusion proof for SMT beacons). Emitted via `cohort-complete` and
10
+ * returned by the participant runner's join helpers.
11
+ */
12
+ export interface CohortCompleteInfo {
13
+ cohortId: string;
14
+ beaconAddress: string;
15
+ beaconType: string;
16
+ /** DID → base64url update hash. Populated only for CAS beacons. */
17
+ casAnnouncement?: Record<string, string>;
18
+ /** Merkle inclusion proof for this participant's slot. Populated only for SMT beacons. */
19
+ smtProof?: SerializedSMTProof;
20
+ }
21
+
5
22
  /**
6
23
  * AggregationServiceRunner events are emitted by the AggregationServiceRunner to signal important
7
24
  * milestones and actions during the aggregation process. They can be listened to by external code
@@ -15,13 +32,13 @@ export type AggregationServiceEvents = {
15
32
  'opt-in-received': [PendingOptIn];
16
33
 
17
34
  /** A participant has been accepted into the cohort. */
18
- 'participant-accepted': [{ participantDid: string }];
35
+ 'participant-accepted': [{ cohortId: string; participantDid: string }];
19
36
 
20
37
  /** Keygen has been finalized — beacon address is now available. */
21
38
  'keygen-complete': [{ cohortId: string; beaconAddress: string }];
22
39
 
23
40
  /** A participant has submitted a signed update. */
24
- 'update-received': [{ participantDid: string }];
41
+ 'update-received': [{ cohortId: string; participantDid: string }];
25
42
 
26
43
  /**
27
44
  * An inbound message was silently dropped by the state machine (bad proof,
@@ -34,13 +51,13 @@ export type AggregationServiceEvents = {
34
51
  'data-distributed': [{ cohortId: string }];
35
52
 
36
53
  /** A participant has acknowledged validation (approved or rejected). */
37
- 'validation-received': [{ participantDid: string; approved: boolean }];
54
+ 'validation-received': [{ cohortId: string; participantDid: string; approved: boolean }];
38
55
 
39
56
  /** Signing has started — auth requests sent to participants. */
40
- 'signing-started': [{ sessionId: string }];
57
+ 'signing-started': [{ cohortId: string; sessionId: string }];
41
58
 
42
59
  /** A participant has contributed their MuSig2 nonce. */
43
- 'nonce-received': [{ participantDid: string }];
60
+ 'nonce-received': [{ cohortId: string; participantDid: string }];
44
61
 
45
62
  /** Signing complete — final aggregated signature is ready to broadcast. */
46
63
  'signing-complete': [AggregationResult];
@@ -83,15 +100,7 @@ export type AggregationParticipantEvents = {
83
100
  * future DID resolution: the CAS Announcement map (for CAS beacons) or the
84
101
  * SMT inclusion proof (for SMT beacons).
85
102
  */
86
- 'cohort-complete': [{
87
- cohortId: string;
88
- beaconAddress: string;
89
- beaconType: string;
90
- /** DID → base64url update hash. Populated only for CAS beacons. */
91
- casAnnouncement?: Record<string, string>;
92
- /** Merkle inclusion proof for this participant's slot. Populated only for SMT beacons. */
93
- smtProof?: SerializedSMTProof;
94
- }];
103
+ 'cohort-complete': [CohortCompleteInfo];
95
104
 
96
105
  /** Cohort failed (rejected validation, signing error, etc.). */
97
106
  'cohort-failed': [{ cohortId: string; reason: string }];