@bsv/wallet-toolbox-client 2.9.0 → 2.10.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.
@@ -4081,7 +4081,7 @@ var EntitySyncState = class EntitySyncState extends EntityBase {
4081
4081
  log += formatSyncSection("OUTPUTS", c.outputs, (r) => `${r.outputId} ${r.txid}.${r.vout} ${r.transactionId} ${r.spendable ? "spendable" : ""} sats:${r.satoshis}`);
4082
4082
  return log;
4083
4083
  }
4084
- async processSyncChunk(writer, args, chunk) {
4084
+ async processSyncChunk(writer, args, chunk, trx) {
4085
4085
  const mes = [
4086
4086
  new MergeEntity(chunk.provenTxs, EntityProvenTx.mergeFind, this.syncMap.provenTx),
4087
4087
  new MergeEntity(chunk.outputBaskets, EntityOutputBasket.mergeFind, this.syncMap.outputBasket),
@@ -4102,16 +4102,16 @@ var EntitySyncState = class EntitySyncState extends EntityBase {
4102
4102
  let done = true;
4103
4103
  if (chunk.user != null) {
4104
4104
  const ei = chunk.user;
4105
- const { found, eo } = await EntityUser.mergeFind(writer, this.userId, ei);
4105
+ const { found, eo } = await EntityUser.mergeFind(writer, this.userId, ei, trx);
4106
4106
  if (found) {
4107
- if (await eo.mergeExisting(writer, args.since, ei)) {
4107
+ if (await eo.mergeExisting(writer, args.since, ei, void 0, trx)) {
4108
4108
  maxUpdated_at = maxDate(maxUpdated_at, ei.updated_at);
4109
4109
  updates++;
4110
4110
  }
4111
4111
  }
4112
4112
  }
4113
4113
  for (const me of mes) {
4114
- const r = await me.merge(args.since, writer, this.userId, this.syncMap);
4114
+ const r = await me.merge(args.since, writer, this.userId, this.syncMap, trx);
4115
4115
  me.esm.count += me.stateArray?.length || 0;
4116
4116
  updates += r.updates;
4117
4117
  inserts += r.inserts;
@@ -4122,7 +4122,7 @@ var EntitySyncState = class EntitySyncState extends EntityBase {
4122
4122
  this.when = maxUpdated_at;
4123
4123
  for (const me of mes) me.esm.count = 0;
4124
4124
  }
4125
- await this.updateStorage(writer, false);
4125
+ await this.updateStorage(writer, false, trx);
4126
4126
  return {
4127
4127
  done,
4128
4128
  maxUpdated_at,
@@ -8254,28 +8254,70 @@ function verifyActionBatchManifestDigest(manifest) {
8254
8254
  //#endregion
8255
8255
  //#region ../src/utility/beefForTxids.ts
8256
8256
  /**
8257
- * Return the minimal subgraph needed to prove the requested transactions.
8257
+ * Return a minimal BEEF when the source contains data outside the requested
8258
+ * transaction dependency closure. Return undefined when no pruning is needed.
8258
8259
  *
8259
- * Parents are added before children so the resulting BEEF preserves dependency
8260
- * order. Shared ancestors and bumps are merged only once.
8260
+ * This form lets forwarding clients retain the caller's original bytes in the
8261
+ * common no-op case instead of rebuilding and reserializing an equivalent BEEF.
8262
+ */
8263
+ function pruneBeefForTxids(source, txids) {
8264
+ const selection = selectTransactions(source, txids);
8265
+ if (selection.transactions.size === source.txs.length && selection.bumpIndexes.size === source.bumps.length) return;
8266
+ return copySelection(source, selection);
8267
+ }
8268
+ /**
8269
+ * Return an independent minimal BEEF needed to prove the requested transactions.
8270
+ *
8271
+ * Transactions remain in source order and are sorted by Beef when serialized.
8272
+ * The source is indexed and walked once, using an explicit stack so a hostile
8273
+ * dependency depth cannot exhaust the JavaScript call stack.
8261
8274
  */
8262
8275
  function beefForTxids(source, txids) {
8263
- const beef = new _bsv_sdk.Beef();
8276
+ return copySelection(source, selectTransactions(source, txids));
8277
+ }
8278
+ function selectTransactions(source, txids) {
8279
+ const byTxid = /* @__PURE__ */ new Map();
8280
+ for (const tx of source.txs) byTxid.set(tx.txid, tx);
8281
+ const transactions = /* @__PURE__ */ new Set();
8282
+ const bumpIndexes = /* @__PURE__ */ new Set();
8264
8283
  const visited = /* @__PURE__ */ new Set();
8265
- const visit = (txid) => {
8266
- if (visited.has(txid)) return;
8284
+ const stack = [...txids];
8285
+ while (stack.length > 0) {
8286
+ const txid = stack.pop();
8287
+ if (txid == null || visited.has(txid)) continue;
8267
8288
  visited.add(txid);
8268
- const sourceTx = source.findTxid(txid);
8269
- if (sourceTx == null) return;
8270
- if (sourceTx.tx != null) {
8271
- for (const input of sourceTx.tx.inputs) if (input.sourceTXID != null) visit(input.sourceTXID);
8272
- }
8273
- if (sourceTx.bumpIndex != null) beef.mergeBump(source.bumps[sourceTx.bumpIndex]);
8274
- beef.mergeBeefTx(sourceTx);
8289
+ const tx = byTxid.get(txid);
8290
+ if (tx == null) continue;
8291
+ transactions.add(tx);
8292
+ const bumpIndex = tx.bumpIndex;
8293
+ if (bumpIndex != null && Number.isSafeInteger(bumpIndex) && bumpIndex >= 0 && bumpIndex < source.bumps.length) bumpIndexes.add(bumpIndex);
8294
+ for (const inputTxid of tx.inputTxids) if (!visited.has(inputTxid)) stack.push(inputTxid);
8295
+ }
8296
+ return {
8297
+ transactions,
8298
+ bumpIndexes
8275
8299
  };
8276
- for (const txid of txids) visit(txid);
8300
+ }
8301
+ function copySelection(source, selection) {
8302
+ const beef = new _bsv_sdk.Beef(source.version);
8303
+ const bumpIndexMap = /* @__PURE__ */ new Map();
8304
+ for (let index = 0; index < source.bumps.length; index++) {
8305
+ if (!selection.bumpIndexes.has(index)) continue;
8306
+ bumpIndexMap.set(index, beef.bumps.length);
8307
+ beef.bumps.push(cloneMerklePath(source.bumps[index]));
8308
+ }
8309
+ for (const sourceTx of source.txs) {
8310
+ if (!selection.transactions.has(sourceTx)) continue;
8311
+ const bumpIndex = sourceTx.bumpIndex == null ? void 0 : bumpIndexMap.get(sourceTx.bumpIndex);
8312
+ const rawTx = sourceTx.rawTxUint8Array;
8313
+ const copy = rawTx == null ? _bsv_sdk.BeefTx.fromTxid(sourceTx.txid, bumpIndex) : new _bsv_sdk.BeefTx(Uint8Array.from(rawTx), bumpIndex, Array.from(sourceTx.inputTxids));
8314
+ beef.txs.push(copy);
8315
+ }
8277
8316
  return beef;
8278
8317
  }
8318
+ function cloneMerklePath(source) {
8319
+ return new _bsv_sdk.MerklePath(source.blockHeight, source.path.map((level) => level.map((leaf) => ({ ...leaf }))), false, false);
8320
+ }
8279
8321
  //#endregion
8280
8322
  //#region ../src/storage/methods/offsetKey.ts
8281
8323
  function keyOffsetToHashedSecret(pub, keyOffset) {
@@ -10973,7 +11015,7 @@ function validateRequiredOutputs(storage, userId, vargs) {
10973
11015
  * @returns {xinputs} extended validated required inputs.
10974
11016
  */
10975
11017
  async function validateRequiredInputs(storage, userId, vargs) {
10976
- const beef = new _bsv_sdk.Beef();
11018
+ let beef = new _bsv_sdk.Beef();
10977
11019
  if (vargs.inputs.length === 0) return {
10978
11020
  storageBeef: beef,
10979
11021
  beef,
@@ -10999,6 +11041,7 @@ async function validateRequiredInputs(storage, userId, vargs) {
10999
11041
  inputsByTxid[input.outpoint.txid] ||= [];
11000
11042
  inputsByTxid[input.outpoint.txid].push(input);
11001
11043
  }
11044
+ beef = beefForTxids(beef, Object.keys(inputsByTxid));
11002
11045
  const localKnownInputTxids = {};
11003
11046
  for (const [txid, txInputs] of Object.entries(inputsByTxid)) localKnownInputTxids[txid] = txInputs.every((input) => {
11004
11047
  const output = preloadedOutputsByOutpoint[`${input.outpoint.txid}.${input.outpoint.vout}`];
@@ -15260,11 +15303,19 @@ var StorageProvider = class StorageProvider extends StorageReaderWriter {
15260
15303
  return await this.updateOutput(output.outputId, { basketId: void 0 });
15261
15304
  }
15262
15305
  async processSyncChunk(args, chunk) {
15263
- const user = verifyTruthy(await this.findUserByIdentityKey(args.identityKey));
15264
- return await new EntitySyncState(verifyOne(await this.findSyncStates({ partial: {
15265
- storageIdentityKey: args.fromStorageIdentityKey,
15266
- userId: user.userId
15267
- } }))).processSyncChunk(this, args, chunk);
15306
+ return await this.transaction(async (trx) => {
15307
+ const user = verifyTruthy(verifyOneOrNone(await this.findUsers({
15308
+ partial: { identityKey: args.identityKey },
15309
+ trx
15310
+ })));
15311
+ return await new EntitySyncState(verifyOne(await this.findSyncStates({
15312
+ partial: {
15313
+ storageIdentityKey: args.fromStorageIdentityKey,
15314
+ userId: user.userId
15315
+ },
15316
+ trx
15317
+ }))).processSyncChunk(this, args, chunk, trx);
15318
+ });
15268
15319
  }
15269
15320
  /**
15270
15321
  * Handles storage changes when a valid MerklePath and mined block header are found for a ProvenTxReq txid.
@@ -17329,8 +17380,10 @@ var StorageIdb = class extends StorageProvider {
17329
17380
  await tx.done;
17330
17381
  return r;
17331
17382
  } catch (err) {
17332
- tx.abort();
17333
- await tx.done;
17383
+ try {
17384
+ tx.abort();
17385
+ await tx.done;
17386
+ } catch {}
17334
17387
  throw err;
17335
17388
  }
17336
17389
  }
@@ -18297,6 +18350,25 @@ var StorageClientBase = class {
18297
18350
  * @returns `StorageCreateActionResults` supporting additional wallet processing to yield `createAction` results.
18298
18351
  */
18299
18352
  async createAction(auth, args) {
18353
+ if (args.inputBEEF != null) if (args.inputs.length === 0) args = {
18354
+ ...args,
18355
+ inputBEEF: void 0
18356
+ };
18357
+ else {
18358
+ let source;
18359
+ try {
18360
+ source = _bsv_sdk.Beef.fromBinary(args.inputBEEF);
18361
+ } catch {
18362
+ source = void 0;
18363
+ }
18364
+ if (source != null) {
18365
+ const pruned = pruneBeefForTxids(source, args.inputs.map((input) => input.outpoint.txid));
18366
+ if (pruned != null) args = {
18367
+ ...args,
18368
+ inputBEEF: pruned.toBinary()
18369
+ };
18370
+ }
18371
+ }
18300
18372
  return await this.rpcCall("createAction", [auth, args]);
18301
18373
  }
18302
18374
  /**
@@ -30967,6 +31039,7 @@ var SetupClient = class SetupClient {
30967
31039
  };
30968
31040
  //#endregion
30969
31041
  //#region ../src/CWIStyleWalletManager.ts
31042
+ const CWI_COMPONENT = "wallet-toolbox.cwi-manager";
30970
31043
  /**
30971
31044
  * Number of rounds used in PBKDF2 for deriving password keys.
30972
31045
  */
@@ -31199,11 +31272,11 @@ var OverlayUMPTokenInteractor = class {
31199
31272
  * @param hash The 32-byte SHA-256 hash of the presentation key.
31200
31273
  * @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
31201
31274
  */
31202
- async findByPresentationKeyHash(hash) {
31203
- return await this.findToken({
31275
+ async findByPresentationKeyHash(hash, options) {
31276
+ return this.findToken({
31204
31277
  service: "ls_users",
31205
31278
  query: { presentationHash: _bsv_sdk.Utils.toHex(hash) }
31206
- }, "presentation");
31279
+ }, "presentation", options);
31207
31280
  }
31208
31281
  /**
31209
31282
  * Finds a UMP token on-chain by the given recovery key hash, if it exists.
@@ -31212,13 +31285,13 @@ var OverlayUMPTokenInteractor = class {
31212
31285
  * @param hash The 32-byte SHA-256 hash of the recovery key.
31213
31286
  * @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
31214
31287
  */
31215
- async findByRecoveryKeyHash(hash) {
31216
- return await this.findToken({
31288
+ async findByRecoveryKeyHash(hash, options) {
31289
+ return this.findToken({
31217
31290
  service: "ls_users",
31218
31291
  query: { recoveryHash: _bsv_sdk.Utils.toHex(hash) }
31219
- }, "recovery");
31292
+ }, "recovery", options);
31220
31293
  }
31221
- async findToken(question, lookupKind) {
31294
+ async findToken(question, lookupKind, options) {
31222
31295
  const correlationId = this.telemetry.enabled === true ? this.telemetry.createCorrelationId() : void 0;
31223
31296
  const startedAt = Date.now();
31224
31297
  this.telemetry.capture({
@@ -31235,34 +31308,39 @@ var OverlayUMPTokenInteractor = class {
31235
31308
  correlationId
31236
31309
  });
31237
31310
  } catch (error) {
31238
- const diagnostics = this.emptyLookupDiagnostics(correlationId);
31239
- this.captureLookupFailure(lookupKind, "lookup-unavailable", diagnostics, startedAt, error);
31311
+ const diagnostics = this.emptyStats(correlationId);
31312
+ this.lookupFailed(lookupKind, "lookup-unavailable", diagnostics, startedAt, error);
31240
31313
  throw new UMPTokenLookupError("lookup-unavailable", diagnostics, { cause: error });
31241
31314
  }
31242
- const diagnostics = this.toLookupDiagnostics(resolution);
31315
+ const diagnostics = this.diagnosticsFor(resolution);
31243
31316
  const tokens = this.parseLookupAnswers(resolution.answer);
31244
31317
  const expectedHash = question.query[lookupKind === "presentation" ? "presentationHash" : "recoveryHash"].toLowerCase();
31245
31318
  const matchingTokens = tokens.filter((token) => _bsv_sdk.Utils.toHex(lookupKind === "presentation" ? token.presentationHash : token.recoveryHash).toLowerCase() === expectedHash);
31246
31319
  if (matchingTokens.length > 1) {
31247
31320
  const newest = this.resolveNewestToken(matchingTokens, resolution.answer.outputs);
31248
31321
  if (newest != null) {
31249
- this.captureLookupCompleted(lookupKind, "found", diagnostics, startedAt, { supersededTokens: matchingTokens.length - 1 });
31322
+ this.lookupDone(lookupKind, "found", diagnostics, startedAt, { supersededTokens: matchingTokens.length - 1 });
31250
31323
  return newest;
31251
31324
  }
31325
+ const pinned = options?.pinnedOutpoint ? matchingTokens.find((token) => token.currentOutpoint === options.pinnedOutpoint) : void 0;
31326
+ if (pinned != null) {
31327
+ this.lookupDone(lookupKind, "found", diagnostics, startedAt);
31328
+ return pinned;
31329
+ }
31252
31330
  const reason = "token-ambiguous";
31253
- this.captureLookupFailure(lookupKind, reason, diagnostics, startedAt);
31331
+ this.lookupFailed(lookupKind, reason, diagnostics, startedAt);
31254
31332
  throw new UMPTokenLookupError(reason, diagnostics);
31255
31333
  }
31256
31334
  if (matchingTokens.length === 1) {
31257
- this.captureLookupCompleted(lookupKind, "found", diagnostics, startedAt);
31335
+ this.lookupDone(lookupKind, "found", diagnostics, startedAt);
31258
31336
  return matchingTokens[0];
31259
31337
  }
31260
31338
  if (resolution.progress.emptyHosts > 0) {
31261
- this.captureLookupCompleted(lookupKind, "not-found", diagnostics, startedAt);
31339
+ this.lookupDone(lookupKind, "not-found", diagnostics, startedAt);
31262
31340
  return;
31263
31341
  }
31264
31342
  const reason = resolution.answer.outputs.length > 0 ? "token-malformed" : "lookup-incomplete";
31265
- this.captureLookupFailure(lookupKind, reason, diagnostics, startedAt);
31343
+ this.lookupFailed(lookupKind, reason, diagnostics, startedAt);
31266
31344
  throw new UMPTokenLookupError(reason, diagnostics);
31267
31345
  }
31268
31346
  /**
@@ -31293,7 +31371,7 @@ var OverlayUMPTokenInteractor = class {
31293
31371
  spent: /* @__PURE__ */ new Set()
31294
31372
  };
31295
31373
  evidence.txs.push(tx);
31296
- this.collectSpentOutpoints(tx, evidence.spent, /* @__PURE__ */ new Set());
31374
+ this.collectSpends(tx, evidence.spent, /* @__PURE__ */ new Set());
31297
31375
  evidenceByCandidate.set(outpoint, evidence);
31298
31376
  } catch {}
31299
31377
  if (evidenceByCandidate.size !== candidates.size) return void 0;
@@ -31302,7 +31380,7 @@ var OverlayUMPTokenInteractor = class {
31302
31380
  const provenContinuations = survivors.filter((outpoint) => {
31303
31381
  const evidence = evidenceByCandidate.get(outpoint);
31304
31382
  const token = candidates.get(outpoint);
31305
- return evidence != null && token != null && evidence.txs.some((tx) => this.consumesSameIdentityToken(tx, token));
31383
+ return evidence != null && token != null && evidence.txs.some((tx) => this.consumesIdentity(tx, token));
31306
31384
  });
31307
31385
  if (provenContinuations.length !== 1) return void 0;
31308
31386
  return candidates.get(provenContinuations[0]);
@@ -31313,7 +31391,7 @@ var OverlayUMPTokenInteractor = class {
31313
31391
  * hash — on-chain proof that the candidate is an update of a same-identity
31314
31392
  * predecessor rather than an independently minted token.
31315
31393
  */
31316
- consumesSameIdentityToken(tx, token) {
31394
+ consumesIdentity(tx, token) {
31317
31395
  const presentationHash = _bsv_sdk.Utils.toHex(token.presentationHash);
31318
31396
  const recoveryHash = _bsv_sdk.Utils.toHex(token.recoveryHash);
31319
31397
  for (const input of tx.inputs) {
@@ -31339,7 +31417,7 @@ var OverlayUMPTokenInteractor = class {
31339
31417
  * renditions are absent from the lookup answer. Iterative so arbitrarily
31340
31418
  * long update chains cannot exhaust the call stack.
31341
31419
  */
31342
- collectSpentOutpoints(tx, spent, visited) {
31420
+ collectSpends(tx, spent, visited) {
31343
31421
  const pending = [tx];
31344
31422
  while (pending.length > 0) {
31345
31423
  const current = pending.pop();
@@ -31354,7 +31432,7 @@ var OverlayUMPTokenInteractor = class {
31354
31432
  }
31355
31433
  }
31356
31434
  }
31357
- emptyLookupDiagnostics(correlationId) {
31435
+ emptyStats(correlationId) {
31358
31436
  return {
31359
31437
  hostCount: 0,
31360
31438
  completedHosts: 0,
@@ -31367,7 +31445,7 @@ var OverlayUMPTokenInteractor = class {
31367
31445
  ...correlationId !== void 0 ? { correlationId } : {}
31368
31446
  };
31369
31447
  }
31370
- toLookupDiagnostics(resolution) {
31448
+ diagnosticsFor(resolution) {
31371
31449
  const progress = resolution.progress;
31372
31450
  return {
31373
31451
  hostCount: progress.hostCount,
@@ -31381,7 +31459,7 @@ var OverlayUMPTokenInteractor = class {
31381
31459
  ...progress.correlationId !== void 0 ? { correlationId: progress.correlationId } : {}
31382
31460
  };
31383
31461
  }
31384
- lookupDiagnosticAttributes(diagnostics) {
31462
+ lookupAttrs(diagnostics) {
31385
31463
  return {
31386
31464
  hostCount: diagnostics.hostCount,
31387
31465
  completedHosts: diagnostics.completedHosts,
@@ -31393,7 +31471,7 @@ var OverlayUMPTokenInteractor = class {
31393
31471
  outputCount: diagnostics.outputCount
31394
31472
  };
31395
31473
  }
31396
- captureLookupCompleted(lookupKind, result, diagnostics, startedAt, extraAttributes = {}) {
31474
+ lookupDone(lookupKind, result, diagnostics, startedAt, extraAttributes = {}) {
31397
31475
  this.telemetry.capture({
31398
31476
  name: "wallet-toolbox.ump.lookup.completed",
31399
31477
  component: "wallet-toolbox.ump",
@@ -31403,12 +31481,12 @@ var OverlayUMPTokenInteractor = class {
31403
31481
  lookupKind,
31404
31482
  result,
31405
31483
  durationMs: Date.now() - startedAt,
31406
- ...this.lookupDiagnosticAttributes(diagnostics),
31484
+ ...this.lookupAttrs(diagnostics),
31407
31485
  ...extraAttributes
31408
31486
  }
31409
31487
  });
31410
31488
  }
31411
- captureLookupFailure(lookupKind, reason, diagnostics, startedAt, error) {
31489
+ lookupFailed(lookupKind, reason, diagnostics, startedAt, error) {
31412
31490
  this.telemetry.capture({
31413
31491
  name: "wallet-toolbox.ump.lookup.indeterminate",
31414
31492
  component: "wallet-toolbox.ump",
@@ -31418,7 +31496,7 @@ var OverlayUMPTokenInteractor = class {
31418
31496
  lookupKind,
31419
31497
  reason,
31420
31498
  durationMs: Date.now() - startedAt,
31421
- ...this.lookupDiagnosticAttributes(diagnostics)
31499
+ ...this.lookupAttrs(diagnostics)
31422
31500
  },
31423
31501
  error
31424
31502
  });
@@ -31436,27 +31514,27 @@ var OverlayUMPTokenInteractor = class {
31436
31514
  * @returns The outpoint of the newly created UMP token (e.g. "abcd1234...ef.0").
31437
31515
  */
31438
31516
  async buildAndSend(wallet, adminOriginator, token, oldTokenToConsume) {
31439
- const fields = this.buildUMPTokenFields(token);
31517
+ const fields = this.tokenFields(token);
31440
31518
  const tokenOutput = [{
31441
31519
  lockingScript: (await new _bsv_sdk.PushDrop(wallet, adminOriginator).lock(fields, [2, "admin user management token"], "1", "self", true, true)).toHex(),
31442
31520
  satoshis: 1,
31443
31521
  outputDescription: "New UMP token output"
31444
31522
  }];
31445
- const { resolvedOldToken, inputToken } = await this.resolveOldTokenInput(oldTokenToConsume);
31523
+ const { resolvedOldToken, inputToken } = await this.resolveOldInput(oldTokenToConsume);
31446
31524
  const inputs = resolvedOldToken?.currentOutpoint ? [{
31447
31525
  outpoint: resolvedOldToken.currentOutpoint,
31448
31526
  unlockingScriptLength: 73,
31449
31527
  inputDescription: "Consume old UMP token"
31450
31528
  }] : [];
31451
- const createResult = await this.createUMPAction(wallet, adminOriginator, inputs, tokenOutput, inputToken, resolvedOldToken);
31452
- if (!createResult.signableTransaction) return await this.broadcastFinishedUMPAction(createResult);
31529
+ const createResult = await this.createAction(wallet, adminOriginator, inputs, tokenOutput, inputToken, resolvedOldToken);
31530
+ if (!createResult.signableTransaction) return this.broadcastFinal(createResult);
31453
31531
  const reference = createResult.signableTransaction.reference;
31454
31532
  const partialTx = _bsv_sdk.Transaction.fromBEEF(createResult.signableTransaction.tx);
31455
- if (resolvedOldToken?.currentOutpoint) return await this.signAndBroadcastWithOldToken(wallet, adminOriginator, reference, partialTx);
31456
- return await this.signAndBroadcastNewToken(wallet, adminOriginator, reference);
31533
+ if (resolvedOldToken?.currentOutpoint) return this.renewToken(wallet, adminOriginator, reference, partialTx);
31534
+ return this.broadcastNew(wallet, adminOriginator, reference);
31457
31535
  }
31458
31536
  /** Assembles the ordered number[][] fields array from a UMPToken. */
31459
- buildUMPTokenFields(token) {
31537
+ tokenFields(token) {
31460
31538
  const fields = [];
31461
31539
  fields[0] = token.passwordSalt;
31462
31540
  fields[1] = token.passwordPresentationPrimary;
@@ -31483,20 +31561,20 @@ var OverlayUMPTokenInteractor = class {
31483
31561
  return fields;
31484
31562
  }
31485
31563
  /** Looks up the old token on the overlay; returns undefined resolved token if not found. */
31486
- async resolveOldTokenInput(oldTokenToConsume) {
31564
+ async resolveOldInput(oldTokenToConsume) {
31487
31565
  if (!oldTokenToConsume?.currentOutpoint) return {
31488
31566
  resolvedOldToken: void 0,
31489
31567
  inputToken: void 0
31490
31568
  };
31491
31569
  const inputToken = await this.findByOutpoint(oldTokenToConsume.currentOutpoint);
31492
- if (inputToken == null) throw new Error("The previous UMP token could not be resolved; refusing to publish a duplicate token.");
31570
+ if (inputToken == null) throw new Error("Previous UMP token unavailable; update refused.");
31493
31571
  return {
31494
31572
  resolvedOldToken: oldTokenToConsume,
31495
31573
  inputToken
31496
31574
  };
31497
31575
  }
31498
31576
  /** Creates the UMP action without dropping a required old-token input on failure. */
31499
- async createUMPAction(wallet, adminOriginator, inputs, outputs, inputToken, resolvedOldToken) {
31577
+ async createAction(wallet, adminOriginator, inputs, outputs, inputToken, resolvedOldToken) {
31500
31578
  try {
31501
31579
  return await wallet.createAction({
31502
31580
  description: resolvedOldToken == null ? "Create new UMP token" : "Renew UMP token (consume old, create new)",
@@ -31523,43 +31601,43 @@ var OverlayUMPTokenInteractor = class {
31523
31601
  }
31524
31602
  }
31525
31603
  /** Handles a fully-finalized (no signable tx) createAction result — broadcasts and returns outpoint. */
31526
- async broadcastFinishedUMPAction(createResult) {
31604
+ async broadcastFinal(createResult) {
31527
31605
  const finalTxid = createResult.txid || (createResult.tx != null ? _bsv_sdk.Transaction.fromAtomicBEEF(createResult.tx).id("hex") : void 0);
31528
- if (!finalTxid) throw new Error("No signableTransaction and no final TX found.");
31529
- if (createResult.tx == null) throw new Error("No final TX data to broadcast.");
31606
+ if (!finalTxid) throw new Error("UMP transaction was not finalized.");
31607
+ if (createResult.tx == null) throw new Error("UMP transaction data missing.");
31530
31608
  const broadcastTx = _bsv_sdk.Transaction.fromAtomicBEEF(createResult.tx);
31531
31609
  const result = await this.broadcaster.broadcast(broadcastTx);
31532
- this.assertSuccessfulBroadcast(result, "create-finalized");
31610
+ this.assertBroadcast(result, "create-finalized");
31533
31611
  return `${finalTxid}.0`;
31534
31612
  }
31535
31613
  /** Signs the old-token input and broadcasts — used during UMP token renewal. */
31536
- async signAndBroadcastWithOldToken(wallet, adminOriginator, reference, partialTx) {
31614
+ async renewToken(wallet, adminOriginator, reference, partialTx) {
31537
31615
  const unlockingScript = await new _bsv_sdk.PushDrop(wallet, adminOriginator).unlock([2, "admin user management token"], "1", "self").sign(partialTx, 0);
31538
31616
  const signResult = await wallet.signAction({
31539
31617
  reference,
31540
31618
  spends: { 0: { unlockingScript: unlockingScript.toHex() } }
31541
31619
  }, adminOriginator);
31542
31620
  const finalTxid = signResult.txid || (signResult.tx == null ? "" : _bsv_sdk.Transaction.fromAtomicBEEF(signResult.tx).id("hex"));
31543
- if (!finalTxid) throw new Error("Could not finalize transaction for renewed UMP token.");
31544
- if (signResult.tx == null) throw new Error("Final transaction data missing after signing renewed UMP token.");
31621
+ if (!finalTxid) throw new Error("Could not finalize renewed UMP token.");
31622
+ if (signResult.tx == null) throw new Error("Renewed UMP token transaction data missing.");
31545
31623
  const result = await this.broadcaster.broadcast(_bsv_sdk.Transaction.fromAtomicBEEF(signResult.tx));
31546
- this.assertSuccessfulBroadcast(result, "renew");
31624
+ this.assertBroadcast(result, "renew");
31547
31625
  return `${finalTxid}.0`;
31548
31626
  }
31549
31627
  /** Signs without input spending and broadcasts — used when creating a brand-new UMP token. */
31550
- async signAndBroadcastNewToken(wallet, adminOriginator, reference) {
31628
+ async broadcastNew(wallet, adminOriginator, reference) {
31551
31629
  const signResult = await wallet.signAction({
31552
31630
  reference,
31553
31631
  spends: {}
31554
31632
  }, adminOriginator);
31555
31633
  const finalTxid = signResult.txid || (signResult.tx == null ? "" : _bsv_sdk.Transaction.fromAtomicBEEF(signResult.tx).id("hex"));
31556
- if (!finalTxid) throw new Error("Failed to finalize new UMP token transaction.");
31557
- if (signResult.tx == null) throw new Error("Final transaction data missing after signing new UMP token.");
31634
+ if (!finalTxid) throw new Error("Could not finalize new UMP token.");
31635
+ if (signResult.tx == null) throw new Error("New UMP token transaction data missing.");
31558
31636
  const result = await this.broadcaster.broadcast(_bsv_sdk.Transaction.fromAtomicBEEF(signResult.tx));
31559
- this.assertSuccessfulBroadcast(result, "create");
31637
+ this.assertBroadcast(result, "create");
31560
31638
  return `${finalTxid}.0`;
31561
31639
  }
31562
- assertSuccessfulBroadcast(result, operation) {
31640
+ assertBroadcast(result, operation) {
31563
31641
  const succeeded = result.status === "success";
31564
31642
  this.telemetry.capture({
31565
31643
  name: succeeded ? "wallet-toolbox.ump.broadcast.completed" : "wallet-toolbox.ump.broadcast.failed",
@@ -31588,12 +31666,12 @@ var OverlayUMPTokenInteractor = class {
31588
31666
  if (answer.type !== "output-list" || answer.outputs.length === 0) return [];
31589
31667
  const tokens = [];
31590
31668
  for (const output of answer.outputs) {
31591
- const token = this.parseLookupOutput(output);
31669
+ const token = this.parseOutput(output);
31592
31670
  if (token != null) tokens.push(token);
31593
31671
  }
31594
31672
  return tokens;
31595
31673
  }
31596
- parseLookupOutput(output) {
31674
+ parseOutput(output) {
31597
31675
  try {
31598
31676
  const tx = _bsv_sdk.Transaction.fromBEEF(output.beef);
31599
31677
  const txOutput = tx.outputs[output.outputIndex];
@@ -31643,14 +31721,14 @@ var OverlayUMPTokenInteractor = class {
31643
31721
  correlationId
31644
31722
  });
31645
31723
  } catch (error) {
31646
- const diagnostics = this.emptyLookupDiagnostics(correlationId);
31647
- this.captureLookupFailure("outpoint", "lookup-unavailable", diagnostics, startedAt, error);
31724
+ const diagnostics = this.emptyStats(correlationId);
31725
+ this.lookupFailed("outpoint", "lookup-unavailable", diagnostics, startedAt, error);
31648
31726
  throw new UMPTokenLookupError("lookup-unavailable", diagnostics, { cause: error });
31649
31727
  }
31650
31728
  if (resolution.answer.outputs.length === 0) {
31651
31729
  if (resolution.progress.emptyHosts === 0) {
31652
- const diagnostics = this.toLookupDiagnostics(resolution);
31653
- this.captureLookupFailure("outpoint", "lookup-incomplete", diagnostics, startedAt);
31730
+ const diagnostics = this.diagnosticsFor(resolution);
31731
+ this.lookupFailed("outpoint", "lookup-incomplete", diagnostics, startedAt);
31654
31732
  throw new UMPTokenLookupError("lookup-incomplete", diagnostics);
31655
31733
  }
31656
31734
  return;
@@ -31792,20 +31870,20 @@ var CWIStyleWalletManager = class {
31792
31870
  if (this._initSnapshot !== void 0) {
31793
31871
  this.telemetry.capture({
31794
31872
  name: "wallet-toolbox.snapshot.initialization.started",
31795
- component: "wallet-toolbox.cwi-manager",
31873
+ component: CWI_COMPONENT,
31796
31874
  severity: "debug"
31797
31875
  });
31798
31876
  try {
31799
31877
  await this.loadSnapshot(this._initSnapshot);
31800
31878
  this.telemetry.capture({
31801
31879
  name: "wallet-toolbox.snapshot.initialization.completed",
31802
- component: "wallet-toolbox.cwi-manager",
31880
+ component: CWI_COMPONENT,
31803
31881
  severity: "info"
31804
31882
  });
31805
31883
  } catch (error) {
31806
31884
  this.telemetry.capture({
31807
31885
  name: "wallet-toolbox.snapshot.initialization.failed",
31808
- component: "wallet-toolbox.cwi-manager",
31886
+ component: CWI_COMPONENT,
31809
31887
  severity: "error",
31810
31888
  error
31811
31889
  });
@@ -31814,9 +31892,11 @@ var CWIStyleWalletManager = class {
31814
31892
  }
31815
31893
  }
31816
31894
  /**
31817
- * Provides the presentation key.
31895
+ * Provides the presentation key. A WAB operator pin may be supplied by the
31896
+ * authentication manager; normal lookup and lineage resolution always run
31897
+ * before this ambiguity-only fallback.
31818
31898
  */
31819
- async providePresentationKey(key) {
31899
+ async providePresentationKey(key, lookupOptions) {
31820
31900
  if (this.authenticated) throw new Error("User is already authenticated");
31821
31901
  if (this.authenticationMode === "recovery-key-and-password") throw new Error("Presentation key is not needed in this mode");
31822
31902
  if (key.length !== 32 || key.some((byte) => !Number.isInteger(byte) || byte < 0 || byte > 255)) throw new TypeError("Presentation key must contain exactly 32 bytes.");
@@ -31825,17 +31905,17 @@ var CWIStyleWalletManager = class {
31825
31905
  const startedAt = Date.now();
31826
31906
  this.telemetry.capture({
31827
31907
  name: "wallet-toolbox.authentication.account-lookup.started",
31828
- component: "wallet-toolbox.cwi-manager",
31908
+ component: CWI_COMPONENT,
31829
31909
  severity: "debug",
31830
31910
  attributes: { lookupKind: "presentation" }
31831
31911
  });
31832
31912
  let token;
31833
31913
  try {
31834
- token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash);
31914
+ token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash, lookupOptions);
31835
31915
  } catch (error) {
31836
31916
  this.telemetry.capture({
31837
31917
  name: "wallet-toolbox.authentication.account-lookup.failed",
31838
- component: "wallet-toolbox.cwi-manager",
31918
+ component: CWI_COMPONENT,
31839
31919
  severity: "warn",
31840
31920
  attributes: {
31841
31921
  lookupKind: "presentation",
@@ -31855,7 +31935,7 @@ var CWIStyleWalletManager = class {
31855
31935
  }
31856
31936
  this.telemetry.capture({
31857
31937
  name: "wallet-toolbox.authentication.account-lookup.completed",
31858
- component: "wallet-toolbox.cwi-manager",
31938
+ component: CWI_COMPONENT,
31859
31939
  severity: "info",
31860
31940
  attributes: {
31861
31941
  lookupKind: "presentation",
@@ -31871,11 +31951,11 @@ var CWIStyleWalletManager = class {
31871
31951
  if (this.authenticated) throw new Error("User is already authenticated");
31872
31952
  if (this.authenticationMode === "presentation-key-and-recovery-key") throw new Error("Password is not needed in this mode");
31873
31953
  if (this.authenticationFlow === "unknown") throw new Error("Determine account status with a presentation or recovery key before providing a password.");
31874
- if (this.authenticationFlow === "existing-user") await this.handleExistingUserPassword(password);
31875
- else await this.handleNewUserPassword(password);
31954
+ if (this.authenticationFlow === "existing-user") await this.unlockExisting(password);
31955
+ else await this.createNewUser(password);
31876
31956
  }
31877
31957
  /** Handles the password step for an existing user — derives keys, sets up infrastructure. */
31878
- async handleExistingUserPassword(password) {
31958
+ async unlockExisting(password) {
31879
31959
  if (this.currentUMPToken == null) throw new Error("Provide presentation or recovery key first.");
31880
31960
  const derivedPasswordKey = await derivePasswordKey(this.currentUMPToken, _bsv_sdk.Utils.toArray(password, "utf8"));
31881
31961
  let rootPrimaryKey;
@@ -31888,11 +31968,11 @@ var CWIStyleWalletManager = class {
31888
31968
  rootPrimaryKey = new _bsv_sdk.SymmetricKey(this.XOR(this.recoveryKey, derivedPasswordKey)).decrypt(this.currentUMPToken.passwordRecoveryPrimary);
31889
31969
  rootPrivilegedKey = new _bsv_sdk.SymmetricKey(this.XOR(rootPrimaryKey, derivedPasswordKey)).decrypt(this.currentUMPToken.passwordPrimaryPrivileged);
31890
31970
  }
31891
- await this.setupRootInfrastructure(rootPrimaryKey, rootPrivilegedKey);
31971
+ await this.setupRoot(rootPrimaryKey, rootPrivilegedKey);
31892
31972
  await this.switchProfile(this.activeProfileId);
31893
31973
  }
31894
31974
  /** Handles the password step for a new user — generates keys, builds UMP token, publishes on-chain. */
31895
- async handleNewUserPassword(password) {
31975
+ async createNewUser(password) {
31896
31976
  if (this.authenticationMode !== "presentation-key-and-password") throw new Error("New-user flow requires presentation key and password mode.");
31897
31977
  if (this.presentationKey == null) throw new Error("No presentation key provided for new-user flow.");
31898
31978
  const recoveryKey = (0, _bsv_sdk.Random)(32);
@@ -31931,14 +32011,14 @@ var CWIStyleWalletManager = class {
31931
32011
  passwordKdf: this.kdfConfig
31932
32012
  };
31933
32013
  this.currentUMPToken = newToken;
31934
- await this.setupRootInfrastructure(rootPrimaryKey);
32014
+ await this.setupRoot(rootPrimaryKey);
31935
32015
  await this.switchProfile(DEFAULT_PROFILE_ID);
31936
32016
  if (this.newWalletFunder != null && this.underlying != null) try {
31937
32017
  await this.newWalletFunder(this.presentationKey, this.underlying, this.adminOriginator);
31938
32018
  } catch (error) {
31939
32019
  this.telemetry.capture({
31940
32020
  name: "wallet-toolbox.authentication.new-wallet-funding.failed",
31941
- component: "wallet-toolbox.cwi-manager",
32021
+ component: CWI_COMPONENT,
31942
32022
  severity: "error",
31943
32023
  error: /* @__PURE__ */ new Error("New wallet funding failed.")
31944
32024
  });
@@ -31969,7 +32049,7 @@ var CWIStyleWalletManager = class {
31969
32049
  const xorKey = this.XOR(this.presentationKey, recoveryKey);
31970
32050
  const rootPrimaryKey = new _bsv_sdk.SymmetricKey(xorKey).decrypt(this.currentUMPToken.presentationRecoveryPrimary);
31971
32051
  const rootPrivilegedKey = new _bsv_sdk.SymmetricKey(xorKey).decrypt(this.currentUMPToken.presentationRecoveryPrivileged);
31972
- await this.setupRootInfrastructure(rootPrimaryKey, rootPrivilegedKey);
32052
+ await this.setupRoot(rootPrimaryKey, rootPrivilegedKey);
31973
32053
  await this.switchProfile(this.activeProfileId);
31974
32054
  }
31975
32055
  }
@@ -32000,7 +32080,7 @@ var CWIStyleWalletManager = class {
32000
32080
  if (snapshot.length > 16777216) throw new Error("Snapshot exceeds the maximum supported size.");
32001
32081
  this.telemetry.capture({
32002
32082
  name: "wallet-toolbox.snapshot.saved",
32003
- component: "wallet-toolbox.cwi-manager",
32083
+ component: CWI_COMPONENT,
32004
32084
  severity: "info",
32005
32085
  attributes: {
32006
32086
  formatVersion: 2,
@@ -32038,12 +32118,12 @@ var CWIStyleWalletManager = class {
32038
32118
  const tokenBytes = payloadReader.read(tokenLen);
32039
32119
  const token = this.deserializeUMPToken(tokenBytes);
32040
32120
  this.currentUMPToken = token;
32041
- await this.setupRootInfrastructure(rootPrimaryKey);
32121
+ await this.setupRoot(rootPrimaryKey);
32042
32122
  await this.switchProfile(activeProfileId);
32043
32123
  this.authenticationFlow = "existing-user";
32044
32124
  this.telemetry.capture({
32045
32125
  name: "wallet-toolbox.snapshot.loaded",
32046
- component: "wallet-toolbox.cwi-manager",
32126
+ component: CWI_COMPONENT,
32047
32127
  severity: "info",
32048
32128
  attributes: {
32049
32129
  formatVersion: version,
@@ -32054,7 +32134,7 @@ var CWIStyleWalletManager = class {
32054
32134
  this.destroy();
32055
32135
  this.telemetry.capture({
32056
32136
  name: "wallet-toolbox.snapshot.load-failed",
32057
- component: "wallet-toolbox.cwi-manager",
32137
+ component: CWI_COMPONENT,
32058
32138
  severity: "error",
32059
32139
  error
32060
32140
  });
@@ -32071,7 +32151,7 @@ var CWIStyleWalletManager = class {
32071
32151
  if (refreshed == null) return false;
32072
32152
  if (refreshed.currentOutpoint && currentToken.currentOutpoint && refreshed.currentOutpoint === currentToken.currentOutpoint) return false;
32073
32153
  this.currentUMPToken = refreshed;
32074
- await this.setupRootInfrastructure(this.rootPrimaryKey);
32154
+ await this.setupRoot(this.rootPrimaryKey);
32075
32155
  this.saveSnapshot();
32076
32156
  return true;
32077
32157
  }
@@ -32130,7 +32210,7 @@ var CWIStyleWalletManager = class {
32130
32210
  createdAt: Math.floor(Date.now() / 1e3)
32131
32211
  };
32132
32212
  this.profiles.push(newProfile);
32133
- await this.updateAuthFactors(this.currentUMPToken.passwordSalt, await this.getFactor("passwordKey"), await this.getFactor("presentationKey"), await this.getFactor("recoveryKey"), this.rootPrimaryKey, await this.getFactor("privilegedKey"), this.profiles);
32213
+ await this.updateFactors(this.currentUMPToken.passwordSalt, await this.getFactor("passwordKey"), await this.getFactor("presentationKey"), await this.getFactor("recoveryKey"), this.rootPrimaryKey, await this.getFactor("privilegedKey"), this.profiles);
32134
32214
  return newProfile.id;
32135
32215
  }
32136
32216
  /**
@@ -32147,7 +32227,7 @@ var CWIStyleWalletManager = class {
32147
32227
  if (profileIndex === -1) throw new Error("Profile not found.");
32148
32228
  this.profiles.splice(profileIndex, 1);
32149
32229
  if (this.activeProfileId.every((x, i) => x === profileId[i])) await this.switchProfile(DEFAULT_PROFILE_ID);
32150
- await this.updateAuthFactors(this.currentUMPToken.passwordSalt, await this.getFactor("passwordKey"), await this.getFactor("presentationKey"), await this.getFactor("recoveryKey"), this.rootPrimaryKey, await this.getFactor("privilegedKey"), this.profiles);
32230
+ await this.updateFactors(this.currentUMPToken.passwordSalt, await this.getFactor("passwordKey"), await this.getFactor("presentationKey"), await this.getFactor("recoveryKey"), this.rootPrimaryKey, await this.getFactor("privilegedKey"), this.profiles);
32151
32231
  }
32152
32232
  /**
32153
32233
  * Switches the active profile. This re-derives keys and rebuilds the underlying wallet.
@@ -32188,14 +32268,14 @@ var CWIStyleWalletManager = class {
32188
32268
  const recoveryKey = await this.getFactor("recoveryKey");
32189
32269
  const presentationKey = await this.getFactor("presentationKey");
32190
32270
  const rootPrivilegedKey = await this.getFactor("privilegedKey");
32191
- await this.updateAuthFactors(passwordSalt, newPasswordKey, presentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32271
+ await this.updateFactors(passwordSalt, newPasswordKey, presentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32192
32272
  }
32193
32273
  /**
32194
32274
  * Retrieves the current recovery key. Requires privileged access.
32195
32275
  */
32196
32276
  async getRecoveryKey() {
32197
32277
  if (!this.authenticated || this.currentUMPToken == null || this.rootPrivilegedKeyManager == null) throw new Error("Not authenticated or missing required data.");
32198
- return await this.getFactor("recoveryKey");
32278
+ return this.getFactor("recoveryKey");
32199
32279
  }
32200
32280
  /**
32201
32281
  * Changes the user's recovery key. Prompts user to save the new key.
@@ -32207,7 +32287,7 @@ var CWIStyleWalletManager = class {
32207
32287
  const rootPrivilegedKey = await this.getFactor("privilegedKey");
32208
32288
  const newRecoveryKey = (0, _bsv_sdk.Random)(32);
32209
32289
  await this.recoveryKeySaver(newRecoveryKey);
32210
- await this.updateAuthFactors(this.currentUMPToken.passwordSalt, passwordKey, presentationKey, newRecoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32290
+ await this.updateFactors(this.currentUMPToken.passwordSalt, passwordKey, presentationKey, newRecoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32211
32291
  }
32212
32292
  /**
32213
32293
  * Changes the user's presentation key.
@@ -32218,7 +32298,7 @@ var CWIStyleWalletManager = class {
32218
32298
  const recoveryKey = await this.getFactor("recoveryKey");
32219
32299
  const passwordKey = await this.getFactor("passwordKey");
32220
32300
  const rootPrivilegedKey = await this.getFactor("privilegedKey");
32221
- await this.updateAuthFactors(this.currentUMPToken.passwordSalt, passwordKey, newPresentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32301
+ await this.updateFactors(this.currentUMPToken.passwordSalt, passwordKey, newPresentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32222
32302
  if (this.presentationKey != null) this.presentationKey = newPresentationKey;
32223
32303
  }
32224
32304
  /**
@@ -32264,7 +32344,7 @@ var CWIStyleWalletManager = class {
32264
32344
  } catch (error) {
32265
32345
  this.telemetry.capture({
32266
32346
  name: "wallet-toolbox.authentication.factor-decryption.failed",
32267
- component: "wallet-toolbox.cwi-manager",
32347
+ component: CWI_COMPONENT,
32268
32348
  severity: "error",
32269
32349
  attributes: { factor: factorName },
32270
32350
  error
@@ -32277,7 +32357,7 @@ var CWIStyleWalletManager = class {
32277
32357
  * Recomputes UMP token fields with updated factors and profiles, then publishes the update.
32278
32358
  * This operation requires the *root* privileged key and the *default* profile wallet.
32279
32359
  */
32280
- async updateAuthFactors(passwordSalt, passwordKey, presentationKey, recoveryKey, rootPrimaryKey, rootPrivilegedKey, profiles) {
32360
+ async updateFactors(passwordSalt, passwordKey, presentationKey, recoveryKey, rootPrimaryKey, rootPrivilegedKey, profiles) {
32281
32361
  if (!this.authenticated || this.rootPrimaryKey == null || this.currentUMPToken == null) throw new Error("Wallet is not properly authenticated or missing data for update.");
32282
32362
  const oldTokenToConsume = { ...this.currentUMPToken };
32283
32363
  if (!oldTokenToConsume.currentOutpoint) throw new Error("Cannot update UMP token: Old token has no outpoint.");
@@ -32328,7 +32408,7 @@ var CWIStyleWalletManager = class {
32328
32408
  if (!currentActiveId.every((x) => x === 0)) {
32329
32409
  this.telemetry.capture({
32330
32410
  name: "wallet-toolbox.ump.profile-switch.started",
32331
- component: "wallet-toolbox.cwi-manager",
32411
+ component: CWI_COMPONENT,
32332
32412
  severity: "debug",
32333
32413
  attributes: { reason: "token-update" }
32334
32414
  });
@@ -32344,7 +32424,7 @@ var CWIStyleWalletManager = class {
32344
32424
  await this.switchProfile(currentActiveId);
32345
32425
  this.telemetry.capture({
32346
32426
  name: "wallet-toolbox.ump.profile-switch.completed",
32347
- component: "wallet-toolbox.cwi-manager",
32427
+ component: CWI_COMPONENT,
32348
32428
  severity: "debug",
32349
32429
  attributes: { reason: "token-update" }
32350
32430
  });
@@ -32471,9 +32551,9 @@ var CWIStyleWalletManager = class {
32471
32551
  * @param rootPrimaryKey The user's root primary key (32 bytes).
32472
32552
  * @param ephemeralRootPrivilegedKey Optional root privileged key (e.g., during recovery flows).
32473
32553
  */
32474
- async setupRootInfrastructure(rootPrimaryKey, ephemeralRootPrivilegedKey) {
32554
+ async setupRoot(rootKey, ephemeralRootPrivilegedKey) {
32475
32555
  if (this.currentUMPToken == null) throw new Error("A UMP token must exist before setting up root infrastructure!");
32476
- this.rootPrimaryKey = rootPrimaryKey;
32556
+ this.rootPrimaryKey = rootKey;
32477
32557
  let oneTimePrivilegedKey = ephemeralRootPrivilegedKey == null ? void 0 : new _bsv_sdk.PrivateKey(ephemeralRootPrivilegedKey);
32478
32558
  this.rootPrivilegedKeyManager = new PrivilegedKeyManager(async (reason) => {
32479
32559
  if (oneTimePrivilegedKey != null) {
@@ -32494,7 +32574,7 @@ var CWIStyleWalletManager = class {
32494
32574
  });
32495
32575
  this.profiles = [];
32496
32576
  if (this.currentUMPToken.profilesEncrypted != null && this.currentUMPToken.profilesEncrypted.length > 0) try {
32497
- const decryptedProfileBytes = new _bsv_sdk.SymmetricKey(rootPrimaryKey).decrypt(this.currentUMPToken.profilesEncrypted);
32577
+ const decryptedProfileBytes = new _bsv_sdk.SymmetricKey(rootKey).decrypt(this.currentUMPToken.profilesEncrypted);
32498
32578
  const profilesJson = _bsv_sdk.Utils.toUTF8(decryptedProfileBytes);
32499
32579
  const profiles = JSON.parse(profilesJson);
32500
32580
  if (!Array.isArray(profiles) || profiles.length > 1e3 || !profiles.every(isValidProfile)) throw new Error("Decrypted profile data is invalid or exceeds supported bounds.");
@@ -32503,7 +32583,7 @@ var CWIStyleWalletManager = class {
32503
32583
  this.profiles = [];
32504
32584
  this.telemetry.capture({
32505
32585
  name: "wallet-toolbox.profile.load-failed",
32506
- component: "wallet-toolbox.cwi-manager",
32586
+ component: CWI_COMPONENT,
32507
32587
  severity: "error",
32508
32588
  error
32509
32589
  });
@@ -32512,98 +32592,98 @@ var CWIStyleWalletManager = class {
32512
32592
  }
32513
32593
  this.authenticated = true;
32514
32594
  }
32515
- checkAuthAndUnderlying(originator) {
32595
+ assertReady(originator) {
32516
32596
  if (!this.authenticated) throw new Error("User is not authenticated.");
32517
32597
  if (this.underlying == null) throw new Error("Underlying wallet for the active profile is not initialized.");
32518
32598
  if (originator === this.adminOriginator) throw new Error("External applications are not allowed to use the admin originator.");
32519
32599
  }
32520
32600
  async getPublicKey(args, originator) {
32521
- this.checkAuthAndUnderlying(originator);
32522
- return await this.underlying.getPublicKey(args, originator);
32601
+ this.assertReady(originator);
32602
+ return this.underlying.getPublicKey(args, originator);
32523
32603
  }
32524
32604
  async revealCounterpartyKeyLinkage(args, originator) {
32525
- this.checkAuthAndUnderlying(originator);
32526
- return await this.underlying.revealCounterpartyKeyLinkage(args, originator);
32605
+ this.assertReady(originator);
32606
+ return this.underlying.revealCounterpartyKeyLinkage(args, originator);
32527
32607
  }
32528
32608
  async revealSpecificKeyLinkage(args, originator) {
32529
- this.checkAuthAndUnderlying(originator);
32530
- return await this.underlying.revealSpecificKeyLinkage(args, originator);
32609
+ this.assertReady(originator);
32610
+ return this.underlying.revealSpecificKeyLinkage(args, originator);
32531
32611
  }
32532
32612
  async encrypt(args, originator) {
32533
- this.checkAuthAndUnderlying(originator);
32534
- return await this.underlying.encrypt(args, originator);
32613
+ this.assertReady(originator);
32614
+ return this.underlying.encrypt(args, originator);
32535
32615
  }
32536
32616
  async decrypt(args, originator) {
32537
- this.checkAuthAndUnderlying(originator);
32538
- return await this.underlying.decrypt(args, originator);
32617
+ this.assertReady(originator);
32618
+ return this.underlying.decrypt(args, originator);
32539
32619
  }
32540
32620
  async createHmac(args, originator) {
32541
- this.checkAuthAndUnderlying(originator);
32542
- return await this.underlying.createHmac(args, originator);
32621
+ this.assertReady(originator);
32622
+ return this.underlying.createHmac(args, originator);
32543
32623
  }
32544
32624
  async verifyHmac(args, originator) {
32545
- this.checkAuthAndUnderlying(originator);
32546
- return await this.underlying.verifyHmac(args, originator);
32625
+ this.assertReady(originator);
32626
+ return this.underlying.verifyHmac(args, originator);
32547
32627
  }
32548
32628
  async createSignature(args, originator) {
32549
- this.checkAuthAndUnderlying(originator);
32550
- return await this.underlying.createSignature(args, originator);
32629
+ this.assertReady(originator);
32630
+ return this.underlying.createSignature(args, originator);
32551
32631
  }
32552
32632
  async verifySignature(args, originator) {
32553
- this.checkAuthAndUnderlying(originator);
32554
- return await this.underlying.verifySignature(args, originator);
32633
+ this.assertReady(originator);
32634
+ return this.underlying.verifySignature(args, originator);
32555
32635
  }
32556
32636
  async createAction(args, originator) {
32557
- this.checkAuthAndUnderlying(originator);
32558
- return await this.underlying.createAction(args, originator);
32637
+ this.assertReady(originator);
32638
+ return this.underlying.createAction(args, originator);
32559
32639
  }
32560
32640
  async signAction(args, originator) {
32561
- this.checkAuthAndUnderlying(originator);
32562
- return await this.underlying.signAction(args, originator);
32641
+ this.assertReady(originator);
32642
+ return this.underlying.signAction(args, originator);
32563
32643
  }
32564
32644
  async abortAction(args, originator) {
32565
- this.checkAuthAndUnderlying(originator);
32566
- return await this.underlying.abortAction(args, originator);
32645
+ this.assertReady(originator);
32646
+ return this.underlying.abortAction(args, originator);
32567
32647
  }
32568
32648
  async listActions(args, originator) {
32569
- this.checkAuthAndUnderlying(originator);
32570
- return await this.underlying.listActions(args, originator);
32649
+ this.assertReady(originator);
32650
+ return this.underlying.listActions(args, originator);
32571
32651
  }
32572
32652
  async internalizeAction(args, originator) {
32573
- this.checkAuthAndUnderlying(originator);
32574
- return await this.underlying.internalizeAction(args, originator);
32653
+ this.assertReady(originator);
32654
+ return this.underlying.internalizeAction(args, originator);
32575
32655
  }
32576
32656
  async listOutputs(args, originator) {
32577
- this.checkAuthAndUnderlying(originator);
32578
- return await this.underlying.listOutputs(args, originator);
32657
+ this.assertReady(originator);
32658
+ return this.underlying.listOutputs(args, originator);
32579
32659
  }
32580
32660
  async relinquishOutput(args, originator) {
32581
- this.checkAuthAndUnderlying(originator);
32582
- return await this.underlying.relinquishOutput(args, originator);
32661
+ this.assertReady(originator);
32662
+ return this.underlying.relinquishOutput(args, originator);
32583
32663
  }
32584
32664
  async acquireCertificate(args, originator) {
32585
- this.checkAuthAndUnderlying(originator);
32586
- return await this.underlying.acquireCertificate(args, originator);
32665
+ this.assertReady(originator);
32666
+ return this.underlying.acquireCertificate(args, originator);
32587
32667
  }
32588
32668
  async listCertificates(args, originator) {
32589
- this.checkAuthAndUnderlying(originator);
32590
- return await this.underlying.listCertificates(args, originator);
32669
+ this.assertReady(originator);
32670
+ return this.underlying.listCertificates(args, originator);
32591
32671
  }
32592
32672
  async proveCertificate(args, originator) {
32593
- this.checkAuthAndUnderlying(originator);
32594
- return await this.underlying.proveCertificate(args, originator);
32673
+ this.assertReady(originator);
32674
+ return this.underlying.proveCertificate(args, originator);
32595
32675
  }
32596
32676
  async relinquishCertificate(args, originator) {
32597
- this.checkAuthAndUnderlying(originator);
32598
- return await this.underlying.relinquishCertificate(args, originator);
32677
+ this.assertReady(originator);
32678
+ return this.underlying.relinquishCertificate(args, originator);
32599
32679
  }
32600
32680
  async discoverByIdentityKey(args, originator) {
32601
- this.checkAuthAndUnderlying(originator);
32602
- return await this.underlying.discoverByIdentityKey(args, originator);
32681
+ this.assertReady(originator);
32682
+ return this.underlying.discoverByIdentityKey(args, originator);
32603
32683
  }
32604
32684
  async discoverByAttributes(args, originator) {
32605
- this.checkAuthAndUnderlying(originator);
32606
- return await this.underlying.discoverByAttributes(args, originator);
32685
+ this.assertReady(originator);
32686
+ return this.underlying.discoverByAttributes(args, originator);
32607
32687
  }
32608
32688
  async isAuthenticated(_, originator) {
32609
32689
  if (!this.authenticated) throw new Error("User is not authenticated.");
@@ -32613,23 +32693,23 @@ var CWIStyleWalletManager = class {
32613
32693
  async waitForAuthentication(_, originator) {
32614
32694
  if (originator === this.adminOriginator) throw new Error("External applications are not allowed to use the admin originator.");
32615
32695
  while (!this.authenticated || this.underlying == null) await new Promise((resolve) => setTimeout(resolve, 100));
32616
- return await this.underlying.waitForAuthentication({}, originator);
32696
+ return this.underlying.waitForAuthentication({}, originator);
32617
32697
  }
32618
32698
  async getHeight(_, originator) {
32619
- this.checkAuthAndUnderlying(originator);
32620
- return await this.underlying.getHeight({}, originator);
32699
+ this.assertReady(originator);
32700
+ return this.underlying.getHeight({}, originator);
32621
32701
  }
32622
32702
  async getHeaderForHeight(args, originator) {
32623
- this.checkAuthAndUnderlying(originator);
32624
- return await this.underlying.getHeaderForHeight(args, originator);
32703
+ this.assertReady(originator);
32704
+ return this.underlying.getHeaderForHeight(args, originator);
32625
32705
  }
32626
32706
  async getNetwork(_, originator) {
32627
- this.checkAuthAndUnderlying(originator);
32628
- return await this.underlying.getNetwork({}, originator);
32707
+ this.assertReady(originator);
32708
+ return this.underlying.getNetwork({}, originator);
32629
32709
  }
32630
32710
  async getVersion(_, originator) {
32631
- this.checkAuthAndUnderlying(originator);
32632
- return await this.underlying.getVersion({}, originator);
32711
+ this.assertReady(originator);
32712
+ return this.underlying.getVersion({}, originator);
32633
32713
  }
32634
32714
  };
32635
32715
  //#endregion
@@ -32973,6 +33053,8 @@ const DEFAULT_MAX_RESPONSE_BYTES = 1024 * 1024;
32973
33053
  const MAX_CONFIGURED_TIMEOUT_MS = 12e4;
32974
33054
  const MAX_CONFIGURED_REQUEST_BYTES = 10 * 1024 * 1024;
32975
33055
  const MAX_CONFIGURED_RESPONSE_BYTES = 10 * 1024 * 1024;
33056
+ const WAB_COMPONENT = "wallet-toolbox.wab-transport";
33057
+ const WAB_REQUEST_EVENT = "wallet-toolbox.wab.request.";
32976
33058
  const defaultFetch = typeof globalThis !== "undefined" && typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
32977
33059
  /**
32978
33060
  * A privacy-safe WAB transport failure. Response bodies and request payloads
@@ -33011,8 +33093,8 @@ function normalizeServerUrl(serverUrl) {
33011
33093
  } catch {
33012
33094
  throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB server URL must be an absolute URL.", false);
33013
33095
  }
33014
- if (parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB server URL must not contain credentials, a query, or a fragment.", false);
33015
- if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && isLocalHostname(parsed.hostname))) throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB server URL must use HTTPS. Plain HTTP is allowed only for localhost development.", false);
33096
+ if (parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB URL cannot include credentials, query, or fragment.", false);
33097
+ if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && isLocalHostname(parsed.hostname))) throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB URL requires HTTPS except on localhost.", false);
33016
33098
  let pathname = parsed.pathname;
33017
33099
  while (pathname.endsWith("/")) pathname = pathname.slice(0, -1);
33018
33100
  return {
@@ -33022,7 +33104,7 @@ function normalizeServerUrl(serverUrl) {
33022
33104
  }
33023
33105
  function normalizePositiveInteger(value, fallback, maximum, name) {
33024
33106
  const resolved = value ?? fallback;
33025
- if (!Number.isInteger(resolved) || resolved <= 0 || resolved > maximum) throw new WABClientError("WAB_INVALID_CONFIGURATION", `${name} must be a positive integer no greater than ${maximum}.`, false);
33107
+ if (!Number.isInteger(resolved) || resolved <= 0 || resolved > maximum) throw new WABClientError("WAB_INVALID_CONFIGURATION", `${name} must be an integer from 1 to ${maximum}.`, false);
33026
33108
  return resolved;
33027
33109
  }
33028
33110
  function assertSafePath(path) {
@@ -33047,20 +33129,20 @@ var WABTransport = class {
33047
33129
  serverUrl;
33048
33130
  serverOrigin;
33049
33131
  telemetry;
33050
- fetchClient;
33051
- timeoutMs;
33052
- maxRequestBytes;
33053
- maxResponseBytes;
33132
+ fetcher;
33133
+ timeout;
33134
+ requestLimit;
33135
+ responseLimit;
33054
33136
  constructor(serverUrl, options = {}) {
33055
33137
  const normalized = normalizeServerUrl(serverUrl);
33056
33138
  this.serverUrl = normalized.baseUrl;
33057
33139
  this.serverOrigin = normalized.origin;
33058
- const fetchClient = options.fetch ?? defaultFetch;
33059
- if (typeof fetchClient !== "function") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WABClient requires a fetch implementation.", false);
33060
- this.fetchClient = fetchClient;
33061
- this.timeoutMs = normalizePositiveInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, MAX_CONFIGURED_TIMEOUT_MS, "timeoutMs");
33062
- this.maxRequestBytes = normalizePositiveInteger(options.maxRequestBytes, DEFAULT_MAX_REQUEST_BYTES, MAX_CONFIGURED_REQUEST_BYTES, "maxRequestBytes");
33063
- this.maxResponseBytes = normalizePositiveInteger(options.maxResponseBytes, DEFAULT_MAX_RESPONSE_BYTES, MAX_CONFIGURED_RESPONSE_BYTES, "maxResponseBytes");
33140
+ const fetcher = options.fetch ?? defaultFetch;
33141
+ if (typeof fetcher !== "function") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WABClient requires a fetch implementation.", false);
33142
+ this.fetcher = fetcher;
33143
+ this.timeout = normalizePositiveInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, MAX_CONFIGURED_TIMEOUT_MS, "timeoutMs");
33144
+ this.requestLimit = normalizePositiveInteger(options.maxRequestBytes, DEFAULT_MAX_REQUEST_BYTES, MAX_CONFIGURED_REQUEST_BYTES, "maxRequestBytes");
33145
+ this.responseLimit = normalizePositiveInteger(options.maxResponseBytes, DEFAULT_MAX_RESPONSE_BYTES, MAX_CONFIGURED_RESPONSE_BYTES, "maxResponseBytes");
33064
33146
  this.telemetry = new _bsv_sdk.Telemetry(options.telemetry);
33065
33147
  }
33066
33148
  createCorrelationId() {
@@ -33068,38 +33150,9 @@ var WABTransport = class {
33068
33150
  return isSafeCorrelationId(correlationId) ? correlationId : new _bsv_sdk.Telemetry().createCorrelationId();
33069
33151
  }
33070
33152
  async request(path, options) {
33071
- const metadata = this.createRequestMetadata(path, options);
33072
- this.captureRequestStarted(metadata);
33073
- const body = this.encodeRequestBody(options, metadata);
33074
- const timeout = this.startRequestTimeout(metadata.errorContext);
33075
- const response = await this.fetchResponse(metadata, body, timeout);
33076
- const responseContext = this.createResponseContext(response, metadata);
33077
- this.assertSuccessfulResponse(response, responseContext, metadata, timeout);
33078
- const responseText = await this.readResponseText(response, responseContext, metadata, timeout);
33079
- const parsed = this.parseResponseObject(responseText, response, responseContext, metadata);
33080
- this.telemetry.capture({
33081
- name: "wallet-toolbox.wab.request.completed",
33082
- component: "wallet-toolbox.wab-transport",
33083
- severity: "info",
33084
- correlationId: metadata.correlationId,
33085
- attributes: {
33086
- operation: metadata.operation,
33087
- method: metadata.method,
33088
- route: metadata.path,
33089
- serverOrigin: this.serverOrigin,
33090
- status: response.status,
33091
- endpointMarkerPresent: responseContext.endpointMarkerPresent,
33092
- responseCorrelationMatched: responseContext.responseCorrelationMatched,
33093
- responseBytes: new TextEncoder().encode(responseText).byteLength,
33094
- durationMs: Date.now() - metadata.startedAt
33095
- }
33096
- });
33097
- return parsed;
33098
- }
33099
- createRequestMetadata(path, options) {
33100
33153
  assertSafePath(path);
33101
33154
  const correlationId = options.correlationId != null && isSafeCorrelationId(options.correlationId) ? options.correlationId : this.createCorrelationId();
33102
- return {
33155
+ const metadata = {
33103
33156
  method: options.method ?? "POST",
33104
33157
  path,
33105
33158
  operation: options.operation,
@@ -33111,46 +33164,73 @@ var WABTransport = class {
33111
33164
  route: path
33112
33165
  }
33113
33166
  };
33114
- }
33115
- captureRequestStarted(metadata) {
33116
33167
  this.telemetry.capture({
33117
- name: "wallet-toolbox.wab.request.started",
33118
- component: "wallet-toolbox.wab-transport",
33168
+ name: `${WAB_REQUEST_EVENT}started`,
33169
+ component: WAB_COMPONENT,
33119
33170
  severity: "debug",
33171
+ correlationId,
33172
+ attributes: {
33173
+ operation: metadata.operation,
33174
+ method: metadata.method,
33175
+ route: path,
33176
+ serverOrigin: this.serverOrigin
33177
+ }
33178
+ });
33179
+ const body = this.bodyFor(options, metadata);
33180
+ const timeout = this.startTimer(metadata.errorContext);
33181
+ const response = await this.fetch(metadata, body, timeout);
33182
+ const responseContext = {
33183
+ ...metadata.errorContext,
33184
+ endpointMarkerPresent: isWabResponse(response),
33185
+ responseCorrelationMatched: response.headers.get("X-Correlation-ID") === correlationId
33186
+ };
33187
+ this.checkResponse(response, responseContext, metadata, timeout);
33188
+ const responseText = await this.readText(response, responseContext, metadata, timeout);
33189
+ const parsed = this.parse(responseText, response, responseContext, metadata);
33190
+ this.telemetry.capture({
33191
+ name: `${WAB_REQUEST_EVENT}completed`,
33192
+ component: WAB_COMPONENT,
33193
+ severity: "info",
33120
33194
  correlationId: metadata.correlationId,
33121
33195
  attributes: {
33122
33196
  operation: metadata.operation,
33123
33197
  method: metadata.method,
33124
33198
  route: metadata.path,
33125
- serverOrigin: this.serverOrigin
33199
+ serverOrigin: this.serverOrigin,
33200
+ status: response.status,
33201
+ endpointMarkerPresent: responseContext.endpointMarkerPresent,
33202
+ responseCorrelationMatched: responseContext.responseCorrelationMatched,
33203
+ responseBytes: new TextEncoder().encode(responseText).byteLength,
33204
+ durationMs: Date.now() - metadata.startedAt
33126
33205
  }
33127
33206
  });
33207
+ return parsed;
33128
33208
  }
33129
- encodeRequestBody(options, metadata) {
33209
+ bodyFor(options, metadata) {
33130
33210
  let body;
33131
33211
  try {
33132
33212
  body = options.body === void 0 ? void 0 : JSON.stringify(options.body);
33133
33213
  } catch (cause) {
33134
- const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request payload could not be encoded.", false, void 0, {
33214
+ const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request encoding failed.", false, void 0, {
33135
33215
  ...metadata.errorContext,
33136
33216
  cause
33137
33217
  });
33138
- this.captureRequestFailure(metadata, error);
33218
+ this.report(metadata, error);
33139
33219
  throw error;
33140
33220
  }
33141
33221
  if (options.body !== void 0 && body === void 0) {
33142
- const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request payload must be JSON-serializable.", false, void 0, metadata.errorContext);
33143
- this.captureRequestFailure(metadata, error);
33222
+ const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request is not JSON-serializable.", false, void 0, metadata.errorContext);
33223
+ this.report(metadata, error);
33144
33224
  throw error;
33145
33225
  }
33146
- if (body != null && new TextEncoder().encode(body).byteLength > this.maxRequestBytes) {
33147
- const error = new WABClientError("WAB_REQUEST_TOO_LARGE", "WAB request exceeded the configured size limit.", false, void 0, metadata.errorContext);
33148
- this.captureRequestFailure(metadata, error);
33226
+ if (body != null && new TextEncoder().encode(body).byteLength > this.requestLimit) {
33227
+ const error = new WABClientError("WAB_REQUEST_TOO_LARGE", "WAB request exceeds its size limit.", false, void 0, metadata.errorContext);
33228
+ this.report(metadata, error);
33149
33229
  throw error;
33150
33230
  }
33151
33231
  return body;
33152
33232
  }
33153
- startRequestTimeout(errorContext) {
33233
+ startTimer(errorContext) {
33154
33234
  const timeout = {
33155
33235
  controller: new AbortController(),
33156
33236
  timedOut: false
@@ -33160,12 +33240,12 @@ var WABTransport = class {
33160
33240
  timeout.timedOut = true;
33161
33241
  timeout.controller.abort();
33162
33242
  reject(new WABClientError("WAB_TIMEOUT", "WAB request timed out.", true, void 0, errorContext));
33163
- }, this.timeoutMs);
33243
+ }, this.timeout);
33164
33244
  });
33165
33245
  return timeout;
33166
33246
  }
33167
- async fetchResponse(metadata, body, timeout) {
33168
- const requestPromise = Promise.resolve().then(() => this.fetchClient(`${this.serverUrl}${metadata.path}`, {
33247
+ async fetch(metadata, body, timeout) {
33248
+ const requestPromise = Promise.resolve().then(() => this.fetcher(`${this.serverUrl}${metadata.path}`, {
33169
33249
  method: metadata.method,
33170
33250
  headers: {
33171
33251
  Accept: "application/json",
@@ -33189,33 +33269,26 @@ var WABTransport = class {
33189
33269
  ...metadata.errorContext,
33190
33270
  cause
33191
33271
  });
33192
- else error = new WABClientError("WAB_NETWORK_ERROR", "WAB request failed before receiving a response.", true, void 0, {
33272
+ else error = new WABClientError("WAB_NETWORK_ERROR", "WAB request failed before response.", true, void 0, {
33193
33273
  ...metadata.errorContext,
33194
33274
  cause
33195
33275
  });
33196
- this.captureRequestFailure(metadata, error);
33276
+ this.report(metadata, error);
33197
33277
  throw error;
33198
33278
  }
33199
33279
  }
33200
- createResponseContext(response, metadata) {
33201
- return {
33202
- ...metadata.errorContext,
33203
- endpointMarkerPresent: isWabResponse(response),
33204
- responseCorrelationMatched: response.headers.get("X-Correlation-ID") === metadata.correlationId
33205
- };
33206
- }
33207
- assertSuccessfulResponse(response, responseContext, metadata, timeout) {
33280
+ checkResponse(response, responseContext, metadata, timeout) {
33208
33281
  if (response.ok) return;
33209
33282
  if (timeout.timer !== void 0) clearTimeout(timeout.timer);
33210
33283
  const endpointMismatch = response.status === 404 && responseContext.endpointMarkerPresent !== true;
33211
- const error = new WABClientError(endpointMismatch ? "WAB_ENDPOINT_MISMATCH" : "WAB_HTTP_ERROR", endpointMismatch ? "Configured WAB endpoint did not return a compatible WAB response." : `WAB request failed with HTTP status ${response.status}.`, isRetryableStatus(response.status), response.status, responseContext);
33212
- this.captureRequestFailure(metadata, error);
33284
+ const error = new WABClientError(endpointMismatch ? "WAB_ENDPOINT_MISMATCH" : "WAB_HTTP_ERROR", endpointMismatch ? "WAB endpoint is incompatible." : `WAB request failed with HTTP status ${response.status}.`, isRetryableStatus(response.status), response.status, responseContext);
33285
+ this.report(metadata, error);
33213
33286
  response.body?.cancel().catch(() => {});
33214
33287
  throw error;
33215
33288
  }
33216
- async readResponseText(response, responseContext, metadata, timeout) {
33289
+ async readText(response, responseContext, metadata, timeout) {
33217
33290
  try {
33218
- return await Promise.race([this.readBoundedResponse(response, responseContext), timeout.promise]);
33291
+ return await Promise.race([this.read(response, responseContext), timeout.promise]);
33219
33292
  } catch (cause) {
33220
33293
  let error;
33221
33294
  if (cause instanceof WABClientError) error = cause;
@@ -33223,17 +33296,17 @@ var WABTransport = class {
33223
33296
  ...responseContext,
33224
33297
  cause
33225
33298
  });
33226
- else error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response could not be read.", true, response.status, {
33299
+ else error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response read failed.", true, response.status, {
33227
33300
  ...responseContext,
33228
33301
  cause
33229
33302
  });
33230
- this.captureRequestFailure(metadata, error);
33303
+ this.report(metadata, error);
33231
33304
  throw error;
33232
33305
  } finally {
33233
33306
  if (timeout.timer !== void 0) clearTimeout(timeout.timer);
33234
33307
  }
33235
33308
  }
33236
- parseResponseObject(responseText, response, responseContext, metadata) {
33309
+ parse(responseText, response, responseContext, metadata) {
33237
33310
  let parsed;
33238
33311
  try {
33239
33312
  parsed = JSON.parse(responseText);
@@ -33242,37 +33315,32 @@ var WABTransport = class {
33242
33315
  ...responseContext,
33243
33316
  cause
33244
33317
  });
33245
- this.captureRequestFailure(metadata, error);
33318
+ this.report(metadata, error);
33246
33319
  throw error;
33247
33320
  }
33248
33321
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
33249
33322
  const error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response must be a JSON object.", true, response.status, responseContext);
33250
- this.captureRequestFailure(metadata, error);
33323
+ this.report(metadata, error);
33251
33324
  throw error;
33252
33325
  }
33253
33326
  return parsed;
33254
33327
  }
33255
- captureRequestFailure(metadata, error) {
33256
- this.captureFailure(metadata.operation, metadata.method, metadata.path, metadata.correlationId, metadata.startedAt, error);
33257
- }
33258
- async readBoundedResponse(response, responseContext) {
33259
- await this.rejectOversizedDeclaredResponse(response, responseContext);
33260
- const reader = response.body?.getReader();
33261
- if (reader == null) return await this.readBoundedArrayBuffer(response, responseContext);
33262
- return await this.readBoundedStream(reader, response, responseContext);
33263
- }
33264
- async rejectOversizedDeclaredResponse(response, responseContext) {
33328
+ async read(response, responseContext) {
33265
33329
  const contentLength = Number(response.headers.get("content-length"));
33266
- if (!Number.isFinite(contentLength) || contentLength <= this.maxResponseBytes) return;
33267
- await this.cancelResponseBody(response);
33268
- throw this.responseTooLargeError(response, responseContext);
33330
+ if (Number.isFinite(contentLength) && contentLength > this.responseLimit) {
33331
+ await this.stopBody(response);
33332
+ throw this.sizeError(response, responseContext);
33333
+ }
33334
+ const reader = response.body?.getReader();
33335
+ if (reader == null) return this.readBuffer(response, responseContext);
33336
+ return this.readStream(reader, response, responseContext);
33269
33337
  }
33270
- async readBoundedArrayBuffer(response, responseContext) {
33338
+ async readBuffer(response, responseContext) {
33271
33339
  const bytes = new Uint8Array(await response.arrayBuffer());
33272
- if (bytes.byteLength > this.maxResponseBytes) throw this.responseTooLargeError(response, responseContext);
33340
+ if (bytes.byteLength > this.responseLimit) throw this.sizeError(response, responseContext);
33273
33341
  return new TextDecoder().decode(bytes);
33274
33342
  }
33275
- async readBoundedStream(reader, response, responseContext) {
33343
+ async readStream(reader, response, responseContext) {
33276
33344
  const chunks = [];
33277
33345
  let total = 0;
33278
33346
  while (true) {
@@ -33280,15 +33348,12 @@ var WABTransport = class {
33280
33348
  if (done) break;
33281
33349
  if (value == null) continue;
33282
33350
  total += value.byteLength;
33283
- if (total > this.maxResponseBytes) {
33284
- await this.cancelResponseReader(reader);
33285
- throw this.responseTooLargeError(response, responseContext);
33351
+ if (total > this.responseLimit) {
33352
+ await this.stopReader(reader);
33353
+ throw this.sizeError(response, responseContext);
33286
33354
  }
33287
33355
  chunks.push(value);
33288
33356
  }
33289
- return this.decodeChunks(chunks, total);
33290
- }
33291
- decodeChunks(chunks, total) {
33292
33357
  const bytes = new Uint8Array(total);
33293
33358
  let offset = 0;
33294
33359
  for (const chunk of chunks) {
@@ -33297,35 +33362,35 @@ var WABTransport = class {
33297
33362
  }
33298
33363
  return new TextDecoder().decode(bytes);
33299
33364
  }
33300
- responseTooLargeError(response, responseContext) {
33301
- return new WABClientError("WAB_RESPONSE_TOO_LARGE", "WAB response exceeded the configured size limit.", false, response.status, responseContext);
33365
+ sizeError(response, responseContext) {
33366
+ return new WABClientError("WAB_RESPONSE_TOO_LARGE", "WAB response exceeds its size limit.", false, response.status, responseContext);
33302
33367
  }
33303
- async cancelResponseBody(response) {
33368
+ async stopBody(response) {
33304
33369
  try {
33305
33370
  await response.body?.cancel();
33306
33371
  } catch {}
33307
33372
  }
33308
- async cancelResponseReader(reader) {
33373
+ async stopReader(reader) {
33309
33374
  try {
33310
33375
  await reader.cancel();
33311
33376
  } catch {}
33312
33377
  }
33313
- captureFailure(operation, method, path, correlationId, startedAt, error) {
33378
+ report(metadata, error) {
33314
33379
  this.telemetry.capture({
33315
- name: "wallet-toolbox.wab.request.failed",
33316
- component: "wallet-toolbox.wab-transport",
33380
+ name: `${WAB_REQUEST_EVENT}failed`,
33381
+ component: WAB_COMPONENT,
33317
33382
  severity: error.retryable ? "warn" : "error",
33318
- correlationId,
33383
+ correlationId: metadata.correlationId,
33319
33384
  attributes: {
33320
- operation,
33321
- method,
33322
- route: path,
33385
+ operation: metadata.operation,
33386
+ method: metadata.method,
33387
+ route: metadata.path,
33323
33388
  serverOrigin: this.serverOrigin,
33324
33389
  retryable: error.retryable,
33325
33390
  ...error.status !== void 0 ? { status: error.status } : {},
33326
33391
  ...error.endpointMarkerPresent !== void 0 ? { endpointMarkerPresent: error.endpointMarkerPresent } : {},
33327
33392
  ...error.responseCorrelationMatched !== void 0 ? { responseCorrelationMatched: error.responseCorrelationMatched } : {},
33328
- durationMs: Date.now() - startedAt
33393
+ durationMs: Date.now() - metadata.startedAt
33329
33394
  },
33330
33395
  error
33331
33396
  });
@@ -33434,8 +33499,8 @@ var WABClient = class {
33434
33499
  constructor(serverUrl, options = {}) {
33435
33500
  this.transport = new WABTransport(serverUrl, options);
33436
33501
  }
33437
- async getInfo() {
33438
- return await this.transport.request("/info", {
33502
+ getInfo() {
33503
+ return this.transport.request("/info", {
33439
33504
  method: "GET",
33440
33505
  operation: "get-info"
33441
33506
  });
@@ -33445,15 +33510,15 @@ var WABClient = class {
33445
33510
  }
33446
33511
  async startAuthMethod(authMethod, presentationKey, payload, correlationId) {
33447
33512
  assertHexIdentifier(presentationKey, "presentationKey");
33448
- return await authMethod.startAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33513
+ return authMethod.startAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33449
33514
  }
33450
33515
  async completeAuthMethod(authMethod, presentationKey, payload, correlationId) {
33451
33516
  assertHexIdentifier(presentationKey, "presentationKey");
33452
- return await authMethod.completeAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33517
+ return authMethod.completeAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33453
33518
  }
33454
33519
  async listLinkedMethods(presentationKey) {
33455
33520
  assertHexIdentifier(presentationKey, "presentationKey");
33456
- return await this.transport.request("/user/linkedMethods", {
33521
+ return this.transport.request("/user/linkedMethods", {
33457
33522
  operation: "list-linked-methods",
33458
33523
  body: { presentationKey }
33459
33524
  });
@@ -33461,7 +33526,7 @@ var WABClient = class {
33461
33526
  async unlinkMethod(presentationKey, authMethodId) {
33462
33527
  assertHexIdentifier(presentationKey, "presentationKey");
33463
33528
  if (!Number.isSafeInteger(authMethodId) || authMethodId <= 0) throw new TypeError("authMethodId must be a positive safe integer.");
33464
- return await this.transport.request("/user/unlinkMethod", {
33529
+ return this.transport.request("/user/unlinkMethod", {
33465
33530
  operation: "unlink-method",
33466
33531
  body: {
33467
33532
  presentationKey,
@@ -33471,14 +33536,14 @@ var WABClient = class {
33471
33536
  }
33472
33537
  async requestFaucet(presentationKey) {
33473
33538
  assertHexIdentifier(presentationKey, "presentationKey");
33474
- return await this.transport.request("/faucet/request", {
33539
+ return this.transport.request("/faucet/request", {
33475
33540
  operation: "request-faucet",
33476
33541
  body: { presentationKey }
33477
33542
  });
33478
33543
  }
33479
33544
  async deleteUser(presentationKey) {
33480
33545
  assertHexIdentifier(presentationKey, "presentationKey");
33481
- return await this.transport.request("/user/delete", {
33546
+ return this.transport.request("/user/delete", {
33482
33547
  operation: "delete-user",
33483
33548
  body: { presentationKey }
33484
33549
  });
@@ -33487,7 +33552,7 @@ var WABClient = class {
33487
33552
  assertMethodType(methodType);
33488
33553
  assertHexIdentifier(userIdHash, "userIdHash");
33489
33554
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33490
- return await this.transport.request("/auth/start", {
33555
+ return this.transport.request("/auth/start", {
33491
33556
  operation: "start-share-auth",
33492
33557
  body: {
33493
33558
  methodType,
@@ -33500,7 +33565,7 @@ var WABClient = class {
33500
33565
  assertMethodType(methodType);
33501
33566
  assertHexIdentifier(userIdHash, "userIdHash");
33502
33567
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33503
- return await this.transport.request("/share/store", {
33568
+ return this.transport.request("/share/store", {
33504
33569
  operation: "store-share",
33505
33570
  body: {
33506
33571
  methodType,
@@ -33514,7 +33579,7 @@ var WABClient = class {
33514
33579
  assertMethodType(methodType);
33515
33580
  assertHexIdentifier(userIdHash, "userIdHash");
33516
33581
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33517
- return await this.transport.request("/share/retrieve", {
33582
+ return this.transport.request("/share/retrieve", {
33518
33583
  operation: "retrieve-share",
33519
33584
  body: {
33520
33585
  methodType,
@@ -33527,7 +33592,7 @@ var WABClient = class {
33527
33592
  assertMethodType(methodType);
33528
33593
  assertHexIdentifier(userIdHash, "userIdHash");
33529
33594
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33530
- return await this.transport.request("/share/update", {
33595
+ return this.transport.request("/share/update", {
33531
33596
  operation: "update-share",
33532
33597
  body: {
33533
33598
  methodType,
@@ -33541,7 +33606,7 @@ var WABClient = class {
33541
33606
  assertMethodType(methodType);
33542
33607
  assertHexIdentifier(userIdHash, "userIdHash");
33543
33608
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33544
- return await this.transport.request("/share/delete", {
33609
+ return this.transport.request("/share/delete", {
33545
33610
  operation: "delete-share-user",
33546
33611
  body: {
33547
33612
  methodType,
@@ -33555,9 +33620,13 @@ var WABClient = class {
33555
33620
  //#region ../src/WalletAuthenticationManager.ts
33556
33621
  const DEFAULT_AUTH_SESSION_TTL_MS = 600 * 1e3;
33557
33622
  const MAX_AUTH_SESSION_TTL_MS = 3600 * 1e3;
33623
+ const AUTH_COMPONENT = "wallet-toolbox.authentication-manager";
33624
+ const AUTH_EVENT = "wallet-toolbox.authentication.";
33625
+ const EXISTING_USER = "existing-user";
33626
+ const NEW_USER = "new-user";
33558
33627
  var WABAccountContinuityError = class extends Error {
33559
33628
  code = "WERR_WAB_ACCOUNT_CONTINUITY";
33560
- constructor(message = "WAB and UMP account state did not agree. Retry or use account recovery.") {
33629
+ constructor(message = "WAB and UMP accounts disagree; retry or recover.") {
33561
33630
  super(message);
33562
33631
  this.name = "WABAccountContinuityError";
33563
33632
  }
@@ -33572,6 +33641,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33572
33641
  wabClient;
33573
33642
  authMethod;
33574
33643
  authSession;
33644
+ phoneChangeSession;
33575
33645
  authSessionTtlMs;
33576
33646
  constructor(...[adminOriginator, walletBuilder, interactor, recoveryKeySaver, passwordRetriever, wabClient, authMethod, stateSnapshot, options = {}]) {
33577
33647
  super(adminOriginator, walletBuilder, interactor, recoveryKeySaver, passwordRetriever, async (presentationKey, wallet, adminOriginator) => {
@@ -33594,7 +33664,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33594
33664
  description: "Fund wallet",
33595
33665
  options: { acceptDelayedBroadcast: false }
33596
33666
  }, adminOriginator);
33597
- if (faucetRedeemTXCreationResult.signableTransaction == null) throw new Error("Faucet redemption did not return a signableTransaction");
33667
+ if (faucetRedeemTXCreationResult.signableTransaction == null) throw new Error("Faucet redemption was not signable.");
33598
33668
  const faucetRedeemTX = _bsv_sdk.Transaction.fromAtomicBEEF(faucetRedeemTXCreationResult.signableTransaction.tx);
33599
33669
  const faucetRedemptionPuzzle = new _bsv_sdk.RPuzzle();
33600
33670
  const randomRedemptionPrivateKey = _bsv_sdk.PrivateKey.fromRandom();
@@ -33627,7 +33697,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33627
33697
  * using the chosen AuthMethodInteractor.
33628
33698
  */
33629
33699
  async startAuth(payload) {
33630
- if (this.authMethod == null) throw new Error("No AuthMethod selected in WalletAuthenticationManager");
33700
+ if (this.authMethod == null) throw new Error("No WAB authentication method selected.");
33631
33701
  const authMethod = this.authMethod;
33632
33702
  if (this.authenticated) throw new Error("User is already authenticated");
33633
33703
  this.cancelAuth();
@@ -33640,8 +33710,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33640
33710
  ...correlationId !== void 0 ? { correlationId } : {}
33641
33711
  };
33642
33712
  this.telemetry.capture({
33643
- name: "wallet-toolbox.authentication.wab-start.started",
33644
- component: "wallet-toolbox.authentication-manager",
33713
+ name: `${AUTH_EVENT}wab-start.started`,
33714
+ component: AUTH_COMPONENT,
33645
33715
  severity: "debug",
33646
33716
  correlationId,
33647
33717
  attributes: { methodType: authMethod.methodType }
@@ -33653,8 +33723,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33653
33723
  throw new Error(message);
33654
33724
  }
33655
33725
  this.telemetry.capture({
33656
- name: "wallet-toolbox.authentication.wab-start.completed",
33657
- component: "wallet-toolbox.authentication-manager",
33726
+ name: `${AUTH_EVENT}wab-start.completed`,
33727
+ component: AUTH_COMPONENT,
33658
33728
  severity: "info",
33659
33729
  correlationId,
33660
33730
  attributes: { methodType: authMethod.methodType }
@@ -33662,8 +33732,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33662
33732
  } catch (error) {
33663
33733
  this.cancelAuth();
33664
33734
  this.telemetry.capture({
33665
- name: "wallet-toolbox.authentication.wab-start.failed",
33666
- component: "wallet-toolbox.authentication-manager",
33735
+ name: `${AUTH_EVENT}wab-start.failed`,
33736
+ component: AUTH_COMPONENT,
33667
33737
  severity: "warn",
33668
33738
  correlationId,
33669
33739
  attributes: { methodType: authMethod.methodType },
@@ -33676,22 +33746,22 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33676
33746
  * Completes the WAB-based flow, retrieving the final presentationKey from WAB if successful.
33677
33747
  */
33678
33748
  async completeAuth(payload) {
33679
- if (this.authMethod == null || this.authSession == null) throw new Error("No AuthMethod selected in WalletAuthenticationManager or startAuth has yet to be called.");
33749
+ if (this.authMethod == null || this.authSession == null) throw new Error("Start WAB authentication first.");
33680
33750
  const authMethod = this.authMethod;
33681
33751
  if (this.authSession.methodType !== authMethod.methodType) {
33682
33752
  this.cancelAuth();
33683
- throw new Error("The selected authentication method changed. Start authentication again.");
33753
+ throw new Error("WAB authentication method changed; restart.");
33684
33754
  }
33685
33755
  if (Date.now() >= this.authSession.expiresAt) {
33686
33756
  this.cancelAuth();
33687
- throw new Error("The WAB authentication session expired. Start authentication again.");
33757
+ throw new Error("WAB authentication expired; restart.");
33688
33758
  }
33689
33759
  const session = this.authSession;
33690
33760
  const result = await this.wabClient.completeAuthMethod(authMethod, session.presentationKey, payload, session.correlationId);
33691
33761
  if (result.success !== true || result.presentationKey == null || result.presentationKey.length === 0) {
33692
33762
  this.telemetry.capture({
33693
- name: "wallet-toolbox.authentication.wab-complete.rejected",
33694
- component: "wallet-toolbox.authentication-manager",
33763
+ name: `${AUTH_EVENT}wab-complete.rejected`,
33764
+ component: AUTH_COMPONENT,
33695
33765
  severity: "warn",
33696
33766
  correlationId: session.correlationId,
33697
33767
  attributes: { methodType: session.methodType }
@@ -33706,11 +33776,11 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33706
33776
  this.cancelAuth();
33707
33777
  const wabAccountStatus = this.inferAccountStatus(result, session.presentationKey);
33708
33778
  try {
33709
- await this.providePresentationKey(_bsv_sdk.Utils.toArray(result.presentationKey, "hex"));
33779
+ await this.provideWABPresentationKey(result, wabAccountStatus);
33710
33780
  } catch (error) {
33711
33781
  this.telemetry.capture({
33712
- name: "wallet-toolbox.authentication.ump-continuity.failed",
33713
- component: "wallet-toolbox.authentication-manager",
33782
+ name: `${AUTH_EVENT}ump-continuity.failed`,
33783
+ component: AUTH_COMPONENT,
33714
33784
  severity: "warn",
33715
33785
  correlationId: session.correlationId,
33716
33786
  attributes: {
@@ -33721,18 +33791,18 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33721
33791
  });
33722
33792
  throw error;
33723
33793
  }
33724
- if (wabAccountStatus === "existing-user" && this.authenticationFlow !== "existing-user") {
33794
+ if (wabAccountStatus === EXISTING_USER && this.authenticationFlow !== EXISTING_USER) {
33725
33795
  super.destroy();
33726
33796
  const error = new WABAccountContinuityError();
33727
33797
  this.telemetry.capture({
33728
- name: "wallet-toolbox.authentication.account-continuity.mismatch",
33729
- component: "wallet-toolbox.authentication-manager",
33798
+ name: `${AUTH_EVENT}account-continuity.mismatch`,
33799
+ component: AUTH_COMPONENT,
33730
33800
  severity: "error",
33731
33801
  correlationId: session.correlationId,
33732
33802
  attributes: {
33733
33803
  methodType: session.methodType,
33734
33804
  wabAccountStatus,
33735
- umpAccountStatus: "new-user"
33805
+ umpAccountStatus: NEW_USER
33736
33806
  },
33737
33807
  error
33738
33808
  });
@@ -33740,8 +33810,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33740
33810
  }
33741
33811
  const continuity = wabAccountStatus === this.authenticationFlow ? "matched" : "ump-existing";
33742
33812
  this.telemetry.capture({
33743
- name: "wallet-toolbox.authentication.completed",
33744
- component: "wallet-toolbox.authentication-manager",
33813
+ name: `${AUTH_EVENT}completed`,
33814
+ component: AUTH_COMPONENT,
33745
33815
  severity: continuity === "matched" ? "info" : "warn",
33746
33816
  correlationId: session.correlationId,
33747
33817
  attributes: {
@@ -33755,23 +33825,131 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33755
33825
  cancelAuth() {
33756
33826
  this.authSession = void 0;
33757
33827
  }
33828
+ readPendingPhoneChange(result) {
33829
+ const presentationKey = result.pendingPresentationKey;
33830
+ const changeId = result.pendingPhoneChangeId;
33831
+ if (presentationKey === void 0 && changeId === void 0) return void 0;
33832
+ if (!/^[0-9a-fA-F]{64}$/.test(presentationKey ?? "") || !Number.isSafeInteger(changeId) || changeId <= 0) throw new WABAccountContinuityError("WAB returned invalid pending phone-change data.");
33833
+ return {
33834
+ presentationKey,
33835
+ changeId
33836
+ };
33837
+ }
33838
+ async provideWABPresentationKey(result, wabAccountStatus) {
33839
+ const umpTokenOutpoint = typeof result.umpTokenOutpoint === "string" ? result.umpTokenOutpoint : void 0;
33840
+ const lookupOptions = umpTokenOutpoint == null ? void 0 : { pinnedOutpoint: umpTokenOutpoint };
33841
+ const pending = this.readPendingPhoneChange(result);
33842
+ let usePending = false;
33843
+ try {
33844
+ await this.providePresentationKey(_bsv_sdk.Utils.toArray(result.presentationKey, "hex"), lookupOptions);
33845
+ } catch (error) {
33846
+ if (pending == null) throw error;
33847
+ usePending = true;
33848
+ }
33849
+ if (pending != null && (usePending || wabAccountStatus === EXISTING_USER && this.authenticationFlow !== EXISTING_USER)) {
33850
+ await this.providePresentationKey(_bsv_sdk.Utils.toArray(pending.presentationKey, "hex"), lookupOptions);
33851
+ if (this.authenticationFlow === EXISTING_USER) await this.finalizePendingPhoneChange(result.presentationKey, pending);
33852
+ }
33853
+ }
33854
+ async finalizePendingPhoneChange(currentPresentationKey, pending) {
33855
+ const finalized = await this.phoneChange("finalize", {
33856
+ changeId: pending.changeId,
33857
+ presentationKey: currentPresentationKey,
33858
+ newPresentationKey: pending.presentationKey
33859
+ });
33860
+ if (finalized.success !== true || finalized.changeId !== pending.changeId) throw new WABAccountContinuityError(finalized.message || "WAB could not finalize the pending phone change.");
33861
+ }
33862
+ /**
33863
+ * Starts OTP verification for a replacement phone number. The same number
33864
+ * is valid and intentionally produces a fresh presentation key/hash.
33865
+ */
33866
+ async startPhoneNumberChange(phoneNumber) {
33867
+ if (!this.authenticated) throw new Error("Not authenticated");
33868
+ const normalizedPhone = phoneNumber.trim();
33869
+ const currentPresentationKey = _bsv_sdk.Utils.toHex(await this.getFactor("presentationKey"));
33870
+ const response = await this.phoneChange("start", {
33871
+ presentationKey: currentPresentationKey,
33872
+ phoneNumber: normalizedPhone
33873
+ });
33874
+ if (response.success !== true) throw new Error(response.message || "Phone change failed");
33875
+ this.phoneChangeSession = {
33876
+ phoneNumber: normalizedPhone,
33877
+ presentationKey: currentPresentationKey
33878
+ };
33879
+ }
33880
+ /**
33881
+ * Completes phone verification and stages the WAB association before
33882
+ * publishing the UMP key rotation. WAB retains both the current and pending
33883
+ * presentation keys until finalization, so either side of an interrupted
33884
+ * transition remains recoverable on the next verified login.
33885
+ */
33886
+ async completePhoneNumberChange(otp) {
33887
+ const session = this.phoneChangeSession;
33888
+ if (session == null) throw new Error("No phone change");
33889
+ if (session.changeToken == null) {
33890
+ const authorization = await this.phoneChange("complete", {
33891
+ presentationKey: session.presentationKey,
33892
+ phoneNumber: session.phoneNumber,
33893
+ otp: otp.trim()
33894
+ });
33895
+ if (authorization.success !== true) throw new Error(authorization.message || "Phone change failed");
33896
+ if (/^[0-9a-fA-F]{64}$/.test(authorization.pendingPresentationKey ?? "") && Number.isSafeInteger(authorization.pendingPhoneChangeId) && authorization.pendingPhoneChangeId > 0) {
33897
+ session.newKey = _bsv_sdk.Utils.toArray(authorization.pendingPresentationKey, "hex");
33898
+ session.changeId = authorization.pendingPhoneChangeId;
33899
+ } else if (typeof authorization.changeToken === "string" && authorization.changeToken.length > 0) session.changeToken = authorization.changeToken;
33900
+ else throw new Error(authorization.message || "Phone change failed");
33901
+ }
33902
+ session.newKey ??= (0, _bsv_sdk.Random)(32);
33903
+ if (session.changeId == null) {
33904
+ const committed = await this.phoneChange("commit", {
33905
+ changeToken: session.changeToken,
33906
+ presentationKey: session.presentationKey,
33907
+ newPresentationKey: _bsv_sdk.Utils.toHex(session.newKey)
33908
+ });
33909
+ if (committed.success !== true || !Number.isSafeInteger(committed.changeId) || committed.changeId <= 0) throw new Error(committed.message || "Phone change failed");
33910
+ session.changeId = committed.changeId;
33911
+ }
33912
+ const changeId = session.changeId;
33913
+ if (session.umpUpdated !== true) {
33914
+ await this.changePresentationKey(session.newKey);
33915
+ session.umpUpdated = true;
33916
+ }
33917
+ const finalized = await this.phoneChange("finalize", {
33918
+ changeId,
33919
+ presentationKey: session.presentationKey,
33920
+ newPresentationKey: _bsv_sdk.Utils.toHex(session.newKey)
33921
+ });
33922
+ if (finalized.success !== true || finalized.changeId !== changeId) throw new Error(finalized.message || "Phone change failed");
33923
+ this.phoneChangeSession = void 0;
33924
+ return { changeId };
33925
+ }
33926
+ cancelPhoneNumberChange() {
33927
+ this.phoneChangeSession = void 0;
33928
+ }
33758
33929
  destroy() {
33759
33930
  this.cancelAuth();
33931
+ this.cancelPhoneNumberChange();
33760
33932
  super.destroy();
33761
33933
  }
33934
+ phoneChange(phase, body) {
33935
+ return this.wabClient.transport.request(`/auth/phone-change/${phase}`, {
33936
+ operation: "phone-change",
33937
+ body
33938
+ });
33939
+ }
33762
33940
  inferAccountStatus(result, temporaryPresentationKey) {
33763
33941
  if (result.presentationKey == null) throw new WABAccountContinuityError("WAB did not return a presentation key.");
33764
33942
  const keyMatchesTemporary = this.constantTimeHexEqual(result.presentationKey, temporaryPresentationKey);
33765
33943
  const rawAccountStatus = result.accountStatus;
33766
- if (rawAccountStatus !== void 0 && rawAccountStatus !== "new-user" && rawAccountStatus !== "existing-user") throw new WABAccountContinuityError("WAB returned an invalid account-continuity status.");
33944
+ if (rawAccountStatus !== void 0 && rawAccountStatus !== NEW_USER && rawAccountStatus !== EXISTING_USER) throw new WABAccountContinuityError("WAB returned an invalid account status.");
33767
33945
  const rawExistingUser = result.existingUser;
33768
- if (rawExistingUser !== void 0 && typeof rawExistingUser !== "boolean") throw new WABAccountContinuityError("WAB returned an invalid existing-user status.");
33769
- if (rawAccountStatus !== void 0 && rawExistingUser !== void 0 && rawAccountStatus === "existing-user" !== rawExistingUser) throw new WABAccountContinuityError("WAB returned contradictory account-continuity statuses.");
33946
+ if (rawExistingUser !== void 0 && typeof rawExistingUser !== "boolean") throw new WABAccountContinuityError("WAB returned invalid existing-user data.");
33947
+ if (rawAccountStatus !== void 0 && rawExistingUser !== void 0 && rawAccountStatus === EXISTING_USER !== rawExistingUser) throw new WABAccountContinuityError("WAB returned conflicting account status.");
33770
33948
  let compatibilityStatus;
33771
- if (typeof rawExistingUser === "boolean") compatibilityStatus = rawExistingUser ? "existing-user" : "new-user";
33949
+ if (typeof rawExistingUser === "boolean") compatibilityStatus = rawExistingUser ? EXISTING_USER : NEW_USER;
33772
33950
  const explicitStatus = rawAccountStatus ?? compatibilityStatus;
33773
- if (explicitStatus === "new-user" && !keyMatchesTemporary || explicitStatus === "existing-user" && keyMatchesTemporary) throw new WABAccountContinuityError("WAB returned contradictory account-continuity data.");
33774
- return explicitStatus ?? (keyMatchesTemporary ? "new-user" : "existing-user");
33951
+ if (explicitStatus === NEW_USER && !keyMatchesTemporary || explicitStatus === EXISTING_USER && keyMatchesTemporary) throw new WABAccountContinuityError("WAB returned conflicting account status.");
33952
+ return explicitStatus ?? (keyMatchesTemporary ? NEW_USER : EXISTING_USER);
33775
33953
  }
33776
33954
  constantTimeHexEqual(left, right) {
33777
33955
  if (left.length !== right.length) return false;