@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.
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { AuthFetch, BEEF_V1, BEEF_V2, Beef, BeefParty, BigNumber, BlockHeadersService, CachedKeyDeriver, Certificate, Curve, Hash, LocalKVStore, LockingScript, LookupResolver, MasterCertificate, MerklePath, P2PKH, PrivateKey, ProtoWallet, PublicKey, PushDrop, RPuzzle, Random, SHIPBroadcaster, Script, ScriptEvaluationError, Signature, Spend, SymmetricKey, Telemetry, Transaction, TransactionSignature, Utils, Validation, Validation as Validation$1, VerifiableCertificate, createNonce, defaultHttpClient, verifyNonce } from "@bsv/sdk";
2
+ import { AuthFetch, BEEF_V1, BEEF_V2, Beef, BeefParty, BeefTx, BigNumber, BlockHeadersService, CachedKeyDeriver, Certificate, Curve, Hash, LocalKVStore, LockingScript, LookupResolver, MasterCertificate, MerklePath, P2PKH, PrivateKey, ProtoWallet, PublicKey, PushDrop, RPuzzle, Random, SHIPBroadcaster, Script, ScriptEvaluationError, Signature, Spend, SymmetricKey, Telemetry, Transaction, TransactionSignature, Utils, Validation, Validation as Validation$1, VerifiableCertificate, createNonce, defaultHttpClient, verifyNonce } from "@bsv/sdk";
3
3
  import { deleteDB, openDB } from "idb";
4
4
  import { AESGCM, AESGCMDecrypt } from "@bsv/sdk/primitives/AESGCM";
5
5
  import argon2Api from "hash-wasm/dist/argon2.umd.min.js";
@@ -4046,7 +4046,7 @@ var EntitySyncState = class EntitySyncState extends EntityBase {
4046
4046
  log += formatSyncSection("OUTPUTS", c.outputs, (r) => `${r.outputId} ${r.txid}.${r.vout} ${r.transactionId} ${r.spendable ? "spendable" : ""} sats:${r.satoshis}`);
4047
4047
  return log;
4048
4048
  }
