@unicitylabs/sphere-sdk 0.14.3 → 0.14.5

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.
@@ -42,6 +42,7 @@ var import_CertificationResponse = require("@unicitylabs/state-transition-sdk/li
42
42
  var import_StateId = require("@unicitylabs/state-transition-sdk/lib/api/StateId.js");
43
43
  var import_InclusionProof = require("@unicitylabs/state-transition-sdk/lib/api/InclusionProof.js");
44
44
  var import_InclusionProofResponse = require("@unicitylabs/state-transition-sdk/lib/api/InclusionProofResponse.js");
45
+ var import_JsonRpcNetworkError = require("@unicitylabs/state-transition-sdk/lib/api/json-rpc/JsonRpcNetworkError.js");
45
46
  var import_RootTrustBase = require("@unicitylabs/state-transition-sdk/lib/api/bft/RootTrustBase.js");
46
47
  var import_InclusionProofUtils = require("@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils.js");
47
48
  var import_InclusionProofVerificationRule = require("@unicitylabs/state-transition-sdk/lib/transaction/verification/rule/InclusionProofVerificationRule.js");
@@ -319,6 +320,75 @@ function decodeSpherePaymentData(bytes) {
319
320
  return Promise.resolve(SpherePaymentData.fromCBOR(bytes));
320
321
  }
321
322
 
323
+ // token-engine/proof-wait.ts
324
+ var DEFAULT_PROOF_TIMEOUT_MS = 1e4;
325
+ function resolveProofTimeoutMs(configured) {
326
+ if (configured === void 0) return DEFAULT_PROOF_TIMEOUT_MS;
327
+ if (!Number.isFinite(configured) || configured <= 0) {
328
+ throw new SphereError(
329
+ `proofTimeoutMs must be a positive number of milliseconds (got ${String(configured)}); an unbounded inclusion-proof wait is not supported`,
330
+ "INVALID_CONFIG"
331
+ );
332
+ }
333
+ return configured;
334
+ }
335
+ var TRANSIENT_HTTP_STATUSES = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
336
+ function isTransientGatewayError(err) {
337
+ return err instanceof import_JsonRpcNetworkError.JsonRpcNetworkError && TRANSIENT_HTTP_STATUSES.has(err.status);
338
+ }
339
+ function pause(ms, signal) {
340
+ return new Promise((resolve) => {
341
+ const timer = setTimeout(resolve, ms);
342
+ signal.addEventListener(
343
+ "abort",
344
+ () => {
345
+ clearTimeout(timer);
346
+ resolve();
347
+ },
348
+ { once: true }
349
+ );
350
+ });
351
+ }
352
+ async function awaitProofBounded(deps, transaction, external) {
353
+ const controller = new AbortController();
354
+ const relayAbort = () => {
355
+ controller.abort(external?.reason);
356
+ };
357
+ if (external !== void 0) {
358
+ if (external.aborted) relayAbort();
359
+ else external.addEventListener("abort", relayAbort, { once: true });
360
+ }
361
+ const timer = setTimeout(() => {
362
+ controller.abort(
363
+ new SphereError(
364
+ `inclusion proof not confirmed within ${String(deps.timeoutMs)} ms`,
365
+ "AGGREGATOR_ERROR"
366
+ )
367
+ );
368
+ }, deps.timeoutMs);
369
+ try {
370
+ for (; ; ) {
371
+ try {
372
+ return await (0, import_InclusionProofUtils.waitInclusionProof)(
373
+ deps.client,
374
+ deps.trustBase,
375
+ deps.predicateVerifier,
376
+ transaction,
377
+ controller.signal,
378
+ deps.intervalMs
379
+ );
380
+ } catch (err) {
381
+ if (controller.signal.aborted) throw err;
382
+ if (!isTransientGatewayError(err)) throw err;
383
+ await pause(deps.intervalMs, controller.signal);
384
+ }
385
+ }
386
+ } finally {
387
+ clearTimeout(timer);
388
+ external?.removeEventListener("abort", relayAbort);
389
+ }
390
+ }
391
+
322
392
  // core/uuid.ts
323
393
  function randomUUID() {
324
394
  const c = globalThis.crypto;
@@ -976,11 +1046,13 @@ var SphereTokenEngine = class {
976
1046
  constructor(deps) {
977
1047
  this.deps = deps;
978
1048
  this.privateKeyHex = import_HexConverter.HexConverter.encode(deps.privateKey);
1049
+ this.proofTimeoutMs = resolveProofTimeoutMs(deps.proofTimeoutMs);
979
1050
  }
980
1051
  /** F13 advertisement: mint under a (transferId, opIndex) seed is idempotent-recoverable — a same-seed re-call converges, never double-mints. */
981
1052
  deterministicMint = true;
982
1053
  /** Hex form of the wallet key — deriveRealization's ikm input (Part E.1). */
983
1054
  privateKeyHex;
1055
+ proofTimeoutMs;
984
1056
  // ── identity ────────────────────────────────────────────────────────────────
985
1057
  getIdentity() {
986
1058
  return { chainPubkey: new Uint8Array(this.deps.signingService.publicKey) };
@@ -1323,14 +1395,17 @@ var SphereTokenEngine = class {
1323
1395
  submitError = err ?? new SphereError(`${failLabel}: submit failed`, failCode);
1324
1396
  }
1325
1397
  try {
1326
- return await (0, import_InclusionProofUtils.waitInclusionProof)(
1327
- this.deps.client,
1328
- this.deps.trustBase,
1329
- this.deps.predicateVerifier,
1398
+ return await awaitProofBounded(
1399
+ {
1400
+ client: this.deps.client,
1401
+ trustBase: this.deps.trustBase,
1402
+ predicateVerifier: this.deps.predicateVerifier,
1403
+ timeoutMs: this.proofTimeoutMs,
1404
+ intervalMs: this.deps.proofPollIntervalMs ?? DEFAULT_PROOF_POLL_INTERVAL_MS
1405
+ // #683
1406
+ },
1330
1407
  transaction,
1331
- options?.signal,
1332
- this.deps.proofPollIntervalMs ?? DEFAULT_PROOF_POLL_INTERVAL_MS
1333
- // #683 finer poll cadence
1408
+ options?.signal
1334
1409
  );
1335
1410
  } catch (err) {
1336
1411
  if (err instanceof Error && err.message === `Invalid inclusion proof status: ${import_InclusionProofVerificationRule.InclusionProofVerificationStatus.TRANSACTION_HASH_MISMATCH}`) {
@@ -1346,6 +1421,13 @@ var SphereTokenEngine = class {
1346
1421
  );
1347
1422
  }
1348
1423
  }
1424
+ /**
1425
+ * One inclusion-proof wait, with the deadline OWNED here (#739). The SDK's own
1426
+ * default deadline is unreliable — see lateDeliveringSignal — and a lost one
1427
+ * means an op that never settles, which also wedges PaymentsFacade.stop().
1428
+ * A deadline hit throws, and the caller maps that to ProofUnconfirmedError
1429
+ * (keep-open), which is the correct posture: the spend may be on-chain.
1430
+ */
1349
1431
  /** Fail fast if this engine's key does not own the token's current state. */
1350
1432
  assertOwned(token) {
1351
1433
  if (!this.isOwnedBy(token, this.deps.signingService.publicKey)) {
@@ -1445,6 +1527,8 @@ async function createSphereTokenEngine(config) {
1445
1527
  networkId: trustBase.networkId,
1446
1528
  // #683: forward the (optional) proof-poll cadence; undefined → the engine default.
1447
1529
  proofPollIntervalMs: config.proofPollIntervalMs,
1530
+ proofTimeoutMs: config.proofTimeoutMs,
1531
+ // #739: was declared but never wired
1448
1532
  // Opt-in parallel verification (2.0.2). Absent → the sequential verifier.
1449
1533
  ...config.verification ? { tokenVerifier: createWorkerTokenVerifier(config.verification) } : {}
1450
1534
  };