@bsv/wallet-toolbox-client 2.9.0 → 2.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,
@@ -7845,6 +7845,23 @@ function mergePriorOptions(caVargs, saArgs) {
7845
7845
  return _bsv_sdk.Validation.validateSignActionArgs(saArgs);
7846
7846
  }
7847
7847
  //#endregion
7848
+ //#region ../src/utility/canonicalizeAtomicBeef.ts
7849
+ /**
7850
+ * Restricts an AtomicBEEF envelope to the transaction named by its BRC-95
7851
+ * prefix and that transaction's recursive dependency closure.
7852
+ *
7853
+ * Older senders could serialize unrelated, otherwise valid BEEF branches into
7854
+ * an AtomicBEEF envelope. Those branches are not part of the payment proof and
7855
+ * must not influence internalization. Proof and transaction validation still
7856
+ * run against the returned closure at each wallet trust boundary.
7857
+ */
7858
+ function canonicalizeAtomicBeef(bytes) {
7859
+ const received = bytes instanceof Uint8Array ? _bsv_sdk.Beef.fromBinaryView(bytes) : _bsv_sdk.Beef.fromBinary(bytes);
7860
+ const txid = received.atomicTxid;
7861
+ if (txid == null || received.findTxid(txid) == null || received.isAtomic(txid)) return received;
7862
+ return _bsv_sdk.Beef.fromBinary(received.toBinaryAtomic(txid));
7863
+ }
7864
+ //#endregion
7848
7865
  //#region ../src/signer/methods/internalizeAction.ts
7849
7866
  /**
7850
7867
  * Internalize Action allows a wallet to take ownership of outputs in a pre-existing transaction.
@@ -7886,7 +7903,7 @@ function mergePriorOptions(caVargs, saArgs) {
7886
7903
  */
