@unicitylabs/sphere-sdk 0.14.11-dev.8 → 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.
@@ -356,6 +356,11 @@ type AckOutcome = {
356
356
  readonly deliveryId: string;
357
357
  readonly status: 'conflict';
358
358
  };
359
+ /** ackBatch failed in a way a per-entry retry would hit too — do not fall back. */
360
+ interface RetryableAckError extends Error {
361
+ readonly retryable: true;
362
+ }
363
+ declare function isRetryableAckError(err: unknown): err is RetryableAckError;
359
364
 
360
365
  interface IntentPayload {
361
366
  v: 2;
@@ -1174,4 +1179,4 @@ declare class PaymentsFacade implements PaymentsV2 {
1174
1179
  declare const HEARTBEAT_SEED_MS = 5000;
1175
1180
  declare const HEARTBEAT_CAP_MS = 120000;
1176
1181
 
1177
- export { ATTENTION_MINT_UNRESOLVED, ATTENTION_RECIPIENT_NETWORK_UNVERIFIED, ATTENTION_RESEED_REJECTED, type ApplyDeltaResult, type CheckpointReseeder, type ConnectionStatus, type DeliverOptions, type DeliveryJournalEntry, type DeliveryPort, type DeliveryReceipt, type DeterministicMintCapable, type FacadeClient, type FacadeSession, HEARTBEAT_CAP_MS, HEARTBEAT_SEED_MS, type HistoryEntry, type HistoryPage, type IncomingDelivery, type IntentBackstopEntry, type IntentPayload, type InventoryAsset, type InventoryItem, type InventoryPage, MAX_RESELECT, type MintJournalEntry, type MintResult, type OpOutcome, type OutcomeClass, type PaymentRequestStatus, type PaymentRequestView, PaymentsFacade, type PaymentsFacadeDeps, type PaymentsRequestsApi, type PaymentsV2, type PaymentsV2Events, type PendingTransfer, type PlannedOp, type RecipientInfo, STORE_KEYS, type ScopedKV, type SendRequest, type SettlingLink, type ShortfallEntry, type StoragePort, type StreamCursor, type StreamName, createScopedKV, supportsDeterministicMint };
1182
+ export { ATTENTION_MINT_UNRESOLVED, ATTENTION_RECIPIENT_NETWORK_UNVERIFIED, ATTENTION_RESEED_REJECTED, type AckOutcome, type AckRequest, type ApplyDeltaResult, type CheckpointReseeder, type ConnectionStatus, type DeliverOptions, type DeliveryJournalEntry, type DeliveryPort, type DeliveryReceipt, type DeterministicMintCapable, type FacadeClient, type FacadeSession, HEARTBEAT_CAP_MS, HEARTBEAT_SEED_MS, type HistoryEntry, type HistoryPage, type IncomingDelivery, type IntentBackstopEntry, type IntentPayload, type InventoryAsset, type InventoryItem, type InventoryPage, MAX_RESELECT, type MintJournalEntry, type MintResult, type OpOutcome, type OutcomeClass, type PaymentRequestStatus, type PaymentRequestView, PaymentsFacade, type PaymentsFacadeDeps, type PaymentsRequestsApi, type PaymentsV2, type PaymentsV2Events, type PendingTransfer, type PlannedOp, type RecipientInfo, type RetryableAckError, STORE_KEYS, type ScopedKV, type SendRequest, type SettlingLink, type ShortfallEntry, type StoragePort, type StreamCursor, type StreamName, createScopedKV, isRetryableAckError, supportsDeterministicMint };
@@ -356,6 +356,11 @@ type AckOutcome = {
356
356
  readonly deliveryId: string;
357
357
  readonly status: 'conflict';
358
358
  };
359
+ /** ackBatch failed in a way a per-entry retry would hit too — do not fall back. */
360
+ interface RetryableAckError extends Error {
361
+ readonly retryable: true;
362
+ }
363
+ declare function isRetryableAckError(err: unknown): err is RetryableAckError;
359
364
 
360
365
  interface IntentPayload {
361
366
  v: 2;
@@ -1174,4 +1179,4 @@ declare class PaymentsFacade implements PaymentsV2 {
1174
1179
  declare const HEARTBEAT_SEED_MS = 5000;
1175
1180
  declare const HEARTBEAT_CAP_MS = 120000;
1176
1181
 
1177
- export { ATTENTION_MINT_UNRESOLVED, ATTENTION_RECIPIENT_NETWORK_UNVERIFIED, ATTENTION_RESEED_REJECTED, type ApplyDeltaResult, type CheckpointReseeder, type ConnectionStatus, type DeliverOptions, type DeliveryJournalEntry, type DeliveryPort, type DeliveryReceipt, type DeterministicMintCapable, type FacadeClient, type FacadeSession, HEARTBEAT_CAP_MS, HEARTBEAT_SEED_MS, type HistoryEntry, type HistoryPage, type IncomingDelivery, type IntentBackstopEntry, type IntentPayload, type InventoryAsset, type InventoryItem, type InventoryPage, MAX_RESELECT, type MintJournalEntry, type MintResult, type OpOutcome, type OutcomeClass, type PaymentRequestStatus, type PaymentRequestView, PaymentsFacade, type PaymentsFacadeDeps, type PaymentsRequestsApi, type PaymentsV2, type PaymentsV2Events, type PendingTransfer, type PlannedOp, type RecipientInfo, STORE_KEYS, type ScopedKV, type SendRequest, type SettlingLink, type ShortfallEntry, type StoragePort, type StreamCursor, type StreamName, createScopedKV, supportsDeterministicMint };
1182
+ export { ATTENTION_MINT_UNRESOLVED, ATTENTION_RECIPIENT_NETWORK_UNVERIFIED, ATTENTION_RESEED_REJECTED, type AckOutcome, type AckRequest, type ApplyDeltaResult, type CheckpointReseeder, type ConnectionStatus, type DeliverOptions, type DeliveryJournalEntry, type DeliveryPort, type DeliveryReceipt, type DeterministicMintCapable, type FacadeClient, type FacadeSession, HEARTBEAT_CAP_MS, HEARTBEAT_SEED_MS, type HistoryEntry, type HistoryPage, type IncomingDelivery, type IntentBackstopEntry, type IntentPayload, type InventoryAsset, type InventoryItem, type InventoryPage, MAX_RESELECT, type MintJournalEntry, type MintResult, type OpOutcome, type OutcomeClass, type PaymentRequestStatus, type PaymentRequestView, PaymentsFacade, type PaymentsFacadeDeps, type PaymentsRequestsApi, type PaymentsV2, type PaymentsV2Events, type PendingTransfer, type PlannedOp, type RecipientInfo, type RetryableAckError, STORE_KEYS, type ScopedKV, type SendRequest, type SettlingLink, type ShortfallEntry, type StoragePort, type StreamCursor, type StreamName, createScopedKV, isRetryableAckError, supportsDeterministicMint };
@@ -1,3 +1,8 @@
1
+ // modules/payments-v2/ports.ts
2
+ function isRetryableAckError(err) {
3
+ return err !== null && typeof err === "object" && err.retryable === true;
4
+ }
5
+
1
6
  // modules/payments-v2/stores.ts
2
7
  function createScopedKV(storage, network, chainPubkey) {
3
8
  const prefix = `pv2:${network}:${chainPubkey}:`;
@@ -3194,11 +3199,6 @@ var logger = {
3194
3199
  }
3195
3200
  };
3196
3201
 
3197
- // modules/payments-v2/ports.ts
3198
- function isRetryableAckError(err) {
3199
- return err !== null && typeof err === "object" && err.retryable === true;
3200
- }
3201
-
3202
3202
  // modules/payments-v2/receive/Receive.ts
3203
3203
  var ACK_BATCH_SIZE = 200;
3204
3204
  var REFRESH_INTERVAL_MS = 2500;
@@ -3247,22 +3247,24 @@ var Receive = class {
3247
3247
  * the tokens just accepted, and the balance would still only move at the end.
3248
3248
  * Ordering is preserved: store() still precedes the ack (§5.7).
3249
3249
  */
3250
- async maybeRefresh(deps, pending, epochOf) {
3250
+ async maybeRefresh(ctx) {
3251
+ const { deps, pending, pageEpoch } = ctx;
3251
3252
  if (deps.refreshView === void 0) return;
3252
3253
  const now = deps.now?.() ?? Date.now();
3253
3254
  if (now - this.lastRefreshAt < REFRESH_INTERVAL_MS) return;
3254
3255
  this.lastRefreshAt = now;
3255
- await flushAcks(deps, pending, epochOf);
3256
- deps.refreshView();
3256
+ if ((await flushAcks(deps, pending, pageEpoch)).progressed) deps.refreshView();
3257
3257
  }
3258
3258
  /** One listing pass: process each entry, flushing and refreshing as it goes. */
3259
3259
  async drainPages(ctx, basis) {
3260
- const { deps, engine, pending, stored, pageEpoch } = ctx;
3260
+ const { deps, pending, pageEpoch, claimable } = ctx;
3261
3261
  for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
3262
- const storedBefore = stored.length;
3263
- await this.processEntry(deps, engine, entry, pending, stored);
3264
- if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
3265
- if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
3262
+ const claimableBefore = claimable.n;
3263
+ await this.processEntry(ctx, entry);
3264
+ if (pending.length >= ACK_BATCH_SIZE) {
3265
+ if (!(await flushAcks(deps, pending, pageEpoch)).progressed) return;
3266
+ }
3267
+ if (claimable.n > claimableBefore) await this.maybeRefresh(ctx);
3266
3268
  }
3267
3269
  await flushAcks(deps, pending, pageEpoch);
3268
3270
  }
@@ -3273,11 +3275,16 @@ var Receive = class {
3273
3275
  const stored = [];
3274
3276
  const pending = [];
3275
3277
  const pageEpoch = () => deps.delivery.incomingEpoch() ?? deps.syncEpoch();
3278
+ const claimable = { n: 0 };
3279
+ const finish = () => {
3280
+ if (claimable.n > 0) deps.refreshView?.();
3281
+ return stored;
3282
+ };
3276
3283
  try {
3277
3284
  const record = await deps.kv.get(STORE_KEYS.streamCursor("mailbox"));
3278
3285
  let basis = record !== null && record.syncEpoch === deps.syncEpoch() ? record : null;
3279
3286
  for (let pass = 0; pass < 2; pass++) {
3280
- await this.drainPages({ deps, engine, pending, stored, pageEpoch }, basis);
3287
+ await this.drainPages({ deps, engine, pending, stored, pageEpoch, claimable }, basis);
3281
3288
  const served = deps.delivery.incomingEpoch();
3282
3289
  if (basis === null || served === null || served === basis.syncEpoch) break;
3283
3290
  await deps.kv.remove(STORE_KEYS.streamCursor("mailbox"));
@@ -3285,22 +3292,25 @@ var Receive = class {
3285
3292
  }
3286
3293
  } catch (err) {
3287
3294
  logger.warn("PaymentsV2", "receive drain interrupted \u2014 unacked entries retry next drain:", err);
3288
- if (isRetryableAckError(err)) return stored;
3295
+ if (isRetryableAckError(err)) return finish();
3289
3296
  await flushAcks(deps, pending, pageEpoch).catch((flushErr) => {
3290
3297
  logger.warn("PaymentsV2", "receive ack flush failed \u2014 cursor holds at the acked prefix:", flushErr);
3298
+ return { progressed: false };
3291
3299
  });
3292
3300
  }
3293
- if (stored.length > 0) deps.refreshView?.();
3294
- return stored;
3301
+ return finish();
3295
3302
  }
3296
- async processEntry(deps, engine, entry, pending, stored) {
3303
+ async processEntry(ctx, entry) {
3304
+ const { deps, engine, pending, stored, claimable } = ctx;
3297
3305
  const screened = await screen(deps, engine, entry);
3298
3306
  if (screened.kind === "ack") {
3299
3307
  pending.push(screened.ack);
3308
+ if (screened.ack.disposition === "claimed") claimable.n += 1;
3300
3309
  return;
3301
3310
  }
3302
3311
  await deps.view.store(screened.record);
3303
3312
  pending.push(claimAck(entry));
3313
+ claimable.n += 1;
3304
3314
  const transfer = await announce(deps, entry, screened.record);
3305
3315
  stored.push(transfer);
3306
3316
  deps.emit("transfer:incoming", transfer);
@@ -3361,7 +3371,8 @@ async function announce(deps, entry, record) {
3361
3371
  };
3362
3372
  }
3363
3373
  async function flushAcks(deps, pending, epochOf) {
3364
- if (pending.length === 0) return;
3374
+ if (pending.length === 0) return { progressed: true };
3375
+ const before = pending.length;
3365
3376
  let lastAcked = null;
3366
3377
  try {
3367
3378
  const settled = await settleAcks(deps, pending);
@@ -3379,6 +3390,7 @@ async function flushAcks(deps, pending, epochOf) {
3379
3390
  await deps.kv.set(STORE_KEYS.streamCursor("mailbox"), record);
3380
3391
  }
3381
3392
  }
3393
+ return { progressed: pending.length < before };
3382
3394
  }
3383
3395
  async function settleAcks(deps, pending) {
3384
3396
  const batch = deps.delivery.ackBatch?.bind(deps.delivery);
@@ -4981,6 +4993,7 @@ export {
4981
4993
  PaymentsFacade,
4982
4994
  STORE_KEYS,
4983
4995
  createScopedKV,
4996
+ isRetryableAckError,
4984
4997
  supportsDeterministicMint
4985
4998
  };
4986
4999
  /*! Bundled license information: