@did-btcr2/api 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/method.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import type { BitcoinConnection } from '@did-btcr2/bitcoin';
2
- import type { DocumentBytes, HexString, KeyBytes, PatchOperation } from '@did-btcr2/common';
3
- import { decode as decodeHash, IdentifierTypes, NotImplementedError } from '@did-btcr2/common';
2
+ import type { DocumentBytes, KeyBytes, PatchOperation } from '@did-btcr2/common';
3
+ import { decode as decodeHash, IdentifierTypes, INVALID_DID_UPDATE, NotImplementedError, UpdateError } from '@did-btcr2/common';
4
4
  import type { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
5
+ import type { Signer } from '@did-btcr2/keypair';
5
6
  import type { Btcr2DidDocument, CASAnnouncement, DidCreateOptions, NeedCASAnnouncement, NeedGenesisDocument, NeedSignedUpdate, ResolutionOptions } from '@did-btcr2/method';
6
- import { BeaconSignalDiscovery, DidBtcr2 } from '@did-btcr2/method';
7
+ import { BeaconFactory, BeaconSignalDiscovery, DidBtcr2 } from '@did-btcr2/method';
7
8
  import type { DidResolutionResult, DidVerificationMethod } from '@web5/dids';
8
9
  import type { BitcoinApi } from './bitcoin.js';
9
10
  import type { CasApi } from './cas.js';
@@ -162,8 +163,16 @@ export class DidMethodApi {
162
163
  }
163
164
 
164
165
  /**
165
- * Update an existing DID document. If a Bitcoin connection is configured on
166
- * the API, it is injected automatically.
166
+ * Update an existing DID document by driving the sans-I/O {@link Updater} state
167
+ * machine (from @did-btcr2/method). This method handles the I/O side:
168
+ * - Signing: supplies the {@link Signer} to `NeedSigningKey`.
169
+ * - Broadcast: establishes a beacon via {@link BeaconFactory} and calls
170
+ * `broadcastSignal()` with the bitcoin connection configured on the API.
171
+ *
172
+ * For multi-party aggregation of SMT/CAS beacons, the caller should drive the
173
+ * Updater directly and delegate `NeedBroadcast` to the aggregation runner
174
+ * rather than using this high-level method.
175
+ *
167
176
  * @param params The update parameters.
168
177
  * @returns The signed update.
169
178
  */
@@ -173,7 +182,7 @@ export class DidMethodApi {
173
182
  sourceVersionId,
174
183
  verificationMethodId,
175
184
  beaconId,
176
- signingMaterial,
185
+ signer,
177
186
  bitcoin,
178
187
  }: {
179
188
  sourceDocument: Btcr2DidDocument;
@@ -181,19 +190,73 @@ export class DidMethodApi {
181
190
  sourceVersionId: number;
182
191
  verificationMethodId: string;
183
192
  beaconId: string;
184
- signingMaterial?: KeyBytes | HexString;
193
+ signer: Signer;
185
194
  bitcoin?: BitcoinConnection;
186
195
  }): Promise<SignedBTCR2Update> {
187
- const btcConnection = bitcoin ?? this.#btc?.connection ?? undefined;
188
- return await DidBtcr2.update({
196
+ // Bitcoin connection resolution order: per-call `bitcoin` param wins over the
197
+ // BitcoinApi injected at DidBtcr2Api construction time. One of the two must
198
+ // be present; this can't be encoded in the type system, so it's a runtime check.
199
+ const btcConnection = bitcoin ?? this.#btc?.connection;
200
+ if(!btcConnection) {
201
+ throw new UpdateError(
202
+ 'Bitcoin connection required for update. Pass a configured `bitcoin` parameter '
203
+ + 'or configure a BitcoinApi on the DidBtcr2Api instance.',
204
+ INVALID_DID_UPDATE, { beaconId }
205
+ );
206
+ }
207
+
208
+ this.#log.debug('Updating DID', sourceDocument.id, { beaconId, verificationMethodId });
209
+
210
+ // Factory validates and returns a sans-I/O state machine
211
+ const updater = DidBtcr2.update({
189
212
  sourceDocument,
190
213
  patches,
191
214
  sourceVersionId,
192
215
  verificationMethodId,
193
216
  beaconId,
194
- signingMaterial,
195
- bitcoin : btcConnection,
196
217
  });
218
+
219
+ // Drive the state machine. All I/O (signing delegation, Bitcoin broadcast)
220
+ // happens inside the need-handlers below — the Updater itself is pure.
221
+ let state = updater.advance();
222
+ while(state.status === 'action-required') {
223
+ for(const need of state.needs) {
224
+ switch(need.kind) {
225
+ case 'NeedSigningKey': {
226
+ this.#log.debug('Providing signer for', need.verificationMethodId);
227
+ updater.provide(need, signer);
228
+ break;
229
+ }
230
+ case 'NeedFunding': {
231
+ this.#log.debug('Checking funding for beacon address %s', need.beaconAddress);
232
+ const utxos = await btcConnection.rest.address.getUtxos(need.beaconAddress);
233
+ if(!utxos.length) {
234
+ throw new UpdateError(
235
+ `Beacon address ${need.beaconAddress} is unfunded. `
236
+ + 'Send BTC to this address before broadcasting the update.',
237
+ INVALID_DID_UPDATE, { beaconAddress: need.beaconAddress }
238
+ );
239
+ }
240
+ this.#log.debug('Beacon address funded (%d UTXOs)', utxos.length);
241
+ updater.provide(need);
242
+ break;
243
+ }
244
+ case 'NeedBroadcast': {
245
+ this.#log.debug(
246
+ 'Broadcasting signed update via %s beacon', need.beaconService.type
247
+ );
248
+ const beacon = BeaconFactory.establish(need.beaconService);
249
+ await beacon.broadcastSignal(need.signedUpdate, signer, btcConnection);
250
+ updater.provide(need);
251
+ break;
252
+ }
253
+ }
254
+ }
255
+ state = updater.advance();
256
+ }
257
+
258
+ this.#log.debug('DID update complete', sourceDocument.id);
259
+ return state.result.signedUpdate;
197
260
  }
198
261
 
199
262
  /**
@@ -217,8 +280,9 @@ export class DidMethodApi {
217
280
  * .buildUpdate(currentDoc)
218
281
  * .patch({ op: 'add', path: '/service/1', value: newService })
219
282
  * .version(2)
220
- * .signer('#initialKey')
283
+ * .verificationMethodId('#initialKey')
221
284
  * .beacon('#beacon-0')
285
+ * .signer(new LocalSigner(secretKey))
222
286
  * .execute();
223
287
  * ```
224
288
  */
@@ -252,7 +316,7 @@ export class UpdateBuilder {
252
316
  #sourceVersionId?: number;
253
317
  #verificationMethodId?: string;
254
318
  #beaconId?: string;
255
- #signingMaterial?: KeyBytes | HexString;
319
+ #signer?: Signer;
256
320
  #bitcoin?: BitcoinConnection;
257
321
 
258
322
  /** @internal */
@@ -279,8 +343,8 @@ export class UpdateBuilder {
279
343
  return this;
280
344
  }
281
345
 
282
- /** Set the verification method ID used for signing. */
283
- signer(methodId: string): this {
346
+ /** Set the verification method ID used for signing the update. */
347
+ verificationMethodId(methodId: string): this {
284
348
  this.#verificationMethodId = methodId;
285
349
  return this;
286
350
  }
@@ -291,32 +355,44 @@ export class UpdateBuilder {
291
355
  return this;
292
356
  }
293
357
 
294
- /** Set the signing material (secret key bytes or hex). */
295
- signingMaterial(material: KeyBytes | HexString): this {
296
- this.#signingMaterial = material;
358
+ /**
359
+ * Set the {@link Signer} that produces the update's BIP-340 Schnorr proof
360
+ * and the beacon transaction's ECDSA input signature. Use `LocalSigner`
361
+ * for in-process secret keys, `KeyManagerSigner` for KMS-managed keys
362
+ * (AWS, Vault, HSM, etc.), or any custom adapter implementing the `Signer`
363
+ * interface.
364
+ */
365
+ signer(s: Signer): this {
366
+ this.#signer = s;
297
367
  return this;
298
368
  }
299
369
 
300
370
  /** Override the Bitcoin connection for this update. */
301
- withBitcoin(connection: BitcoinConnection): this {
371
+ bitcoin(connection: BitcoinConnection): this {
302
372
  this.#bitcoin = connection;
303
373
  return this;
304
374
  }
305
375
 
306
376
  /**
307
377
  * Execute the update.
308
- * @throws {Error} If required fields (version, signer, beacon) are missing.
378
+ * @throws {Error} If required fields (version, verificationMethodId, beacon, signer) are missing.
309
379
  */
310
380
  async execute(): Promise<SignedBTCR2Update> {
311
381
  if (this.#sourceVersionId === undefined) {
312
382
  throw new Error('UpdateBuilder: sourceVersionId is required. Call .version(id) before .execute().');
313
383
  }
314
384
  if (!this.#verificationMethodId) {
315
- throw new Error('UpdateBuilder: verificationMethodId is required. Call .signer(id) before .execute().');
385
+ throw new Error(
386
+ 'UpdateBuilder: verificationMethodId is required. '
387
+ + 'Call .verificationMethodId(id) before .execute().'
388
+ );
316
389
  }
317
390
  if (!this.#beaconId) {
318
391
  throw new Error('UpdateBuilder: beaconId is required. Call .beacon(id) before .execute().');
319
392
  }
393
+ if (!this.#signer) {
394
+ throw new Error('UpdateBuilder: signer is required. Call .signer(s) before .execute().');
395
+ }
320
396
 
321
397
  return this.#methodApi.update({
322
398
  sourceDocument : this.#sourceDocument,
@@ -324,7 +400,7 @@ export class UpdateBuilder {
324
400
  sourceVersionId : this.#sourceVersionId,
325
401
  verificationMethodId : this.#verificationMethodId,
326
402
  beaconId : this.#beaconId,
327
- signingMaterial : this.#signingMaterial,
403
+ signer : this.#signer,
328
404
  bitcoin : this.#bitcoin,
329
405
  });
330
406
  }
package/src/types.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { HttpExecutor, NetworkName, RestConfig, RpcConfig } from '@did-btcr2/bitcoin';
2
- import type { KeyManager } from '@did-btcr2/kms';
2
+ import type { KeyManager } from '@did-btcr2/key-manager';
3
3
  import type { Btcr2DidDocument } from '@did-btcr2/method';
4
4
  import type { DidResolutionResult } from '@web5/dids';
5
5
  import type { CasConfig } from './cas.js';
@@ -1 +0,0 @@
1
- {"version":3,"file":"kms.js","sourceRoot":"","sources":["../../src/kms.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,GAAG,GAEJ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,OAAO,aAAa;IACxB,uCAAuC;IAC9B,GAAG,CAAa;IAEzB,4EAA4E;IAC5E,YAAY,GAAgB;QAC1B,IAAI,CAAC,GAAG,GAAG,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC;IAC9B,CAAC;IAED,8CAA8C;IAC9C,WAAW,CAAC,OAA4B;QACtC,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,4CAA4C;IAC5C,SAAS,CAAC,EAAiB;QACzB,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,qDAAqD;IACrD,YAAY,CAAC,EAAkB;QAC7B,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,6CAA6C;IAC7C,MAAM,CAAC,EAAkB,EAAE,OAA0B;QACnD,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,EAAiB;QACtB,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,YAAY,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,wEAAwE;kBACtE,uDAAuD,CAC1D,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,wCAAwC;IACxC,QAAQ;QACN,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,CAAC;IAED,iCAAiC;IACjC,SAAS,CAAC,EAAiB,EAAE,UAA+B,EAAE;QAC5D,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,IAAW,EAAE,EAAkB,EAAE,OAAqB;QACzD,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,sCAAsC;IACtC,MAAM,CAAC,SAAyB,EAAE,IAAW,EAAE,EAAkB,EAAE,OAAqB;QACtF,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IACvD,CAAC;IAED,gCAAgC;IAChC,MAAM,CAAC,IAAgB;QACrB,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"kms.d.ts","sourceRoot":"","sources":["../../src/kms.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EAErB,KAAK,WAAW,EACjB,MAAM,gBAAgB,CAAC;AAGxB;;;;;;;GAOG;AACH,qBAAa,aAAa;IACxB,uCAAuC;IACvC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IAEzB,4EAA4E;gBAChE,GAAG,CAAC,EAAE,UAAU;IAI5B,8CAA8C;IAC9C,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,aAAa;IAIxD,4CAA4C;IAC5C,SAAS,CAAC,EAAE,EAAE,aAAa,GAAG,IAAI;IAIlC,qDAAqD;IACrD,YAAY,CAAC,EAAE,CAAC,EAAE,aAAa,GAAG,KAAK;IAIvC,6CAA6C;IAC7C,MAAM,CAAC,EAAE,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,aAAa;IAIrE;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,aAAa,GAAG,cAAc;IAUzC,wCAAwC;IACxC,QAAQ,IAAI,aAAa,EAAE;IAI3B,iCAAiC;IACjC,SAAS,CAAC,EAAE,EAAE,aAAa,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,IAAI;IAIrE;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,cAAc;IAK5E,sCAAsC;IACtC,MAAM,CAAC,SAAS,EAAE,cAAc,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO;IAIlG,gCAAgC;IAChC,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS;CAGpC"}