@bsv/wallet-toolbox-client 2.9.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,
@@ -8219,28 +8219,70 @@ function verifyActionBatchManifestDigest(manifest) {
8219
8219
  //#endregion
8220
8220
  //#region ../src/utility/beefForTxids.ts
8221
8221
  /**
8222
- * Return the minimal subgraph needed to prove the requested transactions.
8222
+ * Return a minimal BEEF when the source contains data outside the requested
8223
+ * transaction dependency closure. Return undefined when no pruning is needed.
8223
8224
  *
8224
- * Parents are added before children so the resulting BEEF preserves dependency
8225
- * order. Shared ancestors and bumps are merged only once.
8225
+ * This form lets forwarding clients retain the caller's original bytes in the
8226
+ * common no-op case instead of rebuilding and reserializing an equivalent BEEF.
8227
+ */
8228
+ function pruneBeefForTxids(source, txids) {
8229
+ const selection = selectTransactions(source, txids);
8230
+ if (selection.transactions.size === source.txs.length && selection.bumpIndexes.size === source.bumps.length) return;
8231
+ return copySelection(source, selection);
8232
+ }
8233
+ /**
8234
+ * Return an independent minimal BEEF needed to prove the requested transactions.
8235
+ *
8236
+ * Transactions remain in source order and are sorted by Beef when serialized.
8237
+ * The source is indexed and walked once, using an explicit stack so a hostile
8238
+ * dependency depth cannot exhaust the JavaScript call stack.
8226
8239
  */
8227
8240
  function beefForTxids(source, txids) {
8228
- const beef = new Beef();
8241
+ return copySelection(source, selectTransactions(source, txids));
8242
+ }
8243
+ function selectTransactions(source, txids) {
8244
+ const byTxid = /* @__PURE__ */ new Map();
8245
+ for (const tx of source.txs) byTxid.set(tx.txid, tx);
8246
+ const transactions = /* @__PURE__ */ new Set();
8247
+ const bumpIndexes = /* @__PURE__ */ new Set();
8229
8248
  const visited = /* @__PURE__ */ new Set();
8230
- const visit = (txid) => {
8231
- if (visited.has(txid)) return;
8249
+ const stack = [...txids];
8250
+ while (stack.length > 0) {
8251
+ const txid = stack.pop();
8252
+ if (txid == null || visited.has(txid)) continue;
8232
8253
  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);
8254
+ const tx = byTxid.get(txid);
8255
+ if (tx == null) continue;
8256
+ transactions.add(tx);
8257
+ const bumpIndex = tx.bumpIndex;
8258
+ if (bumpIndex != null && Number.isSafeInteger(bumpIndex) && bumpIndex >= 0 && bumpIndex < source.bumps.length) bumpIndexes.add(bumpIndex);
8259
+ for (const inputTxid of tx.inputTxids) if (!visited.has(inputTxid)) stack.push(inputTxid);
8260
+ }
8261
+ return {
8262
+ transactions,
8263
+ bumpIndexes
8240
8264
  };
8241
- for (const txid of txids) visit(txid);
8265
+ }
8266
+ function copySelection(source, selection) {
8267
+ const beef = new Beef(source.version);
8268
+ const bumpIndexMap = /* @__PURE__ */ new Map();
8269
+ for (let index = 0; index < source.bumps.length; index++) {
8270
+ if (!selection.bumpIndexes.has(index)) continue;
8271
+ bumpIndexMap.set(index, beef.bumps.length);
8272
+ beef.bumps.push(cloneMerklePath(source.bumps[index]));
8273
+ }
8274
+ for (const sourceTx of source.txs) {
8275
+ if (!selection.transactions.has(sourceTx)) continue;
8276
+ const bumpIndex = sourceTx.bumpIndex == null ? void 0 : bumpIndexMap.get(sourceTx.bumpIndex);
8277
+ const rawTx = sourceTx.rawTxUint8Array;
8278
+ const copy = rawTx == null ? BeefTx.fromTxid(sourceTx.txid, bumpIndex) : new BeefTx(Uint8Array.from(rawTx), bumpIndex, Array.from(sourceTx.inputTxids));
8279
+ beef.txs.push(copy);
8280
+ }
8242
8281
  return beef;
8243
8282
  }
8283
+ function cloneMerklePath(source) {
8284
+ return new MerklePath(source.blockHeight, source.path.map((level) => level.map((leaf) => ({ ...leaf }))), false, false);
8285
+ }
8244
8286
  //#endregion
8245
8287
  //#region ../src/storage/methods/offsetKey.ts
8246
8288
  function keyOffsetToHashedSecret(pub, keyOffset) {
@@ -10938,7 +10980,7 @@ function validateRequiredOutputs(storage, userId, vargs) {
10938
10980
  * @returns {xinputs} extended validated required inputs.
10939
10981
  */
10940
10982
  async function validateRequiredInputs(storage, userId, vargs) {
10941
- const beef = new Beef();
10983
+ let beef = new Beef();
10942
10984
  if (vargs.inputs.length === 0) return {
10943
10985
  storageBeef: beef,
10944
10986
  beef,
@@ -10964,6 +11006,7 @@ async function validateRequiredInputs(storage, userId, vargs) {
10964
11006
  inputsByTxid[input.outpoint.txid] ||= [];
10965
11007
  inputsByTxid[input.outpoint.txid].push(input);
10966
11008
  }
11009
+ beef = beefForTxids(beef, Object.keys(inputsByTxid));
10967
11010
  const localKnownInputTxids = {};
10968
11011
  for (const [txid, txInputs] of Object.entries(inputsByTxid)) localKnownInputTxids[txid] = txInputs.every((input) => {
10969
11012
  const output = preloadedOutputsByOutpoint[`${input.outpoint.txid}.${input.outpoint.vout}`];
@@ -15225,11 +15268,19 @@ var StorageProvider = class StorageProvider extends StorageReaderWriter {
15225
15268
  return await this.updateOutput(output.outputId, { basketId: void 0 });
15226
15269
  }
15227
15270
  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);
15271
+ return await this.transaction(async (trx) => {
15272
+ const user = verifyTruthy(verifyOneOrNone(await this.findUsers({
15273
+ partial: { identityKey: args.identityKey },
15274
+ trx
15275
+ })));
15276
+ return await new EntitySyncState(verifyOne(await this.findSyncStates({
15277
+ partial: {
15278
+ storageIdentityKey: args.fromStorageIdentityKey,
15279
+ userId: user.userId
15280
+ },
15281
+ trx
15282
+ }))).processSyncChunk(this, args, chunk, trx);
15283
+ });
15233
15284
  }
15234
15285
  /**
15235
15286
  * Handles storage changes when a valid MerklePath and mined block header are found for a ProvenTxReq txid.
@@ -17294,8 +17345,10 @@ var StorageIdb = class extends StorageProvider {
17294
17345
  await tx.done;
17295
17346
  return r;
17296
17347
  } catch (err) {
17297
- tx.abort();
17298
- await tx.done;
17348
+ try {
17349
+ tx.abort();
17350
+ await tx.done;
17351
+ } catch {}
17299
17352
  throw err;
17300
17353
  }
17301
17354
  }
@@ -18262,6 +18315,25 @@ var StorageClientBase = class {
18262
18315
  * @returns `StorageCreateActionResults` supporting additional wallet processing to yield `createAction` results.
18263
18316
  */
18264
18317
  async createAction(auth, args) {
18318
+ if (args.inputBEEF != null) if (args.inputs.length === 0) args = {
18319
+ ...args,
18320
+ inputBEEF: void 0
18321
+ };
18322
+ else {
18323
+ let source;
18324
+ try {
18325
+ source = Beef.fromBinary(args.inputBEEF);
18326
+ } catch {
18327
+ source = void 0;
18328
+ }
18329
+ if (source != null) {
18330
+ const pruned = pruneBeefForTxids(source, args.inputs.map((input) => input.outpoint.txid));
18331
+ if (pruned != null) args = {
18332
+ ...args,
18333
+ inputBEEF: pruned.toBinary()
18334
+ };
18335
+ }
18336
+ }
18265
18337
  return await this.rpcCall("createAction", [auth, args]);
18266
18338
  }
18267
18339
  /**
@@ -30932,6 +31004,7 @@ var SetupClient = class SetupClient {
30932
31004
  };
30933
31005
  //#endregion
30934
31006
  //#region ../src/CWIStyleWalletManager.ts
31007
+ const CWI_COMPONENT = "wallet-toolbox.cwi-manager";
30935
31008
  /**
30936
31009
  * Number of rounds used in PBKDF2 for deriving password keys.
30937
31010
  */
@@ -31164,11 +31237,11 @@ var OverlayUMPTokenInteractor = class {
31164
31237
  * @param hash The 32-byte SHA-256 hash of the presentation key.
31165
31238
  * @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
31166
31239
  */
31167
- async findByPresentationKeyHash(hash) {
31168
- return await this.findToken({
31240
+ async findByPresentationKeyHash(hash, options) {
31241
+ return this.findToken({
31169
31242
  service: "ls_users",
31170
31243
  query: { presentationHash: Utils.toHex(hash) }
31171
- }, "presentation");
31244
+ }, "presentation", options);
31172
31245
  }
31173
31246
  /**
31174
31247
  * Finds a UMP token on-chain by the given recovery key hash, if it exists.
@@ -31177,13 +31250,13 @@ var OverlayUMPTokenInteractor = class {
31177
31250
  * @param hash The 32-byte SHA-256 hash of the recovery key.
31178
31251
  * @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
31179
31252
  */
31180
- async findByRecoveryKeyHash(hash) {
31181
- return await this.findToken({
31253
+ async findByRecoveryKeyHash(hash, options) {
31254
+ return this.findToken({
31182
31255
  service: "ls_users",
31183
31256
  query: { recoveryHash: Utils.toHex(hash) }
31184
- }, "recovery");
31257
+ }, "recovery", options);
31185
31258
  }
31186
- async findToken(question, lookupKind) {
31259
+ async findToken(question, lookupKind, options) {
31187
31260
  const correlationId = this.telemetry.enabled === true ? this.telemetry.createCorrelationId() : void 0;
31188
31261
  const startedAt = Date.now();
31189
31262
  this.telemetry.capture({
@@ -31200,34 +31273,39 @@ var OverlayUMPTokenInteractor = class {
31200
31273
  correlationId
31201
31274
  });
31202
31275
  } catch (error) {
31203
- const diagnostics = this.emptyLookupDiagnostics(correlationId);
31204
- this.captureLookupFailure(lookupKind, "lookup-unavailable", diagnostics, startedAt, error);
31276
+ const diagnostics = this.emptyStats(correlationId);
31277
+ this.lookupFailed(lookupKind, "lookup-unavailable", diagnostics, startedAt, error);
31205
31278
  throw new UMPTokenLookupError("lookup-unavailable", diagnostics, { cause: error });
31206
31279
  }
31207
- const diagnostics = this.toLookupDiagnostics(resolution);
31280
+ const diagnostics = this.diagnosticsFor(resolution);
31208
31281
  const tokens = this.parseLookupAnswers(resolution.answer);
31209
31282
  const expectedHash = question.query[lookupKind === "presentation" ? "presentationHash" : "recoveryHash"].toLowerCase();
31210
31283
  const matchingTokens = tokens.filter((token) => Utils.toHex(lookupKind === "presentation" ? token.presentationHash : token.recoveryHash).toLowerCase() === expectedHash);
31211
31284
  if (matchingTokens.length > 1) {
31212
31285
  const newest = this.resolveNewestToken(matchingTokens, resolution.answer.outputs);
31213
31286
  if (newest != null) {
31214
- this.captureLookupCompleted(lookupKind, "found", diagnostics, startedAt, { supersededTokens: matchingTokens.length - 1 });
31287
+ this.lookupDone(lookupKind, "found", diagnostics, startedAt, { supersededTokens: matchingTokens.length - 1 });
31215
31288
  return newest;
31216
31289
  }
31290
+ const pinned = options?.pinnedOutpoint ? matchingTokens.find((token) => token.currentOutpoint === options.pinnedOutpoint) : void 0;
31291
+ if (pinned != null) {
31292
+ this.lookupDone(lookupKind, "found", diagnostics, startedAt);
31293
+ return pinned;
31294
+ }
31217
31295
  const reason = "token-ambiguous";
31218
- this.captureLookupFailure(lookupKind, reason, diagnostics, startedAt);
31296
+ this.lookupFailed(lookupKind, reason, diagnostics, startedAt);
31219
31297
  throw new UMPTokenLookupError(reason, diagnostics);
31220
31298
  }
31221
31299
  if (matchingTokens.length === 1) {
31222
- this.captureLookupCompleted(lookupKind, "found", diagnostics, startedAt);
31300
+ this.lookupDone(lookupKind, "found", diagnostics, startedAt);
31223
31301
  return matchingTokens[0];
31224
31302
  }
31225
31303
  if (resolution.progress.emptyHosts > 0) {
31226
- this.captureLookupCompleted(lookupKind, "not-found", diagnostics, startedAt);
31304
+ this.lookupDone(lookupKind, "not-found", diagnostics, startedAt);
31227
31305
  return;
31228
31306
  }
31229
31307
  const reason = resolution.answer.outputs.length > 0 ? "token-malformed" : "lookup-incomplete";
31230
- this.captureLookupFailure(lookupKind, reason, diagnostics, startedAt);
31308
+ this.lookupFailed(lookupKind, reason, diagnostics, startedAt);
31231
31309
  throw new UMPTokenLookupError(reason, diagnostics);
31232
31310
  }
31233
31311
  /**
@@ -31258,7 +31336,7 @@ var OverlayUMPTokenInteractor = class {
31258
31336
  spent: /* @__PURE__ */ new Set()
31259
31337
  };
31260
31338
  evidence.txs.push(tx);
31261
- this.collectSpentOutpoints(tx, evidence.spent, /* @__PURE__ */ new Set());
31339
+ this.collectSpends(tx, evidence.spent, /* @__PURE__ */ new Set());
31262
31340
  evidenceByCandidate.set(outpoint, evidence);
31263
31341
  } catch {}
31264
31342
  if (evidenceByCandidate.size !== candidates.size) return void 0;
@@ -31267,7 +31345,7 @@ var OverlayUMPTokenInteractor = class {
31267
31345
  const provenContinuations = survivors.filter((outpoint) => {
31268
31346
  const evidence = evidenceByCandidate.get(outpoint);
31269
31347
  const token = candidates.get(outpoint);
31270
- return evidence != null && token != null && evidence.txs.some((tx) => this.consumesSameIdentityToken(tx, token));
31348
+ return evidence != null && token != null && evidence.txs.some((tx) => this.consumesIdentity(tx, token));
31271
31349
  });
31272
31350
  if (provenContinuations.length !== 1) return void 0;
31273
31351
  return candidates.get(provenContinuations[0]);
@@ -31278,7 +31356,7 @@ var OverlayUMPTokenInteractor = class {
31278
31356
  * hash — on-chain proof that the candidate is an update of a same-identity
31279
31357
  * predecessor rather than an independently minted token.
31280
31358
  */
31281
- consumesSameIdentityToken(tx, token) {
31359
+ consumesIdentity(tx, token) {
31282
31360
  const presentationHash = Utils.toHex(token.presentationHash);
31283
31361
  const recoveryHash = Utils.toHex(token.recoveryHash);
31284
31362
  for (const input of tx.inputs) {
@@ -31304,7 +31382,7 @@ var OverlayUMPTokenInteractor = class {
31304
31382
  * renditions are absent from the lookup answer. Iterative so arbitrarily
31305
31383
  * long update chains cannot exhaust the call stack.
31306
31384
  */
31307
- collectSpentOutpoints(tx, spent, visited) {
31385
+ collectSpends(tx, spent, visited) {
31308
31386
  const pending = [tx];
31309
31387
  while (pending.length > 0) {
31310
31388
  const current = pending.pop();
@@ -31319,7 +31397,7 @@ var OverlayUMPTokenInteractor = class {
31319
31397
  }
31320
31398
  }
31321
31399
  }
31322
- emptyLookupDiagnostics(correlationId) {
31400
+ emptyStats(correlationId) {
31323
31401
  return {
31324
31402
  hostCount: 0,
31325
31403
  completedHosts: 0,
@@ -31332,7 +31410,7 @@ var OverlayUMPTokenInteractor = class {
31332
31410
  ...correlationId !== void 0 ? { correlationId } : {}
31333
31411
  };
31334
31412
  }
31335
- toLookupDiagnostics(resolution) {
31413
+ diagnosticsFor(resolution) {
31336
31414
  const progress = resolution.progress;
31337
31415
  return {
31338
31416
  hostCount: progress.hostCount,
@@ -31346,7 +31424,7 @@ var OverlayUMPTokenInteractor = class {
31346
31424
  ...progress.correlationId !== void 0 ? { correlationId: progress.correlationId } : {}
31347
31425
  };
31348
31426
  }
31349
- lookupDiagnosticAttributes(diagnostics) {
31427
+ lookupAttrs(diagnostics) {
31350
31428
  return {
31351
31429
  hostCount: diagnostics.hostCount,
31352
31430
  completedHosts: diagnostics.completedHosts,
@@ -31358,7 +31436,7 @@ var OverlayUMPTokenInteractor = class {
31358
31436
  outputCount: diagnostics.outputCount
31359
31437
  };
31360
31438
  }
31361
- captureLookupCompleted(lookupKind, result, diagnostics, startedAt, extraAttributes = {}) {
31439
+ lookupDone(lookupKind, result, diagnostics, startedAt, extraAttributes = {}) {
31362
31440
  this.telemetry.capture({
31363
31441
  name: "wallet-toolbox.ump.lookup.completed",
31364
31442
  component: "wallet-toolbox.ump",
@@ -31368,12 +31446,12 @@ var OverlayUMPTokenInteractor = class {
31368
31446
  lookupKind,
31369
31447
  result,
31370
31448
  durationMs: Date.now() - startedAt,
31371
- ...this.lookupDiagnosticAttributes(diagnostics),
31449
+ ...this.lookupAttrs(diagnostics),
31372
31450
  ...extraAttributes
31373
31451
  }
31374
31452
  });
31375
31453
  }
31376
- captureLookupFailure(lookupKind, reason, diagnostics, startedAt, error) {
31454
+ lookupFailed(lookupKind, reason, diagnostics, startedAt, error) {
31377
31455
  this.telemetry.capture({
31378
31456
  name: "wallet-toolbox.ump.lookup.indeterminate",
31379
31457
  component: "wallet-toolbox.ump",
@@ -31383,7 +31461,7 @@ var OverlayUMPTokenInteractor = class {
31383
31461
  lookupKind,
31384
31462
  reason,
31385
31463
  durationMs: Date.now() - startedAt,
31386
- ...this.lookupDiagnosticAttributes(diagnostics)
31464
+ ...this.lookupAttrs(diagnostics)
31387
31465
  },
31388
31466
  error
31389
31467
  });
@@ -31401,27 +31479,27 @@ var OverlayUMPTokenInteractor = class {
31401
31479
  * @returns The outpoint of the newly created UMP token (e.g. "abcd1234...ef.0").
31402
31480
  */
31403
31481
  async buildAndSend(wallet, adminOriginator, token, oldTokenToConsume) {
31404
- const fields = this.buildUMPTokenFields(token);
31482
+ const fields = this.tokenFields(token);
31405
31483
  const tokenOutput = [{
31406
31484
  lockingScript: (await new PushDrop(wallet, adminOriginator).lock(fields, [2, "admin user management token"], "1", "self", true, true)).toHex(),
31407
31485
  satoshis: 1,
31408
31486
  outputDescription: "New UMP token output"
31409
31487
  }];
31410
- const { resolvedOldToken, inputToken } = await this.resolveOldTokenInput(oldTokenToConsume);
31488
+ const { resolvedOldToken, inputToken } = await this.resolveOldInput(oldTokenToConsume);
31411
31489
  const inputs = resolvedOldToken?.currentOutpoint ? [{
31412
31490
  outpoint: resolvedOldToken.currentOutpoint,
31413
31491
  unlockingScriptLength: 73,
31414
31492
  inputDescription: "Consume old UMP token"
31415
31493
  }] : [];
31416
- const createResult = await this.createUMPAction(wallet, adminOriginator, inputs, tokenOutput, inputToken, resolvedOldToken);
31417
- if (!createResult.signableTransaction) return await this.broadcastFinishedUMPAction(createResult);
31494
+ const createResult = await this.createAction(wallet, adminOriginator, inputs, tokenOutput, inputToken, resolvedOldToken);
31495
+ if (!createResult.signableTransaction) return this.broadcastFinal(createResult);
31418
31496
  const reference = createResult.signableTransaction.reference;
31419
31497
  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);
31498
+ if (resolvedOldToken?.currentOutpoint) return this.renewToken(wallet, adminOriginator, reference, partialTx);
31499
+ return this.broadcastNew(wallet, adminOriginator, reference);
31422
31500
  }
31423
31501
  /** Assembles the ordered number[][] fields array from a UMPToken. */
31424
- buildUMPTokenFields(token) {
31502
+ tokenFields(token) {
31425
31503
  const fields = [];
31426
31504
  fields[0] = token.passwordSalt;
31427
31505
  fields[1] = token.passwordPresentationPrimary;
@@ -31448,20 +31526,20 @@ var OverlayUMPTokenInteractor = class {
31448
31526
  return fields;
31449
31527
  }
31450
31528
  /** Looks up the old token on the overlay; returns undefined resolved token if not found. */
31451
- async resolveOldTokenInput(oldTokenToConsume) {
31529
+ async resolveOldInput(oldTokenToConsume) {
31452
31530
  if (!oldTokenToConsume?.currentOutpoint) return {
31453
31531
  resolvedOldToken: void 0,
31454
31532
  inputToken: void 0
31455
31533
  };
31456
31534
  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.");
31535
+ if (inputToken == null) throw new Error("Previous UMP token unavailable; update refused.");
31458
31536
  return {
31459
31537
  resolvedOldToken: oldTokenToConsume,
31460
31538
  inputToken
31461
31539
  };
31462
31540
  }
31463
31541
  /** Creates the UMP action without dropping a required old-token input on failure. */
31464
- async createUMPAction(wallet, adminOriginator, inputs, outputs, inputToken, resolvedOldToken) {
31542
+ async createAction(wallet, adminOriginator, inputs, outputs, inputToken, resolvedOldToken) {
31465
31543
  try {
31466
31544
  return await wallet.createAction({
31467
31545
  description: resolvedOldToken == null ? "Create new UMP token" : "Renew UMP token (consume old, create new)",
@@ -31488,43 +31566,43 @@ var OverlayUMPTokenInteractor = class {
31488
31566
  }
31489
31567
  }
31490
31568
  /** Handles a fully-finalized (no signable tx) createAction result — broadcasts and returns outpoint. */
31491
- async broadcastFinishedUMPAction(createResult) {
31569
+ async broadcastFinal(createResult) {
31492
31570
  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.");
31571
+ if (!finalTxid) throw new Error("UMP transaction was not finalized.");
31572
+ if (createResult.tx == null) throw new Error("UMP transaction data missing.");
31495
31573
  const broadcastTx = Transaction.fromAtomicBEEF(createResult.tx);
31496
31574
  const result = await this.broadcaster.broadcast(broadcastTx);
31497
- this.assertSuccessfulBroadcast(result, "create-finalized");
31575
+ this.assertBroadcast(result, "create-finalized");
31498
31576
  return `${finalTxid}.0`;
31499
31577
  }
31500
31578
  /** Signs the old-token input and broadcasts — used during UMP token renewal. */
31501
- async signAndBroadcastWithOldToken(wallet, adminOriginator, reference, partialTx) {
31579
+ async renewToken(wallet, adminOriginator, reference, partialTx) {
31502
31580
  const unlockingScript = await new PushDrop(wallet, adminOriginator).unlock([2, "admin user management token"], "1", "self").sign(partialTx, 0);
31503
31581
  const signResult = await wallet.signAction({
31504
31582
  reference,
31505
31583
  spends: { 0: { unlockingScript: unlockingScript.toHex() } }
31506
31584
  }, adminOriginator);
31507
31585
  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.");
31586
+ if (!finalTxid) throw new Error("Could not finalize renewed UMP token.");
31587
+ if (signResult.tx == null) throw new Error("Renewed UMP token transaction data missing.");
31510
31588
  const result = await this.broadcaster.broadcast(Transaction.fromAtomicBEEF(signResult.tx));
31511
- this.assertSuccessfulBroadcast(result, "renew");
31589
+ this.assertBroadcast(result, "renew");
31512
31590
  return `${finalTxid}.0`;
31513
31591
  }
31514
31592
  /** Signs without input spending and broadcasts — used when creating a brand-new UMP token. */
31515
- async signAndBroadcastNewToken(wallet, adminOriginator, reference) {
31593
+ async broadcastNew(wallet, adminOriginator, reference) {
31516
31594
  const signResult = await wallet.signAction({
31517
31595
  reference,
31518
31596
  spends: {}
31519
31597
  }, adminOriginator);
31520
31598
  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.");
31599
+ if (!finalTxid) throw new Error("Could not finalize new UMP token.");
31600
+ if (signResult.tx == null) throw new Error("New UMP token transaction data missing.");
31523
31601
  const result = await this.broadcaster.broadcast(Transaction.fromAtomicBEEF(signResult.tx));
31524
- this.assertSuccessfulBroadcast(result, "create");
31602
+ this.assertBroadcast(result, "create");
31525
31603
  return `${finalTxid}.0`;
31526
31604
  }
31527
- assertSuccessfulBroadcast(result, operation) {
31605
+ assertBroadcast(result, operation) {
31528
31606
  const succeeded = result.status === "success";
31529
31607
  this.telemetry.capture({
31530
31608
  name: succeeded ? "wallet-toolbox.ump.broadcast.completed" : "wallet-toolbox.ump.broadcast.failed",
@@ -31553,12 +31631,12 @@ var OverlayUMPTokenInteractor = class {
31553
31631
  if (answer.type !== "output-list" || answer.outputs.length === 0) return [];
31554
31632
  const tokens = [];
31555
31633
  for (const output of answer.outputs) {
31556
- const token = this.parseLookupOutput(output);
31634
+ const token = this.parseOutput(output);
31557
31635
  if (token != null) tokens.push(token);
31558
31636
  }
31559
31637
  return tokens;
31560
31638
  }
31561
- parseLookupOutput(output) {
31639
+ parseOutput(output) {
31562
31640
  try {
31563
31641
  const tx = Transaction.fromBEEF(output.beef);
31564
31642
  const txOutput = tx.outputs[output.outputIndex];
@@ -31608,14 +31686,14 @@ var OverlayUMPTokenInteractor = class {
31608
31686
  correlationId
31609
31687
  });
31610
31688
  } catch (error) {
31611
- const diagnostics = this.emptyLookupDiagnostics(correlationId);
31612
- this.captureLookupFailure("outpoint", "lookup-unavailable", diagnostics, startedAt, error);
31689
+ const diagnostics = this.emptyStats(correlationId);
31690
+ this.lookupFailed("outpoint", "lookup-unavailable", diagnostics, startedAt, error);
31613
31691
  throw new UMPTokenLookupError("lookup-unavailable", diagnostics, { cause: error });
31614
31692
  }
31615
31693
  if (resolution.answer.outputs.length === 0) {
31616
31694
  if (resolution.progress.emptyHosts === 0) {
31617
- const diagnostics = this.toLookupDiagnostics(resolution);
31618
- this.captureLookupFailure("outpoint", "lookup-incomplete", diagnostics, startedAt);
31695
+ const diagnostics = this.diagnosticsFor(resolution);
31696
+ this.lookupFailed("outpoint", "lookup-incomplete", diagnostics, startedAt);
31619
31697
  throw new UMPTokenLookupError("lookup-incomplete", diagnostics);
31620
31698
  }
31621
31699
  return;
@@ -31757,20 +31835,20 @@ var CWIStyleWalletManager = class {
31757
31835
  if (this._initSnapshot !== void 0) {
31758
31836
  this.telemetry.capture({
31759
31837
  name: "wallet-toolbox.snapshot.initialization.started",
31760
- component: "wallet-toolbox.cwi-manager",
31838
+ component: CWI_COMPONENT,
31761
31839
  severity: "debug"
31762
31840
  });
31763
31841
  try {
31764
31842
  await this.loadSnapshot(this._initSnapshot);
31765
31843
  this.telemetry.capture({
31766
31844
  name: "wallet-toolbox.snapshot.initialization.completed",
31767
- component: "wallet-toolbox.cwi-manager",
31845
+ component: CWI_COMPONENT,
31768
31846
  severity: "info"
31769
31847
  });
31770
31848
  } catch (error) {
31771
31849
  this.telemetry.capture({
31772
31850
  name: "wallet-toolbox.snapshot.initialization.failed",
31773
- component: "wallet-toolbox.cwi-manager",
31851
+ component: CWI_COMPONENT,
31774
31852
  severity: "error",
31775
31853
  error
31776
31854
  });
@@ -31779,9 +31857,11 @@ var CWIStyleWalletManager = class {
31779
31857
  }
31780
31858
  }
31781
31859
  /**
31782
- * Provides the presentation key.
31860
+ * Provides the presentation key. A WAB operator pin may be supplied by the
31861
+ * authentication manager; normal lookup and lineage resolution always run
31862
+ * before this ambiguity-only fallback.
31783
31863
  */
31784
- async providePresentationKey(key) {
31864
+ async providePresentationKey(key, lookupOptions) {
31785
31865
  if (this.authenticated) throw new Error("User is already authenticated");
31786
31866
  if (this.authenticationMode === "recovery-key-and-password") throw new Error("Presentation key is not needed in this mode");
31787
31867
  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 +31870,17 @@ var CWIStyleWalletManager = class {
31790
31870
  const startedAt = Date.now();
31791
31871
  this.telemetry.capture({
31792
31872
  name: "wallet-toolbox.authentication.account-lookup.started",
31793
- component: "wallet-toolbox.cwi-manager",
31873
+ component: CWI_COMPONENT,
31794
31874
  severity: "debug",
31795
31875
  attributes: { lookupKind: "presentation" }
31796
31876
  });
31797
31877
  let token;
31798
31878
  try {
31799
- token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash);
31879
+ token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash, lookupOptions);
31800
31880
  } catch (error) {
31801
31881
  this.telemetry.capture({
31802
31882
  name: "wallet-toolbox.authentication.account-lookup.failed",
31803
- component: "wallet-toolbox.cwi-manager",
31883
+ component: CWI_COMPONENT,
31804
31884
  severity: "warn",
31805
31885
  attributes: {
31806
31886
  lookupKind: "presentation",
@@ -31820,7 +31900,7 @@ var CWIStyleWalletManager = class {
31820
31900
  }
31821
31901
  this.telemetry.capture({
31822
31902
  name: "wallet-toolbox.authentication.account-lookup.completed",
31823
- component: "wallet-toolbox.cwi-manager",
31903
+ component: CWI_COMPONENT,
31824
31904
  severity: "info",
31825
31905
  attributes: {
31826
31906
  lookupKind: "presentation",
@@ -31836,11 +31916,11 @@ var CWIStyleWalletManager = class {
31836
31916
  if (this.authenticated) throw new Error("User is already authenticated");
31837
31917
  if (this.authenticationMode === "presentation-key-and-recovery-key") throw new Error("Password is not needed in this mode");
31838
31918
  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);
31919
+ if (this.authenticationFlow === "existing-user") await this.unlockExisting(password);
31920
+ else await this.createNewUser(password);
31841
31921
  }
31842
31922
  /** Handles the password step for an existing user — derives keys, sets up infrastructure. */
31843
- async handleExistingUserPassword(password) {
31923
+ async unlockExisting(password) {
31844
31924
  if (this.currentUMPToken == null) throw new Error("Provide presentation or recovery key first.");
31845
31925
  const derivedPasswordKey = await derivePasswordKey(this.currentUMPToken, Utils.toArray(password, "utf8"));
31846
31926
  let rootPrimaryKey;
@@ -31853,11 +31933,11 @@ var CWIStyleWalletManager = class {
31853
31933
  rootPrimaryKey = new SymmetricKey(this.XOR(this.recoveryKey, derivedPasswordKey)).decrypt(this.currentUMPToken.passwordRecoveryPrimary);
31854
31934
  rootPrivilegedKey = new SymmetricKey(this.XOR(rootPrimaryKey, derivedPasswordKey)).decrypt(this.currentUMPToken.passwordPrimaryPrivileged);
31855
31935
  }
31856
- await this.setupRootInfrastructure(rootPrimaryKey, rootPrivilegedKey);
31936
+ await this.setupRoot(rootPrimaryKey, rootPrivilegedKey);
31857
31937
  await this.switchProfile(this.activeProfileId);
31858
31938
  }
31859
31939
  /** Handles the password step for a new user — generates keys, builds UMP token, publishes on-chain. */
31860
- async handleNewUserPassword(password) {
31940
+ async createNewUser(password) {
31861
31941
  if (this.authenticationMode !== "presentation-key-and-password") throw new Error("New-user flow requires presentation key and password mode.");
31862
31942
  if (this.presentationKey == null) throw new Error("No presentation key provided for new-user flow.");
31863
31943
  const recoveryKey = Random(32);
@@ -31896,14 +31976,14 @@ var CWIStyleWalletManager = class {
31896
31976
  passwordKdf: this.kdfConfig
31897
31977
  };
31898
31978
  this.currentUMPToken = newToken;
31899
- await this.setupRootInfrastructure(rootPrimaryKey);
31979
+ await this.setupRoot(rootPrimaryKey);
31900
31980
  await this.switchProfile(DEFAULT_PROFILE_ID);
31901
31981
  if (this.newWalletFunder != null && this.underlying != null) try {
31902
31982
  await this.newWalletFunder(this.presentationKey, this.underlying, this.adminOriginator);
31903
31983
  } catch (error) {
31904
31984
  this.telemetry.capture({
31905
31985
  name: "wallet-toolbox.authentication.new-wallet-funding.failed",
31906
- component: "wallet-toolbox.cwi-manager",
31986
+ component: CWI_COMPONENT,
31907
31987
  severity: "error",
31908
31988
  error: /* @__PURE__ */ new Error("New wallet funding failed.")
31909
31989
  });
@@ -31934,7 +32014,7 @@ var CWIStyleWalletManager = class {
31934
32014
  const xorKey = this.XOR(this.presentationKey, recoveryKey);
31935
32015
  const rootPrimaryKey = new SymmetricKey(xorKey).decrypt(this.currentUMPToken.presentationRecoveryPrimary);
31936
32016
  const rootPrivilegedKey = new SymmetricKey(xorKey).decrypt(this.currentUMPToken.presentationRecoveryPrivileged);
31937
- await this.setupRootInfrastructure(rootPrimaryKey, rootPrivilegedKey);
32017
+ await this.setupRoot(rootPrimaryKey, rootPrivilegedKey);
31938
32018
  await this.switchProfile(this.activeProfileId);
31939
32019
  }
31940
32020
  }
@@ -31965,7 +32045,7 @@ var CWIStyleWalletManager = class {
31965
32045
  if (snapshot.length > 16777216) throw new Error("Snapshot exceeds the maximum supported size.");
31966
32046
  this.telemetry.capture({
31967
32047
  name: "wallet-toolbox.snapshot.saved",
31968
- component: "wallet-toolbox.cwi-manager",
32048
+ component: CWI_COMPONENT,
31969
32049
  severity: "info",
31970
32050
  attributes: {
31971
32051
  formatVersion: 2,
@@ -32003,12 +32083,12 @@ var CWIStyleWalletManager = class {
32003
32083
  const tokenBytes = payloadReader.read(tokenLen);
32004
32084
  const token = this.deserializeUMPToken(tokenBytes);
32005
32085
  this.currentUMPToken = token;
32006
- await this.setupRootInfrastructure(rootPrimaryKey);
32086
+ await this.setupRoot(rootPrimaryKey);
32007
32087
  await this.switchProfile(activeProfileId);
32008
32088
  this.authenticationFlow = "existing-user";
32009
32089
  this.telemetry.capture({
32010
32090
  name: "wallet-toolbox.snapshot.loaded",
32011
- component: "wallet-toolbox.cwi-manager",
32091
+ component: CWI_COMPONENT,
32012
32092
  severity: "info",
32013
32093
  attributes: {
32014
32094
  formatVersion: version,
@@ -32019,7 +32099,7 @@ var CWIStyleWalletManager = class {
32019
32099
  this.destroy();
32020
32100
  this.telemetry.capture({
32021
32101
  name: "wallet-toolbox.snapshot.load-failed",
32022
- component: "wallet-toolbox.cwi-manager",
32102
+ component: CWI_COMPONENT,
32023
32103
  severity: "error",
32024
32104
  error
32025
32105
  });
@@ -32036,7 +32116,7 @@ var CWIStyleWalletManager = class {
32036
32116
  if (refreshed == null) return false;
32037
32117
  if (refreshed.currentOutpoint && currentToken.currentOutpoint && refreshed.currentOutpoint === currentToken.currentOutpoint) return false;
32038
32118
  this.currentUMPToken = refreshed;
32039
- await this.setupRootInfrastructure(this.rootPrimaryKey);
32119
+ await this.setupRoot(this.rootPrimaryKey);
32040
32120
  this.saveSnapshot();
32041
32121
  return true;
32042
32122
  }
@@ -32095,7 +32175,7 @@ var CWIStyleWalletManager = class {
32095
32175
  createdAt: Math.floor(Date.now() / 1e3)
32096
32176
  };
32097
32177
  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);
32178
+ 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
32179
  return newProfile.id;
32100
32180
  }
32101
32181
  /**
@@ -32112,7 +32192,7 @@ var CWIStyleWalletManager = class {
32112
32192
  if (profileIndex === -1) throw new Error("Profile not found.");
32113
32193
  this.profiles.splice(profileIndex, 1);
32114
32194
  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);
32195
+ 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
32196
  }
32117
32197
  /**
32118
32198
  * Switches the active profile. This re-derives keys and rebuilds the underlying wallet.
@@ -32153,14 +32233,14 @@ var CWIStyleWalletManager = class {
32153
32233
  const recoveryKey = await this.getFactor("recoveryKey");
32154
32234
  const presentationKey = await this.getFactor("presentationKey");
32155
32235
  const rootPrivilegedKey = await this.getFactor("privilegedKey");
32156
- await this.updateAuthFactors(passwordSalt, newPasswordKey, presentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32236
+ await this.updateFactors(passwordSalt, newPasswordKey, presentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32157
32237
  }
32158
32238
  /**
32159
32239
  * Retrieves the current recovery key. Requires privileged access.
32160
32240
  */
32161
32241
  async getRecoveryKey() {
32162
32242
  if (!this.authenticated || this.currentUMPToken == null || this.rootPrivilegedKeyManager == null) throw new Error("Not authenticated or missing required data.");
32163
- return await this.getFactor("recoveryKey");
32243
+ return this.getFactor("recoveryKey");
32164
32244
  }
32165
32245
  /**
32166
32246
  * Changes the user's recovery key. Prompts user to save the new key.
@@ -32172,7 +32252,7 @@ var CWIStyleWalletManager = class {
32172
32252
  const rootPrivilegedKey = await this.getFactor("privilegedKey");
32173
32253
  const newRecoveryKey = Random(32);
32174
32254
  await this.recoveryKeySaver(newRecoveryKey);
32175
- await this.updateAuthFactors(this.currentUMPToken.passwordSalt, passwordKey, presentationKey, newRecoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32255
+ await this.updateFactors(this.currentUMPToken.passwordSalt, passwordKey, presentationKey, newRecoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32176
32256
  }
32177
32257
  /**
32178
32258
  * Changes the user's presentation key.
@@ -32183,7 +32263,7 @@ var CWIStyleWalletManager = class {
32183
32263
  const recoveryKey = await this.getFactor("recoveryKey");
32184
32264
  const passwordKey = await this.getFactor("passwordKey");
32185
32265
  const rootPrivilegedKey = await this.getFactor("privilegedKey");
32186
- await this.updateAuthFactors(this.currentUMPToken.passwordSalt, passwordKey, newPresentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32266
+ await this.updateFactors(this.currentUMPToken.passwordSalt, passwordKey, newPresentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
32187
32267
  if (this.presentationKey != null) this.presentationKey = newPresentationKey;
32188
32268
  }
32189
32269
  /**
@@ -32229,7 +32309,7 @@ var CWIStyleWalletManager = class {
32229
32309
  } catch (error) {
32230
32310
  this.telemetry.capture({
32231
32311
  name: "wallet-toolbox.authentication.factor-decryption.failed",
32232
- component: "wallet-toolbox.cwi-manager",
32312
+ component: CWI_COMPONENT,
32233
32313
  severity: "error",
32234
32314
  attributes: { factor: factorName },
32235
32315
  error
@@ -32242,7 +32322,7 @@ var CWIStyleWalletManager = class {
32242
32322
  * Recomputes UMP token fields with updated factors and profiles, then publishes the update.
32243
32323
  * This operation requires the *root* privileged key and the *default* profile wallet.
32244
32324
  */
32245
- async updateAuthFactors(passwordSalt, passwordKey, presentationKey, recoveryKey, rootPrimaryKey, rootPrivilegedKey, profiles) {
32325
+ async updateFactors(passwordSalt, passwordKey, presentationKey, recoveryKey, rootPrimaryKey, rootPrivilegedKey, profiles) {
32246
32326
  if (!this.authenticated || this.rootPrimaryKey == null || this.currentUMPToken == null) throw new Error("Wallet is not properly authenticated or missing data for update.");
32247
32327
  const oldTokenToConsume = { ...this.currentUMPToken };
32248
32328
  if (!oldTokenToConsume.currentOutpoint) throw new Error("Cannot update UMP token: Old token has no outpoint.");
@@ -32293,7 +32373,7 @@ var CWIStyleWalletManager = class {
32293
32373
  if (!currentActiveId.every((x) => x === 0)) {
32294
32374
  this.telemetry.capture({
32295
32375
  name: "wallet-toolbox.ump.profile-switch.started",
32296
- component: "wallet-toolbox.cwi-manager",
32376
+ component: CWI_COMPONENT,
32297
32377
  severity: "debug",
32298
32378
  attributes: { reason: "token-update" }
32299
32379
  });
@@ -32309,7 +32389,7 @@ var CWIStyleWalletManager = class {
32309
32389
  await this.switchProfile(currentActiveId);
32310
32390
  this.telemetry.capture({
32311
32391
  name: "wallet-toolbox.ump.profile-switch.completed",
32312
- component: "wallet-toolbox.cwi-manager",
32392
+ component: CWI_COMPONENT,
32313
32393
  severity: "debug",
32314
32394
  attributes: { reason: "token-update" }
32315
32395
  });
@@ -32436,9 +32516,9 @@ var CWIStyleWalletManager = class {
32436
32516
  * @param rootPrimaryKey The user's root primary key (32 bytes).
32437
32517
  * @param ephemeralRootPrivilegedKey Optional root privileged key (e.g., during recovery flows).
32438
32518
  */
32439
- async setupRootInfrastructure(rootPrimaryKey, ephemeralRootPrivilegedKey) {
32519
+ async setupRoot(rootKey, ephemeralRootPrivilegedKey) {
32440
32520
  if (this.currentUMPToken == null) throw new Error("A UMP token must exist before setting up root infrastructure!");
32441
- this.rootPrimaryKey = rootPrimaryKey;
32521
+ this.rootPrimaryKey = rootKey;
32442
32522
  let oneTimePrivilegedKey = ephemeralRootPrivilegedKey == null ? void 0 : new PrivateKey(ephemeralRootPrivilegedKey);
32443
32523
  this.rootPrivilegedKeyManager = new PrivilegedKeyManager(async (reason) => {
32444
32524
  if (oneTimePrivilegedKey != null) {
@@ -32459,7 +32539,7 @@ var CWIStyleWalletManager = class {
32459
32539
  });
32460
32540
  this.profiles = [];
32461
32541
  if (this.currentUMPToken.profilesEncrypted != null && this.currentUMPToken.profilesEncrypted.length > 0) try {
32462
- const decryptedProfileBytes = new SymmetricKey(rootPrimaryKey).decrypt(this.currentUMPToken.profilesEncrypted);
32542
+ const decryptedProfileBytes = new SymmetricKey(rootKey).decrypt(this.currentUMPToken.profilesEncrypted);
32463
32543
  const profilesJson = Utils.toUTF8(decryptedProfileBytes);
32464
32544
  const profiles = JSON.parse(profilesJson);
32465
32545
  if (!Array.isArray(profiles) || profiles.length > 1e3 || !profiles.every(isValidProfile)) throw new Error("Decrypted profile data is invalid or exceeds supported bounds.");
@@ -32468,7 +32548,7 @@ var CWIStyleWalletManager = class {
32468
32548
  this.profiles = [];
32469
32549
  this.telemetry.capture({
32470
32550
  name: "wallet-toolbox.profile.load-failed",
32471
- component: "wallet-toolbox.cwi-manager",
32551
+ component: CWI_COMPONENT,
32472
32552
  severity: "error",
32473
32553
  error
32474
32554
  });
@@ -32477,98 +32557,98 @@ var CWIStyleWalletManager = class {
32477
32557
  }
32478
32558
  this.authenticated = true;
32479
32559
  }
32480
- checkAuthAndUnderlying(originator) {
32560
+ assertReady(originator) {
32481
32561
  if (!this.authenticated) throw new Error("User is not authenticated.");
32482
32562
  if (this.underlying == null) throw new Error("Underlying wallet for the active profile is not initialized.");
32483
32563
  if (originator === this.adminOriginator) throw new Error("External applications are not allowed to use the admin originator.");
32484
32564
  }
32485
32565
  async getPublicKey(args, originator) {
32486
- this.checkAuthAndUnderlying(originator);
32487
- return await this.underlying.getPublicKey(args, originator);
32566
+ this.assertReady(originator);
32567
+ return this.underlying.getPublicKey(args, originator);
32488
32568
  }
32489
32569
  async revealCounterpartyKeyLinkage(args, originator) {
32490
- this.checkAuthAndUnderlying(originator);
32491
- return await this.underlying.revealCounterpartyKeyLinkage(args, originator);
32570
+ this.assertReady(originator);
32571
+ return this.underlying.revealCounterpartyKeyLinkage(args, originator);
32492
32572
  }
32493
32573
  async revealSpecificKeyLinkage(args, originator) {
32494
- this.checkAuthAndUnderlying(originator);
32495
- return await this.underlying.revealSpecificKeyLinkage(args, originator);
32574
+ this.assertReady(originator);
32575
+ return this.underlying.revealSpecificKeyLinkage(args, originator);
32496
32576
  }
32497
32577
  async encrypt(args, originator) {
32498
- this.checkAuthAndUnderlying(originator);
32499
- return await this.underlying.encrypt(args, originator);
32578
+ this.assertReady(originator);
32579
+ return this.underlying.encrypt(args, originator);
32500
32580
  }
32501
32581
  async decrypt(args, originator) {
32502
- this.checkAuthAndUnderlying(originator);
32503
- return await this.underlying.decrypt(args, originator);
32582
+ this.assertReady(originator);
32583
+ return this.underlying.decrypt(args, originator);
32504
32584
  }
32505
32585
  async createHmac(args, originator) {
32506
- this.checkAuthAndUnderlying(originator);
32507
- return await this.underlying.createHmac(args, originator);
32586
+ this.assertReady(originator);
32587
+ return this.underlying.createHmac(args, originator);
32508
32588
  }
32509
32589
  async verifyHmac(args, originator) {
32510
- this.checkAuthAndUnderlying(originator);
32511
- return await this.underlying.verifyHmac(args, originator);
32590
+ this.assertReady(originator);
32591
+ return this.underlying.verifyHmac(args, originator);
32512
32592
  }
32513
32593
  async createSignature(args, originator) {
32514
- this.checkAuthAndUnderlying(originator);
32515
- return await this.underlying.createSignature(args, originator);
32594
+ this.assertReady(originator);
32595
+ return this.underlying.createSignature(args, originator);
32516
32596
  }
32517
32597
  async verifySignature(args, originator) {
32518
- this.checkAuthAndUnderlying(originator);
32519
- return await this.underlying.verifySignature(args, originator);
32598
+ this.assertReady(originator);
32599
+ return this.underlying.verifySignature(args, originator);
32520
32600
  }
32521
32601
  async createAction(args, originator) {
32522
- this.checkAuthAndUnderlying(originator);
32523
- return await this.underlying.createAction(args, originator);
32602
+ this.assertReady(originator);
32603
+ return this.underlying.createAction(args, originator);
32524
32604
  }
32525
32605
  async signAction(args, originator) {
32526
- this.checkAuthAndUnderlying(originator);
32527
- return await this.underlying.signAction(args, originator);
32606
+ this.assertReady(originator);
32607
+ return this.underlying.signAction(args, originator);
32528
32608
  }
32529
32609
  async abortAction(args, originator) {
32530
- this.checkAuthAndUnderlying(originator);
32531
- return await this.underlying.abortAction(args, originator);
32610
+ this.assertReady(originator);
32611
+ return this.underlying.abortAction(args, originator);
32532
32612
  }
32533
32613
  async listActions(args, originator) {
32534
- this.checkAuthAndUnderlying(originator);
32535
- return await this.underlying.listActions(args, originator);
32614
+ this.assertReady(originator);
32615
+ return this.underlying.listActions(args, originator);
32536
32616
  }
32537
32617
  async internalizeAction(args, originator) {
32538
- this.checkAuthAndUnderlying(originator);
32539
- return await this.underlying.internalizeAction(args, originator);
32618
+ this.assertReady(originator);
32619
+ return this.underlying.internalizeAction(args, originator);
32540
32620
  }
32541
32621
  async listOutputs(args, originator) {
32542
- this.checkAuthAndUnderlying(originator);
32543
- return await this.underlying.listOutputs(args, originator);
32622
+ this.assertReady(originator);
32623
+ return this.underlying.listOutputs(args, originator);
32544
32624
  }
32545
32625
  async relinquishOutput(args, originator) {
32546
- this.checkAuthAndUnderlying(originator);
32547
- return await this.underlying.relinquishOutput(args, originator);
32626
+ this.assertReady(originator);
32627
+ return this.underlying.relinquishOutput(args, originator);
32548
32628
  }
32549
32629
  async acquireCertificate(args, originator) {
32550
- this.checkAuthAndUnderlying(originator);
32551
- return await this.underlying.acquireCertificate(args, originator);
32630
+ this.assertReady(originator);
32631
+ return this.underlying.acquireCertificate(args, originator);
32552
32632
  }
32553
32633
  async listCertificates(args, originator) {
32554
- this.checkAuthAndUnderlying(originator);
32555
- return await this.underlying.listCertificates(args, originator);
32634
+ this.assertReady(originator);
32635
+ return this.underlying.listCertificates(args, originator);
32556
32636
  }
32557
32637
  async proveCertificate(args, originator) {
32558
- this.checkAuthAndUnderlying(originator);
32559
- return await this.underlying.proveCertificate(args, originator);
32638
+ this.assertReady(originator);
32639
+ return this.underlying.proveCertificate(args, originator);
32560
32640
  }
32561
32641
  async relinquishCertificate(args, originator) {
32562
- this.checkAuthAndUnderlying(originator);
32563
- return await this.underlying.relinquishCertificate(args, originator);
32642
+ this.assertReady(originator);
32643
+ return this.underlying.relinquishCertificate(args, originator);
32564
32644
  }
32565
32645
  async discoverByIdentityKey(args, originator) {
32566
- this.checkAuthAndUnderlying(originator);
32567
- return await this.underlying.discoverByIdentityKey(args, originator);
32646
+ this.assertReady(originator);
32647
+ return this.underlying.discoverByIdentityKey(args, originator);
32568
32648
  }
32569
32649
  async discoverByAttributes(args, originator) {
32570
- this.checkAuthAndUnderlying(originator);
32571
- return await this.underlying.discoverByAttributes(args, originator);
32650
+ this.assertReady(originator);
32651
+ return this.underlying.discoverByAttributes(args, originator);
32572
32652
  }
32573
32653
  async isAuthenticated(_, originator) {
32574
32654
  if (!this.authenticated) throw new Error("User is not authenticated.");
@@ -32578,23 +32658,23 @@ var CWIStyleWalletManager = class {
32578
32658
  async waitForAuthentication(_, originator) {
32579
32659
  if (originator === this.adminOriginator) throw new Error("External applications are not allowed to use the admin originator.");
32580
32660
  while (!this.authenticated || this.underlying == null) await new Promise((resolve) => setTimeout(resolve, 100));
32581
- return await this.underlying.waitForAuthentication({}, originator);
32661
+ return this.underlying.waitForAuthentication({}, originator);
32582
32662
  }
32583
32663
  async getHeight(_, originator) {
32584
- this.checkAuthAndUnderlying(originator);
32585
- return await this.underlying.getHeight({}, originator);
32664
+ this.assertReady(originator);
32665
+ return this.underlying.getHeight({}, originator);
32586
32666
  }
32587
32667
  async getHeaderForHeight(args, originator) {
32588
- this.checkAuthAndUnderlying(originator);
32589
- return await this.underlying.getHeaderForHeight(args, originator);
32668
+ this.assertReady(originator);
32669
+ return this.underlying.getHeaderForHeight(args, originator);
32590
32670
  }
32591
32671
  async getNetwork(_, originator) {
32592
- this.checkAuthAndUnderlying(originator);
32593
- return await this.underlying.getNetwork({}, originator);
32672
+ this.assertReady(originator);
32673
+ return this.underlying.getNetwork({}, originator);
32594
32674
  }
32595
32675
  async getVersion(_, originator) {
32596
- this.checkAuthAndUnderlying(originator);
32597
- return await this.underlying.getVersion({}, originator);
32676
+ this.assertReady(originator);
32677
+ return this.underlying.getVersion({}, originator);
32598
32678
  }
32599
32679
  };
32600
32680
  //#endregion
@@ -32938,6 +33018,8 @@ const DEFAULT_MAX_RESPONSE_BYTES = 1024 * 1024;
32938
33018
  const MAX_CONFIGURED_TIMEOUT_MS = 12e4;
32939
33019
  const MAX_CONFIGURED_REQUEST_BYTES = 10 * 1024 * 1024;
32940
33020
  const MAX_CONFIGURED_RESPONSE_BYTES = 10 * 1024 * 1024;
33021
+ const WAB_COMPONENT = "wallet-toolbox.wab-transport";
33022
+ const WAB_REQUEST_EVENT = "wallet-toolbox.wab.request.";
32941
33023
  const defaultFetch = typeof globalThis !== "undefined" && typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
32942
33024
  /**
32943
33025
  * A privacy-safe WAB transport failure. Response bodies and request payloads
@@ -32976,8 +33058,8 @@ function normalizeServerUrl(serverUrl) {
32976
33058
  } catch {
32977
33059
  throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB server URL must be an absolute URL.", false);
32978
33060
  }
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);
33061
+ if (parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB URL cannot include credentials, query, or fragment.", false);
33062
+ 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
33063
  let pathname = parsed.pathname;
32982
33064
  while (pathname.endsWith("/")) pathname = pathname.slice(0, -1);
32983
33065
  return {
@@ -32987,7 +33069,7 @@ function normalizeServerUrl(serverUrl) {
32987
33069
  }
32988
33070
  function normalizePositiveInteger(value, fallback, maximum, name) {
32989
33071
  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);
33072
+ 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
33073
  return resolved;
32992
33074
  }
32993
33075
  function assertSafePath(path) {
@@ -33012,20 +33094,20 @@ var WABTransport = class {
33012
33094
  serverUrl;
33013
33095
  serverOrigin;
33014
33096
  telemetry;
33015
- fetchClient;
33016
- timeoutMs;
33017
- maxRequestBytes;
33018
- maxResponseBytes;
33097
+ fetcher;
33098
+ timeout;
33099
+ requestLimit;
33100
+ responseLimit;
33019
33101
  constructor(serverUrl, options = {}) {
33020
33102
  const normalized = normalizeServerUrl(serverUrl);
33021
33103
  this.serverUrl = normalized.baseUrl;
33022
33104
  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");
33105
+ const fetcher = options.fetch ?? defaultFetch;
33106
+ if (typeof fetcher !== "function") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WABClient requires a fetch implementation.", false);
33107
+ this.fetcher = fetcher;
33108
+ this.timeout = normalizePositiveInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, MAX_CONFIGURED_TIMEOUT_MS, "timeoutMs");
33109
+ this.requestLimit = normalizePositiveInteger(options.maxRequestBytes, DEFAULT_MAX_REQUEST_BYTES, MAX_CONFIGURED_REQUEST_BYTES, "maxRequestBytes");
33110
+ this.responseLimit = normalizePositiveInteger(options.maxResponseBytes, DEFAULT_MAX_RESPONSE_BYTES, MAX_CONFIGURED_RESPONSE_BYTES, "maxResponseBytes");
33029
33111
  this.telemetry = new Telemetry(options.telemetry);
33030
33112
  }
33031
33113
  createCorrelationId() {
@@ -33033,38 +33115,9 @@ var WABTransport = class {
33033
33115
  return isSafeCorrelationId(correlationId) ? correlationId : new Telemetry().createCorrelationId();
33034
33116
  }
33035
33117
  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
33118
  assertSafePath(path);
33066
33119
  const correlationId = options.correlationId != null && isSafeCorrelationId(options.correlationId) ? options.correlationId : this.createCorrelationId();
33067
- return {
33120
+ const metadata = {
33068
33121
  method: options.method ?? "POST",
33069
33122
  path,
33070
33123
  operation: options.operation,
@@ -33076,46 +33129,73 @@ var WABTransport = class {
33076
33129
  route: path
33077
33130
  }
33078
33131
  };
33079
- }
33080
- captureRequestStarted(metadata) {
33081
33132
  this.telemetry.capture({
33082
- name: "wallet-toolbox.wab.request.started",
33083
- component: "wallet-toolbox.wab-transport",
33133
+ name: `${WAB_REQUEST_EVENT}started`,
33134
+ component: WAB_COMPONENT,
33084
33135
  severity: "debug",
33136
+ correlationId,
33137
+ attributes: {
33138
+ operation: metadata.operation,
33139
+ method: metadata.method,
33140
+ route: path,
33141
+ serverOrigin: this.serverOrigin
33142
+ }
33143
+ });
33144
+ const body = this.bodyFor(options, metadata);
33145
+ const timeout = this.startTimer(metadata.errorContext);
33146
+ const response = await this.fetch(metadata, body, timeout);
33147
+ const responseContext = {
33148
+ ...metadata.errorContext,
33149
+ endpointMarkerPresent: isWabResponse(response),
33150
+ responseCorrelationMatched: response.headers.get("X-Correlation-ID") === correlationId
33151
+ };
33152
+ this.checkResponse(response, responseContext, metadata, timeout);
33153
+ const responseText = await this.readText(response, responseContext, metadata, timeout);
33154
+ const parsed = this.parse(responseText, response, responseContext, metadata);
33155
+ this.telemetry.capture({
33156
+ name: `${WAB_REQUEST_EVENT}completed`,
33157
+ component: WAB_COMPONENT,
33158
+ severity: "info",
33085
33159
  correlationId: metadata.correlationId,
33086
33160
  attributes: {
33087
33161
  operation: metadata.operation,
33088
33162
  method: metadata.method,
33089
33163
  route: metadata.path,
33090
- serverOrigin: this.serverOrigin
33164
+ serverOrigin: this.serverOrigin,
33165
+ status: response.status,
33166
+ endpointMarkerPresent: responseContext.endpointMarkerPresent,
33167
+ responseCorrelationMatched: responseContext.responseCorrelationMatched,
33168
+ responseBytes: new TextEncoder().encode(responseText).byteLength,
33169
+ durationMs: Date.now() - metadata.startedAt
33091
33170
  }
33092
33171
  });
33172
+ return parsed;
33093
33173
  }
33094
- encodeRequestBody(options, metadata) {
33174
+ bodyFor(options, metadata) {
33095
33175
  let body;
33096
33176
  try {
33097
33177
  body = options.body === void 0 ? void 0 : JSON.stringify(options.body);
33098
33178
  } catch (cause) {
33099
- const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request payload could not be encoded.", false, void 0, {
33179
+ const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request encoding failed.", false, void 0, {
33100
33180
  ...metadata.errorContext,
33101
33181
  cause
33102
33182
  });
33103
- this.captureRequestFailure(metadata, error);
33183
+ this.report(metadata, error);
33104
33184
  throw error;
33105
33185
  }
33106
33186
  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);
33187
+ const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request is not JSON-serializable.", false, void 0, metadata.errorContext);
33188
+ this.report(metadata, error);
33109
33189
  throw error;
33110
33190
  }
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);
33191
+ if (body != null && new TextEncoder().encode(body).byteLength > this.requestLimit) {
33192
+ const error = new WABClientError("WAB_REQUEST_TOO_LARGE", "WAB request exceeds its size limit.", false, void 0, metadata.errorContext);
33193
+ this.report(metadata, error);
33114
33194
  throw error;
33115
33195
  }
33116
33196
  return body;
33117
33197
  }
33118
- startRequestTimeout(errorContext) {
33198
+ startTimer(errorContext) {
33119
33199
  const timeout = {
33120
33200
  controller: new AbortController(),
33121
33201
  timedOut: false
@@ -33125,12 +33205,12 @@ var WABTransport = class {
33125
33205
  timeout.timedOut = true;
33126
33206
  timeout.controller.abort();
33127
33207
  reject(new WABClientError("WAB_TIMEOUT", "WAB request timed out.", true, void 0, errorContext));
33128
- }, this.timeoutMs);
33208
+ }, this.timeout);
33129
33209
  });
33130
33210
  return timeout;
33131
33211
  }
33132
- async fetchResponse(metadata, body, timeout) {
33133
- const requestPromise = Promise.resolve().then(() => this.fetchClient(`${this.serverUrl}${metadata.path}`, {
33212
+ async fetch(metadata, body, timeout) {
33213
+ const requestPromise = Promise.resolve().then(() => this.fetcher(`${this.serverUrl}${metadata.path}`, {
33134
33214
  method: metadata.method,
33135
33215
  headers: {
33136
33216
  Accept: "application/json",
@@ -33154,33 +33234,26 @@ var WABTransport = class {
33154
33234
  ...metadata.errorContext,
33155
33235
  cause
33156
33236
  });
33157
- else error = new WABClientError("WAB_NETWORK_ERROR", "WAB request failed before receiving a response.", true, void 0, {
33237
+ else error = new WABClientError("WAB_NETWORK_ERROR", "WAB request failed before response.", true, void 0, {
33158
33238
  ...metadata.errorContext,
33159
33239
  cause
33160
33240
  });
33161
- this.captureRequestFailure(metadata, error);
33241
+ this.report(metadata, error);
33162
33242
  throw error;
33163
33243
  }
33164
33244
  }
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) {
33245
+ checkResponse(response, responseContext, metadata, timeout) {
33173
33246
  if (response.ok) return;
33174
33247
  if (timeout.timer !== void 0) clearTimeout(timeout.timer);
33175
33248
  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);
33249
+ 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);
33250
+ this.report(metadata, error);
33178
33251
  response.body?.cancel().catch(() => {});
33179
33252
  throw error;
33180
33253
  }
33181
- async readResponseText(response, responseContext, metadata, timeout) {
33254
+ async readText(response, responseContext, metadata, timeout) {
33182
33255
  try {
33183
- return await Promise.race([this.readBoundedResponse(response, responseContext), timeout.promise]);
33256
+ return await Promise.race([this.read(response, responseContext), timeout.promise]);
33184
33257
  } catch (cause) {
33185
33258
  let error;
33186
33259
  if (cause instanceof WABClientError) error = cause;
@@ -33188,17 +33261,17 @@ var WABTransport = class {
33188
33261
  ...responseContext,
33189
33262
  cause
33190
33263
  });
33191
- else error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response could not be read.", true, response.status, {
33264
+ else error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response read failed.", true, response.status, {
33192
33265
  ...responseContext,
33193
33266
  cause
33194
33267
  });
33195
- this.captureRequestFailure(metadata, error);
33268
+ this.report(metadata, error);
33196
33269
  throw error;
33197
33270
  } finally {
33198
33271
  if (timeout.timer !== void 0) clearTimeout(timeout.timer);
33199
33272
  }
33200
33273
  }
33201
- parseResponseObject(responseText, response, responseContext, metadata) {
33274
+ parse(responseText, response, responseContext, metadata) {
33202
33275
  let parsed;
33203
33276
  try {
33204
33277
  parsed = JSON.parse(responseText);
@@ -33207,37 +33280,32 @@ var WABTransport = class {
33207
33280
  ...responseContext,
33208
33281
  cause
33209
33282
  });
33210
- this.captureRequestFailure(metadata, error);
33283
+ this.report(metadata, error);
33211
33284
  throw error;
33212
33285
  }
33213
33286
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
33214
33287
  const error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response must be a JSON object.", true, response.status, responseContext);
33215
- this.captureRequestFailure(metadata, error);
33288
+ this.report(metadata, error);
33216
33289
  throw error;
33217
33290
  }
33218
33291
  return parsed;
33219
33292
  }
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) {
33293
+ async read(response, responseContext) {
33230
33294
  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);
33295
+ if (Number.isFinite(contentLength) && contentLength > this.responseLimit) {
33296
+ await this.stopBody(response);
33297
+ throw this.sizeError(response, responseContext);
33298
+ }
33299
+ const reader = response.body?.getReader();
33300
+ if (reader == null) return this.readBuffer(response, responseContext);
33301
+ return this.readStream(reader, response, responseContext);
33234
33302
  }
33235
- async readBoundedArrayBuffer(response, responseContext) {
33303
+ async readBuffer(response, responseContext) {
33236
33304
  const bytes = new Uint8Array(await response.arrayBuffer());
33237
- if (bytes.byteLength > this.maxResponseBytes) throw this.responseTooLargeError(response, responseContext);
33305
+ if (bytes.byteLength > this.responseLimit) throw this.sizeError(response, responseContext);
33238
33306
  return new TextDecoder().decode(bytes);
33239
33307
  }
33240
- async readBoundedStream(reader, response, responseContext) {
33308
+ async readStream(reader, response, responseContext) {
33241
33309
  const chunks = [];
33242
33310
  let total = 0;
33243
33311
  while (true) {
@@ -33245,15 +33313,12 @@ var WABTransport = class {
33245
33313
  if (done) break;
33246
33314
  if (value == null) continue;
33247
33315
  total += value.byteLength;
33248
- if (total > this.maxResponseBytes) {
33249
- await this.cancelResponseReader(reader);
33250
- throw this.responseTooLargeError(response, responseContext);
33316
+ if (total > this.responseLimit) {
33317
+ await this.stopReader(reader);
33318
+ throw this.sizeError(response, responseContext);
33251
33319
  }
33252
33320
  chunks.push(value);
33253
33321
  }
33254
- return this.decodeChunks(chunks, total);
33255
- }
33256
- decodeChunks(chunks, total) {
33257
33322
  const bytes = new Uint8Array(total);
33258
33323
  let offset = 0;
33259
33324
  for (const chunk of chunks) {
@@ -33262,35 +33327,35 @@ var WABTransport = class {
33262
33327
  }
33263
33328
  return new TextDecoder().decode(bytes);
33264
33329
  }
33265
- responseTooLargeError(response, responseContext) {
33266
- return new WABClientError("WAB_RESPONSE_TOO_LARGE", "WAB response exceeded the configured size limit.", false, response.status, responseContext);
33330
+ sizeError(response, responseContext) {
33331
+ return new WABClientError("WAB_RESPONSE_TOO_LARGE", "WAB response exceeds its size limit.", false, response.status, responseContext);
33267
33332
  }
33268
- async cancelResponseBody(response) {
33333
+ async stopBody(response) {
33269
33334
  try {
33270
33335
  await response.body?.cancel();
33271
33336
  } catch {}
33272
33337
  }
33273
- async cancelResponseReader(reader) {
33338
+ async stopReader(reader) {
33274
33339
  try {
33275
33340
  await reader.cancel();
33276
33341
  } catch {}
33277
33342
  }
33278
- captureFailure(operation, method, path, correlationId, startedAt, error) {
33343
+ report(metadata, error) {
33279
33344
  this.telemetry.capture({
33280
- name: "wallet-toolbox.wab.request.failed",
33281
- component: "wallet-toolbox.wab-transport",
33345
+ name: `${WAB_REQUEST_EVENT}failed`,
33346
+ component: WAB_COMPONENT,
33282
33347
  severity: error.retryable ? "warn" : "error",
33283
- correlationId,
33348
+ correlationId: metadata.correlationId,
33284
33349
  attributes: {
33285
- operation,
33286
- method,
33287
- route: path,
33350
+ operation: metadata.operation,
33351
+ method: metadata.method,
33352
+ route: metadata.path,
33288
33353
  serverOrigin: this.serverOrigin,
33289
33354
  retryable: error.retryable,
33290
33355
  ...error.status !== void 0 ? { status: error.status } : {},
33291
33356
  ...error.endpointMarkerPresent !== void 0 ? { endpointMarkerPresent: error.endpointMarkerPresent } : {},
33292
33357
  ...error.responseCorrelationMatched !== void 0 ? { responseCorrelationMatched: error.responseCorrelationMatched } : {},
33293
- durationMs: Date.now() - startedAt
33358
+ durationMs: Date.now() - metadata.startedAt
33294
33359
  },
33295
33360
  error
33296
33361
  });
@@ -33399,8 +33464,8 @@ var WABClient = class {
33399
33464
  constructor(serverUrl, options = {}) {
33400
33465
  this.transport = new WABTransport(serverUrl, options);
33401
33466
  }
33402
- async getInfo() {
33403
- return await this.transport.request("/info", {
33467
+ getInfo() {
33468
+ return this.transport.request("/info", {
33404
33469
  method: "GET",
33405
33470
  operation: "get-info"
33406
33471
  });
@@ -33410,15 +33475,15 @@ var WABClient = class {
33410
33475
  }
33411
33476
  async startAuthMethod(authMethod, presentationKey, payload, correlationId) {
33412
33477
  assertHexIdentifier(presentationKey, "presentationKey");
33413
- return await authMethod.startAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33478
+ return authMethod.startAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33414
33479
  }
33415
33480
  async completeAuthMethod(authMethod, presentationKey, payload, correlationId) {
33416
33481
  assertHexIdentifier(presentationKey, "presentationKey");
33417
- return await authMethod.completeAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33482
+ return authMethod.completeAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
33418
33483
  }
33419
33484
  async listLinkedMethods(presentationKey) {
33420
33485
  assertHexIdentifier(presentationKey, "presentationKey");
33421
- return await this.transport.request("/user/linkedMethods", {
33486
+ return this.transport.request("/user/linkedMethods", {
33422
33487
  operation: "list-linked-methods",
33423
33488
  body: { presentationKey }
33424
33489
  });
@@ -33426,7 +33491,7 @@ var WABClient = class {
33426
33491
  async unlinkMethod(presentationKey, authMethodId) {
33427
33492
  assertHexIdentifier(presentationKey, "presentationKey");
33428
33493
  if (!Number.isSafeInteger(authMethodId) || authMethodId <= 0) throw new TypeError("authMethodId must be a positive safe integer.");
33429
- return await this.transport.request("/user/unlinkMethod", {
33494
+ return this.transport.request("/user/unlinkMethod", {
33430
33495
  operation: "unlink-method",
33431
33496
  body: {
33432
33497
  presentationKey,
@@ -33436,14 +33501,14 @@ var WABClient = class {
33436
33501
  }
33437
33502
  async requestFaucet(presentationKey) {
33438
33503
  assertHexIdentifier(presentationKey, "presentationKey");
33439
- return await this.transport.request("/faucet/request", {
33504
+ return this.transport.request("/faucet/request", {
33440
33505
  operation: "request-faucet",
33441
33506
  body: { presentationKey }
33442
33507
  });
33443
33508
  }
33444
33509
  async deleteUser(presentationKey) {
33445
33510
  assertHexIdentifier(presentationKey, "presentationKey");
33446
- return await this.transport.request("/user/delete", {
33511
+ return this.transport.request("/user/delete", {
33447
33512
  operation: "delete-user",
33448
33513
  body: { presentationKey }
33449
33514
  });
@@ -33452,7 +33517,7 @@ var WABClient = class {
33452
33517
  assertMethodType(methodType);
33453
33518
  assertHexIdentifier(userIdHash, "userIdHash");
33454
33519
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33455
- return await this.transport.request("/auth/start", {
33520
+ return this.transport.request("/auth/start", {
33456
33521
  operation: "start-share-auth",
33457
33522
  body: {
33458
33523
  methodType,
@@ -33465,7 +33530,7 @@ var WABClient = class {
33465
33530
  assertMethodType(methodType);
33466
33531
  assertHexIdentifier(userIdHash, "userIdHash");
33467
33532
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33468
- return await this.transport.request("/share/store", {
33533
+ return this.transport.request("/share/store", {
33469
33534
  operation: "store-share",
33470
33535
  body: {
33471
33536
  methodType,
@@ -33479,7 +33544,7 @@ var WABClient = class {
33479
33544
  assertMethodType(methodType);
33480
33545
  assertHexIdentifier(userIdHash, "userIdHash");
33481
33546
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33482
- return await this.transport.request("/share/retrieve", {
33547
+ return this.transport.request("/share/retrieve", {
33483
33548
  operation: "retrieve-share",
33484
33549
  body: {
33485
33550
  methodType,
@@ -33492,7 +33557,7 @@ var WABClient = class {
33492
33557
  assertMethodType(methodType);
33493
33558
  assertHexIdentifier(userIdHash, "userIdHash");
33494
33559
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33495
- return await this.transport.request("/share/update", {
33560
+ return this.transport.request("/share/update", {
33496
33561
  operation: "update-share",
33497
33562
  body: {
33498
33563
  methodType,
@@ -33506,7 +33571,7 @@ var WABClient = class {
33506
33571
  assertMethodType(methodType);
33507
33572
  assertHexIdentifier(userIdHash, "userIdHash");
33508
33573
  const normalizedPayload = normalizeAuthPayload(methodType, payload);
33509
- return await this.transport.request("/share/delete", {
33574
+ return this.transport.request("/share/delete", {
33510
33575
  operation: "delete-share-user",
33511
33576
  body: {
33512
33577
  methodType,
@@ -33520,9 +33585,13 @@ var WABClient = class {
33520
33585
  //#region ../src/WalletAuthenticationManager.ts
33521
33586
  const DEFAULT_AUTH_SESSION_TTL_MS = 600 * 1e3;
33522
33587
  const MAX_AUTH_SESSION_TTL_MS = 3600 * 1e3;
33588
+ const AUTH_COMPONENT = "wallet-toolbox.authentication-manager";
33589
+ const AUTH_EVENT = "wallet-toolbox.authentication.";
33590
+ const EXISTING_USER = "existing-user";
33591
+ const NEW_USER = "new-user";
33523
33592
  var WABAccountContinuityError = class extends Error {
33524
33593
  code = "WERR_WAB_ACCOUNT_CONTINUITY";
33525
- constructor(message = "WAB and UMP account state did not agree. Retry or use account recovery.") {
33594
+ constructor(message = "WAB and UMP accounts disagree; retry or recover.") {
33526
33595
  super(message);
33527
33596
  this.name = "WABAccountContinuityError";
33528
33597
  }
@@ -33537,6 +33606,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33537
33606
  wabClient;
33538
33607
  authMethod;
33539
33608
  authSession;
33609
+ phoneChangeSession;
33540
33610
  authSessionTtlMs;
33541
33611
  constructor(...[adminOriginator, walletBuilder, interactor, recoveryKeySaver, passwordRetriever, wabClient, authMethod, stateSnapshot, options = {}]) {
33542
33612
  super(adminOriginator, walletBuilder, interactor, recoveryKeySaver, passwordRetriever, async (presentationKey, wallet, adminOriginator) => {
@@ -33559,7 +33629,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33559
33629
  description: "Fund wallet",
33560
33630
  options: { acceptDelayedBroadcast: false }
33561
33631
  }, adminOriginator);
33562
- if (faucetRedeemTXCreationResult.signableTransaction == null) throw new Error("Faucet redemption did not return a signableTransaction");
33632
+ if (faucetRedeemTXCreationResult.signableTransaction == null) throw new Error("Faucet redemption was not signable.");
33563
33633
  const faucetRedeemTX = Transaction.fromAtomicBEEF(faucetRedeemTXCreationResult.signableTransaction.tx);
33564
33634
  const faucetRedemptionPuzzle = new RPuzzle();
33565
33635
  const randomRedemptionPrivateKey = PrivateKey.fromRandom();
@@ -33592,7 +33662,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33592
33662
  * using the chosen AuthMethodInteractor.
33593
33663
  */
33594
33664
  async startAuth(payload) {
33595
- if (this.authMethod == null) throw new Error("No AuthMethod selected in WalletAuthenticationManager");
33665
+ if (this.authMethod == null) throw new Error("No WAB authentication method selected.");
33596
33666
  const authMethod = this.authMethod;
33597
33667
  if (this.authenticated) throw new Error("User is already authenticated");
33598
33668
  this.cancelAuth();
@@ -33605,8 +33675,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33605
33675
  ...correlationId !== void 0 ? { correlationId } : {}
33606
33676
  };
33607
33677
  this.telemetry.capture({
33608
- name: "wallet-toolbox.authentication.wab-start.started",
33609
- component: "wallet-toolbox.authentication-manager",
33678
+ name: `${AUTH_EVENT}wab-start.started`,
33679
+ component: AUTH_COMPONENT,
33610
33680
  severity: "debug",
33611
33681
  correlationId,
33612
33682
  attributes: { methodType: authMethod.methodType }
@@ -33618,8 +33688,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33618
33688
  throw new Error(message);
33619
33689
  }
33620
33690
  this.telemetry.capture({
33621
- name: "wallet-toolbox.authentication.wab-start.completed",
33622
- component: "wallet-toolbox.authentication-manager",
33691
+ name: `${AUTH_EVENT}wab-start.completed`,
33692
+ component: AUTH_COMPONENT,
33623
33693
  severity: "info",
33624
33694
  correlationId,
33625
33695
  attributes: { methodType: authMethod.methodType }
@@ -33627,8 +33697,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33627
33697
  } catch (error) {
33628
33698
  this.cancelAuth();
33629
33699
  this.telemetry.capture({
33630
- name: "wallet-toolbox.authentication.wab-start.failed",
33631
- component: "wallet-toolbox.authentication-manager",
33700
+ name: `${AUTH_EVENT}wab-start.failed`,
33701
+ component: AUTH_COMPONENT,
33632
33702
  severity: "warn",
33633
33703
  correlationId,
33634
33704
  attributes: { methodType: authMethod.methodType },
@@ -33641,22 +33711,22 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33641
33711
  * Completes the WAB-based flow, retrieving the final presentationKey from WAB if successful.
33642
33712
  */
33643
33713
  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.");
33714
+ if (this.authMethod == null || this.authSession == null) throw new Error("Start WAB authentication first.");
33645
33715
  const authMethod = this.authMethod;
33646
33716
  if (this.authSession.methodType !== authMethod.methodType) {
33647
33717
  this.cancelAuth();
33648
- throw new Error("The selected authentication method changed. Start authentication again.");
33718
+ throw new Error("WAB authentication method changed; restart.");
33649
33719
  }
33650
33720
  if (Date.now() >= this.authSession.expiresAt) {
33651
33721
  this.cancelAuth();
33652
- throw new Error("The WAB authentication session expired. Start authentication again.");
33722
+ throw new Error("WAB authentication expired; restart.");
33653
33723
  }
33654
33724
  const session = this.authSession;
33655
33725
  const result = await this.wabClient.completeAuthMethod(authMethod, session.presentationKey, payload, session.correlationId);
33656
33726
  if (result.success !== true || result.presentationKey == null || result.presentationKey.length === 0) {
33657
33727
  this.telemetry.capture({
33658
- name: "wallet-toolbox.authentication.wab-complete.rejected",
33659
- component: "wallet-toolbox.authentication-manager",
33728
+ name: `${AUTH_EVENT}wab-complete.rejected`,
33729
+ component: AUTH_COMPONENT,
33660
33730
  severity: "warn",
33661
33731
  correlationId: session.correlationId,
33662
33732
  attributes: { methodType: session.methodType }
@@ -33671,11 +33741,11 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33671
33741
  this.cancelAuth();
33672
33742
  const wabAccountStatus = this.inferAccountStatus(result, session.presentationKey);
33673
33743
  try {
33674
- await this.providePresentationKey(Utils.toArray(result.presentationKey, "hex"));
33744
+ await this.provideWABPresentationKey(result, wabAccountStatus);
33675
33745
  } catch (error) {
33676
33746
  this.telemetry.capture({
33677
- name: "wallet-toolbox.authentication.ump-continuity.failed",
33678
- component: "wallet-toolbox.authentication-manager",
33747
+ name: `${AUTH_EVENT}ump-continuity.failed`,
33748
+ component: AUTH_COMPONENT,
33679
33749
  severity: "warn",
33680
33750
  correlationId: session.correlationId,
33681
33751
  attributes: {
@@ -33686,18 +33756,18 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33686
33756
  });
33687
33757
  throw error;
33688
33758
  }
33689
- if (wabAccountStatus === "existing-user" && this.authenticationFlow !== "existing-user") {
33759
+ if (wabAccountStatus === EXISTING_USER && this.authenticationFlow !== EXISTING_USER) {
33690
33760
  super.destroy();
33691
33761
  const error = new WABAccountContinuityError();
33692
33762
  this.telemetry.capture({
33693
- name: "wallet-toolbox.authentication.account-continuity.mismatch",
33694
- component: "wallet-toolbox.authentication-manager",
33763
+ name: `${AUTH_EVENT}account-continuity.mismatch`,
33764
+ component: AUTH_COMPONENT,
33695
33765
  severity: "error",
33696
33766
  correlationId: session.correlationId,
33697
33767
  attributes: {
33698
33768
  methodType: session.methodType,
33699
33769
  wabAccountStatus,
33700
- umpAccountStatus: "new-user"
33770
+ umpAccountStatus: NEW_USER
33701
33771
  },
33702
33772
  error
33703
33773
  });
@@ -33705,8 +33775,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33705
33775
  }
33706
33776
  const continuity = wabAccountStatus === this.authenticationFlow ? "matched" : "ump-existing";
33707
33777
  this.telemetry.capture({
33708
- name: "wallet-toolbox.authentication.completed",
33709
- component: "wallet-toolbox.authentication-manager",
33778
+ name: `${AUTH_EVENT}completed`,
33779
+ component: AUTH_COMPONENT,
33710
33780
  severity: continuity === "matched" ? "info" : "warn",
33711
33781
  correlationId: session.correlationId,
33712
33782
  attributes: {
@@ -33720,23 +33790,131 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
33720
33790
  cancelAuth() {
33721
33791
  this.authSession = void 0;
33722
33792
  }
33793
+ readPendingPhoneChange(result) {
33794
+ const presentationKey = result.pendingPresentationKey;
33795
+ const changeId = result.pendingPhoneChangeId;
33796
+ if (presentationKey === void 0 && changeId === void 0) return void 0;
33797
+ if (!/^[0-9a-fA-F]{64}$/.test(presentationKey ?? "") || !Number.isSafeInteger(changeId) || changeId <= 0) throw new WABAccountContinuityError("WAB returned invalid pending phone-change data.");
33798
+ return {
33799
+ presentationKey,
33800
+ changeId
33801
+ };
33802
+ }
33803
+ async provideWABPresentationKey(result, wabAccountStatus) {
33804
+ const umpTokenOutpoint = typeof result.umpTokenOutpoint === "string" ? result.umpTokenOutpoint : void 0;
33805
+ const lookupOptions = umpTokenOutpoint == null ? void 0 : { pinnedOutpoint: umpTokenOutpoint };
33806
+ const pending = this.readPendingPhoneChange(result);
33807
+ let usePending = false;
33808
+ try {
33809
+ await this.providePresentationKey(Utils.toArray(result.presentationKey, "hex"), lookupOptions);
33810
+ } catch (error) {
33811
+ if (pending == null) throw error;
33812
+ usePending = true;
33813
+ }
33814
+ if (pending != null && (usePending || wabAccountStatus === EXISTING_USER && this.authenticationFlow !== EXISTING_USER)) {
33815
+ await this.providePresentationKey(Utils.toArray(pending.presentationKey, "hex"), lookupOptions);
33816
+ if (this.authenticationFlow === EXISTING_USER) await this.finalizePendingPhoneChange(result.presentationKey, pending);
33817
+ }
33818
+ }
33819
+ async finalizePendingPhoneChange(currentPresentationKey, pending) {
33820
+ const finalized = await this.phoneChange("finalize", {
33821
+ changeId: pending.changeId,
33822
+ presentationKey: currentPresentationKey,
33823
+ newPresentationKey: pending.presentationKey
33824
+ });
33825
+ if (finalized.success !== true || finalized.changeId !== pending.changeId) throw new WABAccountContinuityError(finalized.message || "WAB could not finalize the pending phone change.");
33826
+ }
33827
+ /**
33828
+ * Starts OTP verification for a replacement phone number. The same number
33829
+ * is valid and intentionally produces a fresh presentation key/hash.
33830
+ */
33831
+ async startPhoneNumberChange(phoneNumber) {
33832
+ if (!this.authenticated) throw new Error("Not authenticated");
33833
+ const normalizedPhone = phoneNumber.trim();
33834
+ const currentPresentationKey = Utils.toHex(await this.getFactor("presentationKey"));
33835
+ const response = await this.phoneChange("start", {
33836
+ presentationKey: currentPresentationKey,
33837
+ phoneNumber: normalizedPhone
33838
+ });
33839
+ if (response.success !== true) throw new Error(response.message || "Phone change failed");
33840
+ this.phoneChangeSession = {
33841
+ phoneNumber: normalizedPhone,
33842
+ presentationKey: currentPresentationKey
33843
+ };
33844
+ }
33845
+ /**
33846
+ * Completes phone verification and stages the WAB association before
33847
+ * publishing the UMP key rotation. WAB retains both the current and pending
33848
+ * presentation keys until finalization, so either side of an interrupted
33849
+ * transition remains recoverable on the next verified login.
33850
+ */
33851
+ async completePhoneNumberChange(otp) {
33852
+ const session = this.phoneChangeSession;
33853
+ if (session == null) throw new Error("No phone change");
33854
+ if (session.changeToken == null) {
33855
+ const authorization = await this.phoneChange("complete", {
33856
+ presentationKey: session.presentationKey,
33857
+ phoneNumber: session.phoneNumber,
33858
+ otp: otp.trim()
33859
+ });
33860
+ if (authorization.success !== true) throw new Error(authorization.message || "Phone change failed");
33861
+ if (/^[0-9a-fA-F]{64}$/.test(authorization.pendingPresentationKey ?? "") && Number.isSafeInteger(authorization.pendingPhoneChangeId) && authorization.pendingPhoneChangeId > 0) {
33862
+ session.newKey = Utils.toArray(authorization.pendingPresentationKey, "hex");
33863
+ session.changeId = authorization.pendingPhoneChangeId;
33864
+ } else if (typeof authorization.changeToken === "string" && authorization.changeToken.length > 0) session.changeToken = authorization.changeToken;
33865
+ else throw new Error(authorization.message || "Phone change failed");
33866
+ }
33867
+ session.newKey ??= Random(32);
33868
+ if (session.changeId == null) {
33869
+ const committed = await this.phoneChange("commit", {
33870
+ changeToken: session.changeToken,
33871
+ presentationKey: session.presentationKey,
33872
+ newPresentationKey: Utils.toHex(session.newKey)
33873
+ });
33874
+ if (committed.success !== true || !Number.isSafeInteger(committed.changeId) || committed.changeId <= 0) throw new Error(committed.message || "Phone change failed");
33875
+ session.changeId = committed.changeId;
33876
+ }
33877
+ const changeId = session.changeId;
33878
+ if (session.umpUpdated !== true) {
33879
+ await this.changePresentationKey(session.newKey);
33880
+ session.umpUpdated = true;
33881
+ }
33882
+ const finalized = await this.phoneChange("finalize", {
33883
+ changeId,
33884
+ presentationKey: session.presentationKey,
33885
+ newPresentationKey: Utils.toHex(session.newKey)
33886
+ });
33887
+ if (finalized.success !== true || finalized.changeId !== changeId) throw new Error(finalized.message || "Phone change failed");
33888
+ this.phoneChangeSession = void 0;
33889
+ return { changeId };
33890
+ }
33891
+ cancelPhoneNumberChange() {
33892
+ this.phoneChangeSession = void 0;
33893
+ }
33723
33894
  destroy() {
33724
33895
  this.cancelAuth();
33896
+ this.cancelPhoneNumberChange();
33725
33897
  super.destroy();
33726
33898
  }
33899
+ phoneChange(phase, body) {
33900
+ return this.wabClient.transport.request(`/auth/phone-change/${phase}`, {
33901
+ operation: "phone-change",
33902
+ body
33903
+ });
33904
+ }
33727
33905
  inferAccountStatus(result, temporaryPresentationKey) {
33728
33906
  if (result.presentationKey == null) throw new WABAccountContinuityError("WAB did not return a presentation key.");
33729
33907
  const keyMatchesTemporary = this.constantTimeHexEqual(result.presentationKey, temporaryPresentationKey);
33730
33908
  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.");
33909
+ if (rawAccountStatus !== void 0 && rawAccountStatus !== NEW_USER && rawAccountStatus !== EXISTING_USER) throw new WABAccountContinuityError("WAB returned an invalid account status.");
33732
33910
  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.");
33911
+ if (rawExistingUser !== void 0 && typeof rawExistingUser !== "boolean") throw new WABAccountContinuityError("WAB returned invalid existing-user data.");
33912
+ if (rawAccountStatus !== void 0 && rawExistingUser !== void 0 && rawAccountStatus === EXISTING_USER !== rawExistingUser) throw new WABAccountContinuityError("WAB returned conflicting account status.");
33735
33913
  let compatibilityStatus;
33736
- if (typeof rawExistingUser === "boolean") compatibilityStatus = rawExistingUser ? "existing-user" : "new-user";
33914
+ if (typeof rawExistingUser === "boolean") compatibilityStatus = rawExistingUser ? EXISTING_USER : NEW_USER;
33737
33915
  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");
33916
+ if (explicitStatus === NEW_USER && !keyMatchesTemporary || explicitStatus === EXISTING_USER && keyMatchesTemporary) throw new WABAccountContinuityError("WAB returned conflicting account status.");
33917
+ return explicitStatus ?? (keyMatchesTemporary ? NEW_USER : EXISTING_USER);
33740
33918
  }
33741
33919
  constantTimeHexEqual(left, right) {
33742
33920
  if (left.length !== right.length) return false;