@unicitylabs/sphere-sdk 0.14.11-dev.7 → 0.14.11

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.
@@ -39,10 +39,16 @@ __export(payments_v2_exports, {
39
39
  PaymentsFacade: () => PaymentsFacade,
40
40
  STORE_KEYS: () => STORE_KEYS,
41
41
  createScopedKV: () => createScopedKV,
42
+ isRetryableAckError: () => isRetryableAckError,
42
43
  supportsDeterministicMint: () => supportsDeterministicMint
43
44
  });
44
45
  module.exports = __toCommonJS(payments_v2_exports);
45
46
 
47
+ // modules/payments-v2/ports.ts
48
+ function isRetryableAckError(err) {
49
+ return err !== null && typeof err === "object" && err.retryable === true;
50
+ }
51
+
46
52
  // modules/payments-v2/stores.ts
47
53
  function createScopedKV(storage, network, chainPubkey) {
48
54
  const prefix = `pv2:${network}:${chainPubkey}:`;
@@ -581,12 +587,19 @@ var SerialChain = class {
581
587
  return run;
582
588
  }
583
589
  };
584
- function coalesced(run) {
590
+ function coalesced(run, observe) {
585
591
  let inFlight = false;
586
592
  let queued = false;
587
593
  const start = () => {
588
594
  inFlight = true;
589
- void run().catch(() => void 0).finally(() => {
595
+ let running;
596
+ try {
597
+ running = run();
598
+ } catch {
599
+ running = Promise.resolve();
600
+ }
601
+ observe?.(running);
602
+ void running.catch(() => void 0).finally(() => {
590
603
  inFlight = false;
591
604
  if (!queued) return;
592
605
  queued = false;
@@ -3232,11 +3245,6 @@ var logger = {
3232
3245
  }
3233
3246
  };
3234
3247
 
3235
- // modules/payments-v2/ports.ts
3236
- function isRetryableAckError(err) {
3237
- return err !== null && typeof err === "object" && err.retryable === true;
3238
- }
3239
-
3240
3248
  // modules/payments-v2/receive/Receive.ts
3241
3249
  var ACK_BATCH_SIZE = 200;
3242
3250
  var REFRESH_INTERVAL_MS = 2500;
@@ -3285,13 +3293,26 @@ var Receive = class {
3285
3293
  * the tokens just accepted, and the balance would still only move at the end.
3286
3294
  * Ordering is preserved: store() still precedes the ack (§5.7).
3287
3295
  */
3288
- async maybeRefresh(deps, pending, epochOf) {
3296
+ async maybeRefresh(ctx) {
3297
+ const { deps, pending, pageEpoch } = ctx;
3289
3298
  if (deps.refreshView === void 0) return;
3290
3299
  const now = deps.now?.() ?? Date.now();
3291
3300
  if (now - this.lastRefreshAt < REFRESH_INTERVAL_MS) return;
3292
3301
  this.lastRefreshAt = now;
3293
- await flushAcks(deps, pending, epochOf);
3294
- deps.refreshView();
3302
+ if ((await flushAcks(deps, pending, pageEpoch)).progressed) deps.refreshView();
3303
+ }
3304
+ /** One listing pass: process each entry, flushing and refreshing as it goes. */
3305
+ async drainPages(ctx, basis) {
3306
+ const { deps, pending, pageEpoch, claimable } = ctx;
3307
+ for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
3308
+ const claimableBefore = claimable.n;
3309
+ await this.processEntry(ctx, entry);
3310
+ if (pending.length >= ACK_BATCH_SIZE) {
3311
+ if (!(await flushAcks(deps, pending, pageEpoch)).progressed) return;
3312
+ }
3313
+ if (claimable.n > claimableBefore) await this.maybeRefresh(ctx);
3314
+ }
3315
+ await flushAcks(deps, pending, pageEpoch);
3295
3316
  }
3296
3317
  async doDrain() {
3297
3318
  const deps = this.deps;
@@ -3300,17 +3321,16 @@ var Receive = class {
3300
3321
  const stored = [];
3301
3322
  const pending = [];
3302
3323
  const pageEpoch = () => deps.delivery.incomingEpoch() ?? deps.syncEpoch();
3324
+ const claimable = { n: 0 };
3325
+ const finish = () => {
3326
+ if (claimable.n > 0) deps.refreshView?.();
3327
+ return stored;
3328
+ };
3303
3329
  try {
3304
3330
  const record = await deps.kv.get(STORE_KEYS.streamCursor("mailbox"));
3305
3331
  let basis = record !== null && record.syncEpoch === deps.syncEpoch() ? record : null;
3306
3332
  for (let pass = 0; pass < 2; pass++) {
3307
- for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
3308
- const storedBefore = stored.length;
3309
- await this.processEntry(deps, engine, entry, pending, stored);
3310
- if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
3311
- if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
3312
- }
3313
- await flushAcks(deps, pending, pageEpoch);
3333
+ await this.drainPages({ deps, engine, pending, stored, pageEpoch, claimable }, basis);
3314
3334
  const served = deps.delivery.incomingEpoch();
3315
3335
  if (basis === null || served === null || served === basis.syncEpoch) break;
3316
3336
  await deps.kv.remove(STORE_KEYS.streamCursor("mailbox"));
@@ -3318,21 +3338,25 @@ var Receive = class {
3318
3338
  }
3319
3339
  } catch (err) {
3320
3340
  logger.warn("PaymentsV2", "receive drain interrupted \u2014 unacked entries retry next drain:", err);
3321
- if (isRetryableAckError(err)) return stored;
3341
+ if (isRetryableAckError(err)) return finish();
3322
3342
  await flushAcks(deps, pending, pageEpoch).catch((flushErr) => {
3323
3343
  logger.warn("PaymentsV2", "receive ack flush failed \u2014 cursor holds at the acked prefix:", flushErr);
3344
+ return { progressed: false };
3324
3345
  });
3325
3346
  }
3326
- return stored;
3347
+ return finish();
3327
3348
  }
3328
- async processEntry(deps, engine, entry, pending, stored) {
3349
+ async processEntry(ctx, entry) {
3350
+ const { deps, engine, pending, stored, claimable } = ctx;
3329
3351
  const screened = await screen(deps, engine, entry);
3330
3352
  if (screened.kind === "ack") {
3331
3353
  pending.push(screened.ack);
3354
+ if (screened.ack.disposition === "claimed") claimable.n += 1;
3332
3355
  return;
3333
3356
  }
3334
3357
  await deps.view.store(screened.record);
3335
3358
  pending.push(claimAck(entry));
3359
+ claimable.n += 1;
3336
3360
  const transfer = await announce(deps, entry, screened.record);
3337
3361
  stored.push(transfer);
3338
3362
  deps.emit("transfer:incoming", transfer);
@@ -3393,7 +3417,8 @@ async function announce(deps, entry, record) {
3393
3417
  };
3394
3418
  }
3395
3419
  async function flushAcks(deps, pending, epochOf) {
3396
- if (pending.length === 0) return;
3420
+ if (pending.length === 0) return { progressed: true };
3421
+ const before = pending.length;
3397
3422
  let lastAcked = null;
3398
3423
  try {
3399
3424
  const settled = await settleAcks(deps, pending);
@@ -3411,6 +3436,7 @@ async function flushAcks(deps, pending, epochOf) {
3411
3436
  await deps.kv.set(STORE_KEYS.streamCursor("mailbox"), record);
3412
3437
  }
3413
3438
  }
3439
+ return { progressed: pending.length < before };
3414
3440
  }
3415
3441
  async function settleAcks(deps, pending) {
3416
3442
  const batch = deps.delivery.ackBatch?.bind(deps.delivery);
@@ -4253,7 +4279,7 @@ function composeFacadeParts(deps, hooks) {
4253
4279
  const machineDeps = buildMachineDeps(deps, hooks, historyStore);
4254
4280
  const machineStores = createMachineStores(deps.kv);
4255
4281
  const heldStates = /* @__PURE__ */ new Map();
4256
- const refreshView = coalesced(() => view.delta());
4282
+ const refreshView = coalesced(() => view.delta(), hooks.track);
4257
4283
  return {
4258
4284
  ownPubkeyBytes,
4259
4285
  view,
@@ -4396,7 +4422,8 @@ var PaymentsFacade = class {
4396
4422
  const parts = composeFacadeParts(deps, {
4397
4423
  engine: () => this.engine(),
4398
4424
  send: (request) => this.send(request),
4399
- isActiveOp: (id) => this.activeMoneyOps.has(id)
4425
+ isActiveOp: (id) => this.activeMoneyOps.has(id),
4426
+ track: (op) => this.trackTail(op)
4400
4427
  });
4401
4428
  this.view = parts.view;
4402
4429
  this.wakeRefresh = parts.refreshView;
@@ -4536,7 +4563,6 @@ var PaymentsFacade = class {
4536
4563
  }
4537
4564
  async receive() {
4538
4565
  const transfers = await this.track(this.receiveLoop.drainOnce());
4539
- if (transfers.length > 0) this.trackTail(this.view.delta());
4540
4566
  return { transfers };
4541
4567
  }
4542
4568
  mint(coinId, amount) {
@@ -5014,6 +5040,7 @@ var PaymentsFacade = class {
5014
5040
  PaymentsFacade,
5015
5041
  STORE_KEYS,
5016
5042
  createScopedKV,
5043
+ isRetryableAckError,
5017
5044
  supportsDeterministicMint
5018
5045
  });
5019
5046
  /*! Bundled license information: