@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/core/index.cjs
CHANGED
|
@@ -11303,6 +11303,33 @@ var SerialChain = class {
|
|
|
11303
11303
|
return run;
|
|
11304
11304
|
}
|
|
11305
11305
|
};
|
|
11306
|
+
function coalesced(run, observe) {
|
|
11307
|
+
let inFlight = false;
|
|
11308
|
+
let queued = false;
|
|
11309
|
+
const start = () => {
|
|
11310
|
+
inFlight = true;
|
|
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(() => {
|
|
11319
|
+
inFlight = false;
|
|
11320
|
+
if (!queued) return;
|
|
11321
|
+
queued = false;
|
|
11322
|
+
start();
|
|
11323
|
+
});
|
|
11324
|
+
};
|
|
11325
|
+
return () => {
|
|
11326
|
+
if (inFlight) {
|
|
11327
|
+
queued = true;
|
|
11328
|
+
return;
|
|
11329
|
+
}
|
|
11330
|
+
start();
|
|
11331
|
+
};
|
|
11332
|
+
}
|
|
11306
11333
|
|
|
11307
11334
|
// modules/payments-v2/stores.ts
|
|
11308
11335
|
function createScopedKV(storage, network, chainPubkey) {
|
|
@@ -12750,6 +12777,16 @@ var InventoryView = class {
|
|
|
12750
12777
|
this.inFlight.add(tokenId);
|
|
12751
12778
|
this.deps.emit("inventory:updated");
|
|
12752
12779
|
}
|
|
12780
|
+
/** Reserve a whole plan as ONE change — per token emitted 54 events per send. */
|
|
12781
|
+
markInFlightMany(tokenIds) {
|
|
12782
|
+
let changed = false;
|
|
12783
|
+
for (const tokenId of tokenIds) {
|
|
12784
|
+
if (this.inFlight.has(tokenId)) continue;
|
|
12785
|
+
this.inFlight.add(tokenId);
|
|
12786
|
+
changed = true;
|
|
12787
|
+
}
|
|
12788
|
+
if (changed) this.deps.emit("inventory:updated");
|
|
12789
|
+
}
|
|
12753
12790
|
release(tokenId) {
|
|
12754
12791
|
if (this.inFlight.delete(tokenId)) this.deps.emit("inventory:updated");
|
|
12755
12792
|
}
|
|
@@ -12974,6 +13011,11 @@ var InventoryView = class {
|
|
|
12974
13011
|
}
|
|
12975
13012
|
};
|
|
12976
13013
|
|
|
13014
|
+
// modules/payments-v2/ports.ts
|
|
13015
|
+
function isRetryableAckError(err) {
|
|
13016
|
+
return err !== null && typeof err === "object" && err.retryable === true;
|
|
13017
|
+
}
|
|
13018
|
+
|
|
12977
13019
|
// modules/payments-v2/receive/Receive.ts
|
|
12978
13020
|
var ACK_BATCH_SIZE = 200;
|
|
12979
13021
|
var REFRESH_INTERVAL_MS = 2500;
|
|
@@ -13030,6 +13072,17 @@ var Receive = class {
|
|
|
13030
13072
|
await flushAcks(deps, pending, epochOf);
|
|
13031
13073
|
deps.refreshView();
|
|
13032
13074
|
}
|
|
13075
|
+
/** One listing pass: process each entry, flushing and refreshing as it goes. */
|
|
13076
|
+
async drainPages(ctx, basis) {
|
|
13077
|
+
const { deps, engine, pending, stored, pageEpoch } = ctx;
|
|
13078
|
+
for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
|
|
13079
|
+
const storedBefore = stored.length;
|
|
13080
|
+
await this.processEntry(deps, engine, entry, pending, stored);
|
|
13081
|
+
if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
|
|
13082
|
+
if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
|
|
13083
|
+
}
|
|
13084
|
+
await flushAcks(deps, pending, pageEpoch);
|
|
13085
|
+
}
|
|
13033
13086
|
async doDrain() {
|
|
13034
13087
|
const deps = this.deps;
|
|
13035
13088
|
this.lastRefreshAt = deps.now?.() ?? Date.now();
|
|
@@ -13041,13 +13094,7 @@ var Receive = class {
|
|
|
13041
13094
|
const record = await deps.kv.get(STORE_KEYS.streamCursor("mailbox"));
|
|
13042
13095
|
let basis = record !== null && record.syncEpoch === deps.syncEpoch() ? record : null;
|
|
13043
13096
|
for (let pass = 0; pass < 2; pass++) {
|
|
13044
|
-
|
|
13045
|
-
const storedBefore = stored.length;
|
|
13046
|
-
await this.processEntry(deps, engine, entry, pending, stored);
|
|
13047
|
-
if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
|
|
13048
|
-
if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
|
|
13049
|
-
}
|
|
13050
|
-
await flushAcks(deps, pending, pageEpoch);
|
|
13097
|
+
await this.drainPages({ deps, engine, pending, stored, pageEpoch }, basis);
|
|
13051
13098
|
const served = deps.delivery.incomingEpoch();
|
|
13052
13099
|
if (basis === null || served === null || served === basis.syncEpoch) break;
|
|
13053
13100
|
await deps.kv.remove(STORE_KEYS.streamCursor("mailbox"));
|
|
@@ -13055,10 +13102,12 @@ var Receive = class {
|
|
|
13055
13102
|
}
|
|
13056
13103
|
} catch (err) {
|
|
13057
13104
|
logger.warn("PaymentsV2", "receive drain interrupted \u2014 unacked entries retry next drain:", err);
|
|
13105
|
+
if (isRetryableAckError(err)) return stored;
|
|
13058
13106
|
await flushAcks(deps, pending, pageEpoch).catch((flushErr) => {
|
|
13059
13107
|
logger.warn("PaymentsV2", "receive ack flush failed \u2014 cursor holds at the acked prefix:", flushErr);
|
|
13060
13108
|
});
|
|
13061
13109
|
}
|
|
13110
|
+
if (stored.length > 0) deps.refreshView?.();
|
|
13062
13111
|
return stored;
|
|
13063
13112
|
}
|
|
13064
13113
|
async processEntry(deps, engine, entry, pending, stored) {
|
|
@@ -13129,14 +13178,18 @@ async function announce(deps, entry, record) {
|
|
|
13129
13178
|
};
|
|
13130
13179
|
}
|
|
13131
13180
|
async function flushAcks(deps, pending, epochOf) {
|
|
13181
|
+
if (pending.length === 0) return;
|
|
13132
13182
|
let lastAcked = null;
|
|
13133
13183
|
try {
|
|
13134
|
-
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
lastAcked =
|
|
13138
|
-
|
|
13184
|
+
const settled = await settleAcks(deps, pending);
|
|
13185
|
+
let i = 0;
|
|
13186
|
+
while (i < pending.length && settled.has(pending[i].deliveryId)) {
|
|
13187
|
+
lastAcked = pending[i].cursor;
|
|
13188
|
+
i += 1;
|
|
13139
13189
|
}
|
|
13190
|
+
const stuck = pending.filter((p) => !settled.has(p.deliveryId));
|
|
13191
|
+
pending.length = 0;
|
|
13192
|
+
pending.push(...stuck);
|
|
13140
13193
|
} finally {
|
|
13141
13194
|
if (lastAcked !== null) {
|
|
13142
13195
|
const record = { cursor: lastAcked, syncEpoch: epochOf() };
|
|
@@ -13144,14 +13197,65 @@ async function flushAcks(deps, pending, epochOf) {
|
|
|
13144
13197
|
}
|
|
13145
13198
|
}
|
|
13146
13199
|
}
|
|
13200
|
+
async function settleAcks(deps, pending) {
|
|
13201
|
+
const batch = deps.delivery.ackBatch?.bind(deps.delivery);
|
|
13202
|
+
if (batch === void 0) return settleOneByOne(deps, pending);
|
|
13203
|
+
let outcomes;
|
|
13204
|
+
try {
|
|
13205
|
+
outcomes = await batch(pending.map(toAckRequest));
|
|
13206
|
+
} catch (err) {
|
|
13207
|
+
if (isRetryableAckError(err)) throw err;
|
|
13208
|
+
logger.warn("PaymentsV2", "batched mailbox ack failed \u2014 settling one at a time:", err);
|
|
13209
|
+
return settleOneByOne(deps, pending);
|
|
13210
|
+
}
|
|
13211
|
+
const settled = new Set(outcomes.filter((o) => o.status === "settled").map((o) => o.deliveryId));
|
|
13212
|
+
const conflicts = outcomes.filter((o) => o.status === "conflict").map((o) => o.deliveryId);
|
|
13213
|
+
if (conflicts.length > 0) await resolveConflicts(deps, pending, conflicts, settled);
|
|
13214
|
+
return settled;
|
|
13215
|
+
}
|
|
13216
|
+
async function resolveConflicts(deps, pending, conflicts, settled) {
|
|
13217
|
+
for (const deliveryId of conflicts) {
|
|
13218
|
+
const entry = pending.find((p) => p.deliveryId === deliveryId);
|
|
13219
|
+
try {
|
|
13220
|
+
await rejectStaleClaim(deps, deliveryId, entry?.transferId);
|
|
13221
|
+
} catch (err) {
|
|
13222
|
+
logger.warn("PaymentsV2", `stale-reject failed for ${deliveryId} \u2014 cursor holds here:`, err);
|
|
13223
|
+
continue;
|
|
13224
|
+
}
|
|
13225
|
+
settled.add(deliveryId);
|
|
13226
|
+
}
|
|
13227
|
+
}
|
|
13228
|
+
async function rejectStaleClaim(deps, deliveryId, transferId) {
|
|
13229
|
+
logger.warn("PaymentsV2", `mailbox claim CONFLICT for ${deliveryId} \u2014 rejected('other') as stale`);
|
|
13230
|
+
await deps.delivery.ack(deliveryId, "rejected", "other");
|
|
13231
|
+
deps.attention(transferId ?? "", ATTENTION_CLAIM_CONFLICT, deliveryId);
|
|
13232
|
+
}
|
|
13233
|
+
async function settleOneByOne(deps, pending) {
|
|
13234
|
+
const settled = /* @__PURE__ */ new Set();
|
|
13235
|
+
for (const ack of pending) {
|
|
13236
|
+
try {
|
|
13237
|
+
await ackOne(deps, ack);
|
|
13238
|
+
} catch (err) {
|
|
13239
|
+
logger.warn("PaymentsV2", `mailbox ack failed for ${ack.deliveryId} \u2014 cursor holds here:`, err);
|
|
13240
|
+
break;
|
|
13241
|
+
}
|
|
13242
|
+
settled.add(ack.deliveryId);
|
|
13243
|
+
}
|
|
13244
|
+
return settled;
|
|
13245
|
+
}
|
|
13246
|
+
function toAckRequest(ack) {
|
|
13247
|
+
return {
|
|
13248
|
+
deliveryId: ack.deliveryId,
|
|
13249
|
+
disposition: ack.disposition,
|
|
13250
|
+
...ack.reason !== void 0 ? { reason: ack.reason } : {}
|
|
13251
|
+
};
|
|
13252
|
+
}
|
|
13147
13253
|
async function ackOne(deps, ack) {
|
|
13148
13254
|
try {
|
|
13149
13255
|
await deps.delivery.ack(ack.deliveryId, ack.disposition, ack.reason);
|
|
13150
13256
|
} catch (err) {
|
|
13151
13257
|
if (ack.disposition !== "claimed" || !isClaimConflict(err)) throw err;
|
|
13152
|
-
|
|
13153
|
-
await deps.delivery.ack(ack.deliveryId, "rejected", "other");
|
|
13154
|
-
deps.attention(ack.transferId ?? "", ATTENTION_CLAIM_CONFLICT, ack.deliveryId);
|
|
13258
|
+
await rejectStaleClaim(deps, ack.deliveryId, ack.transferId);
|
|
13155
13259
|
}
|
|
13156
13260
|
}
|
|
13157
13261
|
function claimAck(entry) {
|
|
@@ -13905,26 +14009,6 @@ function parseAmount(raw) {
|
|
|
13905
14009
|
function supportsDeterministicMint(engine) {
|
|
13906
14010
|
return engine.deterministicMint === true;
|
|
13907
14011
|
}
|
|
13908
|
-
function makeCoalescedRefresh(refresh) {
|
|
13909
|
-
let inFlight = false;
|
|
13910
|
-
let queued = false;
|
|
13911
|
-
const run = () => {
|
|
13912
|
-
inFlight = true;
|
|
13913
|
-
void refresh().catch(() => void 0).finally(() => {
|
|
13914
|
-
inFlight = false;
|
|
13915
|
-
if (!queued) return;
|
|
13916
|
-
queued = false;
|
|
13917
|
-
run();
|
|
13918
|
-
});
|
|
13919
|
-
};
|
|
13920
|
-
return () => {
|
|
13921
|
-
if (inFlight) {
|
|
13922
|
-
queued = true;
|
|
13923
|
-
return;
|
|
13924
|
-
}
|
|
13925
|
-
run();
|
|
13926
|
-
};
|
|
13927
|
-
}
|
|
13928
14012
|
function composeFacadeParts(deps, hooks) {
|
|
13929
14013
|
const ownPubkeyBytes = hexToBytes4(deps.ownPubkey);
|
|
13930
14014
|
const ledger = new ReservationLedger();
|
|
@@ -13954,9 +14038,11 @@ function composeFacadeParts(deps, hooks) {
|
|
|
13954
14038
|
const machineDeps = buildMachineDeps(deps, hooks, historyStore);
|
|
13955
14039
|
const machineStores = createMachineStores(deps.kv);
|
|
13956
14040
|
const heldStates = /* @__PURE__ */ new Map();
|
|
14041
|
+
const refreshView = coalesced(() => view.delta(), hooks.track);
|
|
13957
14042
|
return {
|
|
13958
14043
|
ownPubkeyBytes,
|
|
13959
14044
|
view,
|
|
14045
|
+
refreshView,
|
|
13960
14046
|
ledger,
|
|
13961
14047
|
pins: buildPins(deps, hooks, { ledger, view, machineStores, machineDeps }),
|
|
13962
14048
|
queue,
|
|
@@ -13965,7 +14051,7 @@ function composeFacadeParts(deps, hooks) {
|
|
|
13965
14051
|
machineDeps,
|
|
13966
14052
|
machine: new TransferMachine(machineDeps),
|
|
13967
14053
|
heldStates,
|
|
13968
|
-
receiveLoop: buildReceive(deps, hooks, historyStore, heldStates,
|
|
14054
|
+
receiveLoop: buildReceive(deps, hooks, historyStore, heldStates, refreshView),
|
|
13969
14055
|
requests: buildRequests(deps, hooks),
|
|
13970
14056
|
restoreDeps: buildRestoreDeps(deps, machineDeps, machineStores, view)
|
|
13971
14057
|
};
|
|
@@ -14032,7 +14118,7 @@ function buildMachineDeps(deps, hooks, historyStore) {
|
|
|
14032
14118
|
}
|
|
14033
14119
|
};
|
|
14034
14120
|
}
|
|
14035
|
-
function buildReceive(deps, hooks, historyStore, heldStates,
|
|
14121
|
+
function buildReceive(deps, hooks, historyStore, heldStates, refreshView) {
|
|
14036
14122
|
return new Receive({
|
|
14037
14123
|
delivery: deps.deliveryPort,
|
|
14038
14124
|
engine: () => hooks.engine(),
|
|
@@ -14046,8 +14132,7 @@ function buildReceive(deps, hooks, historyStore, heldStates, view) {
|
|
|
14046
14132
|
registry: deps.registry,
|
|
14047
14133
|
recordReceived: (record) => recordReceived(historyStore, record),
|
|
14048
14134
|
emit: (event, transfer) => deps.emit(event, transfer),
|
|
14049
|
-
|
|
14050
|
-
refreshView: makeCoalescedRefresh(() => view.delta()),
|
|
14135
|
+
refreshView,
|
|
14051
14136
|
attention: (transferId, code, detail) => {
|
|
14052
14137
|
deps.emit(
|
|
14053
14138
|
"transfer:attention",
|
|
@@ -14096,10 +14181,11 @@ var PaymentsFacade = class {
|
|
|
14096
14181
|
const parts = composeFacadeParts(deps, {
|
|
14097
14182
|
engine: () => this.engine(),
|
|
14098
14183
|
send: (request) => this.send(request),
|
|
14099
|
-
isActiveOp: (id) => this.activeMoneyOps.has(id)
|
|
14184
|
+
isActiveOp: (id) => this.activeMoneyOps.has(id),
|
|
14185
|
+
track: (op) => this.trackTail(op)
|
|
14100
14186
|
});
|
|
14101
14187
|
this.view = parts.view;
|
|
14102
|
-
this.wakeRefresh =
|
|
14188
|
+
this.wakeRefresh = parts.refreshView;
|
|
14103
14189
|
this.ledger = parts.ledger;
|
|
14104
14190
|
this.queue = parts.queue;
|
|
14105
14191
|
this.machine = parts.machine;
|
|
@@ -14236,7 +14322,6 @@ var PaymentsFacade = class {
|
|
|
14236
14322
|
}
|
|
14237
14323
|
async receive() {
|
|
14238
14324
|
const transfers = await this.track(this.receiveLoop.drainOnce());
|
|
14239
|
-
if (transfers.length > 0) this.trackTail(this.view.delta());
|
|
14240
14325
|
return { transfers };
|
|
14241
14326
|
}
|
|
14242
14327
|
mint(coinId, amount) {
|
|
@@ -14432,7 +14517,7 @@ var PaymentsFacade = class {
|
|
|
14432
14517
|
...spend.plan.direct,
|
|
14433
14518
|
...spend.plan.split !== void 0 ? [spend.plan.split.tokenId] : []
|
|
14434
14519
|
];
|
|
14435
|
-
|
|
14520
|
+
this.view.markInFlightMany(sourceIds);
|
|
14436
14521
|
if (spend.plan.split !== void 0) {
|
|
14437
14522
|
this.queue.declareExpectedChange(transferId, coinId, spend.plan.split.remainderAmount);
|
|
14438
14523
|
}
|
|
@@ -14718,6 +14803,10 @@ var WalletApiHttpError = class extends Error {
|
|
|
14718
14803
|
if (retryAfter !== void 0) this.retryAfter = retryAfter;
|
|
14719
14804
|
}
|
|
14720
14805
|
};
|
|
14806
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([0, 408, 425, 429, 500, 502, 503, 504]);
|
|
14807
|
+
function isRetryableStatus(err) {
|
|
14808
|
+
return err instanceof WalletApiHttpError && RETRYABLE_STATUSES.has(err.status);
|
|
14809
|
+
}
|
|
14721
14810
|
function isWalletApiHttpError(err, status) {
|
|
14722
14811
|
return err instanceof WalletApiHttpError && (status === void 0 || err.status === status);
|
|
14723
14812
|
}
|
|
@@ -15430,6 +15519,23 @@ function computeDeliveryId(tokenIdHex, stateHashHex) {
|
|
|
15430
15519
|
return bytesToHex3(sha256(joined));
|
|
15431
15520
|
}
|
|
15432
15521
|
var DELIVERY_SEEN_KEY = "delivery:seen";
|
|
15522
|
+
var ACK_CHUNK = 50;
|
|
15523
|
+
function chunked(items, size) {
|
|
15524
|
+
const out = [];
|
|
15525
|
+
for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
|
|
15526
|
+
return out;
|
|
15527
|
+
}
|
|
15528
|
+
var RetryableAckFailure = class extends Error {
|
|
15529
|
+
retryable = true;
|
|
15530
|
+
constructor(cause) {
|
|
15531
|
+
super(`mailbox ack batch could not be attempted: ${String(cause)}`);
|
|
15532
|
+
this.name = "RetryableAckFailure";
|
|
15533
|
+
this.cause = cause;
|
|
15534
|
+
}
|
|
15535
|
+
};
|
|
15536
|
+
function asRetryable(err) {
|
|
15537
|
+
return isRetryableStatus(err) ? new RetryableAckFailure(err) : err;
|
|
15538
|
+
}
|
|
15433
15539
|
var WalletApiDeliveryPort = class {
|
|
15434
15540
|
custody;
|
|
15435
15541
|
client;
|
|
@@ -15595,7 +15701,54 @@ var WalletApiDeliveryPort = class {
|
|
|
15595
15701
|
} else {
|
|
15596
15702
|
await this.client.reject([deliveryId], reason);
|
|
15597
15703
|
}
|
|
15598
|
-
await this.
|
|
15704
|
+
await this.addSeenAll([deliveryId]);
|
|
15705
|
+
}
|
|
15706
|
+
/**
|
|
15707
|
+
* §5.7/#757 batched settle. Claims go out grouped, rejects grouped by reason
|
|
15708
|
+
* (the endpoint takes one reason per call), and the seen-set is written ONCE
|
|
15709
|
+
* after every HTTP call has succeeded — never on a throw, so an aborted batch
|
|
15710
|
+
* re-lists rather than being silently forgotten.
|
|
15711
|
+
*/
|
|
15712
|
+
async ackBatch(acks) {
|
|
15713
|
+
const settled = [];
|
|
15714
|
+
const outcomes = [];
|
|
15715
|
+
try {
|
|
15716
|
+
await this.settleClaims(acks, settled, outcomes);
|
|
15717
|
+
await this.settleRejects(acks, settled);
|
|
15718
|
+
} catch (err) {
|
|
15719
|
+
await this.addSeenAll(settled).catch(() => void 0);
|
|
15720
|
+
throw asRetryable(err);
|
|
15721
|
+
}
|
|
15722
|
+
await this.addSeenAll(settled);
|
|
15723
|
+
return [...outcomes, ...settled.map((deliveryId) => ({ deliveryId, status: "settled" }))];
|
|
15724
|
+
}
|
|
15725
|
+
async settleClaims(acks, settled, outcomes) {
|
|
15726
|
+
const ids = acks.filter((a) => a.disposition === "claimed").map((a) => a.deliveryId);
|
|
15727
|
+
for (const chunk of chunked(ids, ACK_CHUNK)) {
|
|
15728
|
+
const result = await this.client.claim(chunk, this.custody === "inventory");
|
|
15729
|
+
settled.push(...result.claimed);
|
|
15730
|
+
settled.push(...result.alreadyClaimed.map((e) => e.entryId));
|
|
15731
|
+
for (const f of result.failed) {
|
|
15732
|
+
if (f.code === "CONFLICT") outcomes.push({ deliveryId: f.entryId, status: "conflict" });
|
|
15733
|
+
else throw new MailboxClaimFailedError(f.entryId, f.code);
|
|
15734
|
+
}
|
|
15735
|
+
}
|
|
15736
|
+
}
|
|
15737
|
+
async settleRejects(acks, settled) {
|
|
15738
|
+
const byReason = /* @__PURE__ */ new Map();
|
|
15739
|
+
for (const a of acks) {
|
|
15740
|
+
if (a.disposition !== "rejected") continue;
|
|
15741
|
+
const key = a.reason ?? "";
|
|
15742
|
+
const group = byReason.get(key) ?? [];
|
|
15743
|
+
group.push(a.deliveryId);
|
|
15744
|
+
byReason.set(key, group);
|
|
15745
|
+
}
|
|
15746
|
+
for (const [reason, group] of byReason) {
|
|
15747
|
+
for (const chunk of chunked(group, ACK_CHUNK)) {
|
|
15748
|
+
await this.client.reject(chunk, reason === "" ? void 0 : reason);
|
|
15749
|
+
settled.push(...chunk);
|
|
15750
|
+
}
|
|
15751
|
+
}
|
|
15599
15752
|
}
|
|
15600
15753
|
onWake(cb) {
|
|
15601
15754
|
if (this.wake === null) return () => void 0;
|
|
@@ -15606,10 +15759,12 @@ var WalletApiDeliveryPort = class {
|
|
|
15606
15759
|
const raw = await this.kv.get(DELIVERY_SEEN_KEY);
|
|
15607
15760
|
return new Set(raw ?? []);
|
|
15608
15761
|
}
|
|
15609
|
-
|
|
15762
|
+
/** SerialChain settles-not-fulfills: a rejected write never bricks later acks. */
|
|
15763
|
+
addSeenAll(deliveryIds) {
|
|
15764
|
+
if (deliveryIds.length === 0) return Promise.resolve();
|
|
15610
15765
|
return this.seenChain.enqueue(async () => {
|
|
15611
15766
|
const seen = await this.readSeen();
|
|
15612
|
-
seen.add(
|
|
15767
|
+
for (const id of deliveryIds) seen.add(id);
|
|
15613
15768
|
await this.kv.set(DELIVERY_SEEN_KEY, [...seen]);
|
|
15614
15769
|
});
|
|
15615
15770
|
}
|