@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.
@@ -11217,12 +11217,19 @@ var SerialChain = class {
11217
11217
  return run;
11218
11218
  }
11219
11219
  };
11220
- function coalesced(run) {
11220
+ function coalesced(run, observe) {
11221
11221
  let inFlight = false;
11222
11222
  let queued = false;
11223
11223
  const start = () => {
11224
11224
  inFlight = true;
11225
- void run().catch(() => void 0).finally(() => {
11225
+ let running;
11226
+ try {
11227
+ running = run();
11228
+ } catch {
11229
+ running = Promise.resolve();
11230
+ }
11231
+ observe?.(running);
11232
+ void running.catch(() => void 0).finally(() => {
11226
11233
  inFlight = false;
11227
11234
  if (!queued) return;
11228
11235
  queued = false;
@@ -12971,13 +12978,26 @@ var Receive = class {
12971
12978
  * the tokens just accepted, and the balance would still only move at the end.
12972
12979
  * Ordering is preserved: store() still precedes the ack (§5.7).
12973
12980
  */
12974
- async maybeRefresh(deps, pending, epochOf) {
12981
+ async maybeRefresh(ctx) {
12982
+ const { deps, pending, pageEpoch } = ctx;
12975
12983
  if (deps.refreshView === void 0) return;
12976
12984
  const now = deps.now?.() ?? Date.now();
12977
12985
  if (now - this.lastRefreshAt < REFRESH_INTERVAL_MS) return;
12978
12986
  this.lastRefreshAt = now;
12979
- await flushAcks(deps, pending, epochOf);
12980
- deps.refreshView();
12987
+ if ((await flushAcks(deps, pending, pageEpoch)).progressed) deps.refreshView();
12988
+ }
12989
+ /** One listing pass: process each entry, flushing and refreshing as it goes. */
12990
+ async drainPages(ctx, basis) {
12991
+ const { deps, pending, pageEpoch, claimable } = ctx;
12992
+ for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
12993
+ const claimableBefore = claimable.n;
12994
+ await this.processEntry(ctx, entry);
12995
+ if (pending.length >= ACK_BATCH_SIZE) {
12996
+ if (!(await flushAcks(deps, pending, pageEpoch)).progressed) return;
12997
+ }
12998
+ if (claimable.n > claimableBefore) await this.maybeRefresh(ctx);
12999
+ }
13000
+ await flushAcks(deps, pending, pageEpoch);
12981
13001
  }
12982
13002
  async doDrain() {
12983
13003
  const deps = this.deps;
@@ -12986,17 +13006,16 @@ var Receive = class {
12986
13006
  const stored = [];
12987
13007
  const pending = [];
12988
13008
  const pageEpoch = () => deps.delivery.incomingEpoch() ?? deps.syncEpoch();
13009
+ const claimable = { n: 0 };
13010
+ const finish = () => {
13011
+ if (claimable.n > 0) deps.refreshView?.();
13012
+ return stored;
13013
+ };
12989
13014
  try {
12990
13015
  const record = await deps.kv.get(STORE_KEYS.streamCursor("mailbox"));
12991
13016
  let basis = record !== null && record.syncEpoch === deps.syncEpoch() ? record : null;
12992
13017
  for (let pass = 0; pass < 2; pass++) {
12993
- for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
12994
- const storedBefore = stored.length;
12995
- await this.processEntry(deps, engine, entry, pending, stored);
12996
- if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
12997
- if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
12998
- }
12999
- await flushAcks(deps, pending, pageEpoch);
13018
+ await this.drainPages({ deps, engine, pending, stored, pageEpoch, claimable }, basis);
13000
13019
  const served = deps.delivery.incomingEpoch();
13001
13020
  if (basis === null || served === null || served === basis.syncEpoch) break;
13002
13021
  await deps.kv.remove(STORE_KEYS.streamCursor("mailbox"));
@@ -13004,21 +13023,25 @@ var Receive = class {
13004
13023
  }
13005
13024
  } catch (err) {
13006
13025
  logger.warn("PaymentsV2", "receive drain interrupted \u2014 unacked entries retry next drain:", err);
13007
- if (isRetryableAckError(err)) return stored;
13026
+ if (isRetryableAckError(err)) return finish();
13008
13027
  await flushAcks(deps, pending, pageEpoch).catch((flushErr) => {
13009
13028
  logger.warn("PaymentsV2", "receive ack flush failed \u2014 cursor holds at the acked prefix:", flushErr);
13029
+ return { progressed: false };
13010
13030
  });
13011
13031
  }
13012
- return stored;
13032
+ return finish();
13013
13033
  }
13014
- async processEntry(deps, engine, entry, pending, stored) {
13034
+ async processEntry(ctx, entry) {
13035
+ const { deps, engine, pending, stored, claimable } = ctx;
13015
13036
  const screened = await screen(deps, engine, entry);
13016
13037
  if (screened.kind === "ack") {
13017
13038
  pending.push(screened.ack);
13039
+ if (screened.ack.disposition === "claimed") claimable.n += 1;
13018
13040
  return;
13019
13041
  }
13020
13042
  await deps.view.store(screened.record);
13021
13043
  pending.push(claimAck(entry));
13044
+ claimable.n += 1;
13022
13045
  const transfer = await announce(deps, entry, screened.record);
13023
13046
  stored.push(transfer);
13024
13047
  deps.emit("transfer:incoming", transfer);
@@ -13079,7 +13102,8 @@ async function announce(deps, entry, record) {
13079
13102
  };
13080
13103
  }
13081
13104
  async function flushAcks(deps, pending, epochOf) {
13082
- if (pending.length === 0) return;
13105
+ if (pending.length === 0) return { progressed: true };
13106
+ const before = pending.length;
13083
13107
  let lastAcked = null;
13084
13108
  try {
13085
13109
  const settled = await settleAcks(deps, pending);
@@ -13097,6 +13121,7 @@ async function flushAcks(deps, pending, epochOf) {
13097
13121
  await deps.kv.set(STORE_KEYS.streamCursor("mailbox"), record);
13098
13122
  }
13099
13123
  }
13124
+ return { progressed: pending.length < before };
13100
13125
  }
13101
13126
  async function settleAcks(deps, pending) {
13102
13127
  const batch = deps.delivery.ackBatch?.bind(deps.delivery);
@@ -13939,7 +13964,7 @@ function composeFacadeParts(deps, hooks) {
13939
13964
  const machineDeps = buildMachineDeps(deps, hooks, historyStore);
13940
13965
  const machineStores = createMachineStores(deps.kv);
13941
13966
  const heldStates = /* @__PURE__ */ new Map();
13942
- const refreshView = coalesced(() => view.delta());
13967
+ const refreshView = coalesced(() => view.delta(), hooks.track);
13943
13968
  return {
13944
13969
  ownPubkeyBytes,
13945
13970
  view,
@@ -14082,7 +14107,8 @@ var PaymentsFacade = class {
14082
14107
  const parts = composeFacadeParts(deps, {
14083
14108
  engine: () => this.engine(),
14084
14109
  send: (request) => this.send(request),
14085
- isActiveOp: (id) => this.activeMoneyOps.has(id)
14110
+ isActiveOp: (id) => this.activeMoneyOps.has(id),
14111
+ track: (op) => this.trackTail(op)
14086
14112
  });
14087
14113
  this.view = parts.view;
14088
14114
  this.wakeRefresh = parts.refreshView;
@@ -14222,7 +14248,6 @@ var PaymentsFacade = class {
14222
14248
  }
14223
14249
  async receive() {
14224
14250
  const transfers = await this.track(this.receiveLoop.drainOnce());
14225
- if (transfers.length > 0) this.trackTail(this.view.delta());
14226
14251
  return { transfers };
14227
14252
  }
14228
14253
  mint(coinId, amount) {
@@ -15617,6 +15642,9 @@ var WalletApiDeliveryPort = class {
15617
15642
  await this.settleClaims(acks, settled, outcomes);
15618
15643
  await this.settleRejects(acks, settled);
15619
15644
  } catch (err) {
15645
+ await this.addSeenAll(settled).catch((seenErr) => {
15646
+ logger.warn("WalletApiDelivery", `seen-set write failed for ${String(settled.length)} committed acks:`, seenErr);
15647
+ });
15620
15648
  throw asRetryable(err);
15621
15649
  }
15622
15650
  await this.addSeenAll(settled);