@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.
package/dist/index.js CHANGED
@@ -11233,12 +11233,19 @@ var SerialChain = class {
11233
11233
  return run;
11234
11234
  }
11235
11235
  };
11236
- function coalesced(run) {
11236
+ function coalesced(run, observe) {
11237
11237
  let inFlight = false;
11238
11238
  let queued = false;
11239
11239
  const start = () => {
11240
11240
  inFlight = true;
11241
- void run().catch(() => void 0).finally(() => {
11241
+ let running;
11242
+ try {
11243
+ running = run();
11244
+ } catch {
11245
+ running = Promise.resolve();
11246
+ }
11247
+ observe?.(running);
11248
+ void running.catch(() => void 0).finally(() => {
11242
11249
  inFlight = false;
11243
11250
  if (!queued) return;
11244
11251
  queued = false;
@@ -12987,13 +12994,26 @@ var Receive = class {
12987
12994
  * the tokens just accepted, and the balance would still only move at the end.
12988
12995
  * Ordering is preserved: store() still precedes the ack (§5.7).
12989
12996
  */
12990
- async maybeRefresh(deps, pending, epochOf) {
12997
+ async maybeRefresh(ctx) {
12998
+ const { deps, pending, pageEpoch } = ctx;
12991
12999
  if (deps.refreshView === void 0) return;
12992
13000
  const now = deps.now?.() ?? Date.now();
12993
13001
  if (now - this.lastRefreshAt < REFRESH_INTERVAL_MS) return;
12994
13002
  this.lastRefreshAt = now;
12995
- await flushAcks(deps, pending, epochOf);
12996
- deps.refreshView();
13003
+ if ((await flushAcks(deps, pending, pageEpoch)).progressed) deps.refreshView();
13004
+ }
13005
+ /** One listing pass: process each entry, flushing and refreshing as it goes. */
13006
+ async drainPages(ctx, basis) {
13007
+ const { deps, pending, pageEpoch, claimable } = ctx;
13008
+ for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
13009
+ const claimableBefore = claimable.n;
13010
+ await this.processEntry(ctx, entry);
13011
+ if (pending.length >= ACK_BATCH_SIZE) {
13012
+ if (!(await flushAcks(deps, pending, pageEpoch)).progressed) return;
13013
+ }
13014
+ if (claimable.n > claimableBefore) await this.maybeRefresh(ctx);
13015
+ }
13016
+ await flushAcks(deps, pending, pageEpoch);
12997
13017
  }
12998
13018
  async doDrain() {
12999
13019
  const deps = this.deps;
@@ -13002,17 +13022,16 @@ var Receive = class {
13002
13022
  const stored = [];
13003
13023
  const pending = [];
13004
13024
  const pageEpoch = () => deps.delivery.incomingEpoch() ?? deps.syncEpoch();
13025
+ const claimable = { n: 0 };
13026
+ const finish = () => {
13027
+ if (claimable.n > 0) deps.refreshView?.();
13028
+ return stored;
13029
+ };
13005
13030
  try {
13006
13031
  const record = await deps.kv.get(STORE_KEYS.streamCursor("mailbox"));
13007
13032
  let basis = record !== null && record.syncEpoch === deps.syncEpoch() ? record : null;
13008
13033
  for (let pass = 0; pass < 2; pass++) {
13009
- for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
13010
- const storedBefore = stored.length;
13011
- await this.processEntry(deps, engine, entry, pending, stored);
13012
- if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
13013
- if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
13014
- }
13015
- await flushAcks(deps, pending, pageEpoch);
13034
+ await this.drainPages({ deps, engine, pending, stored, pageEpoch, claimable }, basis);
13016
13035
  const served = deps.delivery.incomingEpoch();
13017
13036
  if (basis === null || served === null || served === basis.syncEpoch) break;
13018
13037
  await deps.kv.remove(STORE_KEYS.streamCursor("mailbox"));
@@ -13020,21 +13039,25 @@ var Receive = class {
13020
13039
  }
13021
13040
  } catch (err) {
13022
13041
  logger.warn("PaymentsV2", "receive drain interrupted \u2014 unacked entries retry next drain:", err);
13023
- if (isRetryableAckError(err)) return stored;
13042
+ if (isRetryableAckError(err)) return finish();
13024
13043
  await flushAcks(deps, pending, pageEpoch).catch((flushErr) => {
13025
13044
  logger.warn("PaymentsV2", "receive ack flush failed \u2014 cursor holds at the acked prefix:", flushErr);
13045
+ return { progressed: false };
13026
13046
  });
13027
13047
  }
13028
- return stored;
13048
+ return finish();
13029
13049
  }
13030
- async processEntry(deps, engine, entry, pending, stored) {
13050
+ async processEntry(ctx, entry) {
13051
+ const { deps, engine, pending, stored, claimable } = ctx;
13031
13052
  const screened = await screen(deps, engine, entry);
13032
13053
  if (screened.kind === "ack") {
13033
13054
  pending.push(screened.ack);
13055
+ if (screened.ack.disposition === "claimed") claimable.n += 1;
13034
13056
  return;
13035
13057
  }
13036
13058
  await deps.view.store(screened.record);
13037
13059
  pending.push(claimAck(entry));
13060
+ claimable.n += 1;
13038
13061
  const transfer = await announce(deps, entry, screened.record);
13039
13062
  stored.push(transfer);
13040
13063
  deps.emit("transfer:incoming", transfer);
@@ -13095,7 +13118,8 @@ async function announce(deps, entry, record) {
13095
13118
  };
13096
13119
  }
13097
13120
  async function flushAcks(deps, pending, epochOf) {
13098
- if (pending.length === 0) return;
13121
+ if (pending.length === 0) return { progressed: true };
13122
+ const before = pending.length;
13099
13123
  let lastAcked = null;
13100
13124
  try {
13101
13125
  const settled = await settleAcks(deps, pending);
@@ -13113,6 +13137,7 @@ async function flushAcks(deps, pending, epochOf) {
13113
13137
  await deps.kv.set(STORE_KEYS.streamCursor("mailbox"), record);
13114
13138
  }
13115
13139
  }
13140
+ return { progressed: pending.length < before };
13116
13141
  }
13117
13142
  async function settleAcks(deps, pending) {
13118
13143
  const batch = deps.delivery.ackBatch?.bind(deps.delivery);
@@ -13955,7 +13980,7 @@ function composeFacadeParts(deps, hooks) {
13955
13980
  const machineDeps = buildMachineDeps(deps, hooks, historyStore);
13956
13981
  const machineStores = createMachineStores(deps.kv);
13957
13982
  const heldStates = /* @__PURE__ */ new Map();
13958
- const refreshView = coalesced(() => view.delta());
13983
+ const refreshView = coalesced(() => view.delta(), hooks.track);
13959
13984
  return {
13960
13985
  ownPubkeyBytes,
13961
13986
  view,
@@ -14098,7 +14123,8 @@ var PaymentsFacade = class {
14098
14123
  const parts = composeFacadeParts(deps, {
14099
14124
  engine: () => this.engine(),
14100
14125
  send: (request) => this.send(request),
14101
- isActiveOp: (id) => this.activeMoneyOps.has(id)
14126
+ isActiveOp: (id) => this.activeMoneyOps.has(id),
14127
+ track: (op) => this.trackTail(op)
14102
14128
  });
14103
14129
  this.view = parts.view;
14104
14130
  this.wakeRefresh = parts.refreshView;
@@ -14238,7 +14264,6 @@ var PaymentsFacade = class {
14238
14264
  }
14239
14265
  async receive() {
14240
14266
  const transfers = await this.track(this.receiveLoop.drainOnce());
14241
- if (transfers.length > 0) this.trackTail(this.view.delta());
14242
14267
  return { transfers };
14243
14268
  }
14244
14269
  mint(coinId, amount) {
@@ -15633,6 +15658,9 @@ var WalletApiDeliveryPort = class {
15633
15658
  await this.settleClaims(acks, settled, outcomes);
15634
15659
  await this.settleRejects(acks, settled);
15635
15660
  } catch (err) {
15661
+ await this.addSeenAll(settled).catch((seenErr) => {
15662
+ logger.warn("WalletApiDelivery", `seen-set write failed for ${String(settled.length)} committed acks:`, seenErr);
15663
+ });
15636
15664
  throw asRetryable(err);
15637
15665
  }
15638
15666
  await this.addSeenAll(settled);