7887
7904
  async function internalizeAction$1(wallet, auth, args) {
7888
7905
  const vargs = _bsv_sdk.Validation.validateInternalizeActionArgs(args);
7889
- const { tx } = await validateAtomicBeef();
7906
+ const { ab, tx, txid } = await validateAtomicBeef();
7890
7907
  const brc29ProtocolID = [2, "3241645161d8"];
7891
7908
  for (const o of vargs.outputs) {
7892
7909
  if (o.outputIndex < 0 || o.outputIndex >= tx.outputs.length) throw new WERR_INVALID_PARAMETER("outputIndex", `a valid output index in range 0 to ${tx.outputs.length - 1}`);
@@ -7900,7 +7917,10 @@ async function internalizeAction$1(wallet, auth, args) {
7900
7917
  default: throw new WERR_INTERNAL(`unexpected protocol ${o.protocol}`);
7901
7918
  }
7902
7919
  }
7903
- return await wallet.storage.internalizeAction(args);
7920
+ return await wallet.storage.internalizeAction({
7921
+ ...args,
7922
+ tx: ab.toBinaryAtomic(txid)
7923
+ });
7904
7924
  function setupWalletPaymentForOutput(o, _dargs) {
7905
7925
  const p = o.paymentRemittance;
7906
7926
  const output = tx.outputs[o.outputIndex];
@@ -7923,7 +7943,7 @@ async function internalizeAction$1(wallet, auth, args) {
7923
7943
  * 2. That the proofs are for the same block as recorded in the wallet's configured storage in the event of a reorg.
7924
7944
  */
7925
7945
  async function validateAtomicBeef() {
7926
- const ab = _bsv_sdk.Beef.fromBinary(vargs.tx);
7946
+ const ab = canonicalizeAtomicBeef(vargs.tx);
7927
7947
  if (!await ab.verify(await wallet.getServices().getChainTracker(), false) || !ab.atomicTxid) {
7928
7948
  console.log(`internalizeAction beef is invalid: ${ab.toLogString()}`);
7929
7949
  throw new WERR_INVALID_PARAMETER("tx", "valid AtomicBEEF");
@@ -8254,28 +8274,70 @@ function verifyActionBatchManifestDigest(manifest) {
8254
8274
  //#endregion
8255
8275
  //#region ../src/utility/beefForTxids.ts
8256
8276
  /**
8257
- * Return the minimal subgraph needed to prove the requested transactions.
8277
+ * Return a minimal BEEF when the source contains data outside the requested
8278
+ * transaction dependency closure. Return undefined when no pruning is needed.
8279
+ *
8280
+ * This form lets forwarding clients retain the caller's original bytes in the
8281
+ * common no-op case instead of rebuilding and reserializing an equivalent BEEF.
8282
+ */
8283
+ function pruneBeefForTxids(source, txids) {
8284
+ const selection = selectTransactions(source, txids);
8285
+ if (selection.transactions.size === source.txs.length && selection.bumpIndexes.size === source.bumps.length) return;
8286
+ return copySelection(source, selection);
8287
+ }
8288
+ /**
8289
+ * Return an independent minimal BEEF needed to prove the requested transactions.
8258
8290
  *
8259
- * Parents are added before children so the resulting BEEF preserves dependency
8260
- * order. Shared ancestors and bumps are merged only once.
8291
+ * Transactions remain in source order and are sorted by Beef when serialized.
8292
+ * The source is indexed and walked once, using an explicit stack so a hostile
8293
+ * dependency depth cannot exhaust the JavaScript call stack.
8261
8294
  */
8262
8295
  function beefForTxids(source, txids) {
8263
- const beef = new _bsv_sdk.Beef();
8296
+ return copySelection(source, selectTransactions(source, txids));
8297
+ }
8298
+ function selectTransactions(source, txids) {
8299
+ const byTxid = /* @__PURE__ */ new Map();
8300
+ for (const tx of source.txs) byTxid.set(tx.txid, tx);
8301
+ const transactions = /* @__PURE__ */ new Set();
8302
+ const bumpIndexes = /* @__PURE__ */ new Set();
8264
8303
  const visited = /* @__PURE__ */ new Set();
8265
- const visit = (txid) => {
8266
- if (visited.has(txid)) return;
8304
+ const stack = [...txids];
8305
+ while (stack.length > 0) {
8306
+ const txid = stack.pop();
8307
+ if (txid == null || visited.has(txid)) continue;
8267
8308
  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);
8309
+ const tx = byTxid.get(txid);
8310
+ if (tx == null) continue;
8311
+ transactions.add(tx);
8312
+ const bumpIndex = tx.bumpIndex;
8313
+ if (bumpIndex != null && Number.isSafeInteger(bumpIndex) && bumpIndex >= 0 && bumpIndex < source.bumps.length) bumpIndexes.add(bumpIndex);
8314
+ for (const inputTxid of tx.inputTxids) if (!visited.has(inputTxid)) stack.push(inputTxid);
8315
+ }
8316
+ return {
8317
+ transactions,
8318
+ bumpIndexes
8275
8319
  };
8276
- for (const txid of txids) visit(txid);
8320
+ }
8321
+ function copySelection(source, selection) {
8322
+ const beef = new _bsv_sdk.Beef(source.version);
8323
+ const bumpIndexMap = /* @__PURE__ */ new Map();
8324
+ for (let index = 0; index < source.bumps.length; index++) {
8325
+ if (!selection.bumpIndexes.has(index)) continue;
8326
+ bumpIndexMap.set(index, beef.bumps.length);
8327
+ beef.bumps.push(cloneMerklePath(source.bumps[index]));
8328
+ }
8329
+ for (const sourceTx of source.txs) {
8330
+ if (!selection.transactions.has(sourceTx)) continue;
8331
+ const bumpIndex = sourceTx.bumpIndex == null ? void 0 : bumpIndexMap.get(sourceTx.bumpIndex);
8332
+ const rawTx = sourceTx.rawTxUint8Array;
8333
+ const copy = rawTx == null ? _bsv_sdk.BeefTx.fromTxid(sourceTx.txid, bumpIndex) : new _bsv_sdk.BeefTx(Uint8Array.from(rawTx), bumpIndex, Array.from(sourceTx.inputTxids));
8334
+ beef.txs.push(copy);
8335
+ }
8277
8336
  return beef;
8278
8337
  }
8338
+ function cloneMerklePath(source) {
8339
+ return new _bsv_sdk.MerklePath(source.blockHeight, source.path.map((level) => level.map((leaf) => ({ ...leaf }))), false, false);
8340
+ }
8279
8341
  //#endregion
8280
8342
  //#region ../src/storage/methods/offsetKey.ts
8281
8343
  function keyOffsetToHashedSecret(pub, keyOffset) {
@@ -10973,7 +11035,7 @@ function validateRequiredOutputs(storage, userId, vargs) {
10973
11035
  * @returns {xinputs} extended validated required inputs.
10974
11036
  */
10975
11037
  async function validateRequiredInputs(storage, userId, vargs) {
10976
- const beef = new _bsv_sdk.Beef();
11038
+ let beef = new _bsv_sdk.Beef();
10977
11039
  if (vargs.inputs.length === 0) return {
10978
11040
  storageBeef: beef,
10979
11041
  beef,
@@ -10999,6 +11061,7 @@ async function validateRequiredInputs(storage, userId, vargs) {
10999
11061
  inputsByTxid[input.outpoint.txid] ||= [];
11000
11062
  inputsByTxid[input.outpoint.txid].push(input);
11001
11063
  }
11064
+ beef = beefForTxids(beef, Object.keys(inputsByTxid));
11002
11065
  const localKnownInputTxids = {};
11003
11066
  for (const [txid, txInputs] of Object.entries(inputsByTxid)) localKnownInputTxids[txid] = txInputs.every((input) => {
11004
11067
  const output = preloadedOutputsByOutpoint[`${input.outpoint.txid}.${input.outpoint.vout}`];
@@ -12413,7 +12476,7 @@ var InternalizeActionContext = class {
12413
12476
  * @returns
12414
12477
  */
12415
12478
  async validateAtomicBeef(atomicBeef) {
12416
- const ab = atomicBeef instanceof Uint8Array ? _bsv_sdk.Beef.fromBinaryView(atomicBeef) : _bsv_sdk.Beef.fromBinary(atomicBeef);
12479
+ const ab = canonicalizeAtomicBeef(atomicBeef);
12417
12480
  if (!await ab.verify(await this.storage.getServices().getChainTracker(), false) || !ab.atomicTxid) throw new WERR_INVALID_PARAMETER("tx", "valid AtomicBEEF");
12418
12481
  const txid = ab.atomicTxid;
12419
12482
  const btx = ab.findTxid(txid);
@@ -15260,11 +15323,19 @@ var StorageProvider = class StorageProvider extends StorageReaderWriter {
15260
15323
  return await this.updateOutput(output.outputId, { basketId: void 0 });
15261
15324
  }
15262
15325
  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);
15326
+ return await this.transaction(async (trx) => {
15327
+ const user = verifyTruthy(verifyOneOrNone(await this.findUsers({
15328
+ partial: { identityKey: args.identityKey },
15329
+ trx
15330
+ })));
15331
+ return await new EntitySyncState(verifyOne(await this.findSyncStates({
15332
+ partial: {
15333
+ storageIdentityKey: args.fromStorageIdentityKey,
15334
+ userId: user.userId
15335
+ },
15336
+ trx
15337
+ }))).processSyncChunk(this, args, chunk, trx);
15338
+ });
15268
15339
  }
15269
15340
  /**
15270
15341
  * Handles storage changes when a valid MerklePath and mined block header are found for a ProvenTxReq txid.
@@ -17329,8 +17400,10 @@ var StorageIdb = class extends StorageProvider {
17329
17400
  await tx.done;
17330
17401
  return r;
17331
17402
  } catch (err) {
17332
- tx.abort();
17333
- await tx.done;
17403
+ try {
17404
+ tx.abort();
17405
+ await tx.done;
17406
+ } catch {}
17334
17407
  throw err;
17335
17408
  }
17336
17409
  }
@@ -18297,6 +18370,25 @@ var StorageClientBase = class {
18297
18370
  * @returns `StorageCreateActionResults` supporting additional wallet processing to yield `createAction` results.
18298
18371
  */
18299
18372
  async createAction(auth, args) {
18373
+ if (args.inputBEEF != null) if (args.inputs.length === 0) args = {
18374
+ ...args,
18375
+ inputBEEF: void 0
18376
+ };
18377
+ else {
18378
+ let source;
18379
+ try {
18380
+ source = _bsv_sdk.Beef.fromBinary(args.inputBEEF);
18381
+ } catch {
18382
+ source = void 0;
18383
+ }
18384
+ if (source != null) {
18385
+ const pruned = pruneBeefForTxids(source, args.inputs.map((input) => input.outpoint.txid));
18386
+ if (pruned != null) args = {
18387
+ ...args,
18388
+ inputBEEF: pruned.toBinary()
18389
+ };
18390
+ }
18391
+ }
18300
18392
  return await this.rpcCall("createAction", [auth, args]);
18301
18393
  }
18302
18394
  /**
@@ -30967,6 +31059,7 @@ var SetupClient = class SetupClient {
30967
31059
  };
30968
31060
  //#endregion
30969
31061
  //#region ../src/CWIStyleWalletManager.ts
31062
+ const CWI_COMPONENT = "wallet-toolbox.cwi-manager";
30970
31063
  /**
30971
31064
  * Number of rounds used in PBKDF2 for deriving password keys.
30972
31065
  */
@@ -31199,11 +31292,11 @@ var OverlayUMPTokenInteractor = class {
31199
31292
  * @param hash The 32-byte SHA-256 hash of the presentation key.
31200
31293
  * @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
31201
31294
  */
31202
- async findByPresentationKeyHash(hash) {
31203
- return await this.findToken({
31295
+ async findByPresentationKeyHash(hash, options) {
31296
+ return this.findToken({
31204
31297
  service: "ls_users",
31205
31298
  query: { presentationHash: _bsv_sdk.Utils.toHex(hash) }
31206
- }, "presentation");
31299
+ }, "presentation", options);
31207
31300
  }
31208
31301
  /**
31209
31302
  * Finds a UMP token on-chain by the given recovery key hash, if it exists.
@@ -31212,13 +31305,13 @@ var OverlayUMPTokenInteractor = class {
31212
31305
  * @param hash The 32-byte SHA-256 hash of the recovery key.
31213
31306
  * @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
31214
31307
  */
31215
- async findByRecoveryKeyHash(hash) {
31216
- return await this.findToken({
31308
+ async findByRecoveryKeyHash(hash, options) {
31309
+ return this.findToken({
31217
31310
  service: "ls_users",
31218
31311
  query: { recoveryHash: _bsv_sdk.Utils.toHex(hash) }
31219
- }, "recovery");
31312
+ }, "recovery", options);
31220
31313
  }
31221
- async findToken(question, lookupKind) {
31314
+ async findToken(question, lookupKind, options) {
31222
31315
  const correlationId = this.telemetry.enabled === true ? this.telemetry.createCorrelationId() : void 0;
31223
31316
  const startedAt = Date.now();
31224
31317
  this.telemetry.capture({
@@ -31235,34 +31328,39 @@ var OverlayUMPTokenInteractor = class {
31235
31328
  correlationId
31236
31329
  });
31237
31330
  } catch (error) {
31238
- const diagnostics = this.emptyLookupDiagnostics(correlationId);
31239
- this.captureLookupFailure(lookupKind, "lookup-unavailable", diagnostics, startedAt, error);
31331
+ const diagnostics = this.emptyStats(correlationId);
31332
+ this.lookupFailed(lookupKind, "lookup-unavailable", diagnostics, startedAt, error);
31240
31333
  throw new UMPTokenLookupError("lookup-unavailable", diagnostics, { cause: error });
31241
31334
  }
31242
- const diagnostics = this.toLookupDiagnostics(resolution);
31335
+ const diagnostics = this.diagnosticsFor(resolution);
31243
31336
  const tokens = this.parseLookupAnswers(resolution.answer);
31244
31337
  const expectedHash = question.query[lookupKind === "presentation" ? "presentationHash" : "recoveryHash"].toLowerCase();
31245
31338
  const matchingTokens = tokens.filter((token) => _bsv_sdk.Utils.toHex(lookupKind === "presentation" ? token.presentationHash : token.recoveryHash).toLowerCase() === expectedHash);
31246
31339
  if (matchingTokens.length > 1) {
31247
31340
  const newest = this.resolveNewestToken(matchingTokens, resolution.answer.outputs);
31248
31341
  if (newest != null) {
31249
- this.captureLookupCompleted(lookupKind, "found", diagnostics, startedAt, { supersededTokens: matchingTokens.length - 1 });
31342
+ this.lookupDone(lookupKind, "found", diagnostics, startedAt, { supersededTokens: matchingTokens.length - 1 });
31250
31343
  return newest;
31251
31344
  }
31345
+ const pinned = options?.pinnedOutpoint ? matchingTokens.find((token) => token.currentOutpoint === options.pinnedOutpoint) : void 0;
31346
+ if (pinned != null) {
31347
+ this.lookupDone(lookupKind, "found", diagnostics, startedAt);
31348
+ return pinned;
31349
+ }
31252
31350
  const reason = "token-ambiguous";
31253
- this.captureLookupFailure(lookupKind, reason, diagnostics, startedAt);
31351
+ this.lookupFailed(lookupKind, reason, diagnostics, startedAt);
31254
31352
  throw new UMPTokenLookupError(reason, diagnostics);
31255
31353
  }
31256
31354
  if (matchingTokens.length === 1) {
31257
- this.captureLookupCompleted(lookupKind, "found", diagnostics, startedAt);
31355
+ this.lookupDone(lookupKind, "found", diagnostics, startedAt);
31258
31356
  return matchingTokens[0];
31259
31357
  }
31260
31358
  if (resolution.progress.emptyHosts > 0) {
31261
- this.captureLookupCompleted(lookupKind, "not-found", diagnostics, startedAt);
31359
+ this.lookupDone(lookupKind, "not-found", diagnostics, startedAt);
31262
31360
  return;
31263
31361
  }
31264
31362
  const reason = resolution.answer.outputs.length > 0 ? "token-malformed" : "lookup-incomplete";
31265
- this.captureLookupFailure(lookupKind, reason, diagnostics, startedAt);
31363
+ this.lookupFailed(lookupKind, reason, diagnostics, startedAt);
31266
31364
  throw new UMPTokenLookupError(reason, diagnostics);
31267
31365
  }
31268
31366
  /**
@@ -31293,7 +31391,7 @@ var OverlayUMPTokenInteractor = class {
31293
31391
  spent: /* @__PURE__ */ new Set()
31294
31392
  };
31295
31393
  evidence.txs.push(tx);
31296
- this.collectSpentOutpoints(tx, evidence.spent, /* @__PURE__ */ new Set());
31394
+ this.collectSpends(tx, evidence.spent, /* @__PURE__ */ new Set());
31297
31395
  evidenceByCandidate.set(outpoint, evidence);
31298
31396
  } catch {}
31299
31397
  if (evidenceByCandidate.size !== candidates.size) return void 0;
@@ -31302,7 +31400,7 @@ var OverlayUMPTokenInteractor = class {
31302
31400
  const provenContinuations = survivors.filter((outpoint) => {
31303
31401
  const evidence = evidenceByCandidate.get(outpoint);
31304
31402
  const token = candidates.get(outpoint);
31305
- return evidence != null && token != null && evidence.txs.some((tx) => this.consumesSameIdentityToken(tx, token));
31403
+ return evidence != null && token != null && evidence.txs.some((tx) => this.consumesIdentity(tx, token));
31306
31404
  });
31307
31405
  if (provenContinuations.length !== 1) return void 0;
31308
31406
  return candidates.get(provenContinuations[0]);
@@ -31313,7 +31411,7 @@ var OverlayUMPTokenInteractor = class {
31313
31411
  * hash — on-chain proof that the candidate is an update of a same-identity
31314
31412
  * predecessor rather than an independently minted token.
31315
31413
  */
31316
- consumesSameIdentityToken(tx, token) {
31414
+ consumesIdentity(tx, token) {
31317
31415
  const presentationHash = _bsv_sdk.Utils.toHex(token.presentationHash);
31318
31416
  const recoveryHash = _bsv_sdk.Utils.toHex(token.recoveryHash);
31319
31417
  for (const input of tx.inputs) {
@@ -31339,7 +31437,7 @@ var OverlayUMPTokenInteractor = class {
31339
31437
  * renditions are absent from the lookup answer. Iterative so arbitrarily
31340
31438
  * long update chains cannot exhaust the call stack.
31341
31439
  */
31342
- collectSpentOutpoints(tx, spent, visited) {
31440
+ collectSpends(tx, spent, visited) {
31343
31441
  const pending = [tx];
31344
31442
  while (pending.length > 0) {
31345
31443
  const current = pending.pop();
@@ -31354,7 +31452,7 @@ var OverlayUMPTokenInteractor = class {
31354
31452
  }
31355
31453
  }
31356
31454
  }
31357
- emptyLookupDiagnostics(correlationId) {
31455
+ emptyStats(correlationId) {
31358
31456
  return {
31359
31457
  hostCount: 0,
31360
31458
  completedHosts: 0,
@@ -31367,7 +31465,7 @@ var OverlayUMPTokenInteractor = class {
31367
31465
  ...correlationId !== void 0 ? { correlationId } : {}
31368
31466
  };
31369
31467
  }
31370
- toLookupDiagnostics(resolution) {
31468
+ diagnosticsFor(resolution) {
31371
31469
  const progress = resolution.progress;
31372
31470
  return {
31373
31471
  hostCount: progress.hostCount,
@@ -31381,7 +31479,7 @@ var OverlayUMPTokenInteractor = class {
31381
31479
  ...progress.correlationId !== void 0 ? { correlationId: progress.correlationId } : {}
31382
31480
  };
31383
31481
  }
31384
- lookupDiagnosticAttributes(diagnostics) {
31482
+ lookupAttrs(diagnostics) {
31385
31483
  return {
31386
31484
  hostCount: diagnostics.hostCount,
31387
31485
  completedHosts: diagnostics.completedHosts,
@@ -31393,7 +31491,7 @@ var OverlayUMPTokenInteractor = class {
31393
31491
  outputCount: diagnostics.outputCount
31394
31492
  };
31395
31493
  }
31396
- captureLookupCompleted(lookupKind, result, diagnostics, startedAt, extraAttributes = {}) {
31494
+ lookupDone(lookupKind, result, diagnostics, startedAt, extraAttributes = {}) {
31397
31495
  this.telemetry.capture({
31398
31496
  name: "wallet-toolbox.ump.lookup.completed",
31399
31497
  component: "wallet-toolbox.ump",
@@ -31403,12 +31501,12 @@ var OverlayUMPTokenInteractor = class {
31403
31501
  lookupKind,
31404
31502
  result,
31405
31503
  durationMs: Date.now() - startedAt,
31406
- ...this.lookupDiagnosticAttributes(diagnostics),
31504
+ ...this.lookupAttrs(diagnostics),
31407
31505
  ...extraAttributes
31408
31506
  }
31409
31507
  });
31410
31508
  }
31411
- captureLookupFailure(lookupKind, reason, diagnostics, startedAt, error) {
31509
+ lookupFailed(lookupKind, reason, diagnostics, startedAt, error) {
31412
31510
  this.telemetry.capture({
31413
31511
  name: "wallet-toolbox.ump.lookup.indeterminate",
31414
31512
  component: "wallet-toolbox.ump",
@@ -31418,7 +31516,7 @@ var OverlayUMPTokenInteractor = class {
31418
31516
  lookupKind,
31419
31517
  reason,
31420
31518
  durationMs: Date.now() - startedAt,
31421
- ...this.lookupDiagnosticAttributes(diagnostics)
31519
+ ...this.lookupAttrs(diagnostics)
31422
31520
  },
31423
31521
  error
31424
31522
  });
@@ -31436,27 +31534,27 @@ var OverlayUMPTokenInteractor = class {
31436
31534
  * @returns The outpoint of the newly created UMP token (e.g. "abcd1234...ef.0").
31437
31535
  */
31438
31536
  async buildAndSend(wallet, adminOriginator, token, oldTokenToConsume) {
31439
- const fields = this.buildUMPTokenFields(token);
31537
+ const fields = this.tokenFields(token);
31440
31538
  const tokenOutput = [{
31441
31539
  lockingScript: (await new _bsv_sdk.PushDrop(wallet, adminOriginator).lock(fields, [2, "admin user management token"], "1", "self", true, true)).toHex(),
31442
31540
  satoshis: 1,
31443
31541
  outputDescription: "New UMP token output"
31444
31542
  }];
31445
- const { resolvedOldToken, inputToken } = await this.resolveOldTokenInput(oldTokenToConsume);
31543
+ const { resolvedOldToken, inputToken } = await this.resolveOldInput(oldTokenToConsume);
31446
31544
  const inputs = resolvedOldToken?.currentOutpoint ? [{
31447
31545
  outpoint: resolvedOldToken.currentOutpoint,
31448
31546
  unlockingScriptLength: 73,
31449
31547
  inputDescription: "Consume old UMP token"
31450
31548
  }] : [];
31451
- const createResult = await this.createUMPAction(wallet, adminOriginator, inputs, tokenOutput, inputToken, resolvedOldToken);
31452
- if (!createResult.signableTransaction) return await this.broadcastFinishedUMPAction(createResult);
31549
+ const createResult = await this.createAction(wallet, adminOriginator, inputs, tokenOutput, inputToken, resolvedOldToken);
31550
+ if (!createResult.signableTransaction) return this.broadcastFinal(createResult);
31453
31551
  const reference = createResult.signableTransaction.reference;
31454
31552
  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);
31553
+ if (resolvedOldToken?.currentOutpoint) return this.renewToken(wallet, adminOriginator, reference, partialTx);
31554
+ return this.broadcastNew(wallet, adminOriginator, reference);
31457
31555
  }
31458
31556
  /** Assembles the ordered number[][] fields array from a UMPToken. */
31459
- buildUMPTokenFields(token) {
31557
+ tokenFields(token) {
31460
31558
  const fields = [];
31461
31559
  fields[0] = token.passwordSalt;
31462
31560
  fields[1] = token.passwordPresentationPrimary;
@@ -31483,20 +31581,20 @@ var OverlayUMPTokenInteractor = class {
31483
31581
  return fields;
31484
31582
  }
31485
31583
  /** Looks up the old token on the overlay; returns undefined resolved token if not found. */
31486
- async resolveOldTokenInput(oldTokenToConsume) {
31584
+ async resolveOldInput(oldTokenToConsume) {
31487
31585
  if (!oldTokenToConsume?.currentOutpoint) return {
31488
31586
  resolvedOldToken: void 0,
31489
31587
  inputToken: void 0
31490
31588
  };
31491
31589
  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.");
31590
+ if (inputToken == null) throw new Error("Previous UMP token unavailable; update refused.");
31493
31591
  return {
31494
31592
  resolvedOldToken: oldTokenToConsume,
31495
31593
  inputToken
31496
31594
  };
31497
31595
  }
31498
31596
  /** Creates the UMP action without dropping a required old-token input on failure. */
31499
- async createUMPAction(wallet, adminOriginator, inputs, outputs, inputToken, resolvedOldToken) {
31597
+ async createAction(wallet, adminOriginator, inputs, outputs, inputToken, resolvedOldToken) {
31500
31598
  try {
31501
31599
  return await wallet.createAction({
31502
31600
  description: resolvedOldToken == null ? "Create new UMP token" : "Renew UMP token (consume old, create new)",
@@ -31523,43 +31621,43 @@ var OverlayUMPTokenInteractor = class {
31523
31621
  }
31524
31622
  }
31525
31623
  /** Handles a fully-finalized (no signable tx) createAction result — broadcasts and returns outpoint. */
31526
- async broadcastFinishedUMPAction(createResult) {
31624
+ async broadcastFinal(createResult) {
31527
31625
  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.");
31626
+ if (!finalTxid) throw new Error("UMP transaction was not finalized.");
31627
+ if (createResult.tx == null) throw new Error("UMP transaction data missing.");
31530
31628
  const broadcastTx = _bsv_sdk.Transaction.fromAtomicBEEF(createResult.tx);
31531
31629
  const result = await this.broadcaster.broadcast(broadcastTx);
31532
- this.assertSuccessfulBroadcast(result, "create-finalized");
31630
+ this.assertBroadcast(result, "create-finalized");
31533
31631
  return `${finalTxid}.0`;
31534
31632
  }
31535
31633
  /** Signs the old-token input and broadcasts — used during UMP token renewal. */
31536
- async signAndBroadcastWithOldToken(wallet, adminOriginator, reference, partialTx) {
31634
+ async renewToken(wallet, adminOriginator, reference, partialTx) {
31537
31635
  const unlockingScript = await new _bsv_sdk.PushDrop(wallet, adminOriginator).unlock([2, "admin user management token"], "1", "self").sign(partialTx, 0);
31538
31636
  const signResult = await wallet.signAction({
31539
31637
  reference,
31540
31638
  spends: { 0: { unlockingScript: unlockingScript.toHex() } }
31541
31639
  }, adminOriginator);
31542
31640
  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.");
31641
+ if (!finalTxid) throw new Error("Could not finalize renewed UMP token.");
31642
+ if (signResult.tx == null) throw new Error("Renewed UMP token transaction data missing.");
31545
31643
  const result = await this.broadcaster.broadcast(_bsv_sdk.Transaction.fromAtomicBEEF(signResult.tx));
31546
- this.assertSuccessfulBroadcast(result, "renew");
31644
+ this.assertBroadcast(result, "renew");
31547
31645
  return `${finalTxid}.0`;
31548
31646
  }
31549
31647
  /** Signs without input spending and broadcasts — used when creating a brand-new UMP token. */
31550
- async signAndBroadcastNewToken(wallet, adminOriginator, reference) {
31648
+ async broadcastNew(wallet, adminOriginator, reference) {
31551
31649
  const signResult = await wallet.signAction({
31552
31650
  reference,
31553
31651
  spends: {}
31554
31652
  }, adminOriginator);
31555
31653
  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.");
31654
+ if (!finalTxid) throw new Error("Could not finalize new UMP token.");
31655
+ if (signResult.tx == null) throw new Error("New UMP token transaction data missing.");
31558
31656
  const result = await this.broadcaster.broadcast(_bsv_sdk.Transaction.fromAtomicBEEF(signResult.tx));
31559
- this.assertSuccessfulBroadcast(result, "create");
31657
+ this.assertBroadcast(result, "create");
31560
31658
  return `${finalTxid}.0`;
31561
31659
  }
31562
- assertSuccessfulBroadcast(result, operation) {
31660
+ assertBroadcast(result, operation) {
31563
31661
  const succeeded = result.status === "success";
31564
31662
  this.telemetry.capture({
31565
31663
  name: succeeded ? "wallet-toolbox.ump.broadcast.completed" : "wallet-toolbox.ump.broadcast.failed",
@@ -31588,12 +31686,12 @@ var OverlayUMPTokenInteractor = class {
31588
31686
  if (answer.type !== "output-list" || answer.outputs.length === 0) return [];
31589
31687
  const tokens = [];
31590
31688
  for (const output of answer.outputs) {
31591
- const token = this.parseLookupOutput(output);
31689
+ const token = this.parseOutput(output);
31592
31690
  if (token != null) tokens.push(token);
31593
31691
  }
31594
31692
  return tokens;
31595
31693
  }
31596
- parseLookupOutput(output) {
31694
+ parseOutput(output) {
31597
31695
  try {
31598
31696
  const tx = _bsv_sdk.Transaction.fromBEEF(output.beef);
31599
31697
  const txOutput = tx.outputs[output.outputIndex];
@@ -31643,14 +31741,14 @@ var OverlayUMPTokenInteractor = class {
31643
31741
  correlationId
31644
31742
  });
31645
31743
  } catch (error) {
31646
- const diagnostics = this.emptyLookupDiagnostics(correlationId);
31647
- this.captureLookupFailure("outpoint", "lookup-unavailable", diagnostics, startedAt, error);
31744
+ const diagnostics = this.emptyStats(correlationId);
31745
+ this.lookupFailed("outpoint", "lookup-unavailable", diagnostics, startedAt, error);
31648
31746
  throw new UMPTokenLookupError("lookup-unavailable", diagnostics, { cause: error });
31649
31747
  }
31650
31748
  if (resolution.answer.outputs.length === 0) {
31651
31749
  if (resolution.progress.emptyHosts === 0) {
31652
- const diagnostics = this.toLookupDiagnostics(resolution);
31653
- this.captureLookupFailure("outpoint", "lookup-incomplete", diagnostics, startedAt);
31750
+ const diagnostics = this.diagnosticsFor(resolution);
31751
+ this.lookupFailed("outpoint", "lookup-incomplete", diagnostics, startedAt);
31654
31752
  throw new UMPTokenLookupError("lookup-incomplete", diagnostics);
31655
31753
  }
31656
31754
  return;
@@ -31792,20 +31890,20 @@ var CWIStyleWalletManager = class {
31792
31890
  if (this._initSnapshot !== void 0) {
31793
31891
  this.telemetry.capture({
31794
31892
  name: "wallet-toolbox.snapshot.initialization.started",
31795
- component: "wallet-toolbox.cwi-manager",
31893
+ component: CWI_COMPONENT,
31796
31894
  severity: "debug"
31797
31895
  });
31798
31896
  try {
31799
31897
  await this.loadSnapshot(this._initSnapshot);
31800
31898
  this.telemetry.capture({
31801
31899
  name: "wallet-toolbox.snapshot.initialization.completed",
31802
- component: "wallet-toolbox.cwi-manager",
31900
+ component: CWI_COMPONENT,
31803
31901
  severity: "info"
31804
31902
  });
31805
31903
  } catch (error) {
31806
31904
  this.telemetry.capture({
31807
31905
  name: "wallet-toolbox.snapshot.initialization.failed",
31808
- component: "wallet-toolbox.cwi-manager",
31906
+ component: CWI_COMPONENT,
31809
31907
  severity: "error",
31810
31908
  error
31811
31909
  });
@@ -31814,9 +31912,11 @@ var CWIStyleWalletManager = class {
31814
31912
  }
31815
31913
  }
31816
31914
  /**
31817
- * Provides the presentation key.
31915
+ * Provides the presentation key. A WAB operator pin may be supplied by the
31916
+ * authentication manager; normal lookup and lineage resolution always run
31917
+ * before this ambiguity-only fallback.
31818
31918
  */
31819
- async providePresentationKey(key) {
31919
+ async providePresentationKey(key, lookupOptions) {
31820
31920
  if (this.authenticated) throw new Error("User is already authenticated");
31821
31921
  if (this.authenticationMode === "recovery-key-and-password") throw new Error("Presentation key is not needed in this mode");
31822
31922
  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 +31925,17 @@ var CWIStyleWalletManager = class {
31825
31925
  const startedAt = Date.now();
31826
31926
  this.telemetry.capture({
31827
31927
  name: "wallet-toolbox.authentication.account-lookup.started",
31828
- component: "wallet-toolbox.cwi-manager",
31928
+ component: CWI_COMPONENT,
31829
31929
  severity: "debug",
31830
31930
  attributes: { lookupKind: "presentation" }
31831
31931
  });
31832
31932
  let token;
31833
31933
  try {
31834
- token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash);
31934
+ token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash, lookupOptions);
31835
31935
  } catch (error) {
31836
31936
  this.telemetry.capture({
31837
31937
  name: "wallet-toolbox.authentication.account-lookup.failed",
31838
- component: "wallet-toolbox.cwi-manager",
31938
+ component: CWI_COMPONENT,
31839
31939
  severity: "warn",
31840
31940
  attributes: {
31841
31941
  lookupKind: "presentation",
@@ -31855,7 +31955,7 @@ var CWIStyleWalletManager = class {
31855
31955
  }
31856
31956
  this.telemetry.capture({
31857
31957
  name: "wallet-toolbox.authentication.account-lookup.completed",
31858
- component: "wallet-toolbox.cwi-manager",
31958
+ component: CWI_COMPONENT,
31859
31959
  severity: "info",
31860
31960
  attributes: {
31861
31961
  lookupKind: "presentation",
@@ -31871,11 +31971,11 @@ var CWIStyleWalletManager = class {
31871
31971
  if (this.authenticated) throw new Error("User is already authenticated");
31872
31972
  if (this.authenticationMode === "presentation-key-and-recovery-key") throw new Error("Password is not needed in this mode");
31873
31973
  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);
31974
+ if (this.authenticationFlow === "existing-user") await this.unlockExisting(password);
31975
+ else await this.createNewUser(password);
31876
31976
  }
31877
31977
  /** Handles the password step for an existing user — derives keys, sets up infrastructure. */
31878
- async handleExistingUserPassword(password) {
31978
+ async unlockExisting(password) {
31879
31979
  if (this.currentUMPToken == null) throw new Error("Provide presentation or recovery key first.");
31880
31980
  const derivedPasswordKey = await derivePasswordKey(this.currentUMPToken, _bsv_sdk.Utils.toArray(password, "utf8"));
31881
31981
  let rootPrimaryKey;
@@ -31888,11 +31988,11 @@ var CWIStyleWalletManager = class {
31888
31988
  rootPrimaryKey = new _bsv_sdk.SymmetricKey(this.XOR(this.recoveryKey, derivedPasswordKey)).decrypt(this.currentUMPToken.passwordRecoveryPrimary);
31889
31989
  rootPrivilegedKey = new _bsv_sdk.SymmetricKey(this.XOR(rootPrimaryKey, derivedPasswordKey)).decrypt(this.currentUMPToken.passwordPrimaryPrivileged);
31890
31990
  }
31891
- await this.setupRootInfrastructure(rootPrimaryKey, rootPrivilegedKey);
31991
+ await this.setupRoot(rootPrimaryKey, rootPrivilegedKey);
31892
31992
  await this.switchProfile(this.activeProfileId);
31893
31993
  }
31894
31994
  /** Handles the password step for a new user — generates keys, builds UMP token, publishes on-chain. */
31895
- async handleNewUserPassword(password) {
31995
+ async createNewUser(password) {
31896
31996
  if (this.authenticationMode !== "presentation-key-and-password") throw new Error("New-user flow requires presentation key and password mode.");
31897
31997
  if (this.presentationKey == null) throw new Error("No presentation key provided for new-user flow.");
31898
31998
  const recoveryKey = (0, _bsv_sdk.Random)(32);
@@ -31931,14 +32031,14 @@ var CWIStyleWalletManager = class {
31931
32031
  passwordKdf: this.kdfConfig
31932
32032
  };
31933
32033
  this.currentUMPToken = newToken;
31934
- await this.setupRootInfrastructure(rootPrimaryKey);
32034
+ await this.setupRoot(rootPrimaryKey);
31935
32035
  await this.switchProfile(DEFAULT_PROFILE_ID);
31936
32036
  if (this.newWalletFunder != null && this.underlying != null) try {
31937
32037
  await this.newWalletFunder(this.presentationKey, this.underlying, this.adminOriginator);
31938
32038
  } catch (error) {
31939
32039
  this.telemetry.capture({
31940
32040
  name: "wallet-toolbox.authentication.new-wallet-funding.failed",
31941
- component: "wallet-toolbox.cwi-manager",
32041
+ component: CWI_COMPONENT,
31942
32042
  severity: "error",
31943
32043
  error: /* @__PURE__ */ new Error("New wallet funding failed.")
31944
32044
  });
@@ -31969,7 +32069,7 @@ var CWIStyleWalletManager = class {
31969
32069
  const xorKey = this.XOR(this.presentationKey, recoveryKey);
31970
32070
  const rootPrimaryKey = new _bsv_sdk.SymmetricKey(xorKey).decrypt(this.currentUMPToken.presentationRecoveryPrimary);
31971
32071
  const rootPrivilegedKey = new _bsv_sdk.SymmetricKey(xorKey).decrypt(this.currentUMPToken.presentationRecoveryPrivileged);
31972
- await this.setupRootInfrastructure(rootPrimaryKey, rootPrivilegedKey);
32072
+ await this.setupRoot(rootPrimaryKey, rootPrivilegedKey);
31973
32073
  await this.switchProfile(this.activeProfileId);
31974
32074
  }
31975
32075
  }
@@ -32000,7 +32100,7 @@ var CWIStyleWalletManager = class {
32000
32100
  if (snapshot.length > 16777216) throw new Error("Snapshot exceeds the maximum supported size.");
32001
32101
  this.telemetry.capture({
32002
32102
  name: "wallet-toolbox.snapshot.saved",
32003
- component: "wallet-toolbox.cwi-manager",
32103
+ component: CWI_COMPONENT,
32004
32104
  severity: "info",
32005
32105
  attributes: {
32006
32106
  formatVersion: 2,
@@ -32038,12 +32138,12 @@ var CWIStyleWalletManager = class {
32038
32138
  const tokenBytes = payloadReader.read(tokenLen);
32039
32139
  const token = this.deserializeUMPToken(tokenBytes);
32040
32140
  this.currentUMPToken = token;
32041
- await this.setupRootInfrastructure(rootPrimaryKey);
32141
+ await this.setupRoot(rootPrimaryKey);
32042
32142
  await this.switchProfile(activeProfileId);
32043
32143
  this.authenticationFlow = "existing-user";
32044
32144
  this.telemetry.capture({
32045
32145
  name: "wallet-toolbox.snapshot.loaded",
32046
- component: "wallet-toolbox.cwi-manager",
32146
+ component: CWI_COMPONENT,
32047
32147
  severity: "info",
32048
32148
  attributes: {
32049
32149
  formatVersion: version,
@@ -32054,7 +32154,7 @@ var CWIStyleWalletManager = class {
32054
32154
  this.destroy();
32055
32155
  this.telemetry.capture({
32056
32156
  name: "wallet-toolbox.snapshot.load-failed",
32057
- component: "wallet-toolbox.cwi-manager",
32157
+ component: CWI_COMPONENT,
32058
32158
  severity: "error",
32059
32159
  error
32060
32160
  });
@@ -32071,7 +32171,7 @@ var CWIStyleWalletManager = class {
32071
32171
  if (refreshed == null) return false;
32072
32172
  if (refreshed.currentOutpoint && currentToken.currentOutpoint && refreshed.currentOutpoint === currentToken.currentOutpoint) return false;
32073
32173
  this.currentUMPToken = refreshed;
32074
- await this.setupRootInfrastructure(this.rootPrimaryKey);
32174
+ await this.setupRoot(this.rootPrimaryKey);
32075
32175
  this.saveSnapshot();
32076
32176
  return true;
32077
32177
  }
@@ -32130,7 +32230,7 @@ var CWIStyleWalletManager = class {
32130
32230
  createdAt: Math.floor(Date.now() / 1e3)
32131
32231
  };
32132
32232
  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);
32233
+ 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
32234
  return newProfile.id;
32135
32235
  }
32136
32236
  /**
@@ -32147,7 +32247,7 @@ var CWIStyleWalletManager = class {
32147
32247
  if (profileIndex === -1) throw new Error("Profile not found.");
32148
32248
  this.profiles.splice(profileIndex, 1);
32149
32249
  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);
32250
+ 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
32251
  }
32152
32252
  /**
32153
32253
  * Switches the active profile. This re-derives keys and rebuilds the underlying wallet.
@@ -32188,14 +32288,14 @@ var CWIStyleWalletManager = class {
32188
32288
  const recoveryKey = await this.getFactor("recoveryKey");
32189
32289
  const presentationKey = await this.getFactor("presentationKey");
32190
32290
  const rootPrivilegedKey = await this.getFactor("privilegedKey");
32191
- await this.updateAuthFactors(passwordSalt, newPasswordKey, presentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32291
+ await this.updateFactors(passwordSalt, newPasswordKey, presentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32192
32292
  }
32193
32293
  /**
32194
32294
  * Retrieves the current recovery key. Requires privileged access.
32195
32295
  */
32196
32296
  async getRecoveryKey() {
32197
32297
  if (!this.authenticated || this.currentUMPToken == null || this.rootPrivilegedKeyManager == null) throw new Error("Not authenticated or missing required data.");
32198
- return await this.getFactor("recoveryKey");
32298
+ return this.getFactor("recoveryKey");
32199
32299
  }
32200
32300
  /**
32201
32301
  * Changes the user's recovery key. Prompts user to save the new key.
@@ -32207,7 +32307,7 @@ var CWIStyleWalletManager = class {
32207
32307
  const rootPrivilegedKey = await this.getFactor("privilegedKey");
32208
32308
  const newRecoveryKey = (0, _bsv_sdk.Random)(32);
32209
32309
  await this.recoveryKeySaver(newRecoveryKey);
32210
- await this.updateAuthFactors(this.currentUMPToken.passwordSalt, passwordKey, presentationKey, newRecoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32310
+ await this.updateFactors(this.currentUMPToken.passwordSalt, passwordKey, presentationKey, newRecoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32211
32311
  }
32212
32312
  /**
32213
32313
  * Changes the user's presentation key.
@@ -32218,7 +32318,7 @@ var CWIStyleWalletManager = class {
32218
32318
  const recoveryKey = await this.getFactor("recoveryKey");
32219
32319
  const passwordKey = await this.getFactor("passwordKey");
32220
32320
  const rootPrivilegedKey = await this.getFactor("privilegedKey");
32221
- await this.updateAuthFactors(this.currentUMPToken.passwordSalt, passwordKey, newPresentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32321
+ await this.updateFactors(this.currentUMPToken.passwordSalt, passwordKey, newPresentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32222
32322
  if (this.presentationKey != null) this.presentationKey = newPresentationKey;
32223
32323
  }
32224
32324
  /**
@@ -32264,7 +32364,7 @@ var CWIStyleWalletManager = class {
32264
32364
  } catch (error) {
32265
32365
  this.telemetry.capture({
32266
32366
  name: "wallet-toolbox.authentication.factor-decryption.failed",
32267
- component: "wallet-toolbox.cwi-manager",
32367
+ component: CWI_COMPONENT,
32268
32368
  severity: "error",
32269
32369
  attributes: { factor: factorName },
32270
32370
  error
@@ -32277,7 +32377,7 @@ var CWIStyleWalletManager = class {
32277
32377
  * Recomputes UMP token fields with updated factors and profiles, then publishes the update.
32278
32378
  * This operation requires the *root* privileged key and the *default* profile wallet.
32279
32379
  */
32280
- async updateAuthFactors(passwordSalt, passwordKey, presentationKey, recoveryKey, rootPrimaryKey, rootPrivilegedKey, profiles) {
32380
+ async updateFactors(passwordSalt, passwordKey, presentationKey, recoveryKey, rootPrimaryKey, rootPrivilegedKey, profiles) {
32281
32381
  if (!this.authenticated || this.rootPrimaryKey == null || this.currentUMPToken == null) throw new Error("Wallet is not properly authenticated or missing data for update.");
32282
32382
  const oldTokenToConsume = { ...this.currentUMPToken };
32283
32383
  if (!oldTokenToConsume.currentOutpoint) throw new Error("Cannot update UMP token: Old token has no outpoint.");
@@ -32328,7 +32428,7 @@ var CWIStyleWalletManager = class {
32328
32428
  if (!currentActiveId.every((x) => x === 0)) {
32329
32429
  this.telemetry.capture({
32330
32430
  name: "wallet-toolbox.ump.profile-switch.started",
32331
- component: "wallet-toolbox.cwi-manager",
32431
+ component: CWI_COMPONENT,
32332
32432
  severity: "debug",
32333
32433
  attributes: { reason: "token-update" }
32334
32434
  });
@@ -32344,7 +32444,7 @@ var CWIStyleWalletManager = class {
32344
32444
  await this.switchProfile(currentActiveId);
32345
32445
  this.telemetry.capture({
32346
32446
  name: "wallet-toolbox.ump.profile-switch.completed",
32347
- component: "wallet-toolbox.cwi-manager",
32447
+ component: CWI_COMPONENT,
32348
32448
  severity: "debug",
32349
32449
  attributes: { reason: "token-update" }
32350
32450
  });
@@ -32471,9 +32571,9 @@ var CWIStyleWalletManager = class {
32471
32571
  * @param rootPrimaryKey The user's root primary key (32 bytes).
32472
32572
  * @param ephemeralRootPrivilegedKey Optional root privileged key (e.g., during recovery flows).
32473
32573
  */
32474
- async setupRootInfrastructure(rootPrimaryKey, ephemeralRootPrivilegedKey) {
32574
+ async setupRoot(rootKey, ephemeralRootPrivilegedKey) {
32475
32575
  if (this.currentUMPToken == null) throw new Error("A UMP token must exist before setting up root infrastructure!");
32476
- this.rootPrimaryKey = rootPrimaryKey;
32576
+ this.rootPrimaryKey = rootKey;
32477
32577
  let oneTimePrivilegedKey = ephemeralRootPrivilegedKey == null ? void 0 : new _bsv_sdk.PrivateKey(ephemeralRootPrivilegedKey);
32478
32578
  this.rootPrivilegedKeyManager = new PrivilegedKeyManager(async (reason) => {
32479
32579
  if (oneTimePrivilegedKey != null) {
@@ -32494,7 +32594,7 @@ var CWIStyleWalletManager = class {
32494
32594
  });
32495
32595
  this.profiles = [];
32496
32596
  if (this.currentUMPToken.profilesEncrypted != null && this.currentUMPToken.profilesEncrypted.length > 0) try {
32497
- const decryptedProfileBytes = new _bsv_sdk.SymmetricKey(rootPrimaryKey).decrypt(this.currentUMPToken.profilesEncrypted);
32597
+ const decryptedProfileBytes = new _bsv_sdk.SymmetricKey(rootKey).decrypt(this.currentUMPToken.profilesEncrypted);
32498
32598
  const profilesJson = _bsv_sdk.Utils.toUTF8(decryptedProfileBytes);
32499
32599
  const profiles = JSON.parse(profilesJson);
32500
32600
  if (!Array.isArray(profiles) || profiles.length > 1e3 || !profiles.every(isValidProfile)) throw new Error("Decrypted profile data is invalid or exceeds supported bounds.");
@@ -32503,7 +32603,7 @@ var CWIStyleWalletManager = class {
32503
32603
  this.profiles = [];
32504
32604
  this.telemetry.capture({
32505
32605
  name: "wallet-toolbox.profile.load-failed",
32506
- component: "wallet-toolbox.cwi-manager",
32606
+ component: CWI_COMPONENT,
32507
32607
  severity: "error",
32508
32608
  error
32509
32609
  });
@@ -32512,98 +32612,98 @@ var CWIStyleWalletManager = class {
32512
32612
  }
32513
32613
  this.authenticated = true;
32514
32614
  }
32515
- checkAuthAndUnderlying(originator) {
32615
+ assertReady(originator) {
32516
32616
  if (!this.authenticated) throw new Error("User is not authenticated.");
32517
32617
  if (this.underlying == null) throw new Error("Underlying wallet for the active profile is not initialized.");
32518
32618
  if (originator === this.adminOriginator) throw new Error("External applications are not allowed to use the admin originator.");
32519
32619
  }
32520
32620
  async getPublicKey(args, originator) {
32521
- this.checkAuthAndUnderlying(originator);
32522
- return await this.underlying.getPublicKey(args, originator);
32621
+ this.assertReady(originator);
32622
+ return this.underlying.getPublicKey(args, originator);
32523
32623
  }
32524
32624
  async revealCounterpartyKeyLinkage(args, originator) {
32525
- this.checkAuthAndUnderlying(originator);
32526
- return await this.underlying.revealCounterpartyKeyLinkage(args, originator);
32625
+ this.assertReady(originator);
32626
+ return this.underlying.revealCounterpartyKeyLinkage(args, originator);
32527
32627
  }
32528
32628
  async revealSpecificKeyLinkage(args, originator) {
32529
- this.checkAuthAndUnderlying(originator);
32530
- return await this.underlying.revealSpecificKeyLinkage(args, originator);
32629
+ this.assertReady(originator);
32630
+ return this.underlying.revealSpecificKeyLinkage(args, originator);
32531
32631
  }
32532
32632
  async encrypt(args, originator) {
32533
- this.checkAuthAndUnderlying(originator);
32534
- return await this.underlying.encrypt(args, originator);
32633
+ this.assertReady(originator);
32634
+ return this.underlying.encrypt(args, originator);
32535
32635
  }
32536
32636
  async decrypt(args, originator) {
32537
- this.checkAuthAndUnderlying(originator);
32538
- return await this.underlying.decrypt(args, originator);
32637
+ this.assertReady(originator);
32638
+ return this.underlying.decrypt(args, originator);
32539
32639
  }
32540
32640
  async createHmac(args, originator) {
32541
- this.checkAuthAndUnderlying(originator);
32542
- return await this.underlying.createHmac(args, originator);
32641
+ this.assertReady(originator);
32642
+ return this.underlying.createHmac(args, originator);
32543
32643
  }
32544
32644
  async verifyHmac(args, originator) {
32545
- this.checkAuthAndUnderlying(originator);
32546
- return await this.underlying.verifyHmac(args, originator);
32645
+ this.assertReady(originator);
32646
+ return this.underlying.verifyHmac(args, originator);
32547
32647
  }
32548
32648
  async createSignature(args, originator) {
32549
- this.checkAuthAndUnderlying(originator);
32550
- return await this.underlying.createSignature(args, originator);
32649
+ this.assertReady(originator);
32650
+ return this.underlying.createSignature(args, originator);
32551
32651
  }
32552
32652
  async verifySignature(args, originator) {
32553
- this.checkAuthAndUnderlying(originator);
32554
- return await this.underlying.verifySignature(args, originator);
32653
+ this.assertReady(originator);
32654
+ return this.underlying.verifySignature(args, originator);
32555
32655
  }
32556
32656
  async createAction(args, originator) {
32557
- this.checkAuthAndUnderlying(originator);
32558
- return await this.underlying.createAction(args, originator);
32657
+ this.assertReady(originator);
32658
+ return this.underlying.createAction(args, originator);
32559
32659
  }
32560
32660
  async signAction(args, originator) {
32561
- this.checkAuthAndUnderlying(originator);
32562
- return await this.underlying.signAction(args, originator);
32661
+ this.assertReady(originator);
32662
+ return this.underlying.signAction(args, originator);
32563
32663
  }
32564
32664
  async abortAction(args, originator) {
32565
- this.checkAuthAndUnderlying(originator);
32566
- return await this.underlying.abortAction(args, originator);
32665
+ this.assertReady(originator);
32666
+ return this.underlying.abortAction(args, originator);
32567
32667
  }
32568
32668
  async listActions(args, originator) {
32569
- this.checkAuthAndUnderlying(originator);
32570
- return await this.underlying.listActions(args, originator);
32669
+ this.assertReady(originator);
32670
+ return this.underlying.listActions(args, originator);
32571
32671
  }
32572
32672
  async internalizeAction(args, originator) {
32573
- this.checkAuthAndUnderlying(originator);
32574
- return await this.underlying.internalizeAction(args, originator);
32673
+ this.assertReady(originator);
32674
+ return this.underlying.internalizeAction(args, originator);
32575
32675
  }
32576
32676
  async listOutputs(args, originator) {
32577
- this.checkAuthAndUnderlying(originator);
32578
- return await this.underlying.listOutputs(args, originator);
32677
+ this.assertReady(originator);
32678
+ return this.underlying.listOutputs(args, originator);
32579
32679
  }
32580
32680
  async relinquishOutput(args, originator) {
32581
- this.checkAuthAndUnderlying(originator);
32582
- return await this.underlying.relinquishOutput(args, originator);
32681
+ this.assertReady(originator);
32682
+ return this.underlying.relinquishOutput(args, originator);
32583
32683
  }
32584
32684
  async acquireCertificate(args, originator) {
32585
- this.checkAuthAndUnderlying(originator);
32586
- return await this.underlying.acquireCertificate(args, originator);
32685
+ this.assertReady(originator);
32686
+ return this.underlying.acquireCertificate(args, originator);
32587
32687
  }
32588
32688
  async listCertificates(args, originator) {
32589
- this.checkAuthAndUnderlying(originator);
32590
- return await this.underlying.listCertificates(args, originator);
32689
+ this.assertReady(originator);
32690
+ return this.underlying.listCertificates(args, originator);
32591
32691
  }
32592
32692
  async proveCertificate(args, originator) {
32593
- this.checkAuthAndUnderlying(originator);
32594
- return await this.underlying.proveCertificate(args, originator);
32693
+ this.assertReady(originator);
32694
+ return this.underlying.proveCertificate(args, originator);
32595
32695
  }
32596
32696
  async relinquishCertificate(args, originator) {
32597
- this.checkAuthAndUnderlying(originator);
32598
- return await this.underlying.relinquishCertificate(args, originator);
32697
+ this.assertReady(originator);
32698
+ return this.underlying.relinquishCertificate(args, originator);
32599
32699
  }
32600
32700
  async discoverByIdentityKey(args, originator) {
32601
- this.checkAuthAndUnderlying(originator);
32602
- return await this.underlying.discoverByIdentityKey(args, originator);
32701
+ this.assertReady(originator);
32702
+ return this.underlying.discoverByIdentityKey(args, originator);
32603
32703
  }
32604
32704
  async discoverByAttributes(args, originator) {
32605
- this.checkAuthAndUnderlying(originator);
32606
- return await this.underlying.discoverByAttributes(args, originator);
32705
+ this.assertReady(originator);
32706
+ return this.underlying.discoverByAttributes(args, originator);
32607
32707
  }
32608
32708
  async isAuthenticated(_, originator) {
32609
32709
  if (!this.authenticated) throw new Error("User is not authenticated.");
@@ -32613,23 +32713,23 @@ var CWIStyleWalletManager = class {
32613
32713
  async waitForAuthentication(_, originator) {
32614
32714
  if (originator === this.adminOriginator) throw new Error("External applications are not allowed to use the admin originator.");
32615
32715
  while (!this.authenticated || this.underlying == null) await new Promise((resolve) => setTimeout(resolve, 100));
32616
- return await this.underlying.waitForAuthentication({}, originator);
32716
+ return this.underlying.waitForAuthentication({}, originator);
32617
32717
  }
32618
32718
  async getHeight(_, originator) {
32619
- this.checkAuthAndUnderlying(originator);
32620
- return await this.underlying.getHeight({}, originator);
32719
+ this.assertReady(originator);
32720
+ return this.underlying.getHeight({}, originator);
32621
32721
  }
32622
32722
  async getHeaderForHeight(args, originator) {
32623
- this.checkAuthAndUnderlying(originator);
32624
- return await this.underlying.getHeaderForHeight(args, originator);
32723
+ this.assertReady(originator);
32724
+ return this.underlying.getHeaderForHeight(args, originator);
32625
32725
  }
32626
32726
  async getNetwork(_, originator) {
32627
- this.checkAuthAndUnderlying(originator);
32628
- return await this.underlying.getNetwork({}, originator);
32727
+ this.assertReady(originator);
32728
+ return this.underlying.getNetwork({}, originator);
32629
32729
  }
32630
32730
  async getVersion(_, originator) {
32631
- this.checkAuthAndUnderlying(originator);
32632
- return await this.underlying.getVersion({}, originator);
32731
+ this.assertReady(originator);
32732
+ return this.underlying.getVersion({}, originator);
32633
32733
  }
32634
32734
  };
32635
32735
  //#endregion
@@ -32973,6 +33073,8 @@ const DEFAULT_MAX_RESPONSE_BYTES = 1024 * 1024;
32973
33073
  const MAX_CONFIGURED_TIMEOUT_MS = 12e4;
32974
33074
  const MAX_CONFIGURED_REQUEST_BYTES = 10 * 1024 * 1024;
32975
33075
  const MAX_CONFIGURED_RESPONSE_BYTES = 10 * 1024 * 1024;
33076
+ const WAB_COMPONENT = "wallet-toolbox.wab-transport";
33077
+ const WAB_REQUEST_EVENT = "wallet-toolbox.wab.request.";
32976
33078
  const defaultFetch = typeof globalThis !== "undefined" && typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
32977
33079
  /**
32978
33080
  * A privacy-safe WAB transport failure. Response bodies and request payloads
@@ -33011,8 +33113,8 @@ function normalizeServerUrl(serverUrl) {
33011
33113
  } catch {
33012
33114
  throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB server URL must be an absolute URL.", false);
33013
33115
  }
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);
33116
+ if (parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB URL cannot include credentials, query, or fragment.", false);
33117
+ 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
33118
  let pathname = parsed.pathname;
33017
33119
  while (pathname.endsWith("/")) pathname = pathname.slice(0, -1);
33018
33120
  return {
@@ -33022,7 +33124,7 @@ function normalizeServerUrl(serverUrl) {
33022
33124
  }
33023
33125
  function normalizePositiveInteger(value, fallback, maximum, name) {
33024
33126
  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);
33127
+ 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
33128
  return resolved;
33027
33129
  }
33028
33130
  function assertSafePath(path) {
@@ -33047,20 +33149,20 @@ var WABTransport = class {
33047
33149
  serverUrl;
33048
33150
  serverOrigin;
33049
33151
  telemetry;
33050
- fetchClient;
33051
- timeoutMs;
33052
- maxRequestBytes;
33053
- maxResponseBytes;
33152
+ fetcher;
33153
+ timeout;
33154
+ requestLimit;
33155
+ responseLimit;
33054
33156
  constructor(serverUrl, options = {}) {
33055
33157
  const normalized = normalizeServerUrl(serverUrl);
33056
33158
  this.serverUrl = normalized.baseUrl;
33057
33159
  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");
33160
+ const fetcher = options.fetch ?? defaultFetch;
33161
+ if (typeof fetcher !== "function") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WABClient requires a fetch implementation.", false);
33162
+ this.fetcher = fetcher;
33163
+ this.timeout = normalizePositiveInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, MAX_CONFIGURED_TIMEOUT_MS, "timeoutMs");
33164
+ this.requestLimit = normalizePositiveInteger(options.maxRequestBytes, DEFAULT_MAX_REQUEST_BYTES, MAX_CONFIGURED_REQUEST_BYTES, "maxRequestBytes");
33165
+ this.responseLimit = normalizePositiveInteger(options.maxResponseBytes, DEFAULT_MAX_RESPONSE_BYTES, MAX_CONFIGURED_RESPONSE_BYTES, "maxResponseBytes");
33064
33166
  this.telemetry = new _bsv_sdk.Telemetry(options.telemetry);
33065
33167
  }
33066
33168
  createCorrelationId() {
@@ -33068,38 +33170,9 @@ var WABTransport = class {
33068
33170
  return isSafeCorrelationId(correlationId) ? correlationId : new _bsv_sdk.Telemetry().createCorrelationId();
33069
33171
  }
33070
33172
  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
33173
  assertSafePath(path);
33101
33174
  const correlationId = options.correlationId != null && isSafeCorrelationId(options.correlationId) ? options.correlationId : this.createCorrelationId();
33102
- return {
33175
+ const metadata = {
33103
33176
  method: options.method ?? "POST",
33104
33177
  path,
33105
33178
  operation: options.operation,
@@ -33111,46 +33184,73 @@ var WABTransport = class {
33111
33184
  route: path
33112
33185
  }
33113
33186
  };
33114
- }
33115
- captureRequestStarted(metadata) {
33116
33187
  this.telemetry.capture({
33117
- name: "wallet-toolbox.wab.request.started",
33118
- component: "wallet-toolbox.wab-transport",
33188
+ name: `${WAB_REQUEST_EVENT}started`,
33189
+ component: WAB_COMPONENT,
33119
33190
  severity: "debug",
33191
+ correlationId,
33192
+ attributes: {
33193
+ operation: metadata.operation,
33194
+ method: metadata.method,
33195
+ route: path,
33196
+ serverOrigin: this.serverOrigin
33197
+ }
33198
+ });
33199
+ const body = this.bodyFor(options, metadata);
33200
+ const timeout = this.startTimer(metadata.errorContext);
33201
+ const response = await this.fetch(metadata, body, timeout);
33202
+ const responseContext = {
33203
+ ...metadata.errorContext,
33204
+ endpointMarkerPresent: isWabResponse(response),
33205
+ responseCorrelationMatched: response.headers.get("X-Correlation-ID") === correlationId
33206
+ };
33207
+ this.checkResponse(response, responseContext, metadata, timeout);
33208
+ const responseText = await this.readText(response, responseContext, metadata, timeout);
33209
+ const parsed = this.parse(responseText, response, responseContext, metadata);
33210
+ this.telemetry.capture({
33211
+ name: `${WAB_REQUEST_EVENT}completed`,
33212
+ component: WAB_COMPONENT,
33213
+ severity: "info",
33120
33214
  correlationId: metadata.correlationId,
33121
33215
  attributes: {
33122
33216
  operation: metadata.operation,
33123
33217
  method: metadata.method,
33124
33218
  route: metadata.path,
33125
- serverOrigin: this.serverOrigin
33219
+ serverOrigin: this.serverOrigin,
33220
+ status: response.status,
33221
+ endpointMarkerPresent: responseContext.endpointMarkerPresent,
33222
+ responseCorrelationMatched: responseContext.responseCorrelationMatched,
33223
+ responseBytes: new TextEncoder().encode(responseText).byteLength,
33224
+ durationMs: Date.now() - metadata.startedAt
33126
33225
  }
33127
33226
  });
33227
+ return parsed;
33128
33228
  }
33129
- encodeRequestBody(options, metadata) {
33229
+ bodyFor(options, metadata) {
33130
33230
  let body;
33131
33231
  try {
33132
33232
  body = options.body === void 0 ? void 0 : JSON.stringify(options.body);
33133
33233
  } catch (cause) {
33134
- const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request payload could not be encoded.", false, void 0, {
33234
+ const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request encoding failed.", false, void 0, {
33135
33235
  ...metadata.errorContext,
33136
33236
  cause
33137
33237
  });
33138
- this.captureRequestFailure(metadata, error);
33238
+ this.report(metadata, error);
33139
33239
  throw error;
33140
33240
  }
33141
33241
  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);
33242
+ const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request is not JSON-serializable.", false, void 0, metadata.errorContext);
33243
+ this.report(metadata, error);
33144
33244
  throw error;
33145
33245
  }
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);
33246
+ if (body != null && new TextEncoder().encode(body).byteLength > this.requestLimit) {
33247
+ const error = new WABClientError("WAB_REQUEST_TOO_LARGE", "WAB request exceeds its size limit.", false, void 0, metadata.errorContext);
33248
+ this.report(metadata, error);
33149
33249
  throw error;
33150
33250
  }
33151
33251
  return body;
33152
33252
  }
33153
- startRequestTimeout(errorContext) {
33253
+ startTimer(errorContext) {
33154
33254
  const timeout = {
33155
33255
  controller: new AbortController(),
33156
33256
  timedOut: false
@@ -33160,12 +33260,12 @@ var WABTransport = class {
33160
33260
  timeout.timedOut = true;
33161
33261
  timeout.controller.abort();
33162
33262
  reject(new WABClientError("WAB_TIMEOUT", "WAB request timed out.", true, void 0, errorContext));
33163
- }, this.timeoutMs);
33263
+ }, this.timeout);
33164
33264
  });
33165
33265
  return timeout;
33166
33266
  }
33167
- async fetchResponse(metadata, body, timeout) {
33168
- const requestPromise = Promise.resolve().then(() => this.fetchClient(`${this.serverUrl}${metadata.path}`, {
33267
+ async fetch(metadata, body, timeout) {
33268
+ const requestPromise = Promise.resolve().then(() => this.fetcher(`${this.serverUrl}${metadata.path}`, {
33169
33269
  method: metadata.method,
33170
33270
  headers: {
33171
33271
  Accept: "application/json",
@@ -33189,33 +33289,26 @@ var WABTransport = class {
33189
33289
  ...metadata.errorContext,
33190
33290
  cause
33191
33291
  });
33192
- else error = new WABClientError("WAB_NETWORK_ERROR", "WAB request failed before receiving a response.", true, void 0, {
33292
+ else error = new WABClientError("WAB_NETWORK_ERROR", "WAB request failed before response.", true, void 0, {
33193
33293
  ...metadata.errorContext,
33194
33294
  cause
33195
33295
  });
33196
- this.captureRequestFailure(metadata, error);
33296
+ this.report(metadata, error);
33197
33297
  throw error;
33198
33298
  }
33199
33299
  }
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) {
33300
+ checkResponse(response, responseContext, metadata, timeout) {
33208
33301
  if (response.ok) return;
33209
33302
  if (timeout.timer !== void 0) clearTimeout(timeout.timer);
33210
33303
  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);
33304
+ 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);
33305
+ this.report(metadata, error);
33213
33306
  response.body?.cancel().catch(() => {});
33214
33307
  throw error;
33215
33308
  }
33216
- async readResponseText(response, responseContext, metadata, timeout) {
33309
+ async readText(response, responseContext, metadata, timeout) {
33217
33310
  try {
33218
- return await Promise.race([this.readBoundedResponse(response, responseContext), timeout.promise]);
33311
+ return await Promise.race([this.read(response, responseContext), timeout.promise]);
33219
33312
  } catch (cause) {
33220
33313
  let error;
33221
33314
  if (cause instanceof WABClientError) error = cause;
@@ -33223,17 +33316,17 @@ var WABTransport = class {
33223
33316
  ...responseContext,
33224
33317
  cause
33225
33318
  });
33226
- else error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response could not be read.", true, response.status, {
33319
+ else error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response read failed.", true, response.status, {
33227
33320
  ...responseContext,
33228
33321
  cause
33229
33322
  });
33230
- this.captureRequestFailure(metadata, error);
33323
+ this.report(metadata, error);
33231
33324
  throw error;
33232
33325
  } finally {
33233
33326
  if (timeout.timer !== void 0) clearTimeout(timeout.timer);
33234
33327
  }
33235
33328
  }
33236
- parseResponseObject(responseText, response, responseContext, metadata) {
33329
+ parse(responseText, response, responseContext, metadata) {
33237
33330
  let parsed;
33238
33331
  try {
33239
33332
  parsed = JSON.parse(responseText);
@@ -33242,37 +33335,32 @@ var WABTransport = class {
33242
33335
  ...responseContext,
33243
33336
  cause
33244
33337
  });
33245
- this.captureRequestFailure(metadata, error);
33338
+ this.report(metadata, error);
33246
33339
  throw error;
33247
33340
  }
33248
33341
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
33249
33342
  const error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response must be a JSON object.", true, response.status, responseContext);
33250
- this.captureRequestFailure(metadata, error);
33343
+ this.report(metadata, error);
33251
33344
  throw error;
33252
33345
  }
33253
33346
  return parsed;
33254
33347
  }
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) {
33348
+ async read(response, responseContext) {
33265
33349
  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);
33350
+ if (Number.isFinite(contentLength) && contentLength > this.responseLimit) {
33351
+ await this.stopBody(response);
33352
+ throw this.sizeError(response, responseContext);
33353
+ }
33354
+ const reader = response.body?.getReader();
33355
+ if (reader == null) return this.readBuffer(response, responseContext);
33356
+ return this.readStream(reader, response, responseContext);
33269
33357
  }
33270
- async readBoundedArrayBuffer(response, responseContext) {
33358
+ async readBuffer(response, responseContext) {
33271
33359
  const bytes = new Uint8Array(await response.arrayBuffer());
33272
- if (bytes.byteLength > this.maxResponseBytes) throw this.responseTooLargeError(response, responseContext);
33360
+ if (bytes.byteLength > this.responseLimit) throw this.sizeError(response, responseContext);
33273
33361
  return new TextDecoder().decode(bytes);
33274
33362
  }
33275
- async readBoundedStream(reader, response, responseContext) {
33363
+ async readStream(reader, response, responseContext) {
33276
33364
  const chunks = [];
33277
33365
  let total = 0;
33278
33366
  while (true) {
@@ -33280,15 +33368,12 @@ var WABTransport = class {
33280
33368
  if (done) break;
33281
33369
  if (value == null) continue;
33282
33370
  total += value.byteLength;
33283
- if (total > this.maxResponseBytes) {
33284
- await this.cancelResponseReader(reader);
33285
- throw this.responseTooLargeError(response, responseContext);
33371
+ if (total > this.responseLimit) {
33372
+ await this.stopReader(reader);
33373
+ throw this.sizeError(response, responseContext);
33286
33374
  }
33287
33375
  chunks.push(value);
33288
33376
  }
33289
- return this.decodeChunks(chunks, total);
33290
- }
33291
- decodeChunks(chunks, total) {
33292
33377
  const bytes = new Uint8Array(total);
33293
33378
  let offset = 0;
33294
33379
  for (const chunk of chunks) {
@@ -33297,35 +33382,35 @@ var WABTransport = class {
33297
33382
  }
33298
33383
  return new TextDecoder().decode(bytes);
33299
33384
  }
33300
- responseTooLargeError(response, responseContext) {
33301
- return new WABClientError("WAB_RESPONSE_TOO_LARGE", "WAB response exceeded the configured size limit.", false, response.status, responseContext);
33385
+ sizeError(response, responseContext) {
33386
+ return new WABClientError("WAB_RESPONSE_TOO_LARGE", "WAB response exceeds its size limit.", false, response.status, responseContext);
33302
33387
  }
33303
- async cancelResponseBody(response) {
33388
+ async stopBody(response) {
33304
33389
  try {
33305
33390
  await response.body?.cancel();
33306
33391
  } catch {}
33307
33392
  }
33308
- async cancelResponseReader(reader) {
33393
+ async stopReader(reader) {
33309
33394
  try {
33310
33395
  await reader.cancel();
33311
33396
  } catch {}
33312
33397
  }
33313
- captureFailure(operation, method, path, correlationId, startedAt, error) {
33398
+ report(metadata, error) {
33314
33399
  this.telemetry.capture({
33315
- name: "wallet-toolbox.wab.request.failed",
33316
- component: "wallet-toolbox.wab-transport",
33400
+ name: `${WAB_REQUEST_EVENT}failed`,
33401
+ component: WAB_COMPONENT,
33317
33402
  severity: error.retryable ? "warn" : "error",
33318
- correlationId,
33403
+ correlationId: metadata.correlationId,
33319
33404
  attributes: {
33320
- operation,
33321
- method,
33322
- route: path,
33405
+ operation: metadata.operation,
33406
+ method: metadata.method,
33407
+ route: metadata.path,
33323
33408
  serverOrigin: this.serverOrigin,
33324
33409
  retryable: error.retryable,
33325
33410
  ...error.status !== void 0 ? { status: error.status } : {},
33326
33411
  ...error.endpointMarkerPresent !== void 0 ? { endpointMarkerPresent: error.endpointMarkerPresent } : {},
33327
33412
  ...error.responseCorrelationMatched !== void 0 ? { responseCorrelationMatched: error.responseCorrelationMatched } : {},
33328
- durationMs: Date.now() - startedAt
33413
+ durationMs: Date.now() - metadata.startedAt
33329
33414
  },
33330
33415
  error
33331
33416
  });
@@ -33434,8 +33519,8 @@ var WABClient = class {
33434
33519
  constructor(serverUrl, options = {}) {
33435
33520
  this.transport = new WABTransport(serverUrl, options);
33436
33521
  }
33437
- async getInfo() {
33438
- return await this.transport.request("/info", {
33522
+ getInfo() {
33523
+ return this.transport.request("/info", {
33439
33524
  method: "GET",
33440
33525
  operation: "get-info"
33441
33526
  });
@@ -33445,15 +33530,15 @@ var WABClient = class {
33445
33530
  }
33446
33531
  async startAuthMethod(authMethod, presentationKey, payload, correlationId) {
33447
33532
  assertHexIdentifier(presentationKey, "presentationKey");
33448
- return await authMethod.startAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33533
+ return authMethod.startAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33449
33534
  }
33450
33535
  async completeAuthMethod(authMethod, presentationKey, payload, correlationId) {
33451
33536
  assertHexIdentifier(presentationKey, "presentationKey");
33452
- return await authMethod.completeAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33537
+ return authMethod.completeAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33453
33538
  }
33454
33539
  async listLinkedMethods(presentationKey) {
33455
33540
  assertHexIdentifier(presentationKey, "presentationKey");
33456
- return await this.transport.request("/user/linkedMethods", {
33541
+ return this.transport.request("/user/linkedMethods", {
33457
33542
  operation: "list-linked-methods",
33458
33543
  body: { presentationKey }
33459
33544
  });
@@ -33461,7 +33546,7 @@ var WABClient = class {
33461
33546
  async unlinkMethod(presentationKey, authMethodId) {
33462
33547
  assertHexIdentifier(presentationKey, "presentationKey");
33463
33548
  if (!Number.isSafeInteger(authMethodId) || authMethodId <= 0) throw new TypeError("authMethodId must be a positive safe integer.");
33464
- return await this.transport.request("/user/unlinkMethod", {
33549
+ return this.transport.request("/user/unlinkMethod", {
33465
33550
  operation: "unlink-method",
33466
33551
  body: {
33467
33552
  presentationKey,
@@ -33471,14 +33556,14 @@ var WABClient = class {
33471
33556
  }
33472
33557
  async requestFaucet(presentationKey) {
33473
33558
  assertHexIdentifier(presentationKey, "presentationKey");
33474
- return await this.transport.request("/faucet/request", {
33559
+ return this.transport.request("/faucet/request", {
33475
33560
  operation: "request-faucet",
33476
33561
  body: { presentationKey }
33477
33562
  });
33478
33563
  }
33479
33564
  async deleteUser(presentationKey) {
33480
33565
  assertHexIdentifier(presentationKey, "presentationKey");
33481
- return await this.transport.request("/user/delete", {
33566
+ return this.transport.request("/user/delete", {
33482
33567
  operation: "delete-user",
33483
33568
  body: { presentationKey }
33484
33569
  });
@@ -33487,7 +33572,7 @@ var WABClient = class {
33487
33572
  assertMethodType(methodType);
33488
33573
  assertHexIdentifier(userIdHash, "userIdHash");
33489
33574
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33490
- return await this.transport.request("/auth/start", {
33575
+ return this.transport.request("/auth/start", {
33491
33576
  operation: "start-share-auth",
33492
33577
  body: {
33493
33578
  methodType,
@@ -33500,7 +33585,7 @@ var WABClient = class {
33500
33585
  assertMethodType(methodType);
33501
33586
  assertHexIdentifier(userIdHash, "userIdHash");
33502
33587
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33503
- return await this.transport.request("/share/store", {
33588
+ return this.transport.request("/share/store", {
33504
33589
  operation: "store-share",
33505
33590
  body: {
33506
33591
  methodType,
@@ -33514,7 +33599,7 @@ var WABClient = class {
33514
33599
  assertMethodType(methodType);
33515
33600
  assertHexIdentifier(userIdHash, "userIdHash");
33516
33601
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33517
- return await this.transport.request("/share/retrieve", {
33602
+ return this.transport.request("/share/retrieve", {
33518
33603
  operation: "retrieve-share",
33519
33604
  body: {
33520
33605
  methodType,
@@ -33527,7 +33612,7 @@ var WABClient = class {
33527
33612
  assertMethodType(methodType);
33528
33613
  assertHexIdentifier(userIdHash, "userIdHash");
33529
33614
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33530
- return await this.transport.request("/share/update", {
33615
+ return this.transport.request("/share/update", {
33531
33616
  operation: "update-share",
33532
33617
  body: {
33533
33618
  methodType,
@@ -33541,7 +33626,7 @@ var WABClient = class {
33541
33626
  assertMethodType(methodType);
33542
33627
  assertHexIdentifier(userIdHash, "userIdHash");
33543
33628
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33544
- return await this.transport.request("/share/delete", {
33629
+ return this.transport.request("/share/delete", {
33545
33630
  operation: "delete-share-user",
33546
33631
  body: {
33547
33632
  methodType,
@@ -33555,9 +33640,13 @@ var WABClient = class {
33555
33640
  //#region ../src/WalletAuthenticationManager.ts
33556
33641
  const DEFAULT_AUTH_SESSION_TTL_MS = 600 * 1e3;
33557
33642
  const MAX_AUTH_SESSION_TTL_MS = 3600 * 1e3;
33643
+ const AUTH_COMPONENT = "wallet-toolbox.authentication-manager";
33644
+ const AUTH_EVENT = "wallet-toolbox.authentication.";
33645
+ const EXISTING_USER = "existing-user";
33646
+ const NEW_USER = "new-user";
33558
33647
  var WABAccountContinuityError = class extends Error {
33559
33648
  code = "WERR_WAB_ACCOUNT_CONTINUITY";
33560
- constructor(message = "WAB and UMP account state did not agree. Retry or use account recovery.") {
33649
+ constructor(message = "WAB and UMP accounts disagree; retry or recover.") {
33561
33650
  super(message);
33562
33651
  this.name = "WABAccountContinuityError";
33563
33652
  }
@@ -33572,6 +33661,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33572
33661
  wabClient;
33573
33662
  authMethod;
33574
33663
  authSession;
33664
+ phoneChangeSession;
33575
33665
  authSessionTtlMs;
33576
33666
  constructor(...[adminOriginator, walletBuilder, interactor, recoveryKeySaver, passwordRetriever, wabClient, authMethod, stateSnapshot, options = {}]) {
33577
33667
  super(adminOriginator, walletBuilder, interactor, recoveryKeySaver, passwordRetriever, async (presentationKey, wallet, adminOriginator) => {
@@ -33594,7 +33684,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33594
33684
  description: "Fund wallet",
33595
33685
  options: { acceptDelayedBroadcast: false }
33596
33686
  }, adminOriginator);
33597
- if (faucetRedeemTXCreationResult.signableTransaction == null) throw new Error("Faucet redemption did not return a signableTransaction");
33687
+ if (faucetRedeemTXCreationResult.signableTransaction == null) throw new Error("Faucet redemption was not signable.");
33598
33688
  const faucetRedeemTX = _bsv_sdk.Transaction.fromAtomicBEEF(faucetRedeemTXCreationResult.signableTransaction.tx);
33599
33689
  const faucetRedemptionPuzzle = new _bsv_sdk.RPuzzle();
33600
33690
  const randomRedemptionPrivateKey = _bsv_sdk.PrivateKey.fromRandom();
@@ -33627,7 +33717,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33627
33717
  * using the chosen AuthMethodInteractor.
33628
33718
  */
33629
33719
  async startAuth(payload) {
33630
- if (this.authMethod == null) throw new Error("No AuthMethod selected in WalletAuthenticationManager");
33720
+ if (this.authMethod == null) throw new Error("No WAB authentication method selected.");
33631
33721
  const authMethod = this.authMethod;
33632
33722
  if (this.authenticated) throw new Error("User is already authenticated");
33633
33723
  this.cancelAuth();
@@ -33640,8 +33730,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33640
33730
  ...correlationId !== void 0 ? { correlationId } : {}
33641
33731
  };
33642
33732
  this.telemetry.capture({
33643
- name: "wallet-toolbox.authentication.wab-start.started",
33644
- component: "wallet-toolbox.authentication-manager",
33733
+ name: `${AUTH_EVENT}wab-start.started`,
33734
+ component: AUTH_COMPONENT,
33645
33735
  severity: "debug",
33646
33736
  correlationId,
33647
33737
  attributes: { methodType: authMethod.methodType }
@@ -33653,8 +33743,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33653
33743
  throw new Error(message);
33654
33744
  }
33655
33745
  this.telemetry.capture({
33656
- name: "wallet-toolbox.authentication.wab-start.completed",
33657
- component: "wallet-toolbox.authentication-manager",
33746
+ name: `${AUTH_EVENT}wab-start.completed`,
33747
+ component: AUTH_COMPONENT,
33658
33748
  severity: "info",
33659
33749
  correlationId,
33660
33750
  attributes: { methodType: authMethod.methodType }
@@ -33662,8 +33752,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33662
33752
  } catch (error) {
33663
33753
  this.cancelAuth();
33664
33754
  this.telemetry.capture({
33665
- name: "wallet-toolbox.authentication.wab-start.failed",
33666
- component: "wallet-toolbox.authentication-manager",
33755
+ name: `${AUTH_EVENT}wab-start.failed`,
33756
+ component: AUTH_COMPONENT,
33667
33757
  severity: "warn",
33668
33758
  correlationId,
33669
33759
  attributes: { methodType: authMethod.methodType },
@@ -33676,22 +33766,22 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33676
33766
  * Completes the WAB-based flow, retrieving the final presentationKey from WAB if successful.
33677
33767
  */
33678
33768
  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.");
33769
+ if (this.authMethod == null || this.authSession == null) throw new Error("Start WAB authentication first.");
33680
33770
  const authMethod = this.authMethod;
33681
33771
  if (this.authSession.methodType !== authMethod.methodType) {
33682
33772
  this.cancelAuth();
33683
- throw new Error("The selected authentication method changed. Start authentication again.");
33773
+ throw new Error("WAB authentication method changed; restart.");
33684
33774
  }
33685
33775
  if (Date.now() >= this.authSession.expiresAt) {
33686
33776
  this.cancelAuth();
33687
- throw new Error("The WAB authentication session expired. Start authentication again.");
33777
+ throw new Error("WAB authentication expired; restart.");
33688
33778
  }
33689
33779
  const session = this.authSession;
33690
33780
  const result = await this.wabClient.completeAuthMethod(authMethod, session.presentationKey, payload, session.correlationId);
33691
33781
  if (result.success !== true || result.presentationKey == null || result.presentationKey.length === 0) {
33692
33782
  this.telemetry.capture({
33693
- name: "wallet-toolbox.authentication.wab-complete.rejected",
33694
- component: "wallet-toolbox.authentication-manager",
33783
+ name: `${AUTH_EVENT}wab-complete.rejected`,
33784
+ component: AUTH_COMPONENT,
33695
33785
  severity: "warn",
33696
33786
  correlationId: session.correlationId,
33697
33787
  attributes: { methodType: session.methodType }
@@ -33706,11 +33796,11 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33706
33796
  this.cancelAuth();
33707
33797
  const wabAccountStatus = this.inferAccountStatus(result, session.presentationKey);
33708
33798
  try {
33709
- await this.providePresentationKey(_bsv_sdk.Utils.toArray(result.presentationKey, "hex"));
33799
+ await this.provideWABPresentationKey(result, wabAccountStatus);
33710
33800
  } catch (error) {
33711
33801
  this.telemetry.capture({
33712
- name: "wallet-toolbox.authentication.ump-continuity.failed",
33713
- component: "wallet-toolbox.authentication-manager",
33802
+ name: `${AUTH_EVENT}ump-continuity.failed`,
33803
+ component: AUTH_COMPONENT,
33714
33804
  severity: "warn",
33715
33805
  correlationId: session.correlationId,
33716
33806
  attributes: {
@@ -33721,18 +33811,18 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33721
33811
  });
33722
33812
  throw error;
33723
33813
  }
33724
- if (wabAccountStatus === "existing-user" && this.authenticationFlow !== "existing-user") {
33814
+ if (wabAccountStatus === EXISTING_USER && this.authenticationFlow !== EXISTING_USER) {
33725
33815
  super.destroy();
33726
33816
  const error = new WABAccountContinuityError();
33727
33817
  this.telemetry.capture({
33728
- name: "wallet-toolbox.authentication.account-continuity.mismatch",
33729
- component: "wallet-toolbox.authentication-manager",
33818
+ name: `${AUTH_EVENT}account-continuity.mismatch`,
33819
+ component: AUTH_COMPONENT,
33730
33820
  severity: "error",
33731
33821
  correlationId: session.correlationId,
33732
33822
  attributes: {
33733
33823
  methodType: session.methodType,
33734
33824
  wabAccountStatus,
33735
- umpAccountStatus: "new-user"
33825
+ umpAccountStatus: NEW_USER
33736
33826
  },
33737
33827
  error
33738
33828
  });
@@ -33740,8 +33830,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33740
33830
  }
33741
33831
  const continuity = wabAccountStatus === this.authenticationFlow ? "matched" : "ump-existing";
33742
33832
  this.telemetry.capture({
33743
- name: "wallet-toolbox.authentication.completed",
33744
- component: "wallet-toolbox.authentication-manager",
33833
+ name: `${AUTH_EVENT}completed`,
33834
+ component: AUTH_COMPONENT,
33745
33835
  severity: continuity === "matched" ? "info" : "warn",
33746
33836
  correlationId: session.correlationId,
33747
33837
  attributes: {
@@ -33755,23 +33845,131 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33755
33845
  cancelAuth() {
33756
33846
  this.authSession = void 0;
33757
33847
  }
33848
+ readPendingPhoneChange(result) {
33849
+ const presentationKey = result.pendingPresentationKey;
33850
+ const changeId = result.pendingPhoneChangeId;
33851
+ if (presentationKey === void 0 && changeId === void 0) return void 0;
33852
+ if (!/^[0-9a-fA-F]{64}$/.test(presentationKey ?? "") || !Number.isSafeInteger(changeId) || changeId <= 0) throw new WABAccountContinuityError("WAB returned invalid pending phone-change data.");
33853
+ return {
33854
+ presentationKey,
33855
+ changeId
33856
+ };
33857
+ }
33858
+ async provideWABPresentationKey(result, wabAccountStatus) {
33859
+ const umpTokenOutpoint = typeof result.umpTokenOutpoint === "string" ? result.umpTokenOutpoint : void 0;
33860
+ const lookupOptions = umpTokenOutpoint == null ? void 0 : { pinnedOutpoint: umpTokenOutpoint };
33861
+ const pending = this.readPendingPhoneChange(result);
33862
+ let usePending = false;
33863
+ try {
33864
+ await this.providePresentationKey(_bsv_sdk.Utils.toArray(result.presentationKey, "hex"), lookupOptions);
33865
+ } catch (error) {
33866
+ if (pending == null) throw error;
33867
+ usePending = true;
33868
+ }
33869
+ if (pending != null && (usePending || wabAccountStatus === EXISTING_USER && this.authenticationFlow !== EXISTING_USER)) {
33870
+ await this.providePresentationKey(_bsv_sdk.Utils.toArray(pending.presentationKey, "hex"), lookupOptions);
33871
+ if (this.authenticationFlow === EXISTING_USER) await this.finalizePendingPhoneChange(result.presentationKey, pending);
33872
+ }
33873
+ }
33874
+ async finalizePendingPhoneChange(currentPresentationKey, pending) {
33875
+ const finalized = await this.phoneChange("finalize", {
33876
+ changeId: pending.changeId,
33877
+ presentationKey: currentPresentationKey,
33878
+ newPresentationKey: pending.presentationKey
33879
+ });
33880
+ if (finalized.success !== true || finalized.changeId !== pending.changeId) throw new WABAccountContinuityError(finalized.message || "WAB could not finalize the pending phone change.");
33881
+ }
33882
+ /**
33883
+ * Starts OTP verification for a replacement phone number. The same number
33884
+ * is valid and intentionally produces a fresh presentation key/hash.
33885
+ */
33886
+ async startPhoneNumberChange(phoneNumber) {
33887
+ if (!this.authenticated) throw new Error("Not authenticated");
33888
+ const normalizedPhone = phoneNumber.trim();
33889
+ const currentPresentationKey = _bsv_sdk.Utils.toHex(await this.getFactor("presentationKey"));
33890
+ const response = await this.phoneChange("start", {
33891
+ presentationKey: currentPresentationKey,
33892
+ phoneNumber: normalizedPhone
33893
+ });
33894
+ if (response.success !== true) throw new Error(response.message || "Phone change failed");
33895
+ this.phoneChangeSession = {
33896
+ phoneNumber: normalizedPhone,
33897
+ presentationKey: currentPresentationKey
33898
+ };
33899
+ }
33900
+ /**
33901
+ * Completes phone verification and stages the WAB association before
33902
+ * publishing the UMP key rotation. WAB retains both the current and pending
33903
+ * presentation keys until finalization, so either side of an interrupted
33904
+ * transition remains recoverable on the next verified login.
33905
+ */
33906
+ async completePhoneNumberChange(otp) {
33907
+ const session = this.phoneChangeSession;
33908
+ if (session == null) throw new Error("No phone change");
33909
+ if (session.changeToken == null) {
33910
+ const authorization = await this.phoneChange("complete", {
33911
+ presentationKey: session.presentationKey,
33912
+ phoneNumber: session.phoneNumber,
33913
+ otp: otp.trim()
33914
+ });
33915
+ if (authorization.success !== true) throw new Error(authorization.message || "Phone change failed");
33916
+ if (/^[0-9a-fA-F]{64}$/.test(authorization.pendingPresentationKey ?? "") && Number.isSafeInteger(authorization.pendingPhoneChangeId) && authorization.pendingPhoneChangeId > 0) {
33917
+ session.newKey = _bsv_sdk.Utils.toArray(authorization.pendingPresentationKey, "hex");
33918
+ session.changeId = authorization.pendingPhoneChangeId;
33919
+ } else if (typeof authorization.changeToken === "string" && authorization.changeToken.length > 0) session.changeToken = authorization.changeToken;
33920
+ else throw new Error(authorization.message || "Phone change failed");
33921
+ }
33922
+ session.newKey ??= (0, _bsv_sdk.Random)(32);
33923
+ if (session.changeId == null) {
33924
+ const committed = await this.phoneChange("commit", {
33925
+ changeToken: session.changeToken,
33926
+ presentationKey: session.presentationKey,
33927
+ newPresentationKey: _bsv_sdk.Utils.toHex(session.newKey)
33928
+ });
33929
+ if (committed.success !== true || !Number.isSafeInteger(committed.changeId) || committed.changeId <= 0) throw new Error(committed.message || "Phone change failed");
33930
+ session.changeId = committed.changeId;
33931
+ }
33932
+ const changeId = session.changeId;
33933
+ if (session.umpUpdated !== true) {
33934
+ await this.changePresentationKey(session.newKey);
33935
+ session.umpUpdated = true;
33936
+ }
33937
+ const finalized = await this.phoneChange("finalize", {
33938
+ changeId,
33939
+ presentationKey: session.presentationKey,
33940
+ newPresentationKey: _bsv_sdk.Utils.toHex(session.newKey)
33941
+ });
33942
+ if (finalized.success !== true || finalized.changeId !== changeId) throw new Error(finalized.message || "Phone change failed");
33943
+ this.phoneChangeSession = void 0;
33944
+ return { changeId };
33945
+ }
33946
+ cancelPhoneNumberChange() {
33947
+ this.phoneChangeSession = void 0;
33948
+ }
33758
33949
  destroy() {
33759
33950
  this.cancelAuth();
33951
+ this.cancelPhoneNumberChange();
33760
33952
  super.destroy();
33761
33953
  }
33954
+ phoneChange(phase, body) {
33955
+ return this.wabClient.transport.request(`/auth/phone-change/${phase}`, {
33956
+ operation: "phone-change",
33957
+ body
33958
+ });
33959
+ }
33762
33960
  inferAccountStatus(result, temporaryPresentationKey) {
33763
33961
  if (result.presentationKey == null) throw new WABAccountContinuityError("WAB did not return a presentation key.");
33764
33962
  const keyMatchesTemporary = this.constantTimeHexEqual(result.presentationKey, temporaryPresentationKey);
33765
33963
  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.");
33964
+ if (rawAccountStatus !== void 0 && rawAccountStatus !== NEW_USER && rawAccountStatus !== EXISTING_USER) throw new WABAccountContinuityError("WAB returned an invalid account status.");
33767
33965
  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.");
33966
+ if (rawExistingUser !== void 0 && typeof rawExistingUser !== "boolean") throw new WABAccountContinuityError("WAB returned invalid existing-user data.");
33967
+ if (rawAccountStatus !== void 0 && rawExistingUser !== void 0 && rawAccountStatus === EXISTING_USER !== rawExistingUser) throw new WABAccountContinuityError("WAB returned conflicting account status.");
33770
33968
  let compatibilityStatus;
33771
- if (typeof rawExistingUser === "boolean") compatibilityStatus = rawExistingUser ? "existing-user" : "new-user";
33969
+ if (typeof rawExistingUser === "boolean") compatibilityStatus = rawExistingUser ? EXISTING_USER : NEW_USER;
33772
33970
  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");
33971
+ if (explicitStatus === NEW_USER && !keyMatchesTemporary || explicitStatus === EXISTING_USER && keyMatchesTemporary) throw new WABAccountContinuityError("WAB returned conflicting account status.");
33972
+ return explicitStatus ?? (keyMatchesTemporary ? NEW_USER : EXISTING_USER);
33775
33973
  }
33776
33974
  constantTimeHexEqual(left, right) {
33777
33975
  if (left.length !== right.length) return false;