@unicitylabs/sphere-sdk 0.14.11-dev.6 → 0.14.11-dev.8
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/connect/index.cjs +1 -1
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +1 -1
- package/dist/connect/index.js.map +1 -1
- package/dist/core/index.cjs +201 -46
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +201 -46
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/connect/index.cjs +1 -1
- package/dist/impl/browser/connect/index.cjs.map +1 -1
- package/dist/impl/browser/connect/index.js +1 -1
- package/dist/impl/browser/connect/index.js.map +1 -1
- package/dist/impl/wallet-api-v2/index.cjs +73 -3
- package/dist/impl/wallet-api-v2/index.cjs.map +1 -1
- package/dist/impl/wallet-api-v2/index.d.cts +25 -1
- package/dist/impl/wallet-api-v2/index.d.ts +25 -1
- package/dist/impl/wallet-api-v2/index.js +73 -3
- package/dist/impl/wallet-api-v2/index.js.map +1 -1
- package/dist/index.cjs +201 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +201 -46
- package/dist/index.js.map +1 -1
- package/dist/modules/payments-v2/index.cjs +128 -43
- package/dist/modules/payments-v2/index.cjs.map +1 -1
- package/dist/modules/payments-v2/index.d.cts +14 -0
- package/dist/modules/payments-v2/index.d.ts +14 -0
- package/dist/modules/payments-v2/index.js +128 -43
- package/dist/modules/payments-v2/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -11361,6 +11361,33 @@ var SerialChain = class {
|
|
|
11361
11361
|
return run;
|
|
11362
11362
|
}
|
|
11363
11363
|
};
|
|
11364
|
+
function coalesced(run, observe) {
|
|
11365
|
+
let inFlight = false;
|
|
11366
|
+
let queued = false;
|
|
11367
|
+
const start = () => {
|
|
11368
|
+
inFlight = true;
|
|
11369
|
+
let running;
|
|
11370
|
+
try {
|
|
11371
|
+
running = run();
|
|
11372
|
+
} catch {
|
|
11373
|
+
running = Promise.resolve();
|
|
11374
|
+
}
|
|
11375
|
+
observe?.(running);
|
|
11376
|
+
void running.catch(() => void 0).finally(() => {
|
|
11377
|
+
inFlight = false;
|
|
11378
|
+
if (!queued) return;
|
|
11379
|
+
queued = false;
|
|
11380
|
+
start();
|
|
11381
|
+
});
|
|
11382
|
+
};
|
|
11383
|
+
return () => {
|
|
11384
|
+
if (inFlight) {
|
|
11385
|
+
queued = true;
|
|
11386
|
+
return;
|
|
11387
|
+
}
|
|
11388
|
+
start();
|
|
11389
|
+
};
|
|
11390
|
+
}
|
|
11364
11391
|
|
|
11365
11392
|
// modules/payments-v2/stores.ts
|
|
11366
11393
|
function createScopedKV(storage, network, chainPubkey) {
|
|
@@ -12808,6 +12835,16 @@ var InventoryView = class {
|
|
|
12808
12835
|
this.inFlight.add(tokenId);
|
|
12809
12836
|
this.deps.emit("inventory:updated");
|
|
12810
12837
|
}
|
|
12838
|
+
/** Reserve a whole plan as ONE change — per token emitted 54 events per send. */
|
|
12839
|
+
markInFlightMany(tokenIds) {
|
|
12840
|
+
let changed = false;
|
|
12841
|
+
for (const tokenId of tokenIds) {
|
|
12842
|
+
if (this.inFlight.has(tokenId)) continue;
|
|
12843
|
+
this.inFlight.add(tokenId);
|
|
12844
|
+
changed = true;
|
|
12845
|
+
}
|
|
12846
|
+
if (changed) this.deps.emit("inventory:updated");
|
|
12847
|
+
}
|
|
12811
12848
|
release(tokenId) {
|
|
12812
12849
|
if (this.inFlight.delete(tokenId)) this.deps.emit("inventory:updated");
|
|
12813
12850
|
}
|
|
@@ -13032,6 +13069,11 @@ var InventoryView = class {
|
|
|
13032
13069
|
}
|
|
13033
13070
|
};
|
|
13034
13071
|
|
|
13072
|
+
// modules/payments-v2/ports.ts
|
|
13073
|
+
function isRetryableAckError(err) {
|
|
13074
|
+
return err !== null && typeof err === "object" && err.retryable === true;
|
|
13075
|
+
}
|
|
13076
|
+
|
|
13035
13077
|
// modules/payments-v2/receive/Receive.ts
|
|
13036
13078
|
var ACK_BATCH_SIZE = 200;
|
|
13037
13079
|
var REFRESH_INTERVAL_MS = 2500;
|
|
@@ -13088,6 +13130,17 @@ var Receive = class {
|
|
|
13088
13130
|
await flushAcks(deps, pending, epochOf);
|
|
13089
13131
|
deps.refreshView();
|
|
13090
13132
|
}
|
|
13133
|
+
/** One listing pass: process each entry, flushing and refreshing as it goes. */
|
|
13134
|
+
async drainPages(ctx, basis) {
|
|
13135
|
+
const { deps, engine, pending, stored, pageEpoch } = ctx;
|
|
13136
|
+
for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
|
|
13137
|
+
const storedBefore = stored.length;
|
|
13138
|
+
await this.processEntry(deps, engine, entry, pending, stored);
|
|
13139
|
+
if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
|
|
13140
|
+
if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
|
|
13141
|
+
}
|
|
13142
|
+
await flushAcks(deps, pending, pageEpoch);
|
|
13143
|
+
}
|
|
13091
13144
|
async doDrain() {
|
|
13092
13145
|
const deps = this.deps;
|
|
13093
13146
|
this.lastRefreshAt = deps.now?.() ?? Date.now();
|
|
@@ -13099,13 +13152,7 @@ var Receive = class {
|
|
|
13099
13152
|
const record = await deps.kv.get(STORE_KEYS.streamCursor("mailbox"));
|
|
13100
13153
|
let basis = record !== null && record.syncEpoch === deps.syncEpoch() ? record : null;
|
|
13101
13154
|
for (let pass = 0; pass < 2; pass++) {
|
|
13102
|
-
|
|
13103
|
-
const storedBefore = stored.length;
|
|
13104
|
-
await this.processEntry(deps, engine, entry, pending, stored);
|
|
13105
|
-
if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
|
|
13106
|
-
if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
|
|
13107
|
-
}
|
|
13108
|
-
await flushAcks(deps, pending, pageEpoch);
|
|
13155
|
+
await this.drainPages({ deps, engine, pending, stored, pageEpoch }, basis);
|
|
13109
13156
|
const served = deps.delivery.incomingEpoch();
|
|
13110
13157
|
if (basis === null || served === null || served === basis.syncEpoch) break;
|
|
13111
13158
|
await deps.kv.remove(STORE_KEYS.streamCursor("mailbox"));
|
|
@@ -13113,10 +13160,12 @@ var Receive = class {
|
|
|
13113
13160
|
}
|
|
13114
13161
|
} catch (err) {
|
|
13115
13162
|
logger.warn("PaymentsV2", "receive drain interrupted \u2014 unacked entries retry next drain:", err);
|
|
13163
|
+
if (isRetryableAckError(err)) return stored;
|
|
13116
13164
|
await flushAcks(deps, pending, pageEpoch).catch((flushErr) => {
|
|
13117
13165
|
logger.warn("PaymentsV2", "receive ack flush failed \u2014 cursor holds at the acked prefix:", flushErr);
|
|
13118
13166
|
});
|
|
13119
13167
|
}
|
|
13168
|
+
if (stored.length > 0) deps.refreshView?.();
|
|
13120
13169
|
return stored;
|
|
13121
13170
|
}
|
|
13122
13171
|
async processEntry(deps, engine, entry, pending, stored) {
|
|
@@ -13187,14 +13236,18 @@ async function announce(deps, entry, record) {
|
|
|
13187
13236
|
};
|
|
13188
13237
|
}
|
|
13189
13238
|
async function flushAcks(deps, pending, epochOf) {
|
|
13239
|
+
if (pending.length === 0) return;
|
|
13190
13240
|
let lastAcked = null;
|
|
13191
13241
|
try {
|
|
13192
|
-
|
|
13193
|
-
|
|
13194
|
-
|
|
13195
|
-
lastAcked =
|
|
13196
|
-
|
|
13242
|
+
const settled = await settleAcks(deps, pending);
|
|
13243
|
+
let i = 0;
|
|
13244
|
+
while (i < pending.length && settled.has(pending[i].deliveryId)) {
|
|
13245
|
+
lastAcked = pending[i].cursor;
|
|
13246
|
+
i += 1;
|
|
13197
13247
|
}
|
|
13248
|
+
const stuck = pending.filter((p) => !settled.has(p.deliveryId));
|
|
13249
|
+
pending.length = 0;
|
|
13250
|
+
pending.push(...stuck);
|
|
13198
13251
|
} finally {
|
|
13199
13252
|
if (lastAcked !== null) {
|
|
13200
13253
|
const record = { cursor: lastAcked, syncEpoch: epochOf() };
|
|
@@ -13202,14 +13255,65 @@ async function flushAcks(deps, pending, epochOf) {
|
|
|
13202
13255
|
}
|
|
13203
13256
|
}
|
|
13204
13257
|
}
|
|
13258
|
+
async function settleAcks(deps, pending) {
|
|
13259
|
+
const batch = deps.delivery.ackBatch?.bind(deps.delivery);
|
|
13260
|
+
if (batch === void 0) return settleOneByOne(deps, pending);
|
|
13261
|
+
let outcomes;
|
|
13262
|
+
try {
|
|
13263
|
+
outcomes = await batch(pending.map(toAckRequest));
|
|
13264
|
+
} catch (err) {
|
|
13265
|
+
if (isRetryableAckError(err)) throw err;
|
|
13266
|
+
logger.warn("PaymentsV2", "batched mailbox ack failed \u2014 settling one at a time:", err);
|
|
13267
|
+
return settleOneByOne(deps, pending);
|
|
13268
|
+
}
|
|
13269
|
+
const settled = new Set(outcomes.filter((o) => o.status === "settled").map((o) => o.deliveryId));
|
|
13270
|
+
const conflicts = outcomes.filter((o) => o.status === "conflict").map((o) => o.deliveryId);
|
|
13271
|
+
if (conflicts.length > 0) await resolveConflicts(deps, pending, conflicts, settled);
|
|
13272
|
+
return settled;
|
|
13273
|
+
}
|
|
13274
|
+
async function resolveConflicts(deps, pending, conflicts, settled) {
|
|
13275
|
+
for (const deliveryId of conflicts) {
|
|
13276
|
+
const entry = pending.find((p) => p.deliveryId === deliveryId);
|
|
13277
|
+
try {
|
|
13278
|
+
await rejectStaleClaim(deps, deliveryId, entry?.transferId);
|
|
13279
|
+
} catch (err) {
|
|
13280
|
+
logger.warn("PaymentsV2", `stale-reject failed for ${deliveryId} \u2014 cursor holds here:`, err);
|
|
13281
|
+
continue;
|
|
13282
|
+
}
|
|
13283
|
+
settled.add(deliveryId);
|
|
13284
|
+
}
|
|
13285
|
+
}
|
|
13286
|
+
async function rejectStaleClaim(deps, deliveryId, transferId) {
|
|
13287
|
+
logger.warn("PaymentsV2", `mailbox claim CONFLICT for ${deliveryId} \u2014 rejected('other') as stale`);
|
|
13288
|
+
await deps.delivery.ack(deliveryId, "rejected", "other");
|
|
13289
|
+
deps.attention(transferId ?? "", ATTENTION_CLAIM_CONFLICT, deliveryId);
|
|
13290
|
+
}
|
|
13291
|
+
async function settleOneByOne(deps, pending) {
|
|
13292
|
+
const settled = /* @__PURE__ */ new Set();
|
|
13293
|
+
for (const ack of pending) {
|
|
13294
|
+
try {
|
|
13295
|
+
await ackOne(deps, ack);
|
|
13296
|
+
} catch (err) {
|
|
13297
|
+
logger.warn("PaymentsV2", `mailbox ack failed for ${ack.deliveryId} \u2014 cursor holds here:`, err);
|
|
13298
|
+
break;
|
|
13299
|
+
}
|
|
13300
|
+
settled.add(ack.deliveryId);
|
|
13301
|
+
}
|
|
13302
|
+
return settled;
|
|
13303
|
+
}
|
|
13304
|
+
function toAckRequest(ack) {
|
|
13305
|
+
return {
|
|
13306
|
+
deliveryId: ack.deliveryId,
|
|
13307
|
+
disposition: ack.disposition,
|
|
13308
|
+
...ack.reason !== void 0 ? { reason: ack.reason } : {}
|
|
13309
|
+
};
|
|
13310
|
+
}
|
|
13205
13311
|
async function ackOne(deps, ack) {
|
|
13206
13312
|
try {
|
|
13207
13313
|
await deps.delivery.ack(ack.deliveryId, ack.disposition, ack.reason);
|
|
13208
13314
|
} catch (err) {
|
|
13209
13315
|
if (ack.disposition !== "claimed" || !isClaimConflict(err)) throw err;
|
|
13210
|
-
|
|
13211
|
-
await deps.delivery.ack(ack.deliveryId, "rejected", "other");
|
|
13212
|
-
deps.attention(ack.transferId ?? "", ATTENTION_CLAIM_CONFLICT, ack.deliveryId);
|
|
13316
|
+
await rejectStaleClaim(deps, ack.deliveryId, ack.transferId);
|
|
13213
13317
|
}
|
|
13214
13318
|
}
|
|
13215
13319
|
function claimAck(entry) {
|
|
@@ -13963,26 +14067,6 @@ function parseAmount(raw) {
|
|
|
13963
14067
|
function supportsDeterministicMint(engine) {
|
|
13964
14068
|
return engine.deterministicMint === true;
|
|
13965
14069
|
}
|
|
13966
|
-
function makeCoalescedRefresh(refresh) {
|
|
13967
|
-
let inFlight = false;
|
|
13968
|
-
let queued = false;
|
|
13969
|
-
const run = () => {
|
|
13970
|
-
inFlight = true;
|
|
13971
|
-
void refresh().catch(() => void 0).finally(() => {
|
|
13972
|
-
inFlight = false;
|
|
13973
|
-
if (!queued) return;
|
|
13974
|
-
queued = false;
|
|
13975
|
-
run();
|
|
13976
|
-
});
|
|
13977
|
-
};
|
|
13978
|
-
return () => {
|
|
13979
|
-
if (inFlight) {
|
|
13980
|
-
queued = true;
|
|
13981
|
-
return;
|
|
13982
|
-
}
|
|
13983
|
-
run();
|
|
13984
|
-
};
|
|
13985
|
-
}
|
|
13986
14070
|
function composeFacadeParts(deps, hooks) {
|
|
13987
14071
|
const ownPubkeyBytes = hexToBytes4(deps.ownPubkey);
|
|
13988
14072
|
const ledger = new ReservationLedger();
|
|
@@ -14012,9 +14096,11 @@ function composeFacadeParts(deps, hooks) {
|
|
|
14012
14096
|
const machineDeps = buildMachineDeps(deps, hooks, historyStore);
|
|
14013
14097
|
const machineStores = createMachineStores(deps.kv);
|
|
14014
14098
|
const heldStates = /* @__PURE__ */ new Map();
|
|
14099
|
+
const refreshView = coalesced(() => view.delta(), hooks.track);
|
|
14015
14100
|
return {
|
|
14016
14101
|
ownPubkeyBytes,
|
|
14017
14102
|
view,
|
|
14103
|
+
refreshView,
|
|
14018
14104
|
ledger,
|
|
14019
14105
|
pins: buildPins(deps, hooks, { ledger, view, machineStores, machineDeps }),
|
|
14020
14106
|
queue,
|
|
@@ -14023,7 +14109,7 @@ function composeFacadeParts(deps, hooks) {
|
|
|
14023
14109
|
machineDeps,
|
|
14024
14110
|
machine: new TransferMachine(machineDeps),
|
|
14025
14111
|
heldStates,
|
|
14026
|
-
receiveLoop: buildReceive(deps, hooks, historyStore, heldStates,
|
|
14112
|
+
receiveLoop: buildReceive(deps, hooks, historyStore, heldStates, refreshView),
|
|
14027
14113
|
requests: buildRequests(deps, hooks),
|
|
14028
14114
|
restoreDeps: buildRestoreDeps(deps, machineDeps, machineStores, view)
|
|
14029
14115
|
};
|
|
@@ -14090,7 +14176,7 @@ function buildMachineDeps(deps, hooks, historyStore) {
|
|
|
14090
14176
|
}
|
|
14091
14177
|
};
|
|
14092
14178
|
}
|
|
14093
|
-
function buildReceive(deps, hooks, historyStore, heldStates,
|
|
14179
|
+
function buildReceive(deps, hooks, historyStore, heldStates, refreshView) {
|
|
14094
14180
|
return new Receive({
|
|
14095
14181
|
delivery: deps.deliveryPort,
|
|
14096
14182
|
engine: () => hooks.engine(),
|
|
@@ -14104,8 +14190,7 @@ function buildReceive(deps, hooks, historyStore, heldStates, view) {
|
|
|
14104
14190
|
registry: deps.registry,
|
|
14105
14191
|
recordReceived: (record) => recordReceived(historyStore, record),
|
|
14106
14192
|
emit: (event, transfer) => deps.emit(event, transfer),
|
|
14107
|
-
|
|
14108
|
-
refreshView: makeCoalescedRefresh(() => view.delta()),
|
|
14193
|
+
refreshView,
|
|
14109
14194
|
attention: (transferId, code, detail) => {
|
|
14110
14195
|
deps.emit(
|
|
14111
14196
|
"transfer:attention",
|
|
@@ -14154,10 +14239,11 @@ var PaymentsFacade = class {
|
|
|
14154
14239
|
const parts = composeFacadeParts(deps, {
|
|
14155
14240
|
engine: () => this.engine(),
|
|
14156
14241
|
send: (request) => this.send(request),
|
|
14157
|
-
isActiveOp: (id) => this.activeMoneyOps.has(id)
|
|
14242
|
+
isActiveOp: (id) => this.activeMoneyOps.has(id),
|
|
14243
|
+
track: (op) => this.trackTail(op)
|
|
14158
14244
|
});
|
|
14159
14245
|
this.view = parts.view;
|
|
14160
|
-
this.wakeRefresh =
|
|
14246
|
+
this.wakeRefresh = parts.refreshView;
|
|
14161
14247
|
this.ledger = parts.ledger;
|
|
14162
14248
|
this.queue = parts.queue;
|
|
14163
14249
|
this.machine = parts.machine;
|
|
@@ -14294,7 +14380,6 @@ var PaymentsFacade = class {
|
|
|
14294
14380
|
}
|
|
14295
14381
|
async receive() {
|
|
14296
14382
|
const transfers = await this.track(this.receiveLoop.drainOnce());
|
|
14297
|
-
if (transfers.length > 0) this.trackTail(this.view.delta());
|
|
14298
14383
|
return { transfers };
|
|
14299
14384
|
}
|
|
14300
14385
|
mint(coinId, amount) {
|
|
@@ -14490,7 +14575,7 @@ var PaymentsFacade = class {
|
|
|
14490
14575
|
...spend.plan.direct,
|
|
14491
14576
|
...spend.plan.split !== void 0 ? [spend.plan.split.tokenId] : []
|
|
14492
14577
|
];
|
|
14493
|
-
|
|
14578
|
+
this.view.markInFlightMany(sourceIds);
|
|
14494
14579
|
if (spend.plan.split !== void 0) {
|
|
14495
14580
|
this.queue.declareExpectedChange(transferId, coinId, spend.plan.split.remainderAmount);
|
|
14496
14581
|
}
|
|
@@ -14776,6 +14861,10 @@ var WalletApiHttpError = class extends Error {
|
|
|
14776
14861
|
if (retryAfter !== void 0) this.retryAfter = retryAfter;
|
|
14777
14862
|
}
|
|
14778
14863
|
};
|
|
14864
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([0, 408, 425, 429, 500, 502, 503, 504]);
|
|
14865
|
+
function isRetryableStatus(err) {
|
|
14866
|
+
return err instanceof WalletApiHttpError && RETRYABLE_STATUSES.has(err.status);
|
|
14867
|
+
}
|
|
14779
14868
|
function isWalletApiHttpError(err, status) {
|
|
14780
14869
|
return err instanceof WalletApiHttpError && (status === void 0 || err.status === status);
|
|
14781
14870
|
}
|
|
@@ -15488,6 +15577,23 @@ function computeDeliveryId(tokenIdHex, stateHashHex) {
|
|
|
15488
15577
|
return bytesToHex3(sha256(joined));
|
|
15489
15578
|
}
|
|
15490
15579
|
var DELIVERY_SEEN_KEY = "delivery:seen";
|
|
15580
|
+
var ACK_CHUNK = 50;
|
|
15581
|
+
function chunked(items, size) {
|
|
15582
|
+
const out = [];
|
|
15583
|
+
for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
|
|
15584
|
+
return out;
|
|
15585
|
+
}
|
|
15586
|
+
var RetryableAckFailure = class extends Error {
|
|
15587
|
+
retryable = true;
|
|
15588
|
+
constructor(cause) {
|
|
15589
|
+
super(`mailbox ack batch could not be attempted: ${String(cause)}`);
|
|
15590
|
+
this.name = "RetryableAckFailure";
|
|
15591
|
+
this.cause = cause;
|
|
15592
|
+
}
|
|
15593
|
+
};
|
|
15594
|
+
function asRetryable(err) {
|
|
15595
|
+
return isRetryableStatus(err) ? new RetryableAckFailure(err) : err;
|
|
15596
|
+
}
|
|
15491
15597
|
var WalletApiDeliveryPort = class {
|
|
15492
15598
|
custody;
|
|
15493
15599
|
client;
|
|
@@ -15653,7 +15759,54 @@ var WalletApiDeliveryPort = class {
|
|
|
15653
15759
|
} else {
|
|
15654
15760
|
await this.client.reject([deliveryId], reason);
|
|
15655
15761
|
}
|
|
15656
|
-
await this.
|
|
15762
|
+
await this.addSeenAll([deliveryId]);
|
|
15763
|
+
}
|
|
15764
|
+
/**
|
|
15765
|
+
* §5.7/#757 batched settle. Claims go out grouped, rejects grouped by reason
|
|
15766
|
+
* (the endpoint takes one reason per call), and the seen-set is written ONCE
|
|
15767
|
+
* after every HTTP call has succeeded — never on a throw, so an aborted batch
|
|
15768
|
+
* re-lists rather than being silently forgotten.
|
|
15769
|
+
*/
|
|
15770
|
+
async ackBatch(acks) {
|
|
15771
|
+
const settled = [];
|
|
15772
|
+
const outcomes = [];
|
|
15773
|
+
try {
|
|
15774
|
+
await this.settleClaims(acks, settled, outcomes);
|
|
15775
|
+
await this.settleRejects(acks, settled);
|
|
15776
|
+
} catch (err) {
|
|
15777
|
+
await this.addSeenAll(settled).catch(() => void 0);
|
|
15778
|
+
throw asRetryable(err);
|
|
15779
|
+
}
|
|
15780
|
+
await this.addSeenAll(settled);
|
|
15781
|
+
return [...outcomes, ...settled.map((deliveryId) => ({ deliveryId, status: "settled" }))];
|
|
15782
|
+
}
|
|
15783
|
+
async settleClaims(acks, settled, outcomes) {
|
|
15784
|
+
const ids = acks.filter((a) => a.disposition === "claimed").map((a) => a.deliveryId);
|
|
15785
|
+
for (const chunk of chunked(ids, ACK_CHUNK)) {
|
|
15786
|
+
const result = await this.client.claim(chunk, this.custody === "inventory");
|
|
15787
|
+
settled.push(...result.claimed);
|
|
15788
|
+
settled.push(...result.alreadyClaimed.map((e) => e.entryId));
|
|
15789
|
+
for (const f of result.failed) {
|
|
15790
|
+
if (f.code === "CONFLICT") outcomes.push({ deliveryId: f.entryId, status: "conflict" });
|
|
15791
|
+
else throw new MailboxClaimFailedError(f.entryId, f.code);
|
|
15792
|
+
}
|
|
15793
|
+
}
|
|
15794
|
+
}
|
|
15795
|
+
async settleRejects(acks, settled) {
|
|
15796
|
+
const byReason = /* @__PURE__ */ new Map();
|
|
15797
|
+
for (const a of acks) {
|
|
15798
|
+
if (a.disposition !== "rejected") continue;
|
|
15799
|
+
const key = a.reason ?? "";
|
|
15800
|
+
const group = byReason.get(key) ?? [];
|
|
15801
|
+
group.push(a.deliveryId);
|
|
15802
|
+
byReason.set(key, group);
|
|
15803
|
+
}
|
|
15804
|
+
for (const [reason, group] of byReason) {
|
|
15805
|
+
for (const chunk of chunked(group, ACK_CHUNK)) {
|
|
15806
|
+
await this.client.reject(chunk, reason === "" ? void 0 : reason);
|
|
15807
|
+
settled.push(...chunk);
|
|
15808
|
+
}
|
|
15809
|
+
}
|
|
15657
15810
|
}
|
|
15658
15811
|
onWake(cb) {
|
|
15659
15812
|
if (this.wake === null) return () => void 0;
|
|
@@ -15664,10 +15817,12 @@ var WalletApiDeliveryPort = class {
|
|
|
15664
15817
|
const raw = await this.kv.get(DELIVERY_SEEN_KEY);
|
|
15665
15818
|
return new Set(raw ?? []);
|
|
15666
15819
|
}
|
|
15667
|
-
|
|
15820
|
+
/** SerialChain settles-not-fulfills: a rejected write never bricks later acks. */
|
|
15821
|
+
addSeenAll(deliveryIds) {
|
|
15822
|
+
if (deliveryIds.length === 0) return Promise.resolve();
|
|
15668
15823
|
return this.seenChain.enqueue(async () => {
|
|
15669
15824
|
const seen = await this.readSeen();
|
|
15670
|
-
seen.add(
|
|
15825
|
+
for (const id of deliveryIds) seen.add(id);
|
|
15671
15826
|
await this.kv.set(DELIVERY_SEEN_KEY, [...seen]);
|
|
15672
15827
|
});
|
|
15673
15828
|
}
|