4049
- async processSyncChunk(writer, args, chunk) {
4049
+ async processSyncChunk(writer, args, chunk, trx) {
4050
4050
  const mes = [
4051
4051
  new MergeEntity(chunk.provenTxs, EntityProvenTx.mergeFind, this.syncMap.provenTx),
4052
4052
  new MergeEntity(chunk.outputBaskets, EntityOutputBasket.mergeFind, this.syncMap.outputBasket),
@@ -4067,16 +4067,16 @@ var EntitySyncState = class EntitySyncState extends EntityBase {
4067
4067
  let done = true;
4068
4068
  if (chunk.user != null) {
4069
4069
  const ei = chunk.user;
4070
- const { found, eo } = await EntityUser.mergeFind(writer, this.userId, ei);
4070
+ const { found, eo } = await EntityUser.mergeFind(writer, this.userId, ei, trx);
4071
4071
  if (found) {
4072
- if (await eo.mergeExisting(writer, args.since, ei)) {
4072
+ if (await eo.mergeExisting(writer, args.since, ei, void 0, trx)) {
4073
4073
  maxUpdated_at = maxDate(maxUpdated_at, ei.updated_at);
4074
4074
  updates++;
4075
4075
  }
4076
4076
  }
4077
4077
  }
4078
4078
  for (const me of mes) {
4079
- const r = await me.merge(args.since, writer, this.userId, this.syncMap);
4079
+ const r = await me.merge(args.since, writer, this.userId, this.syncMap, trx);
4080
4080
  me.esm.count += me.stateArray?.length || 0;
4081
4081
  updates += r.updates;
4082
4082
  inserts += r.inserts;
@@ -4087,7 +4087,7 @@ var EntitySyncState = class EntitySyncState extends EntityBase {
4087
4087
  this.when = maxUpdated_at;
4088
4088
  for (const me of mes) me.esm.count = 0;
4089
4089
  }
4090
- await this.updateStorage(writer, false);
4090
+ await this.updateStorage(writer, false, trx);
4091
4091
  return {
4092
4092
  done,
4093
4093
  maxUpdated_at,
@@ -7810,6 +7810,23 @@ function mergePriorOptions(caVargs, saArgs) {
7810
7810
  return Validation.validateSignActionArgs(saArgs);
7811
7811
  }
7812
7812
  //#endregion
7813
+ //#region ../src/utility/canonicalizeAtomicBeef.ts
7814
+ /**
7815
+ * Restricts an AtomicBEEF envelope to the transaction named by its BRC-95
7816
+ * prefix and that transaction's recursive dependency closure.
7817
+ *
7818
+ * Older senders could serialize unrelated, otherwise valid BEEF branches into
7819
+ * an AtomicBEEF envelope. Those branches are not part of the payment proof and
7820
+ * must not influence internalization. Proof and transaction validation still
7821
+ * run against the returned closure at each wallet trust boundary.
7822
+ */
7823
+ function canonicalizeAtomicBeef(bytes) {
7824
+ const received = bytes instanceof Uint8Array ? Beef.fromBinaryView(bytes) : Beef.fromBinary(bytes);
7825
+ const txid = received.atomicTxid;
7826
+ if (txid == null || received.findTxid(txid) == null || received.isAtomic(txid)) return received;
7827
+ return Beef.fromBinary(received.toBinaryAtomic(txid));
7828
+ }
7829
+ //#endregion
7813
7830
  //#region ../src/signer/methods/internalizeAction.ts
7814
7831
  /**
7815
7832
  * Internalize Action allows a wallet to take ownership of outputs in a pre-existing transaction.
@@ -7851,7 +7868,7 @@ function mergePriorOptions(caVargs, saArgs) {
7851
7868
  */
7852
7869
  async function internalizeAction$1(wallet, auth, args) {
7853
7870
  const vargs = Validation.validateInternalizeActionArgs(args);
7854
- const { tx } = await validateAtomicBeef();
7871
+ const { ab, tx, txid } = await validateAtomicBeef();
7855
7872
  const brc29ProtocolID = [2, "3241645161d8"];
7856
7873
  for (const o of vargs.outputs) {
7857
7874
  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}`);
@@ -7865,7 +7882,10 @@ async function internalizeAction$1(wallet, auth, args) {
7865
7882
  default: throw new WERR_INTERNAL(`unexpected protocol ${o.protocol}`);
7866
7883
  }
7867
7884
  }
7868
- return await wallet.storage.internalizeAction(args);
7885
+ return await wallet.storage.internalizeAction({
7886
+ ...args,
7887
+ tx: ab.toBinaryAtomic(txid)
7888
+ });
7869
7889
  function setupWalletPaymentForOutput(o, _dargs) {
7870
7890
  const p = o.paymentRemittance;
7871
7891
  const output = tx.outputs[o.outputIndex];
@@ -7888,7 +7908,7 @@ async function internalizeAction$1(wallet, auth, args) {
7888
7908
  * 2. That the proofs are for the same block as recorded in the wallet's configured storage in the event of a reorg.
7889
7909
  */
7890
7910
  async function validateAtomicBeef() {
7891
- const ab = Beef.fromBinary(vargs.tx);
7911
+ const ab = canonicalizeAtomicBeef(vargs.tx);
7892
7912
  if (!await ab.verify(await wallet.getServices().getChainTracker(), false) || !ab.atomicTxid) {
7893
7913
  console.log(`internalizeAction beef is invalid: ${ab.toLogString()}`);
7894
7914
  throw new WERR_INVALID_PARAMETER("tx", "valid AtomicBEEF");
@@ -8219,28 +8239,70 @@ function verifyActionBatchManifestDigest(manifest) {
8219
8239
  //#endregion
8220
8240
  //#region ../src/utility/beefForTxids.ts
8221
8241
  /**
8222
- * Return the minimal subgraph needed to prove the requested transactions.
8242
+ * Return a minimal BEEF when the source contains data outside the requested
8243
+ * transaction dependency closure. Return undefined when no pruning is needed.
8244
+ *
8245
+ * This form lets forwarding clients retain the caller's original bytes in the
8246
+ * common no-op case instead of rebuilding and reserializing an equivalent BEEF.
8247
+ */
8248
+ function pruneBeefForTxids(source, txids) {
8249
+ const selection = selectTransactions(source, txids);
8250
+ if (selection.transactions.size === source.txs.length && selection.bumpIndexes.size === source.bumps.length) return;
8251
+ return copySelection(source, selection);
8252
+ }
8253
+ /**
8254
+ * Return an independent minimal BEEF needed to prove the requested transactions.
8223
8255
  *
8224
- * Parents are added before children so the resulting BEEF preserves dependency
8225
- * order. Shared ancestors and bumps are merged only once.
8256
+ * Transactions remain in source order and are sorted by Beef when serialized.
8257
+ * The source is indexed and walked once, using an explicit stack so a hostile
8258
+ * dependency depth cannot exhaust the JavaScript call stack.
8226
8259
  */
8227
8260
  function beefForTxids(source, txids) {
8228
- const beef = new Beef();
8261
+ return copySelection(source, selectTransactions(source, txids));
8262
+ }
8263
+ function selectTransactions(source, txids) {
8264
+ const byTxid = /* @__PURE__ */ new Map();
8265
+ for (const tx of source.txs) byTxid.set(tx.txid, tx);
8266
+ const transactions = /* @__PURE__ */ new Set();
8267
+ const bumpIndexes = /* @__PURE__ */ new Set();
8229
8268
  const visited = /* @__PURE__ */ new Set();
8230
- const visit = (txid) => {
8231
- if (visited.has(txid)) return;
8269
+ const stack = [...txids];
8270
+ while (stack.length > 0) {
8271
+ const txid = stack.pop();
8272
+ if (txid == null || visited.has(txid)) continue;
8232
8273
  visited.add(txid);
8233
- const sourceTx = source.findTxid(txid);
8234
- if (sourceTx == null) return;
8235
- if (sourceTx.tx != null) {
8236
- for (const input of sourceTx.tx.inputs) if (input.sourceTXID != null) visit(input.sourceTXID);
8237
- }
8238
- if (sourceTx.bumpIndex != null) beef.mergeBump(source.bumps[sourceTx.bumpIndex]);
8239
- beef.mergeBeefTx(sourceTx);
8274
+ const tx = byTxid.get(txid);
8275
+ if (tx == null) continue;
8276
+ transactions.add(tx);
8277
+ const bumpIndex = tx.bumpIndex;
8278
+ if (bumpIndex != null && Number.isSafeInteger(bumpIndex) && bumpIndex >= 0 && bumpIndex < source.bumps.length) bumpIndexes.add(bumpIndex);
8279
+ for (const inputTxid of tx.inputTxids) if (!visited.has(inputTxid)) stack.push(inputTxid);
8280
+ }
8281
+ return {
8282
+ transactions,
8283
+ bumpIndexes
8240
8284
  };
8241
- for (const txid of txids) visit(txid);
8285
+ }
8286
+ function copySelection(source, selection) {
8287
+ const beef = new Beef(source.version);
8288
+ const bumpIndexMap = /* @__PURE__ */ new Map();
8289
+ for (let index = 0; index < source.bumps.length; index++) {
8290
+ if (!selection.bumpIndexes.has(index)) continue;
8291
+ bumpIndexMap.set(index, beef.bumps.length);
8292
+ beef.bumps.push(cloneMerklePath(source.bumps[index]));
8293
+ }
8294
+ for (const sourceTx of source.txs) {
8295
+ if (!selection.transactions.has(sourceTx)) continue;
8296
+ const bumpIndex = sourceTx.bumpIndex == null ? void 0 : bumpIndexMap.get(sourceTx.bumpIndex);
8297
+ const rawTx = sourceTx.rawTxUint8Array;
8298
+ const copy = rawTx == null ? BeefTx.fromTxid(sourceTx.txid, bumpIndex) : new BeefTx(Uint8Array.from(rawTx), bumpIndex, Array.from(sourceTx.inputTxids));
8299
+ beef.txs.push(copy);
8300
+ }
8242
8301
  return beef;
8243
8302
  }
8303
+ function cloneMerklePath(source) {
8304
+ return new MerklePath(source.blockHeight, source.path.map((level) => level.map((leaf) => ({ ...leaf }))), false, false);
8305
+ }
8244
8306
  //#endregion
8245
8307
  //#region ../src/storage/methods/offsetKey.ts
8246
8308
  function keyOffsetToHashedSecret(pub, keyOffset) {
@@ -10938,7 +11000,7 @@ function validateRequiredOutputs(storage, userId, vargs) {
10938
11000
  * @returns {xinputs} extended validated required inputs.
10939
11001
  */
10940
11002
  async function validateRequiredInputs(storage, userId, vargs) {
10941
- const beef = new Beef();
11003
+ let beef = new Beef();
10942
11004
  if (vargs.inputs.length === 0) return {
10943
11005
  storageBeef: beef,
10944
11006
  beef,
@@ -10964,6 +11026,7 @@ async function validateRequiredInputs(storage, userId, vargs) {
10964
11026
  inputsByTxid[input.outpoint.txid] ||= [];
10965
11027
  inputsByTxid[input.outpoint.txid].push(input);
10966
11028
  }
11029
+ beef = beefForTxids(beef, Object.keys(inputsByTxid));
10967
11030
  const localKnownInputTxids = {};
10968
11031
  for (const [txid, txInputs] of Object.entries(inputsByTxid)) localKnownInputTxids[txid] = txInputs.every((input) => {
10969
11032
  const output = preloadedOutputsByOutpoint[`${input.outpoint.txid}.${input.outpoint.vout}`];
@@ -12378,7 +12441,7 @@ var InternalizeActionContext = class {
12378
12441
  * @returns
12379
12442
  */
12380
12443
  async validateAtomicBeef(atomicBeef) {
12381
- const ab = atomicBeef instanceof Uint8Array ? Beef.fromBinaryView(atomicBeef) : Beef.fromBinary(atomicBeef);
12444
+ const ab = canonicalizeAtomicBeef(atomicBeef);
12382
12445
  if (!await ab.verify(await this.storage.getServices().getChainTracker(), false) || !ab.atomicTxid) throw new WERR_INVALID_PARAMETER("tx", "valid AtomicBEEF");
12383
12446
  const txid = ab.atomicTxid;
12384
12447
  const btx = ab.findTxid(txid);
@@ -15225,11 +15288,19 @@ var StorageProvider = class StorageProvider extends StorageReaderWriter {
15225
15288
  return await this.updateOutput(output.outputId, { basketId: void 0 });
15226
15289
  }
15227
15290
  async processSyncChunk(args, chunk) {
15228
- const user = verifyTruthy(await this.findUserByIdentityKey(args.identityKey));
15229
- return await new EntitySyncState(verifyOne(await this.findSyncStates({ partial: {
15230
- storageIdentityKey: args.fromStorageIdentityKey,
15231
- userId: user.userId
15232
- } }))).processSyncChunk(this, args, chunk);
15291
+ return await this.transaction(async (trx) => {
15292
+ const user = verifyTruthy(verifyOneOrNone(await this.findUsers({
15293
+ partial: { identityKey: args.identityKey },
15294
+ trx
15295
+ })));
15296
+ return await new EntitySyncState(verifyOne(await this.findSyncStates({
15297
+ partial: {
15298
+ storageIdentityKey: args.fromStorageIdentityKey,
15299
+ userId: user.userId
15300
+ },
15301
+ trx
15302
+ }))).processSyncChunk(this, args, chunk, trx);
15303
+ });
15233
15304
  }
15234
15305
  /**
15235
15306
  * Handles storage changes when a valid MerklePath and mined block header are found for a ProvenTxReq txid.
@@ -17294,8 +17365,10 @@ var StorageIdb = class extends StorageProvider {
17294
17365
  await tx.done;
17295
17366
  return r;
17296
17367
  } catch (err) {
17297
- tx.abort();
17298
- await tx.done;
17368
+ try {
17369
+ tx.abort();
17370
+ await tx.done;
17371
+ } catch {}
17299
17372
  throw err;
17300
17373
  }
17301
17374
  }
@@ -18262,6 +18335,25 @@ var StorageClientBase = class {
18262
18335
  * @returns `StorageCreateActionResults` supporting additional wallet processing to yield `createAction` results.
18263
18336
  */
18264
18337
  async createAction(auth, args) {
18338
+ if (args.inputBEEF != null) if (args.inputs.length === 0) args = {
18339
+ ...args,
18340
+ inputBEEF: void 0
18341
+ };
18342
+ else {
18343
+ let source;
18344
+ try {
18345
+ source = Beef.fromBinary(args.inputBEEF);
18346
+ } catch {
18347
+ source = void 0;
18348
+ }
18349
+ if (source != null) {
18350
+ const pruned = pruneBeefForTxids(source, args.inputs.map((input) => input.outpoint.txid));
18351
+ if (pruned != null) args = {
18352
+ ...args,
18353
+ inputBEEF: pruned.toBinary()
18354
+ };
18355
+ }
18356
+ }
18265
18357
  return await this.rpcCall("createAction", [auth, args]);
18266
18358
  }
18267
18359
  /**
@@ -30932,6 +31024,7 @@ var SetupClient = class SetupClient {
30932
31024
  };
30933
31025
  //#endregion
30934
31026
  //#region ../src/CWIStyleWalletManager.ts
31027
+ const CWI_COMPONENT = "wallet-toolbox.cwi-manager";
30935
31028
  /**
30936
31029
  * Number of rounds used in PBKDF2 for deriving password keys.
30937
31030
  */
@@ -31164,11 +31257,11 @@ var OverlayUMPTokenInteractor = class {
31164
31257
  * @param hash The 32-byte SHA-256 hash of the presentation key.
31165
31258
  * @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
31166
31259
  */
31167
- async findByPresentationKeyHash(hash) {
31168
- return await this.findToken({
31260
+ async findByPresentationKeyHash(hash, options) {
31261
+ return this.findToken({
31169
31262
  service: "ls_users",
31170
31263
  query: { presentationHash: Utils.toHex(hash) }
31171
- }, "presentation");
31264
+ }, "presentation", options);
31172
31265
  }
31173
31266
  /**
31174
31267
  * Finds a UMP token on-chain by the given recovery key hash, if it exists.
@@ -31177,13 +31270,13 @@ var OverlayUMPTokenInteractor = class {
31177
31270
  * @param hash The 32-byte SHA-256 hash of the recovery key.
31178
31271
  * @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
31179
31272
  */
31180
- async findByRecoveryKeyHash(hash) {
31181
- return await this.findToken({
31273
+ async findByRecoveryKeyHash(hash, options) {
31274
+ return this.findToken({
31182
31275
  service: "ls_users",
31183
31276
  query: { recoveryHash: Utils.toHex(hash) }
31184
- }, "recovery");
31277
+ }, "recovery", options);
31185
31278
  }
31186
- async findToken(question, lookupKind) {
31279
+ async findToken(question, lookupKind, options) {
31187
31280
  const correlationId = this.telemetry.enabled === true ? this.telemetry.createCorrelationId() : void 0;
31188
31281
  const startedAt = Date.now();
31189
31282
  this.telemetry.capture({
@@ -31200,34 +31293,39 @@ var OverlayUMPTokenInteractor = class {
31200
31293
  correlationId
31201
31294
  });
31202
31295
  } catch (error) {
31203
- const diagnostics = this.emptyLookupDiagnostics(correlationId);
31204
- this.captureLookupFailure(lookupKind, "lookup-unavailable", diagnostics, startedAt, error);
31296
+ const diagnostics = this.emptyStats(correlationId);
31297
+ this.lookupFailed(lookupKind, "lookup-unavailable", diagnostics, startedAt, error);
31205
31298
  throw new UMPTokenLookupError("lookup-unavailable", diagnostics, { cause: error });
31206
31299
  }
31207
- const diagnostics = this.toLookupDiagnostics(resolution);
31300
+ const diagnostics = this.diagnosticsFor(resolution);
31208
31301
  const tokens = this.parseLookupAnswers(resolution.answer);
31209
31302
  const expectedHash = question.query[lookupKind === "presentation" ? "presentationHash" : "recoveryHash"].toLowerCase();
31210
31303
  const matchingTokens = tokens.filter((token) => Utils.toHex(lookupKind === "presentation" ? token.presentationHash : token.recoveryHash).toLowerCase() === expectedHash);
31211
31304
  if (matchingTokens.length > 1) {
31212
31305
  const newest = this.resolveNewestToken(matchingTokens, resolution.answer.outputs);
31213
31306
  if (newest != null) {
31214
- this.captureLookupCompleted(lookupKind, "found", diagnostics, startedAt, { supersededTokens: matchingTokens.length - 1 });
31307
+ this.lookupDone(lookupKind, "found", diagnostics, startedAt, { supersededTokens: matchingTokens.length - 1 });
31215
31308
  return newest;
31216
31309
  }
31310
+ const pinned = options?.pinnedOutpoint ? matchingTokens.find((token) => token.currentOutpoint === options.pinnedOutpoint) : void 0;
31311
+ if (pinned != null) {
31312
+ this.lookupDone(lookupKind, "found", diagnostics, startedAt);
31313
+ return pinned;
31314
+ }
31217
31315
  const reason = "token-ambiguous";
31218
- this.captureLookupFailure(lookupKind, reason, diagnostics, startedAt);
31316
+ this.lookupFailed(lookupKind, reason, diagnostics, startedAt);
31219
31317
  throw new UMPTokenLookupError(reason, diagnostics);
31220
31318
  }
31221
31319
  if (matchingTokens.length === 1) {
31222
- this.captureLookupCompleted(lookupKind, "found", diagnostics, startedAt);
31320
+ this.lookupDone(lookupKind, "found", diagnostics, startedAt);
31223
31321
  return matchingTokens[0];
31224
31322
  }
31225
31323
  if (resolution.progress.emptyHosts > 0) {
31226
- this.captureLookupCompleted(lookupKind, "not-found", diagnostics, startedAt);
31324
+ this.lookupDone(lookupKind, "not-found", diagnostics, startedAt);
31227
31325
  return;
31228
31326
  }
31229
31327
  const reason = resolution.answer.outputs.length > 0 ? "token-malformed" : "lookup-incomplete";
31230
- this.captureLookupFailure(lookupKind, reason, diagnostics, startedAt);
31328
+ this.lookupFailed(lookupKind, reason, diagnostics, startedAt);
31231
31329
  throw new UMPTokenLookupError(reason, diagnostics);
31232
31330
  }
31233
31331
  /**
@@ -31258,7 +31356,7 @@ var OverlayUMPTokenInteractor = class {
31258
31356
  spent: /* @__PURE__ */ new Set()
31259
31357
  };
31260
31358
  evidence.txs.push(tx);
31261
- this.collectSpentOutpoints(tx, evidence.spent, /* @__PURE__ */ new Set());
31359
+ this.collectSpends(tx, evidence.spent, /* @__PURE__ */ new Set());
31262
31360
  evidenceByCandidate.set(outpoint, evidence);
31263
31361
  } catch {}
31264
31362
  if (evidenceByCandidate.size !== candidates.size) return void 0;
@@ -31267,7 +31365,7 @@ var OverlayUMPTokenInteractor = class {
31267
31365
  const provenContinuations = survivors.filter((outpoint) => {
31268
31366
  const evidence = evidenceByCandidate.get(outpoint);
31269
31367
  const token = candidates.get(outpoint);
31270
- return evidence != null && token != null && evidence.txs.some((tx) => this.consumesSameIdentityToken(tx, token));
31368
+ return evidence != null && token != null && evidence.txs.some((tx) => this.consumesIdentity(tx, token));
31271
31369
  });
31272
31370
  if (provenContinuations.length !== 1) return void 0;
31273
31371
  return candidates.get(provenContinuations[0]);
@@ -31278,7 +31376,7 @@ var OverlayUMPTokenInteractor = class {
31278
31376
  * hash — on-chain proof that the candidate is an update of a same-identity
31279
31377
  * predecessor rather than an independently minted token.
31280
31378
  */
31281
- consumesSameIdentityToken(tx, token) {
31379
+ consumesIdentity(tx, token) {
31282
31380
  const presentationHash = Utils.toHex(token.presentationHash);
31283
31381
  const recoveryHash = Utils.toHex(token.recoveryHash);
31284
31382
  for (const input of tx.inputs) {
@@ -31304,7 +31402,7 @@ var OverlayUMPTokenInteractor = class {
31304
31402
  * renditions are absent from the lookup answer. Iterative so arbitrarily
31305
31403
  * long update chains cannot exhaust the call stack.
31306
31404
  */
31307
- collectSpentOutpoints(tx, spent, visited) {
31405
+ collectSpends(tx, spent, visited) {
31308
31406
  const pending = [tx];
31309
31407
  while (pending.length > 0) {
31310
31408
  const current = pending.pop();
@@ -31319,7 +31417,7 @@ var OverlayUMPTokenInteractor = class {
31319
31417
  }
31320
31418
  }
31321
31419
  }
31322
- emptyLookupDiagnostics(correlationId) {
31420
+ emptyStats(correlationId) {
31323
31421
  return {
31324
31422
  hostCount: 0,
31325
31423
  completedHosts: 0,
@@ -31332,7 +31430,7 @@ var OverlayUMPTokenInteractor = class {
31332
31430
  ...correlationId !== void 0 ? { correlationId } : {}
31333
31431
  };
31334
31432
  }
31335
- toLookupDiagnostics(resolution) {
31433
+ diagnosticsFor(resolution) {
31336
31434
  const progress = resolution.progress;
31337
31435
  return {
31338
31436
  hostCount: progress.hostCount,
@@ -31346,7 +31444,7 @@ var OverlayUMPTokenInteractor = class {
31346
31444
  ...progress.correlationId !== void 0 ? { correlationId: progress.correlationId } : {}
31347
31445
  };
31348
31446
  }
31349
- lookupDiagnosticAttributes(diagnostics) {
31447
+ lookupAttrs(diagnostics) {
31350
31448
  return {
31351
31449
  hostCount: diagnostics.hostCount,
31352
31450
  completedHosts: diagnostics.completedHosts,
@@ -31358,7 +31456,7 @@ var OverlayUMPTokenInteractor = class {
31358
31456
  outputCount: diagnostics.outputCount
31359
31457
  };
31360
31458
  }
31361
- captureLookupCompleted(lookupKind, result, diagnostics, startedAt, extraAttributes = {}) {
31459
+ lookupDone(lookupKind, result, diagnostics, startedAt, extraAttributes = {}) {
31362
31460
  this.telemetry.capture({
31363
31461
  name: "wallet-toolbox.ump.lookup.completed",
31364
31462
  component: "wallet-toolbox.ump",
@@ -31368,12 +31466,12 @@ var OverlayUMPTokenInteractor = class {
31368
31466
  lookupKind,
31369
31467
  result,
31370
31468
  durationMs: Date.now() - startedAt,
31371
- ...this.lookupDiagnosticAttributes(diagnostics),
31469
+ ...this.lookupAttrs(diagnostics),
31372
31470
  ...extraAttributes
31373
31471
  }
31374
31472
  });
31375
31473
  }
31376
- captureLookupFailure(lookupKind, reason, diagnostics, startedAt, error) {
31474
+ lookupFailed(lookupKind, reason, diagnostics, startedAt, error) {
31377
31475
  this.telemetry.capture({
31378
31476
  name: "wallet-toolbox.ump.lookup.indeterminate",
31379
31477
  component: "wallet-toolbox.ump",
@@ -31383,7 +31481,7 @@ var OverlayUMPTokenInteractor = class {
31383
31481
  lookupKind,
31384
31482
  reason,
31385
31483
  durationMs: Date.now() - startedAt,
31386
- ...this.lookupDiagnosticAttributes(diagnostics)
31484
+ ...this.lookupAttrs(diagnostics)
31387
31485
  },
31388
31486
  error
31389
31487
  });
@@ -31401,27 +31499,27 @@ var OverlayUMPTokenInteractor = class {
31401
31499
  * @returns The outpoint of the newly created UMP token (e.g. "abcd1234...ef.0").
31402
31500
  */
31403
31501
  async buildAndSend(wallet, adminOriginator, token, oldTokenToConsume) {
31404
- const fields = this.buildUMPTokenFields(token);
31502
+ const fields = this.tokenFields(token);
31405
31503
  const tokenOutput = [{
31406
31504
  lockingScript: (await new PushDrop(wallet, adminOriginator).lock(fields, [2, "admin user management token"], "1", "self", true, true)).toHex(),
31407
31505
  satoshis: 1,
31408
31506
  outputDescription: "New UMP token output"
31409
31507
  }];
31410
- const { resolvedOldToken, inputToken } = await this.resolveOldTokenInput(oldTokenToConsume);
31508
+ const { resolvedOldToken, inputToken } = await this.resolveOldInput(oldTokenToConsume);
31411
31509
  const inputs = resolvedOldToken?.currentOutpoint ? [{
31412
31510
  outpoint: resolvedOldToken.currentOutpoint,
31413
31511
  unlockingScriptLength: 73,
31414
31512
  inputDescription: "Consume old UMP token"
31415
31513
  }] : [];
31416
- const createResult = await this.createUMPAction(wallet, adminOriginator, inputs, tokenOutput, inputToken, resolvedOldToken);
31417
- if (!createResult.signableTransaction) return await this.broadcastFinishedUMPAction(createResult);
31514
+ const createResult = await this.createAction(wallet, adminOriginator, inputs, tokenOutput, inputToken, resolvedOldToken);
31515
+ if (!createResult.signableTransaction) return this.broadcastFinal(createResult);
31418
31516
  const reference = createResult.signableTransaction.reference;
31419
31517
  const partialTx = Transaction.fromBEEF(createResult.signableTransaction.tx);
31420
- if (resolvedOldToken?.currentOutpoint) return await this.signAndBroadcastWithOldToken(wallet, adminOriginator, reference, partialTx);
31421
- return await this.signAndBroadcastNewToken(wallet, adminOriginator, reference);
31518
+ if (resolvedOldToken?.currentOutpoint) return this.renewToken(wallet, adminOriginator, reference, partialTx);
31519
+ return this.broadcastNew(wallet, adminOriginator, reference);
31422
31520
  }
31423
31521
  /** Assembles the ordered number[][] fields array from a UMPToken. */
31424
- buildUMPTokenFields(token) {
31522
+ tokenFields(token) {
31425
31523
  const fields = [];
31426
31524
  fields[0] = token.passwordSalt;
31427
31525
  fields[1] = token.passwordPresentationPrimary;
@@ -31448,20 +31546,20 @@ var OverlayUMPTokenInteractor = class {
31448
31546
  return fields;
31449
31547
  }
31450
31548
  /** Looks up the old token on the overlay; returns undefined resolved token if not found. */
31451
- async resolveOldTokenInput(oldTokenToConsume) {
31549
+ async resolveOldInput(oldTokenToConsume) {
31452
31550
  if (!oldTokenToConsume?.currentOutpoint) return {
31453
31551
  resolvedOldToken: void 0,
31454
31552
  inputToken: void 0
31455
31553
  };
31456
31554
  const inputToken = await this.findByOutpoint(oldTokenToConsume.currentOutpoint);
31457
- if (inputToken == null) throw new Error("The previous UMP token could not be resolved; refusing to publish a duplicate token.");
31555
+ if (inputToken == null) throw new Error("Previous UMP token unavailable; update refused.");
31458
31556
  return {
31459
31557
  resolvedOldToken: oldTokenToConsume,
31460
31558
  inputToken
31461
31559
  };
31462
31560
  }
31463
31561
  /** Creates the UMP action without dropping a required old-token input on failure. */
31464
- async createUMPAction(wallet, adminOriginator, inputs, outputs, inputToken, resolvedOldToken) {
31562
+ async createAction(wallet, adminOriginator, inputs, outputs, inputToken, resolvedOldToken) {
31465
31563
  try {
31466
31564
  return await wallet.createAction({
31467
31565
  description: resolvedOldToken == null ? "Create new UMP token" : "Renew UMP token (consume old, create new)",
@@ -31488,43 +31586,43 @@ var OverlayUMPTokenInteractor = class {
31488
31586
  }
31489
31587
  }
31490
31588
  /** Handles a fully-finalized (no signable tx) createAction result — broadcasts and returns outpoint. */
31491
- async broadcastFinishedUMPAction(createResult) {
31589
+ async broadcastFinal(createResult) {
31492
31590
  const finalTxid = createResult.txid || (createResult.tx != null ? Transaction.fromAtomicBEEF(createResult.tx).id("hex") : void 0);
31493
- if (!finalTxid) throw new Error("No signableTransaction and no final TX found.");
31494
- if (createResult.tx == null) throw new Error("No final TX data to broadcast.");
31591
+ if (!finalTxid) throw new Error("UMP transaction was not finalized.");
31592
+ if (createResult.tx == null) throw new Error("UMP transaction data missing.");
31495
31593
  const broadcastTx = Transaction.fromAtomicBEEF(createResult.tx);
31496
31594
  const result = await this.broadcaster.broadcast(broadcastTx);
31497
- this.assertSuccessfulBroadcast(result, "create-finalized");
31595
+ this.assertBroadcast(result, "create-finalized");
31498
31596
  return `${finalTxid}.0`;
31499
31597
  }
31500
31598
  /** Signs the old-token input and broadcasts — used during UMP token renewal. */
31501
- async signAndBroadcastWithOldToken(wallet, adminOriginator, reference, partialTx) {
31599
+ async renewToken(wallet, adminOriginator, reference, partialTx) {
31502
31600
  const unlockingScript = await new PushDrop(wallet, adminOriginator).unlock([2, "admin user management token"], "1", "self").sign(partialTx, 0);
31503
31601
  const signResult = await wallet.signAction({
31504
31602
  reference,
31505
31603
  spends: { 0: { unlockingScript: unlockingScript.toHex() } }
31506
31604
  }, adminOriginator);
31507
31605
  const finalTxid = signResult.txid || (signResult.tx == null ? "" : Transaction.fromAtomicBEEF(signResult.tx).id("hex"));
31508
- if (!finalTxid) throw new Error("Could not finalize transaction for renewed UMP token.");
31509
- if (signResult.tx == null) throw new Error("Final transaction data missing after signing renewed UMP token.");
31606
+ if (!finalTxid) throw new Error("Could not finalize renewed UMP token.");
31607
+ if (signResult.tx == null) throw new Error("Renewed UMP token transaction data missing.");
31510
31608
  const result = await this.broadcaster.broadcast(Transaction.fromAtomicBEEF(signResult.tx));
31511
- this.assertSuccessfulBroadcast(result, "renew");
31609
+ this.assertBroadcast(result, "renew");
31512
31610
  return `${finalTxid}.0`;
31513
31611
  }
31514
31612
  /** Signs without input spending and broadcasts — used when creating a brand-new UMP token. */
31515
- async signAndBroadcastNewToken(wallet, adminOriginator, reference) {
31613
+ async broadcastNew(wallet, adminOriginator, reference) {
31516
31614
  const signResult = await wallet.signAction({
31517
31615
  reference,
31518
31616
  spends: {}
31519
31617
  }, adminOriginator);
31520
31618
  const finalTxid = signResult.txid || (signResult.tx == null ? "" : Transaction.fromAtomicBEEF(signResult.tx).id("hex"));
31521
- if (!finalTxid) throw new Error("Failed to finalize new UMP token transaction.");
31522
- if (signResult.tx == null) throw new Error("Final transaction data missing after signing new UMP token.");
31619
+ if (!finalTxid) throw new Error("Could not finalize new UMP token.");
31620
+ if (signResult.tx == null) throw new Error("New UMP token transaction data missing.");
31523
31621
  const result = await this.broadcaster.broadcast(Transaction.fromAtomicBEEF(signResult.tx));
31524
- this.assertSuccessfulBroadcast(result, "create");
31622
+ this.assertBroadcast(result, "create");
31525
31623
  return `${finalTxid}.0`;
31526
31624
  }
31527
- assertSuccessfulBroadcast(result, operation) {
31625
+ assertBroadcast(result, operation) {
31528
31626
  const succeeded = result.status === "success";
31529
31627
  this.telemetry.capture({
31530
31628
  name: succeeded ? "wallet-toolbox.ump.broadcast.completed" : "wallet-toolbox.ump.broadcast.failed",
@@ -31553,12 +31651,12 @@ var OverlayUMPTokenInteractor = class {
31553
31651
  if (answer.type !== "output-list" || answer.outputs.length === 0) return [];
31554
31652
  const tokens = [];
31555
31653
  for (const output of answer.outputs) {
31556
- const token = this.parseLookupOutput(output);
31654
+ const token = this.parseOutput(output);
31557
31655
  if (token != null) tokens.push(token);
31558
31656
  }
31559
31657
  return tokens;
31560
31658
  }
31561
- parseLookupOutput(output) {
31659
+ parseOutput(output) {
31562
31660
  try {
31563
31661
  const tx = Transaction.fromBEEF(output.beef);
31564
31662
  const txOutput = tx.outputs[output.outputIndex];
@@ -31608,14 +31706,14 @@ var OverlayUMPTokenInteractor = class {
31608
31706
  correlationId
31609
31707
  });
31610
31708
  } catch (error) {
31611
- const diagnostics = this.emptyLookupDiagnostics(correlationId);
31612
- this.captureLookupFailure("outpoint", "lookup-unavailable", diagnostics, startedAt, error);
31709
+ const diagnostics = this.emptyStats(correlationId);
31710
+ this.lookupFailed("outpoint", "lookup-unavailable", diagnostics, startedAt, error);
31613
31711
  throw new UMPTokenLookupError("lookup-unavailable", diagnostics, { cause: error });
31614
31712
  }
31615
31713
  if (resolution.answer.outputs.length === 0) {
31616
31714
  if (resolution.progress.emptyHosts === 0) {
31617
- const diagnostics = this.toLookupDiagnostics(resolution);
31618
- this.captureLookupFailure("outpoint", "lookup-incomplete", diagnostics, startedAt);
31715
+ const diagnostics = this.diagnosticsFor(resolution);
31716
+ this.lookupFailed("outpoint", "lookup-incomplete", diagnostics, startedAt);
31619
31717
  throw new UMPTokenLookupError("lookup-incomplete", diagnostics);
31620
31718
  }
31621
31719
  return;
@@ -31757,20 +31855,20 @@ var CWIStyleWalletManager = class {
31757
31855
  if (this._initSnapshot !== void 0) {
31758
31856
  this.telemetry.capture({
31759
31857
  name: "wallet-toolbox.snapshot.initialization.started",
31760
- component: "wallet-toolbox.cwi-manager",
31858
+ component: CWI_COMPONENT,
31761
31859
  severity: "debug"
31762
31860
  });
31763
31861
  try {
31764
31862
  await this.loadSnapshot(this._initSnapshot);
31765
31863
  this.telemetry.capture({
31766
31864
  name: "wallet-toolbox.snapshot.initialization.completed",
31767
- component: "wallet-toolbox.cwi-manager",
31865
+ component: CWI_COMPONENT,
31768
31866
  severity: "info"
31769
31867
  });
31770
31868
  } catch (error) {
31771
31869
  this.telemetry.capture({
31772
31870
  name: "wallet-toolbox.snapshot.initialization.failed",
31773
- component: "wallet-toolbox.cwi-manager",
31871
+ component: CWI_COMPONENT,
31774
31872
  severity: "error",
31775
31873
  error
31776
31874
  });
@@ -31779,9 +31877,11 @@ var CWIStyleWalletManager = class {
31779
31877
  }
31780
31878
  }
31781
31879
  /**
31782
- * Provides the presentation key.
31880
+ * Provides the presentation key. A WAB operator pin may be supplied by the
31881
+ * authentication manager; normal lookup and lineage resolution always run
31882
+ * before this ambiguity-only fallback.
31783
31883
  */
31784
- async providePresentationKey(key) {
31884
+ async providePresentationKey(key, lookupOptions) {
31785
31885
  if (this.authenticated) throw new Error("User is already authenticated");
31786
31886
  if (this.authenticationMode === "recovery-key-and-password") throw new Error("Presentation key is not needed in this mode");
31787
31887
  if (key.length !== 32 || key.some((byte) => !Number.isInteger(byte) || byte < 0 || byte > 255)) throw new TypeError("Presentation key must contain exactly 32 bytes.");
@@ -31790,17 +31890,17 @@ var CWIStyleWalletManager = class {
31790
31890
  const startedAt = Date.now();
31791
31891
  this.telemetry.capture({
31792
31892
  name: "wallet-toolbox.authentication.account-lookup.started",
31793
- component: "wallet-toolbox.cwi-manager",
31893
+ component: CWI_COMPONENT,
31794
31894
  severity: "debug",
31795
31895
  attributes: { lookupKind: "presentation" }
31796
31896
  });
31797
31897
  let token;
31798
31898
  try {
31799
- token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash);
31899
+ token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash, lookupOptions);
31800
31900
  } catch (error) {
31801
31901
  this.telemetry.capture({
31802
31902
  name: "wallet-toolbox.authentication.account-lookup.failed",
31803
- component: "wallet-toolbox.cwi-manager",
31903
+ component: CWI_COMPONENT,
31804
31904
  severity: "warn",
31805
31905
  attributes: {
31806
31906
  lookupKind: "presentation",
@@ -31820,7 +31920,7 @@ var CWIStyleWalletManager = class {
31820
31920
  }
31821
31921
  this.telemetry.capture({
31822
31922
  name: "wallet-toolbox.authentication.account-lookup.completed",
31823
- component: "wallet-toolbox.cwi-manager",
31923
+ component: CWI_COMPONENT,
31824
31924
  severity: "info",
31825
31925
  attributes: {
31826
31926
  lookupKind: "presentation",
@@ -31836,11 +31936,11 @@ var CWIStyleWalletManager = class {
31836
31936
  if (this.authenticated) throw new Error("User is already authenticated");
31837
31937
  if (this.authenticationMode === "presentation-key-and-recovery-key") throw new Error("Password is not needed in this mode");
31838
31938
  if (this.authenticationFlow === "unknown") throw new Error("Determine account status with a presentation or recovery key before providing a password.");
31839
- if (this.authenticationFlow === "existing-user") await this.handleExistingUserPassword(password);
31840
- else await this.handleNewUserPassword(password);
31939
+ if (this.authenticationFlow === "existing-user") await this.unlockExisting(password);
31940
+ else await this.createNewUser(password);
31841
31941
  }
31842
31942
  /** Handles the password step for an existing user — derives keys, sets up infrastructure. */
31843
- async handleExistingUserPassword(password) {
31943
+ async unlockExisting(password) {
31844
31944
  if (this.currentUMPToken == null) throw new Error("Provide presentation or recovery key first.");
31845
31945
  const derivedPasswordKey = await derivePasswordKey(this.currentUMPToken, Utils.toArray(password, "utf8"));
31846
31946
  let rootPrimaryKey;
@@ -31853,11 +31953,11 @@ var CWIStyleWalletManager = class {
31853
31953
  rootPrimaryKey = new SymmetricKey(this.XOR(this.recoveryKey, derivedPasswordKey)).decrypt(this.currentUMPToken.passwordRecoveryPrimary);
31854
31954
  rootPrivilegedKey = new SymmetricKey(this.XOR(rootPrimaryKey, derivedPasswordKey)).decrypt(this.currentUMPToken.passwordPrimaryPrivileged);
31855
31955
  }
31856
- await this.setupRootInfrastructure(rootPrimaryKey, rootPrivilegedKey);
31956
+ await this.setupRoot(rootPrimaryKey, rootPrivilegedKey);
31857
31957
  await this.switchProfile(this.activeProfileId);
31858
31958
  }
31859
31959
  /** Handles the password step for a new user — generates keys, builds UMP token, publishes on-chain. */
31860
- async handleNewUserPassword(password) {
31960
+ async createNewUser(password) {
31861
31961
  if (this.authenticationMode !== "presentation-key-and-password") throw new Error("New-user flow requires presentation key and password mode.");
31862
31962
  if (this.presentationKey == null) throw new Error("No presentation key provided for new-user flow.");
31863
31963
  const recoveryKey = Random(32);
@@ -31896,14 +31996,14 @@ var CWIStyleWalletManager = class {
31896
31996
  passwordKdf: this.kdfConfig
31897
31997
  };
31898
31998
  this.currentUMPToken = newToken;
31899
- await this.setupRootInfrastructure(rootPrimaryKey);
31999
+ await this.setupRoot(rootPrimaryKey);
31900
32000
  await this.switchProfile(DEFAULT_PROFILE_ID);
31901
32001
  if (this.newWalletFunder != null && this.underlying != null) try {
31902
32002
  await this.newWalletFunder(this.presentationKey, this.underlying, this.adminOriginator);
31903
32003
  } catch (error) {
31904
32004
  this.telemetry.capture({
31905
32005
  name: "wallet-toolbox.authentication.new-wallet-funding.failed",
31906
- component: "wallet-toolbox.cwi-manager",
32006
+ component: CWI_COMPONENT,
31907
32007
  severity: "error",
31908
32008
  error: /* @__PURE__ */ new Error("New wallet funding failed.")
31909
32009
  });
@@ -31934,7 +32034,7 @@ var CWIStyleWalletManager = class {
31934
32034
  const xorKey = this.XOR(this.presentationKey, recoveryKey);
31935
32035
  const rootPrimaryKey = new SymmetricKey(xorKey).decrypt(this.currentUMPToken.presentationRecoveryPrimary);
31936
32036
  const rootPrivilegedKey = new SymmetricKey(xorKey).decrypt(this.currentUMPToken.presentationRecoveryPrivileged);
31937
- await this.setupRootInfrastructure(rootPrimaryKey, rootPrivilegedKey);
32037
+ await this.setupRoot(rootPrimaryKey, rootPrivilegedKey);
31938
32038
  await this.switchProfile(this.activeProfileId);
31939
32039
  }
31940
32040
  }
@@ -31965,7 +32065,7 @@ var CWIStyleWalletManager = class {
31965
32065
  if (snapshot.length > 16777216) throw new Error("Snapshot exceeds the maximum supported size.");
31966
32066
  this.telemetry.capture({
31967
32067
  name: "wallet-toolbox.snapshot.saved",
31968
- component: "wallet-toolbox.cwi-manager",
32068
+ component: CWI_COMPONENT,
31969
32069
  severity: "info",
31970
32070
  attributes: {
31971
32071
  formatVersion: 2,
@@ -32003,12 +32103,12 @@ var CWIStyleWalletManager = class {
32003
32103
  const tokenBytes = payloadReader.read(tokenLen);
32004
32104
  const token = this.deserializeUMPToken(tokenBytes);
32005
32105
  this.currentUMPToken = token;
32006
- await this.setupRootInfrastructure(rootPrimaryKey);
32106
+ await this.setupRoot(rootPrimaryKey);
32007
32107
  await this.switchProfile(activeProfileId);
32008
32108
  this.authenticationFlow = "existing-user";
32009
32109
  this.telemetry.capture({
32010
32110
  name: "wallet-toolbox.snapshot.loaded",
32011
- component: "wallet-toolbox.cwi-manager",
32111
+ component: CWI_COMPONENT,
32012
32112
  severity: "info",
32013
32113
  attributes: {
32014
32114
  formatVersion: version,
@@ -32019,7 +32119,7 @@ var CWIStyleWalletManager = class {
32019
32119
  this.destroy();
32020
32120
  this.telemetry.capture({
32021
32121
  name: "wallet-toolbox.snapshot.load-failed",
32022
- component: "wallet-toolbox.cwi-manager",
32122
+ component: CWI_COMPONENT,
32023
32123
  severity: "error",
32024
32124
  error
32025
32125
  });
@@ -32036,7 +32136,7 @@ var CWIStyleWalletManager = class {
32036
32136
  if (refreshed == null) return false;
32037
32137
  if (refreshed.currentOutpoint && currentToken.currentOutpoint && refreshed.currentOutpoint === currentToken.currentOutpoint) return false;
32038
32138
  this.currentUMPToken = refreshed;
32039
- await this.setupRootInfrastructure(this.rootPrimaryKey);
32139
+ await this.setupRoot(this.rootPrimaryKey);
32040
32140
  this.saveSnapshot();
32041
32141
  return true;
32042
32142
  }
@@ -32095,7 +32195,7 @@ var CWIStyleWalletManager = class {
32095
32195
  createdAt: Math.floor(Date.now() / 1e3)
32096
32196
  };
32097
32197
  this.profiles.push(newProfile);
32098
- 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);
32198
+ 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);
32099
32199
  return newProfile.id;
32100
32200
  }
32101
32201
  /**
@@ -32112,7 +32212,7 @@ var CWIStyleWalletManager = class {
32112
32212
  if (profileIndex === -1) throw new Error("Profile not found.");
32113
32213
  this.profiles.splice(profileIndex, 1);
32114
32214
  if (this.activeProfileId.every((x, i) => x === profileId[i])) await this.switchProfile(DEFAULT_PROFILE_ID);
32115
- 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);
32215
+ 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);
32116
32216
  }
32117
32217
  /**
32118
32218
  * Switches the active profile. This re-derives keys and rebuilds the underlying wallet.
@@ -32153,14 +32253,14 @@ var CWIStyleWalletManager = class {
32153
32253
  const recoveryKey = await this.getFactor("recoveryKey");
32154
32254
  const presentationKey = await this.getFactor("presentationKey");
32155
32255
  const rootPrivilegedKey = await this.getFactor("privilegedKey");
32156
- await this.updateAuthFactors(passwordSalt, newPasswordKey, presentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32256
+ await this.updateFactors(passwordSalt, newPasswordKey, presentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32157
32257
  }
32158
32258
  /**
32159
32259
  * Retrieves the current recovery key. Requires privileged access.
32160
32260
  */
32161
32261
  async getRecoveryKey() {
32162
32262
  if (!this.authenticated || this.currentUMPToken == null || this.rootPrivilegedKeyManager == null) throw new Error("Not authenticated or missing required data.");
32163
- return await this.getFactor("recoveryKey");
32263
+ return this.getFactor("recoveryKey");
32164
32264
  }
32165
32265
  /**
32166
32266
  * Changes the user's recovery key. Prompts user to save the new key.
@@ -32172,7 +32272,7 @@ var CWIStyleWalletManager = class {
32172
32272
  const rootPrivilegedKey = await this.getFactor("privilegedKey");
32173
32273
  const newRecoveryKey = Random(32);
32174
32274
  await this.recoveryKeySaver(newRecoveryKey);
32175
- await this.updateAuthFactors(this.currentUMPToken.passwordSalt, passwordKey, presentationKey, newRecoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32275
+ await this.updateFactors(this.currentUMPToken.passwordSalt, passwordKey, presentationKey, newRecoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32176
32276
  }
32177
32277
  /**
32178
32278
  * Changes the user's presentation key.
@@ -32183,7 +32283,7 @@ var CWIStyleWalletManager = class {
32183
32283
  const recoveryKey = await this.getFactor("recoveryKey");
32184
32284
  const passwordKey = await this.getFactor("passwordKey");
32185
32285
  const rootPrivilegedKey = await this.getFactor("privilegedKey");
32186
- await this.updateAuthFactors(this.currentUMPToken.passwordSalt, passwordKey, newPresentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32286
+ await this.updateFactors(this.currentUMPToken.passwordSalt, passwordKey, newPresentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32187
32287
  if (this.presentationKey != null) this.presentationKey = newPresentationKey;
32188
32288
  }
32189
32289
  /**
@@ -32229,7 +32329,7 @@ var CWIStyleWalletManager = class {
32229
32329
  } catch (error) {
32230
32330
  this.telemetry.capture({
32231
32331
  name: "wallet-toolbox.authentication.factor-decryption.failed",
32232
- component: "wallet-toolbox.cwi-manager",
32332
+ component: CWI_COMPONENT,
32233
32333
  severity: "error",
32234
32334
  attributes: { factor: factorName },
32235
32335
  error
@@ -32242,7 +32342,7 @@ var CWIStyleWalletManager = class {
32242
32342
  * Recomputes UMP token fields with updated factors and profiles, then publishes the update.
32243
32343
  * This operation requires the *root* privileged key and the *default* profile wallet.
32244
32344
  */
32245
- async updateAuthFactors(passwordSalt, passwordKey, presentationKey, recoveryKey, rootPrimaryKey, rootPrivilegedKey, profiles) {
32345
+ async updateFactors(passwordSalt, passwordKey, presentationKey, recoveryKey, rootPrimaryKey, rootPrivilegedKey, profiles) {
32246
32346
  if (!this.authenticated || this.rootPrimaryKey == null || this.currentUMPToken == null) throw new Error("Wallet is not properly authenticated or missing data for update.");
32247
32347
  const oldTokenToConsume = { ...this.currentUMPToken };
32248
32348
  if (!oldTokenToConsume.currentOutpoint) throw new Error("Cannot update UMP token: Old token has no outpoint.");
@@ -32293,7 +32393,7 @@ var CWIStyleWalletManager = class {
32293
32393
  if (!currentActiveId.every((x) => x === 0)) {
32294
32394
  this.telemetry.capture({
32295
32395
  name: "wallet-toolbox.ump.profile-switch.started",
32296
- component: "wallet-toolbox.cwi-manager",
32396
+ component: CWI_COMPONENT,
32297
32397
  severity: "debug",
32298
32398
  attributes: { reason: "token-update" }
32299
32399
  });
@@ -32309,7 +32409,7 @@ var CWIStyleWalletManager = class {
32309
32409
  await this.switchProfile(currentActiveId);
32310
32410
  this.telemetry.capture({
32311
32411
  name: "wallet-toolbox.ump.profile-switch.completed",
32312
- component: "wallet-toolbox.cwi-manager",
32412
+ component: CWI_COMPONENT,
32313
32413
  severity: "debug",
32314
32414
  attributes: { reason: "token-update" }
32315
32415
  });
@@ -32436,9 +32536,9 @@ var CWIStyleWalletManager = class {
32436
32536
  * @param rootPrimaryKey The user's root primary key (32 bytes).
32437
32537
  * @param ephemeralRootPrivilegedKey Optional root privileged key (e.g., during recovery flows).
32438
32538
  */
32439
- async setupRootInfrastructure(rootPrimaryKey, ephemeralRootPrivilegedKey) {
32539
+ async setupRoot(rootKey, ephemeralRootPrivilegedKey) {
32440
32540
  if (this.currentUMPToken == null) throw new Error("A UMP token must exist before setting up root infrastructure!");
32441
- this.rootPrimaryKey = rootPrimaryKey;
32541
+ this.rootPrimaryKey = rootKey;
32442
32542
  let oneTimePrivilegedKey = ephemeralRootPrivilegedKey == null ? void 0 : new PrivateKey(ephemeralRootPrivilegedKey);
32443
32543
  this.rootPrivilegedKeyManager = new PrivilegedKeyManager(async (reason) => {
32444
32544
  if (oneTimePrivilegedKey != null) {
@@ -32459,7 +32559,7 @@ var CWIStyleWalletManager = class {
32459
32559
  });
32460
32560
  this.profiles = [];
32461
32561
  if (this.currentUMPToken.profilesEncrypted != null && this.currentUMPToken.profilesEncrypted.length > 0) try {
32462
- const decryptedProfileBytes = new SymmetricKey(rootPrimaryKey).decrypt(this.currentUMPToken.profilesEncrypted);
32562
+ const decryptedProfileBytes = new SymmetricKey(rootKey).decrypt(this.currentUMPToken.profilesEncrypted);
32463
32563
  const profilesJson = Utils.toUTF8(decryptedProfileBytes);
32464
32564
  const profiles = JSON.parse(profilesJson);
32465
32565
  if (!Array.isArray(profiles) || profiles.length > 1e3 || !profiles.every(isValidProfile)) throw new Error("Decrypted profile data is invalid or exceeds supported bounds.");
@@ -32468,7 +32568,7 @@ var CWIStyleWalletManager = class {
32468
32568
  this.profiles = [];
32469
32569
  this.telemetry.capture({
32470
32570
  name: "wallet-toolbox.profile.load-failed",
32471
- component: "wallet-toolbox.cwi-manager",
32571
+ component: CWI_COMPONENT,
32472
32572
  severity: "error",
32473
32573
  error
32474
32574
  });
@@ -32477,98 +32577,98 @@ var CWIStyleWalletManager = class {
32477
32577
  }
32478
32578
  this.authenticated = true;
32479
32579
  }
32480
- checkAuthAndUnderlying(originator) {
32580
+ assertReady(originator) {
32481
32581
  if (!this.authenticated) throw new Error("User is not authenticated.");
32482
32582
  if (this.underlying == null) throw new Error("Underlying wallet for the active profile is not initialized.");
32483
32583
  if (originator === this.adminOriginator) throw new Error("External applications are not allowed to use the admin originator.");
32484
32584
  }
32485
32585
  async getPublicKey(args, originator) {
32486
- this.checkAuthAndUnderlying(originator);
32487
- return await this.underlying.getPublicKey(args, originator);
32586
+ this.assertReady(originator);
32587
+ return this.underlying.getPublicKey(args, originator);
32488
32588
  }
32489
32589
  async revealCounterpartyKeyLinkage(args, originator) {
32490
- this.checkAuthAndUnderlying(originator);
32491
- return await this.underlying.revealCounterpartyKeyLinkage(args, originator);
32590
+ this.assertReady(originator);
32591
+ return this.underlying.revealCounterpartyKeyLinkage(args, originator);
32492
32592
  }
32493
32593
  async revealSpecificKeyLinkage(args, originator) {
32494
- this.checkAuthAndUnderlying(originator);
32495
- return await this.underlying.revealSpecificKeyLinkage(args, originator);
32594
+ this.assertReady(originator);
32595
+ return this.underlying.revealSpecificKeyLinkage(args, originator);
32496
32596
  }
32497
32597
  async encrypt(args, originator) {
32498
- this.checkAuthAndUnderlying(originator);
32499
- return await this.underlying.encrypt(args, originator);
32598
+ this.assertReady(originator);
32599
+ return this.underlying.encrypt(args, originator);
32500
32600
  }
32501
32601
  async decrypt(args, originator) {
32502
- this.checkAuthAndUnderlying(originator);
32503
- return await this.underlying.decrypt(args, originator);
32602
+ this.assertReady(originator);
32603
+ return this.underlying.decrypt(args, originator);
32504
32604
  }
32505
32605
  async createHmac(args, originator) {
32506
- this.checkAuthAndUnderlying(originator);
32507
- return await this.underlying.createHmac(args, originator);
32606
+ this.assertReady(originator);
32607
+ return this.underlying.createHmac(args, originator);
32508
32608
  }
32509
32609
  async verifyHmac(args, originator) {
32510
- this.checkAuthAndUnderlying(originator);
32511
- return await this.underlying.verifyHmac(args, originator);
32610
+ this.assertReady(originator);
32611
+ return this.underlying.verifyHmac(args, originator);
32512
32612
  }
32513
32613
  async createSignature(args, originator) {
32514
- this.checkAuthAndUnderlying(originator);
32515
- return await this.underlying.createSignature(args, originator);
32614
+ this.assertReady(originator);
32615
+ return this.underlying.createSignature(args, originator);
32516
32616
  }
32517
32617
  async verifySignature(args, originator) {
32518
- this.checkAuthAndUnderlying(originator);
32519
- return await this.underlying.verifySignature(args, originator);
32618
+ this.assertReady(originator);
32619
+ return this.underlying.verifySignature(args, originator);
32520
32620
  }
32521
32621
  async createAction(args, originator) {
32522
- this.checkAuthAndUnderlying(originator);
32523
- return await this.underlying.createAction(args, originator);
32622
+ this.assertReady(originator);
32623
+ return this.underlying.createAction(args, originator);
32524
32624
  }
32525
32625
  async signAction(args, originator) {
32526
- this.checkAuthAndUnderlying(originator);
32527
- return await this.underlying.signAction(args, originator);
32626
+ this.assertReady(originator);
32627
+ return this.underlying.signAction(args, originator);
32528
32628
  }
32529
32629
  async abortAction(args, originator) {
32530
- this.checkAuthAndUnderlying(originator);
32531
- return await this.underlying.abortAction(args, originator);
32630
+ this.assertReady(originator);
32631
+ return this.underlying.abortAction(args, originator);
32532
32632
  }
32533
32633
  async listActions(args, originator) {
32534
- this.checkAuthAndUnderlying(originator);
32535
- return await this.underlying.listActions(args, originator);
32634
+ this.assertReady(originator);
32635
+ return this.underlying.listActions(args, originator);
32536
32636
  }
32537
32637
  async internalizeAction(args, originator) {
32538
- this.checkAuthAndUnderlying(originator);
32539
- return await this.underlying.internalizeAction(args, originator);
32638
+ this.assertReady(originator);
32639
+ return this.underlying.internalizeAction(args, originator);
32540
32640
  }
32541
32641
  async listOutputs(args, originator) {
32542
- this.checkAuthAndUnderlying(originator);
32543
- return await this.underlying.listOutputs(args, originator);
32642
+ this.assertReady(originator);
32643
+ return this.underlying.listOutputs(args, originator);
32544
32644
  }
32545
32645
  async relinquishOutput(args, originator) {
32546
- this.checkAuthAndUnderlying(originator);
32547
- return await this.underlying.relinquishOutput(args, originator);
32646
+ this.assertReady(originator);
32647
+ return this.underlying.relinquishOutput(args, originator);
32548
32648
  }
32549
32649
  async acquireCertificate(args, originator) {
32550
- this.checkAuthAndUnderlying(originator);
32551
- return await this.underlying.acquireCertificate(args, originator);
32650
+ this.assertReady(originator);
32651
+ return this.underlying.acquireCertificate(args, originator);
32552
32652
  }
32553
32653
  async listCertificates(args, originator) {
32554
- this.checkAuthAndUnderlying(originator);
32555
- return await this.underlying.listCertificates(args, originator);
32654
+ this.assertReady(originator);
32655
+ return this.underlying.listCertificates(args, originator);
32556
32656
  }
32557
32657
  async proveCertificate(args, originator) {
32558
- this.checkAuthAndUnderlying(originator);
32559
- return await this.underlying.proveCertificate(args, originator);
32658
+ this.assertReady(originator);
32659
+ return this.underlying.proveCertificate(args, originator);
32560
32660
  }
32561
32661
  async relinquishCertificate(args, originator) {
32562
- this.checkAuthAndUnderlying(originator);
32563
- return await this.underlying.relinquishCertificate(args, originator);
32662
+ this.assertReady(originator);
32663
+ return this.underlying.relinquishCertificate(args, originator);
32564
32664
  }
32565
32665
  async discoverByIdentityKey(args, originator) {
32566
- this.checkAuthAndUnderlying(originator);
32567
- return await this.underlying.discoverByIdentityKey(args, originator);
32666
+ this.assertReady(originator);
32667
+ return this.underlying.discoverByIdentityKey(args, originator);
32568
32668
  }
32569
32669
  async discoverByAttributes(args, originator) {
32570
- this.checkAuthAndUnderlying(originator);
32571
- return await this.underlying.discoverByAttributes(args, originator);
32670
+ this.assertReady(originator);
32671
+ return this.underlying.discoverByAttributes(args, originator);
32572
32672
  }
32573
32673
  async isAuthenticated(_, originator) {
32574
32674
  if (!this.authenticated) throw new Error("User is not authenticated.");
@@ -32578,23 +32678,23 @@ var CWIStyleWalletManager = class {
32578
32678
  async waitForAuthentication(_, originator) {
32579
32679
  if (originator === this.adminOriginator) throw new Error("External applications are not allowed to use the admin originator.");
32580
32680
  while (!this.authenticated || this.underlying == null) await new Promise((resolve) => setTimeout(resolve, 100));
32581
- return await this.underlying.waitForAuthentication({}, originator);
32681
+ return this.underlying.waitForAuthentication({}, originator);
32582
32682
  }
32583
32683
  async getHeight(_, originator) {
32584
- this.checkAuthAndUnderlying(originator);
32585
- return await this.underlying.getHeight({}, originator);
32684
+ this.assertReady(originator);
32685
+ return this.underlying.getHeight({}, originator);
32586
32686
  }
32587
32687
  async getHeaderForHeight(args, originator) {
32588
- this.checkAuthAndUnderlying(originator);
32589
- return await this.underlying.getHeaderForHeight(args, originator);
32688
+ this.assertReady(originator);
32689
+ return this.underlying.getHeaderForHeight(args, originator);
32590
32690
  }
32591
32691
  async getNetwork(_, originator) {
32592
- this.checkAuthAndUnderlying(originator);
32593
- return await this.underlying.getNetwork({}, originator);
32692
+ this.assertReady(originator);
32693
+ return this.underlying.getNetwork({}, originator);
32594
32694
  }
32595
32695
  async getVersion(_, originator) {
32596
- this.checkAuthAndUnderlying(originator);
32597
- return await this.underlying.getVersion({}, originator);
32696
+ this.assertReady(originator);
32697
+ return this.underlying.getVersion({}, originator);
32598
32698
  }
32599
32699
  };
32600
32700
  //#endregion
@@ -32938,6 +33038,8 @@ const DEFAULT_MAX_RESPONSE_BYTES = 1024 * 1024;
32938
33038
  const MAX_CONFIGURED_TIMEOUT_MS = 12e4;
32939
33039
  const MAX_CONFIGURED_REQUEST_BYTES = 10 * 1024 * 1024;
32940
33040
  const MAX_CONFIGURED_RESPONSE_BYTES = 10 * 1024 * 1024;
33041
+ const WAB_COMPONENT = "wallet-toolbox.wab-transport";
33042
+ const WAB_REQUEST_EVENT = "wallet-toolbox.wab.request.";
32941
33043
  const defaultFetch = typeof globalThis !== "undefined" && typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
32942
33044
  /**
32943
33045
  * A privacy-safe WAB transport failure. Response bodies and request payloads
@@ -32976,8 +33078,8 @@ function normalizeServerUrl(serverUrl) {
32976
33078
  } catch {
32977
33079
  throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB server URL must be an absolute URL.", false);
32978
33080
  }
32979
- 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);
32980
- 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);
33081
+ if (parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB URL cannot include credentials, query, or fragment.", false);
33082
+ if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && isLocalHostname(parsed.hostname))) throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB URL requires HTTPS except on localhost.", false);
32981
33083
  let pathname = parsed.pathname;
32982
33084
  while (pathname.endsWith("/")) pathname = pathname.slice(0, -1);
32983
33085
  return {
@@ -32987,7 +33089,7 @@ function normalizeServerUrl(serverUrl) {
32987
33089
  }
32988
33090
  function normalizePositiveInteger(value, fallback, maximum, name) {
32989
33091
  const resolved = value ?? fallback;
32990
- 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);
33092
+ if (!Number.isInteger(resolved) || resolved <= 0 || resolved > maximum) throw new WABClientError("WAB_INVALID_CONFIGURATION", `${name} must be an integer from 1 to ${maximum}.`, false);
32991
33093
  return resolved;
32992
33094
  }
32993
33095
  function assertSafePath(path) {
@@ -33012,20 +33114,20 @@ var WABTransport = class {
33012
33114
  serverUrl;
33013
33115
  serverOrigin;
33014
33116
  telemetry;
33015
- fetchClient;
33016
- timeoutMs;
33017
- maxRequestBytes;
33018
- maxResponseBytes;
33117
+ fetcher;
33118
+ timeout;
33119
+ requestLimit;
33120
+ responseLimit;
33019
33121
  constructor(serverUrl, options = {}) {
33020
33122
  const normalized = normalizeServerUrl(serverUrl);
33021
33123
  this.serverUrl = normalized.baseUrl;
33022
33124
  this.serverOrigin = normalized.origin;
33023
- const fetchClient = options.fetch ?? defaultFetch;
33024
- if (typeof fetchClient !== "function") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WABClient requires a fetch implementation.", false);
33025
- this.fetchClient = fetchClient;
33026
- this.timeoutMs = normalizePositiveInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, MAX_CONFIGURED_TIMEOUT_MS, "timeoutMs");
33027
- this.maxRequestBytes = normalizePositiveInteger(options.maxRequestBytes, DEFAULT_MAX_REQUEST_BYTES, MAX_CONFIGURED_REQUEST_BYTES, "maxRequestBytes");
33028
- this.maxResponseBytes = normalizePositiveInteger(options.maxResponseBytes, DEFAULT_MAX_RESPONSE_BYTES, MAX_CONFIGURED_RESPONSE_BYTES, "maxResponseBytes");
33125
+ const fetcher = options.fetch ?? defaultFetch;
33126
+ if (typeof fetcher !== "function") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WABClient requires a fetch implementation.", false);
33127
+ this.fetcher = fetcher;
33128
+ this.timeout = normalizePositiveInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, MAX_CONFIGURED_TIMEOUT_MS, "timeoutMs");
33129
+ this.requestLimit = normalizePositiveInteger(options.maxRequestBytes, DEFAULT_MAX_REQUEST_BYTES, MAX_CONFIGURED_REQUEST_BYTES, "maxRequestBytes");
33130
+ this.responseLimit = normalizePositiveInteger(options.maxResponseBytes, DEFAULT_MAX_RESPONSE_BYTES, MAX_CONFIGURED_RESPONSE_BYTES, "maxResponseBytes");
33029
33131
  this.telemetry = new Telemetry(options.telemetry);
33030
33132
  }
33031
33133
  createCorrelationId() {
@@ -33033,38 +33135,9 @@ var WABTransport = class {
33033
33135
  return isSafeCorrelationId(correlationId) ? correlationId : new Telemetry().createCorrelationId();
33034
33136
  }
33035
33137
  async request(path, options) {
33036
- const metadata = this.createRequestMetadata(path, options);
33037
- this.captureRequestStarted(metadata);
33038
- const body = this.encodeRequestBody(options, metadata);
33039
- const timeout = this.startRequestTimeout(metadata.errorContext);
33040
- const response = await this.fetchResponse(metadata, body, timeout);
33041
- const responseContext = this.createResponseContext(response, metadata);
33042
- this.assertSuccessfulResponse(response, responseContext, metadata, timeout);
33043
- const responseText = await this.readResponseText(response, responseContext, metadata, timeout);
33044
- const parsed = this.parseResponseObject(responseText, response, responseContext, metadata);
33045
- this.telemetry.capture({
33046
- name: "wallet-toolbox.wab.request.completed",
33047
- component: "wallet-toolbox.wab-transport",
33048
- severity: "info",
33049
- correlationId: metadata.correlationId,
33050
- attributes: {
33051
- operation: metadata.operation,
33052
- method: metadata.method,
33053
- route: metadata.path,
33054
- serverOrigin: this.serverOrigin,
33055
- status: response.status,
33056
- endpointMarkerPresent: responseContext.endpointMarkerPresent,
33057
- responseCorrelationMatched: responseContext.responseCorrelationMatched,
33058
- responseBytes: new TextEncoder().encode(responseText).byteLength,
33059
- durationMs: Date.now() - metadata.startedAt
33060
- }
33061
- });
33062
- return parsed;
33063
- }
33064
- createRequestMetadata(path, options) {
33065
33138
  assertSafePath(path);
33066
33139
  const correlationId = options.correlationId != null && isSafeCorrelationId(options.correlationId) ? options.correlationId : this.createCorrelationId();
33067
- return {
33140
+ const metadata = {
33068
33141
  method: options.method ?? "POST",
33069
33142
  path,
33070
33143
  operation: options.operation,
@@ -33076,46 +33149,73 @@ var WABTransport = class {
33076
33149
  route: path
33077
33150
  }
33078
33151
  };
33079
- }
33080
- captureRequestStarted(metadata) {
33081
33152
  this.telemetry.capture({
33082
- name: "wallet-toolbox.wab.request.started",
33083
- component: "wallet-toolbox.wab-transport",
33153
+ name: `${WAB_REQUEST_EVENT}started`,
33154
+ component: WAB_COMPONENT,
33084
33155
  severity: "debug",
33156
+ correlationId,
33157
+ attributes: {
33158
+ operation: metadata.operation,
33159
+ method: metadata.method,
33160
+ route: path,
33161
+ serverOrigin: this.serverOrigin
33162
+ }
33163
+ });
33164
+ const body = this.bodyFor(options, metadata);
33165
+ const timeout = this.startTimer(metadata.errorContext);
33166
+ const response = await this.fetch(metadata, body, timeout);
33167
+ const responseContext = {
33168
+ ...metadata.errorContext,
33169
+ endpointMarkerPresent: isWabResponse(response),
33170
+ responseCorrelationMatched: response.headers.get("X-Correlation-ID") === correlationId
33171
+ };
33172
+ this.checkResponse(response, responseContext, metadata, timeout);
33173
+ const responseText = await this.readText(response, responseContext, metadata, timeout);
33174
+ const parsed = this.parse(responseText, response, responseContext, metadata);
33175
+ this.telemetry.capture({
33176
+ name: `${WAB_REQUEST_EVENT}completed`,
33177
+ component: WAB_COMPONENT,
33178
+ severity: "info",
33085
33179
  correlationId: metadata.correlationId,
33086
33180
  attributes: {
33087
33181
  operation: metadata.operation,
33088
33182
  method: metadata.method,
33089
33183
  route: metadata.path,
33090
- serverOrigin: this.serverOrigin
33184
+ serverOrigin: this.serverOrigin,
33185
+ status: response.status,
33186
+ endpointMarkerPresent: responseContext.endpointMarkerPresent,
33187
+ responseCorrelationMatched: responseContext.responseCorrelationMatched,
33188
+ responseBytes: new TextEncoder().encode(responseText).byteLength,
33189
+ durationMs: Date.now() - metadata.startedAt
33091
33190
  }
33092
33191
  });
33192
+ return parsed;
33093
33193
  }
33094
- encodeRequestBody(options, metadata) {
33194
+ bodyFor(options, metadata) {
33095
33195
  let body;
33096
33196
  try {
33097
33197
  body = options.body === void 0 ? void 0 : JSON.stringify(options.body);
33098
33198
  } catch (cause) {
33099
- const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request payload could not be encoded.", false, void 0, {
33199
+ const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request encoding failed.", false, void 0, {
33100
33200
  ...metadata.errorContext,
33101
33201
  cause
33102
33202
  });
33103
- this.captureRequestFailure(metadata, error);
33203
+ this.report(metadata, error);
33104
33204
  throw error;
33105
33205
  }
33106
33206
  if (options.body !== void 0 && body === void 0) {
33107
- const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request payload must be JSON-serializable.", false, void 0, metadata.errorContext);
33108
- this.captureRequestFailure(metadata, error);
33207
+ const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request is not JSON-serializable.", false, void 0, metadata.errorContext);
33208
+ this.report(metadata, error);
33109
33209
  throw error;
33110
33210
  }
33111
- if (body != null && new TextEncoder().encode(body).byteLength > this.maxRequestBytes) {
33112
- const error = new WABClientError("WAB_REQUEST_TOO_LARGE", "WAB request exceeded the configured size limit.", false, void 0, metadata.errorContext);
33113
- this.captureRequestFailure(metadata, error);
33211
+ if (body != null && new TextEncoder().encode(body).byteLength > this.requestLimit) {
33212
+ const error = new WABClientError("WAB_REQUEST_TOO_LARGE", "WAB request exceeds its size limit.", false, void 0, metadata.errorContext);
33213
+ this.report(metadata, error);
33114
33214
  throw error;
33115
33215
  }
33116
33216
  return body;
33117
33217
  }
33118
- startRequestTimeout(errorContext) {
33218
+ startTimer(errorContext) {
33119
33219
  const timeout = {
33120
33220
  controller: new AbortController(),
33121
33221
  timedOut: false
@@ -33125,12 +33225,12 @@ var WABTransport = class {
33125
33225
  timeout.timedOut = true;
33126
33226
  timeout.controller.abort();
33127
33227
  reject(new WABClientError("WAB_TIMEOUT", "WAB request timed out.", true, void 0, errorContext));
33128
- }, this.timeoutMs);
33228
+ }, this.timeout);
33129
33229
  });
33130
33230
  return timeout;
33131
33231
  }
33132
- async fetchResponse(metadata, body, timeout) {
33133
- const requestPromise = Promise.resolve().then(() => this.fetchClient(`${this.serverUrl}${metadata.path}`, {
33232
+ async fetch(metadata, body, timeout) {
33233
+ const requestPromise = Promise.resolve().then(() => this.fetcher(`${this.serverUrl}${metadata.path}`, {
33134
33234
  method: metadata.method,
33135
33235
  headers: {
33136
33236
  Accept: "application/json",
@@ -33154,33 +33254,26 @@ var WABTransport = class {
33154
33254
  ...metadata.errorContext,
33155
33255
  cause
33156
33256
  });
33157
- else error = new WABClientError("WAB_NETWORK_ERROR", "WAB request failed before receiving a response.", true, void 0, {
33257
+ else error = new WABClientError("WAB_NETWORK_ERROR", "WAB request failed before response.", true, void 0, {
33158
33258
  ...metadata.errorContext,
33159
33259
  cause
33160
33260
  });
33161
- this.captureRequestFailure(metadata, error);
33261
+ this.report(metadata, error);
33162
33262
  throw error;
33163
33263
  }
33164
33264
  }
33165
- createResponseContext(response, metadata) {
33166
- return {
33167
- ...metadata.errorContext,
33168
- endpointMarkerPresent: isWabResponse(response),
33169
- responseCorrelationMatched: response.headers.get("X-Correlation-ID") === metadata.correlationId
33170
- };
33171
- }
33172
- assertSuccessfulResponse(response, responseContext, metadata, timeout) {
33265
+ checkResponse(response, responseContext, metadata, timeout) {
33173
33266
  if (response.ok) return;
33174
33267
  if (timeout.timer !== void 0) clearTimeout(timeout.timer);
33175
33268
  const endpointMismatch = response.status === 404 && responseContext.endpointMarkerPresent !== true;
33176
- 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);
33177
- this.captureRequestFailure(metadata, error);
33269
+ 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);
33270
+ this.report(metadata, error);
33178
33271
  response.body?.cancel().catch(() => {});
33179
33272
  throw error;
33180
33273
  }
33181
- async readResponseText(response, responseContext, metadata, timeout) {
33274
+ async readText(response, responseContext, metadata, timeout) {
33182
33275
  try {
33183
- return await Promise.race([this.readBoundedResponse(response, responseContext), timeout.promise]);
33276
+ return await Promise.race([this.read(response, responseContext), timeout.promise]);
33184
33277
  } catch (cause) {
33185
33278
  let error;
33186
33279
  if (cause instanceof WABClientError) error = cause;
@@ -33188,17 +33281,17 @@ var WABTransport = class {
33188
33281
  ...responseContext,
33189
33282
  cause
33190
33283
  });
33191
- else error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response could not be read.", true, response.status, {
33284
+ else error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response read failed.", true, response.status, {
33192
33285
  ...responseContext,
33193
33286
  cause
33194
33287
  });
33195
- this.captureRequestFailure(metadata, error);
33288
+ this.report(metadata, error);
33196
33289
  throw error;
33197
33290
  } finally {
33198
33291
  if (timeout.timer !== void 0) clearTimeout(timeout.timer);
33199
33292
  }
33200
33293
  }
33201
- parseResponseObject(responseText, response, responseContext, metadata) {
33294
+ parse(responseText, response, responseContext, metadata) {
33202
33295
  let parsed;
33203
33296
  try {
33204
33297
  parsed = JSON.parse(responseText);
@@ -33207,37 +33300,32 @@ var WABTransport = class {
33207
33300
  ...responseContext,
33208
33301
  cause
33209
33302
  });
33210
- this.captureRequestFailure(metadata, error);
33303
+ this.report(metadata, error);
33211
33304
  throw error;
33212
33305
  }
33213
33306
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
33214
33307
  const error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response must be a JSON object.", true, response.status, responseContext);
33215
- this.captureRequestFailure(metadata, error);
33308
+ this.report(metadata, error);
33216
33309
  throw error;
33217
33310
  }
33218
33311
  return parsed;
33219
33312
  }
33220
- captureRequestFailure(metadata, error) {
33221
- this.captureFailure(metadata.operation, metadata.method, metadata.path, metadata.correlationId, metadata.startedAt, error);
33222
- }
33223
- async readBoundedResponse(response, responseContext) {
33224
- await this.rejectOversizedDeclaredResponse(response, responseContext);
33225
- const reader = response.body?.getReader();
33226
- if (reader == null) return await this.readBoundedArrayBuffer(response, responseContext);
33227
- return await this.readBoundedStream(reader, response, responseContext);
33228
- }
33229
- async rejectOversizedDeclaredResponse(response, responseContext) {
33313
+ async read(response, responseContext) {
33230
33314
  const contentLength = Number(response.headers.get("content-length"));
33231
- if (!Number.isFinite(contentLength) || contentLength <= this.maxResponseBytes) return;
33232
- await this.cancelResponseBody(response);
33233
- throw this.responseTooLargeError(response, responseContext);
33315
+ if (Number.isFinite(contentLength) && contentLength > this.responseLimit) {
33316
+ await this.stopBody(response);
33317
+ throw this.sizeError(response, responseContext);
33318
+ }
33319
+ const reader = response.body?.getReader();
33320
+ if (reader == null) return this.readBuffer(response, responseContext);
33321
+ return this.readStream(reader, response, responseContext);
33234
33322
  }
33235
- async readBoundedArrayBuffer(response, responseContext) {
33323
+ async readBuffer(response, responseContext) {
33236
33324
  const bytes = new Uint8Array(await response.arrayBuffer());
33237
- if (bytes.byteLength > this.maxResponseBytes) throw this.responseTooLargeError(response, responseContext);
33325
+ if (bytes.byteLength > this.responseLimit) throw this.sizeError(response, responseContext);
33238
33326
  return new TextDecoder().decode(bytes);
33239
33327
  }
33240
- async readBoundedStream(reader, response, responseContext) {
33328
+ async readStream(reader, response, responseContext) {
33241
33329
  const chunks = [];
33242
33330
  let total = 0;
33243
33331
  while (true) {
@@ -33245,15 +33333,12 @@ var WABTransport = class {
33245
33333
  if (done) break;
33246
33334
  if (value == null) continue;
33247
33335
  total += value.byteLength;
33248
- if (total > this.maxResponseBytes) {
33249
- await this.cancelResponseReader(reader);
33250
- throw this.responseTooLargeError(response, responseContext);
33336
+ if (total > this.responseLimit) {
33337
+ await this.stopReader(reader);
33338
+ throw this.sizeError(response, responseContext);
33251
33339
  }
33252
33340
  chunks.push(value);
33253
33341
  }
33254
- return this.decodeChunks(chunks, total);
33255
- }
33256
- decodeChunks(chunks, total) {
33257
33342
  const bytes = new Uint8Array(total);
33258
33343
  let offset = 0;
33259
33344
  for (const chunk of chunks) {
@@ -33262,35 +33347,35 @@ var WABTransport = class {
33262
33347
  }
33263
33348
  return new TextDecoder().decode(bytes);
33264
33349
  }
33265
- responseTooLargeError(response, responseContext) {
33266
- return new WABClientError("WAB_RESPONSE_TOO_LARGE", "WAB response exceeded the configured size limit.", false, response.status, responseContext);
33350
+ sizeError(response, responseContext) {
33351
+ return new WABClientError("WAB_RESPONSE_TOO_LARGE", "WAB response exceeds its size limit.", false, response.status, responseContext);
33267
33352
  }
33268
- async cancelResponseBody(response) {
33353
+ async stopBody(response) {
33269
33354
  try {
33270
33355
  await response.body?.cancel();
33271
33356
  } catch {}
33272
33357
  }
33273
- async cancelResponseReader(reader) {
33358
+ async stopReader(reader) {
33274
33359
  try {
33275
33360
  await reader.cancel();
33276
33361
  } catch {}
33277
33362
  }
33278
- captureFailure(operation, method, path, correlationId, startedAt, error) {
33363
+ report(metadata, error) {
33279
33364
  this.telemetry.capture({
33280
- name: "wallet-toolbox.wab.request.failed",
33281
- component: "wallet-toolbox.wab-transport",
33365
+ name: `${WAB_REQUEST_EVENT}failed`,
33366
+ component: WAB_COMPONENT,
33282
33367
  severity: error.retryable ? "warn" : "error",
33283
- correlationId,
33368
+ correlationId: metadata.correlationId,
33284
33369
  attributes: {
33285
- operation,
33286
- method,
33287
- route: path,
33370
+ operation: metadata.operation,
33371
+ method: metadata.method,
33372
+ route: metadata.path,
33288
33373
  serverOrigin: this.serverOrigin,
33289
33374
  retryable: error.retryable,
33290
33375
  ...error.status !== void 0 ? { status: error.status } : {},
33291
33376
  ...error.endpointMarkerPresent !== void 0 ? { endpointMarkerPresent: error.endpointMarkerPresent } : {},
33292
33377
  ...error.responseCorrelationMatched !== void 0 ? { responseCorrelationMatched: error.responseCorrelationMatched } : {},
33293
- durationMs: Date.now() - startedAt
33378
+ durationMs: Date.now() - metadata.startedAt
33294
33379
  },
33295
33380
  error
33296
33381
  });
@@ -33399,8 +33484,8 @@ var WABClient = class {
33399
33484
  constructor(serverUrl, options = {}) {
33400
33485
  this.transport = new WABTransport(serverUrl, options);
33401
33486
  }
33402
- async getInfo() {
33403
- return await this.transport.request("/info", {
33487
+ getInfo() {
33488
+ return this.transport.request("/info", {
33404
33489
  method: "GET",
33405
33490
  operation: "get-info"
33406
33491
  });
@@ -33410,15 +33495,15 @@ var WABClient = class {
33410
33495
  }
33411
33496
  async startAuthMethod(authMethod, presentationKey, payload, correlationId) {
33412
33497
  assertHexIdentifier(presentationKey, "presentationKey");
33413
- return await authMethod.startAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33498
+ return authMethod.startAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33414
33499
  }
33415
33500
  async completeAuthMethod(authMethod, presentationKey, payload, correlationId) {
33416
33501
  assertHexIdentifier(presentationKey, "presentationKey");
33417
- return await authMethod.completeAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33502
+ return authMethod.completeAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33418
33503
  }
33419
33504
  async listLinkedMethods(presentationKey) {
33420
33505
  assertHexIdentifier(presentationKey, "presentationKey");
33421
- return await this.transport.request("/user/linkedMethods", {
33506
+ return this.transport.request("/user/linkedMethods", {
33422
33507
  operation: "list-linked-methods",
33423
33508
  body: { presentationKey }
33424
33509
  });
@@ -33426,7 +33511,7 @@ var WABClient = class {
33426
33511
  async unlinkMethod(presentationKey, authMethodId) {
33427
33512
  assertHexIdentifier(presentationKey, "presentationKey");
33428
33513
  if (!Number.isSafeInteger(authMethodId) || authMethodId <= 0) throw new TypeError("authMethodId must be a positive safe integer.");
33429
- return await this.transport.request("/user/unlinkMethod", {
33514
+ return this.transport.request("/user/unlinkMethod", {
33430
33515
  operation: "unlink-method",
33431
33516
  body: {
33432
33517
  presentationKey,
@@ -33436,14 +33521,14 @@ var WABClient = class {
33436
33521
  }
33437
33522
  async requestFaucet(presentationKey) {
33438
33523
  assertHexIdentifier(presentationKey, "presentationKey");
33439
- return await this.transport.request("/faucet/request", {
33524
+ return this.transport.request("/faucet/request", {
33440
33525
  operation: "request-faucet",
33441
33526
  body: { presentationKey }
33442
33527
  });
33443
33528
  }
33444
33529
  async deleteUser(presentationKey) {
33445
33530
  assertHexIdentifier(presentationKey, "presentationKey");
33446
- return await this.transport.request("/user/delete", {
33531
+ return this.transport.request("/user/delete", {
33447
33532
  operation: "delete-user",
33448
33533
  body: { presentationKey }
33449
33534
  });
@@ -33452,7 +33537,7 @@ var WABClient = class {
33452
33537
  assertMethodType(methodType);
33453
33538
  assertHexIdentifier(userIdHash, "userIdHash");
33454
33539
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33455
- return await this.transport.request("/auth/start", {
33540
+ return this.transport.request("/auth/start", {
33456
33541
  operation: "start-share-auth",
33457
33542
  body: {
33458
33543
  methodType,
@@ -33465,7 +33550,7 @@ var WABClient = class {
33465
33550
  assertMethodType(methodType);
33466
33551
  assertHexIdentifier(userIdHash, "userIdHash");
33467
33552
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33468
- return await this.transport.request("/share/store", {
33553
+ return this.transport.request("/share/store", {
33469
33554
  operation: "store-share",
33470
33555
  body: {
33471
33556
  methodType,
@@ -33479,7 +33564,7 @@ var WABClient = class {
33479
33564
  assertMethodType(methodType);
33480
33565
  assertHexIdentifier(userIdHash, "userIdHash");
33481
33566
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33482
- return await this.transport.request("/share/retrieve", {
33567
+ return this.transport.request("/share/retrieve", {
33483
33568
  operation: "retrieve-share",
33484
33569
  body: {
33485
33570
  methodType,
@@ -33492,7 +33577,7 @@ var WABClient = class {
33492
33577
  assertMethodType(methodType);
33493
33578
  assertHexIdentifier(userIdHash, "userIdHash");
33494
33579
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33495
- return await this.transport.request("/share/update", {
33580
+ return this.transport.request("/share/update", {
33496
33581
  operation: "update-share",
33497
33582
  body: {
33498
33583
  methodType,
@@ -33506,7 +33591,7 @@ var WABClient = class {
33506
33591
  assertMethodType(methodType);
33507
33592
  assertHexIdentifier(userIdHash, "userIdHash");
33508
33593
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33509
- return await this.transport.request("/share/delete", {
33594
+ return this.transport.request("/share/delete", {
33510
33595
  operation: "delete-share-user",
33511
33596
  body: {
33512
33597
  methodType,
@@ -33520,9 +33605,13 @@ var WABClient = class {
33520
33605
  //#region ../src/WalletAuthenticationManager.ts
33521
33606
  const DEFAULT_AUTH_SESSION_TTL_MS = 600 * 1e3;
33522
33607
  const MAX_AUTH_SESSION_TTL_MS = 3600 * 1e3;
33608
+ const AUTH_COMPONENT = "wallet-toolbox.authentication-manager";
33609
+ const AUTH_EVENT = "wallet-toolbox.authentication.";
33610
+ const EXISTING_USER = "existing-user";
33611
+ const NEW_USER = "new-user";
33523
33612
  var WABAccountContinuityError = class extends Error {
33524
33613
  code = "WERR_WAB_ACCOUNT_CONTINUITY";
33525
- constructor(message = "WAB and UMP account state did not agree. Retry or use account recovery.") {
33614
+ constructor(message = "WAB and UMP accounts disagree; retry or recover.") {
33526
33615
  super(message);
33527
33616
  this.name = "WABAccountContinuityError";
33528
33617
  }
@@ -33537,6 +33626,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33537
33626
  wabClient;
33538
33627
  authMethod;
33539
33628
  authSession;
33629
+ phoneChangeSession;
33540
33630
  authSessionTtlMs;
33541
33631
  constructor(...[adminOriginator, walletBuilder, interactor, recoveryKeySaver, passwordRetriever, wabClient, authMethod, stateSnapshot, options = {}]) {
33542
33632
  super(adminOriginator, walletBuilder, interactor, recoveryKeySaver, passwordRetriever, async (presentationKey, wallet, adminOriginator) => {
@@ -33559,7 +33649,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33559
33649
  description: "Fund wallet",
33560
33650
  options: { acceptDelayedBroadcast: false }
33561
33651
  }, adminOriginator);
33562
- if (faucetRedeemTXCreationResult.signableTransaction == null) throw new Error("Faucet redemption did not return a signableTransaction");
33652
+ if (faucetRedeemTXCreationResult.signableTransaction == null) throw new Error("Faucet redemption was not signable.");
33563
33653
  const faucetRedeemTX = Transaction.fromAtomicBEEF(faucetRedeemTXCreationResult.signableTransaction.tx);
33564
33654
  const faucetRedemptionPuzzle = new RPuzzle();
33565
33655
  const randomRedemptionPrivateKey = PrivateKey.fromRandom();
@@ -33592,7 +33682,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33592
33682
  * using the chosen AuthMethodInteractor.
33593
33683
  */
33594
33684
  async startAuth(payload) {
33595
- if (this.authMethod == null) throw new Error("No AuthMethod selected in WalletAuthenticationManager");
33685
+ if (this.authMethod == null) throw new Error("No WAB authentication method selected.");
33596
33686
  const authMethod = this.authMethod;
33597
33687
  if (this.authenticated) throw new Error("User is already authenticated");
33598
33688
  this.cancelAuth();
@@ -33605,8 +33695,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33605
33695
  ...correlationId !== void 0 ? { correlationId } : {}
33606
33696
  };
33607
33697
  this.telemetry.capture({
33608
- name: "wallet-toolbox.authentication.wab-start.started",
33609
- component: "wallet-toolbox.authentication-manager",
33698
+ name: `${AUTH_EVENT}wab-start.started`,
33699
+ component: AUTH_COMPONENT,
33610
33700
  severity: "debug",
33611
33701
  correlationId,
33612
33702
  attributes: { methodType: authMethod.methodType }
@@ -33618,8 +33708,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33618
33708
  throw new Error(message);
33619
33709
  }
33620
33710
  this.telemetry.capture({
33621
- name: "wallet-toolbox.authentication.wab-start.completed",
33622
- component: "wallet-toolbox.authentication-manager",
33711
+ name: `${AUTH_EVENT}wab-start.completed`,
33712
+ component: AUTH_COMPONENT,
33623
33713
  severity: "info",
33624
33714
  correlationId,
33625
33715
  attributes: { methodType: authMethod.methodType }
@@ -33627,8 +33717,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33627
33717
  } catch (error) {
33628
33718
  this.cancelAuth();
33629
33719
  this.telemetry.capture({
33630
- name: "wallet-toolbox.authentication.wab-start.failed",
33631
- component: "wallet-toolbox.authentication-manager",
33720
+ name: `${AUTH_EVENT}wab-start.failed`,
33721
+ component: AUTH_COMPONENT,
33632
33722
  severity: "warn",
33633
33723
  correlationId,
33634
33724
  attributes: { methodType: authMethod.methodType },
@@ -33641,22 +33731,22 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33641
33731
  * Completes the WAB-based flow, retrieving the final presentationKey from WAB if successful.
33642
33732
  */
33643
33733
  async completeAuth(payload) {
33644
- if (this.authMethod == null || this.authSession == null) throw new Error("No AuthMethod selected in WalletAuthenticationManager or startAuth has yet to be called.");
33734
+ if (this.authMethod == null || this.authSession == null) throw new Error("Start WAB authentication first.");
33645
33735
  const authMethod = this.authMethod;
33646
33736
  if (this.authSession.methodType !== authMethod.methodType) {
33647
33737
  this.cancelAuth();
33648
- throw new Error("The selected authentication method changed. Start authentication again.");
33738
+ throw new Error("WAB authentication method changed; restart.");
33649
33739
  }
33650
33740
  if (Date.now() >= this.authSession.expiresAt) {
33651
33741
  this.cancelAuth();
33652
- throw new Error("The WAB authentication session expired. Start authentication again.");
33742
+ throw new Error("WAB authentication expired; restart.");
33653
33743
  }
33654
33744
  const session = this.authSession;
33655
33745
  const result = await this.wabClient.completeAuthMethod(authMethod, session.presentationKey, payload, session.correlationId);
33656
33746
  if (result.success !== true || result.presentationKey == null || result.presentationKey.length === 0) {
33657
33747
  this.telemetry.capture({
33658
- name: "wallet-toolbox.authentication.wab-complete.rejected",
33659
- component: "wallet-toolbox.authentication-manager",
33748
+ name: `${AUTH_EVENT}wab-complete.rejected`,
33749
+ component: AUTH_COMPONENT,
33660
33750
  severity: "warn",
33661
33751
  correlationId: session.correlationId,
33662
33752
  attributes: { methodType: session.methodType }
@@ -33671,11 +33761,11 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33671
33761
  this.cancelAuth();
33672
33762
  const wabAccountStatus = this.inferAccountStatus(result, session.presentationKey);
33673
33763
  try {
33674
- await this.providePresentationKey(Utils.toArray(result.presentationKey, "hex"));
33764
+ await this.provideWABPresentationKey(result, wabAccountStatus);
33675
33765
  } catch (error) {
33676
33766
  this.telemetry.capture({
33677
- name: "wallet-toolbox.authentication.ump-continuity.failed",
33678
- component: "wallet-toolbox.authentication-manager",
33767
+ name: `${AUTH_EVENT}ump-continuity.failed`,
33768
+ component: AUTH_COMPONENT,
33679
33769
  severity: "warn",
33680
33770
  correlationId: session.correlationId,
33681
33771
  attributes: {
@@ -33686,18 +33776,18 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33686
33776
  });
33687
33777
  throw error;
33688
33778
  }
33689
- if (wabAccountStatus === "existing-user" && this.authenticationFlow !== "existing-user") {
33779
+ if (wabAccountStatus === EXISTING_USER && this.authenticationFlow !== EXISTING_USER) {
33690
33780
  super.destroy();
33691
33781
  const error = new WABAccountContinuityError();
33692
33782
  this.telemetry.capture({
33693
- name: "wallet-toolbox.authentication.account-continuity.mismatch",
33694
- component: "wallet-toolbox.authentication-manager",
33783
+ name: `${AUTH_EVENT}account-continuity.mismatch`,
33784
+ component: AUTH_COMPONENT,
33695
33785
  severity: "error",
33696
33786
  correlationId: session.correlationId,
33697
33787
  attributes: {
33698
33788
  methodType: session.methodType,
33699
33789
  wabAccountStatus,
33700
- umpAccountStatus: "new-user"
33790
+ umpAccountStatus: NEW_USER
33701
33791
  },
33702
33792
  error
33703
33793
  });
@@ -33705,8 +33795,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33705
33795
  }
33706
33796
  const continuity = wabAccountStatus === this.authenticationFlow ? "matched" : "ump-existing";
33707
33797
  this.telemetry.capture({
33708
- name: "wallet-toolbox.authentication.completed",
33709
- component: "wallet-toolbox.authentication-manager",
33798
+ name: `${AUTH_EVENT}completed`,
33799
+ component: AUTH_COMPONENT,
33710
33800
  severity: continuity === "matched" ? "info" : "warn",
33711
33801
  correlationId: session.correlationId,
33712
33802
  attributes: {
@@ -33720,23 +33810,131 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33720
33810
  cancelAuth() {
33721
33811
  this.authSession = void 0;
33722
33812
  }
33813
+ readPendingPhoneChange(result) {
33814
+ const presentationKey = result.pendingPresentationKey;
33815
+ const changeId = result.pendingPhoneChangeId;
33816
+ if (presentationKey === void 0 && changeId === void 0) return void 0;
33817
+ if (!/^[0-9a-fA-F]{64}$/.test(presentationKey ?? "") || !Number.isSafeInteger(changeId) || changeId <= 0) throw new WABAccountContinuityError("WAB returned invalid pending phone-change data.");
33818
+ return {
33819
+ presentationKey,
33820
+ changeId
33821
+ };
33822
+ }
33823
+ async provideWABPresentationKey(result, wabAccountStatus) {
33824
+ const umpTokenOutpoint = typeof result.umpTokenOutpoint === "string" ? result.umpTokenOutpoint : void 0;
33825
+ const lookupOptions = umpTokenOutpoint == null ? void 0 : { pinnedOutpoint: umpTokenOutpoint };
33826
+ const pending = this.readPendingPhoneChange(result);
33827
+ let usePending = false;
33828
+ try {
33829
+ await this.providePresentationKey(Utils.toArray(result.presentationKey, "hex"), lookupOptions);
33830
+ } catch (error) {
33831
+ if (pending == null) throw error;
33832
+ usePending = true;
33833
+ }
33834
+ if (pending != null && (usePending || wabAccountStatus === EXISTING_USER && this.authenticationFlow !== EXISTING_USER)) {
33835
+ await this.providePresentationKey(Utils.toArray(pending.presentationKey, "hex"), lookupOptions);
33836
+ if (this.authenticationFlow === EXISTING_USER) await this.finalizePendingPhoneChange(result.presentationKey, pending);
33837
+ }
33838
+ }
33839
+ async finalizePendingPhoneChange(currentPresentationKey, pending) {
33840
+ const finalized = await this.phoneChange("finalize", {
33841
+ changeId: pending.changeId,
33842
+ presentationKey: currentPresentationKey,
33843
+ newPresentationKey: pending.presentationKey
33844
+ });
33845
+ if (finalized.success !== true || finalized.changeId !== pending.changeId) throw new WABAccountContinuityError(finalized.message || "WAB could not finalize the pending phone change.");
33846
+ }
33847
+ /**
33848
+ * Starts OTP verification for a replacement phone number. The same number
33849
+ * is valid and intentionally produces a fresh presentation key/hash.
33850
+ */
33851
+ async startPhoneNumberChange(phoneNumber) {
33852
+ if (!this.authenticated) throw new Error("Not authenticated");
33853
+ const normalizedPhone = phoneNumber.trim();
33854
+ const currentPresentationKey = Utils.toHex(await this.getFactor("presentationKey"));
33855
+ const response = await this.phoneChange("start", {
33856
+ presentationKey: currentPresentationKey,
33857
+ phoneNumber: normalizedPhone
33858
+ });
33859
+ if (response.success !== true) throw new Error(response.message || "Phone change failed");
33860
+ this.phoneChangeSession = {
33861
+ phoneNumber: normalizedPhone,
33862
+ presentationKey: currentPresentationKey
33863
+ };
33864
+ }
33865
+ /**
33866
+ * Completes phone verification and stages the WAB association before
33867
+ * publishing the UMP key rotation. WAB retains both the current and pending
33868
+ * presentation keys until finalization, so either side of an interrupted
33869
+ * transition remains recoverable on the next verified login.
33870
+ */
33871
+ async completePhoneNumberChange(otp) {
33872
+ const session = this.phoneChangeSession;
33873
+ if (session == null) throw new Error("No phone change");
33874
+ if (session.changeToken == null) {
33875
+ const authorization = await this.phoneChange("complete", {
33876
+ presentationKey: session.presentationKey,
33877
+ phoneNumber: session.phoneNumber,
33878
+ otp: otp.trim()
33879
+ });
33880
+ if (authorization.success !== true) throw new Error(authorization.message || "Phone change failed");
33881
+ if (/^[0-9a-fA-F]{64}$/.test(authorization.pendingPresentationKey ?? "") && Number.isSafeInteger(authorization.pendingPhoneChangeId) && authorization.pendingPhoneChangeId > 0) {
33882
+ session.newKey = Utils.toArray(authorization.pendingPresentationKey, "hex");
33883
+ session.changeId = authorization.pendingPhoneChangeId;
33884
+ } else if (typeof authorization.changeToken === "string" && authorization.changeToken.length > 0) session.changeToken = authorization.changeToken;
33885
+ else throw new Error(authorization.message || "Phone change failed");
33886
+ }
33887
+ session.newKey ??= Random(32);
33888
+ if (session.changeId == null) {
33889
+ const committed = await this.phoneChange("commit", {
33890
+ changeToken: session.changeToken,
33891
+ presentationKey: session.presentationKey,
33892
+ newPresentationKey: Utils.toHex(session.newKey)
33893
+ });
33894
+ if (committed.success !== true || !Number.isSafeInteger(committed.changeId) || committed.changeId <= 0) throw new Error(committed.message || "Phone change failed");
33895
+ session.changeId = committed.changeId;
33896
+ }
33897
+ const changeId = session.changeId;
33898
+ if (session.umpUpdated !== true) {
33899
+ await this.changePresentationKey(session.newKey);
33900
+ session.umpUpdated = true;
33901
+ }
33902
+ const finalized = await this.phoneChange("finalize", {
33903
+ changeId,
33904
+ presentationKey: session.presentationKey,
33905
+ newPresentationKey: Utils.toHex(session.newKey)
33906
+ });
33907
+ if (finalized.success !== true || finalized.changeId !== changeId) throw new Error(finalized.message || "Phone change failed");
33908
+ this.phoneChangeSession = void 0;
33909
+ return { changeId };
33910
+ }
33911
+ cancelPhoneNumberChange() {
33912
+ this.phoneChangeSession = void 0;
33913
+ }
33723
33914
  destroy() {
33724
33915
  this.cancelAuth();
33916
+ this.cancelPhoneNumberChange();
33725
33917
  super.destroy();
33726
33918
  }
33919
+ phoneChange(phase, body) {
33920
+ return this.wabClient.transport.request(`/auth/phone-change/${phase}`, {
33921
+ operation: "phone-change",
33922
+ body
33923
+ });
33924
+ }
33727
33925
  inferAccountStatus(result, temporaryPresentationKey) {
33728
33926
  if (result.presentationKey == null) throw new WABAccountContinuityError("WAB did not return a presentation key.");
33729
33927
  const keyMatchesTemporary = this.constantTimeHexEqual(result.presentationKey, temporaryPresentationKey);
33730
33928
  const rawAccountStatus = result.accountStatus;
33731
- if (rawAccountStatus !== void 0 && rawAccountStatus !== "new-user" && rawAccountStatus !== "existing-user") throw new WABAccountContinuityError("WAB returned an invalid account-continuity status.");
33929
+ if (rawAccountStatus !== void 0 && rawAccountStatus !== NEW_USER && rawAccountStatus !== EXISTING_USER) throw new WABAccountContinuityError("WAB returned an invalid account status.");
33732
33930
  const rawExistingUser = result.existingUser;
33733
- if (rawExistingUser !== void 0 && typeof rawExistingUser !== "boolean") throw new WABAccountContinuityError("WAB returned an invalid existing-user status.");
33734
- if (rawAccountStatus !== void 0 && rawExistingUser !== void 0 && rawAccountStatus === "existing-user" !== rawExistingUser) throw new WABAccountContinuityError("WAB returned contradictory account-continuity statuses.");
33931
+ if (rawExistingUser !== void 0 && typeof rawExistingUser !== "boolean") throw new WABAccountContinuityError("WAB returned invalid existing-user data.");
33932
+ if (rawAccountStatus !== void 0 && rawExistingUser !== void 0 && rawAccountStatus === EXISTING_USER !== rawExistingUser) throw new WABAccountContinuityError("WAB returned conflicting account status.");
33735
33933
  let compatibilityStatus;
33736
- if (typeof rawExistingUser === "boolean") compatibilityStatus = rawExistingUser ? "existing-user" : "new-user";
33934
+ if (typeof rawExistingUser === "boolean") compatibilityStatus = rawExistingUser ? EXISTING_USER : NEW_USER;
33737
33935
  const explicitStatus = rawAccountStatus ?? compatibilityStatus;
33738
- if (explicitStatus === "new-user" && !keyMatchesTemporary || explicitStatus === "existing-user" && keyMatchesTemporary) throw new WABAccountContinuityError("WAB returned contradictory account-continuity data.");
33739
- return explicitStatus ?? (keyMatchesTemporary ? "new-user" : "existing-user");
33936
+ if (explicitStatus === NEW_USER && !keyMatchesTemporary || explicitStatus === EXISTING_USER && keyMatchesTemporary) throw new WABAccountContinuityError("WAB returned conflicting account status.");
33937
+ return explicitStatus ?? (keyMatchesTemporary ? NEW_USER : EXISTING_USER);
33740
33938
  }
33741
33939
  constantTimeHexEqual(left, right) {
33742
33940
  if (left.length !== right.length) return false;