@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.
@@ -11303,12 +11303,19 @@ var SerialChain = class {
11303
11303
  return run;
11304
11304
  }
11305
11305
  };
11306
- function coalesced(run) {
11306
+ function coalesced(run, observe) {
11307
11307
  let inFlight = false;
11308
11308
  let queued = false;
11309
11309
  const start = () => {
11310
11310
  inFlight = true;
11311
- void run().catch(() => void 0).finally(() => {
11311
+ let running;
11312
+ try {
11313
+ running = run();
11314
+ } catch {
11315
+ running = Promise.resolve();
11316
+ }
11317
+ observe?.(running);
11318
+ void running.catch(() => void 0).finally(() => {
11312
11319
  inFlight = false;
11313
11320
  if (!queued) return;
11314
11321
  queued = false;
@@ -13057,13 +13064,26 @@ var Receive = class {
13057
13064
  * the tokens just accepted, and the balance would still only move at the end.
13058
13065
  * Ordering is preserved: store() still precedes the ack (§5.7).
13059
13066
  */
13060
- async maybeRefresh(deps, pending, epochOf) {
13067
+ async maybeRefresh(ctx) {
13068
+ const { deps, pending, pageEpoch } = ctx;
13061
13069
  if (deps.refreshView === void 0) return;
13062
13070
  const now = deps.now?.() ?? Date.now();
13063
13071
  if (now - this.lastRefreshAt < REFRESH_INTERVAL_MS) return;
13064
13072
  this.lastRefreshAt = now;
13065
- await flushAcks(deps, pending, epochOf);
13066
- deps.refreshView();
13073
+ if ((await flushAcks(deps, pending, pageEpoch)).progressed) deps.refreshView();
13074
+ }
13075
+ /** One listing pass: process each entry, flushing and refreshing as it goes. */
13076
+ async drainPages(ctx, basis) {
13077
+ const { deps, pending, pageEpoch, claimable } = ctx;
13078
+ for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
13079
+ const claimableBefore = claimable.n;
13080
+ await this.processEntry(ctx, entry);
13081
+ if (pending.length >= ACK_BATCH_SIZE) {
13082
+ if (!(await flushAcks(deps, pending, pageEpoch)).progressed) return;
13083
+ }
13084
+ if (claimable.n > claimableBefore) await this.maybeRefresh(ctx);
13085
+ }
13086
+ await flushAcks(deps, pending, pageEpoch);
13067
13087
  }
13068
13088
  async doDrain() {
13069
13089
  const deps = this.deps;
@@ -13072,17 +13092,16 @@ var Receive = class {
13072
13092
  const stored = [];
13073
13093
  const pending = [];
13074
13094
  const pageEpoch = () => deps.delivery.incomingEpoch() ?? deps.syncEpoch();
13095
+ const claimable = { n: 0 };
13096
+ const finish = () => {
13097
+ if (claimable.n > 0) deps.refreshView?.();
13098
+ return stored;
13099
+ };
13075
13100
  try {
13076
13101
  const record = await deps.kv.get(STORE_KEYS.streamCursor("mailbox"));
13077
13102
  let basis = record !== null && record.syncEpoch === deps.syncEpoch() ? record : null;
13078
13103
  for (let pass = 0; pass < 2; pass++) {
13079
- for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
13080
- const storedBefore = stored.length;
13081
- await this.processEntry(deps, engine, entry, pending, stored);
13082
- if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
13083
- if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
13084
- }
13085
- await flushAcks(deps, pending, pageEpoch);
13104
+ await this.drainPages({ deps, engine, pending, stored, pageEpoch, claimable }, basis);
13086
13105
  const served = deps.delivery.incomingEpoch();
13087
13106
  if (basis === null || served === null || served === basis.syncEpoch) break;
13088
13107
  await deps.kv.remove(STORE_KEYS.streamCursor("mailbox"));
@@ -13090,21 +13109,25 @@ var Receive = class {
13090
13109
  }
13091
13110
  } catch (err) {
13092
13111
  logger.warn("PaymentsV2", "receive drain interrupted \u2014 unacked entries retry next drain:", err);
13093
- if (isRetryableAckError(err)) return stored;
13112
+ if (isRetryableAckError(err)) return finish();
13094
13113
  await flushAcks(deps, pending, pageEpoch).catch((flushErr) => {
13095
13114
  logger.warn("PaymentsV2", "receive ack flush failed \u2014 cursor holds at the acked prefix:", flushErr);
13115
+ return { progressed: false };
13096
13116
  });
13097
13117
  }
13098
- return stored;
13118
+ return finish();
13099
13119
  }
13100
- async processEntry(deps, engine, entry, pending, stored) {
13120
+ async processEntry(ctx, entry) {
13121
+ const { deps, engine, pending, stored, claimable } = ctx;
13101
13122
  const screened = await screen(deps, engine, entry);
13102
13123
  if (screened.kind === "ack") {
13103
13124
  pending.push(screened.ack);
13125
+ if (screened.ack.disposition === "claimed") claimable.n += 1;
13104
13126
  return;
13105
13127
  }
13106
13128
  await deps.view.store(screened.record);
13107
13129
  pending.push(claimAck(entry));
13130
+ claimable.n += 1;
13108
13131
  const transfer = await announce(deps, entry, screened.record);
13109
13132
  stored.push(transfer);
13110
13133
  deps.emit("transfer:incoming", transfer);
@@ -13165,7 +13188,8 @@ async function announce(deps, entry, record) {
13165
13188
  };
13166
13189
  }
13167
13190
  async function flushAcks(deps, pending, epochOf) {
13168
- if (pending.length === 0) return;
13191
+ if (pending.length === 0) return { progressed: true };
13192
+ const before = pending.length;
13169
13193
  let lastAcked = null;
13170
13194
  try {
13171
13195
  const settled = await settleAcks(deps, pending);
@@ -13183,6 +13207,7 @@ async function flushAcks(deps, pending, epochOf) {
13183
13207
  await deps.kv.set(STORE_KEYS.streamCursor("mailbox"), record);
13184
13208
  }
13185
13209
  }
13210
+ return { progressed: pending.length < before };
13186
13211
  }
13187
13212
  async function settleAcks(deps, pending) {
13188
13213
  const batch = deps.delivery.ackBatch?.bind(deps.delivery);
@@ -14025,7 +14050,7 @@ function composeFacadeParts(deps, hooks) {
14025
14050
  const machineDeps = buildMachineDeps(deps, hooks, historyStore);
14026
14051
  const machineStores = createMachineStores(deps.kv);
14027
14052
  const heldStates = /* @__PURE__ */ new Map();
14028
- const refreshView = coalesced(() => view.delta());
14053
+ const refreshView = coalesced(() => view.delta(), hooks.track);
14029
14054
  return {
14030
14055
  ownPubkeyBytes,
14031
14056
  view,
@@ -14168,7 +14193,8 @@ var PaymentsFacade = class {
14168
14193
  const parts = composeFacadeParts(deps, {
14169
14194
  engine: () => this.engine(),
14170
14195
  send: (request) => this.send(request),
14171
- isActiveOp: (id) => this.activeMoneyOps.has(id)
14196
+ isActiveOp: (id) => this.activeMoneyOps.has(id),
14197
+ track: (op) => this.trackTail(op)
14172
14198
  });
14173
14199
  this.view = parts.view;
14174
14200
  this.wakeRefresh = parts.refreshView;
@@ -14308,7 +14334,6 @@ var PaymentsFacade = class {
14308
14334
  }
14309
14335
  async receive() {
14310
14336
  const transfers = await this.track(this.receiveLoop.drainOnce());
14311
- if (transfers.length > 0) this.trackTail(this.view.delta());
14312
14337
  return { transfers };
14313
14338
  }
14314
14339
  mint(coinId, amount) {
@@ -15703,6 +15728,9 @@ var WalletApiDeliveryPort = class {
15703
15728
  await this.settleClaims(acks, settled, outcomes);
15704
15729
  await this.settleRejects(acks, settled);
15705
15730
  } catch (err) {
15731
+ await this.addSeenAll(settled).catch((seenErr) => {
15732
+ logger.warn("WalletApiDelivery", `seen-set write failed for ${String(settled.length)} committed acks:`, seenErr);
15733
+ });
15706
15734
  throw asRetryable(err);
15707
15735
  }
15708
15736
  await this.addSeenAll(settled);