@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.js
CHANGED
|
@@ -11233,6 +11233,33 @@ var SerialChain = class {
|
|
|
11233
11233
|
return run;
|
|
11234
11234
|
}
|
|
11235
11235
|
};
|
|
11236
|
+
function coalesced(run, observe) {
|
|
11237
|
+
let inFlight = false;
|
|
11238
|
+
let queued = false;
|
|
11239
|
+
const start = () => {
|
|
11240
|
+
inFlight = true;
|
|
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(() => {
|
|
11249
|
+
inFlight = false;
|
|
11250
|
+
if (!queued) return;
|
|
11251
|
+
queued = false;
|
|
11252
|
+
start();
|
|
11253
|
+
});
|
|
11254
|
+
};
|
|
11255
|
+
return () => {
|
|
11256
|
+
if (inFlight) {
|
|
11257
|
+
queued = true;
|
|
11258
|
+
return;
|
|
11259
|
+
}
|
|
11260
|
+
start();
|
|
11261
|
+
};
|
|
11262
|
+
}
|
|
11236
11263
|
|
|
11237
11264
|
// modules/payments-v2/stores.ts
|
|
11238
11265
|
function createScopedKV(storage, network, chainPubkey) {
|
|
@@ -12680,6 +12707,16 @@ var InventoryView = class {
|
|
|
12680
12707
|
this.inFlight.add(tokenId);
|
|
12681
12708
|
this.deps.emit("inventory:updated");
|
|
12682
12709
|
}
|
|
12710
|
+
/** Reserve a whole plan as ONE change — per token emitted 54 events per send. */
|
|
12711
|
+
markInFlightMany(tokenIds) {
|
|
12712
|
+
let changed = false;
|
|
12713
|
+
for (const tokenId of tokenIds) {
|
|
12714
|
+
if (this.inFlight.has(tokenId)) continue;
|
|
12715
|
+
this.inFlight.add(tokenId);
|
|
12716
|
+
changed = true;
|
|
12717
|
+
}
|
|
12718
|
+
if (changed) this.deps.emit("inventory:updated");
|
|
12719
|
+
}
|
|
12683
12720
|
release(tokenId) {
|
|
12684
12721
|
if (this.inFlight.delete(tokenId)) this.deps.emit("inventory:updated");
|
|
12685
12722
|
}
|
|
@@ -12904,6 +12941,11 @@ var InventoryView = class {
|
|
|
12904
12941
|
}
|
|
12905
12942
|
};
|
|
12906
12943
|
|
|
12944
|
+
// modules/payments-v2/ports.ts
|
|
12945
|
+
function isRetryableAckError(err) {
|
|
12946
|
+
return err !== null && typeof err === "object" && err.retryable === true;
|
|
12947
|
+
}
|
|
12948
|
+
|
|
12907
12949
|
// modules/payments-v2/receive/Receive.ts
|
|
12908
12950
|
var ACK_BATCH_SIZE = 200;
|
|
12909
12951
|
var REFRESH_INTERVAL_MS = 2500;
|
|
@@ -12960,6 +13002,17 @@ var Receive = class {
|
|
|
12960
13002
|
await flushAcks(deps, pending, epochOf);
|
|
12961
13003
|
deps.refreshView();
|
|
12962
13004
|
}
|
|
13005
|
+
/** One listing pass: process each entry, flushing and refreshing as it goes. */
|
|
13006
|
+
async drainPages(ctx, basis) {
|
|
13007
|
+
const { deps, engine, pending, stored, pageEpoch } = ctx;
|
|
13008
|
+
for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
|
|
13009
|
+
const storedBefore = stored.length;
|
|
13010
|
+
await this.processEntry(deps, engine, entry, pending, stored);
|
|
13011
|
+
if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
|
|
13012
|
+
if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
|
|
13013
|
+
}
|
|
13014
|
+
await flushAcks(deps, pending, pageEpoch);
|
|
13015
|
+
}
|
|
12963
13016
|
async doDrain() {
|
|
12964
13017
|
const deps = this.deps;
|
|
12965
13018
|
this.lastRefreshAt = deps.now?.() ?? Date.now();
|
|
@@ -12971,13 +13024,7 @@ var Receive = class {
|
|
|
12971
13024
|
const record = await deps.kv.get(STORE_KEYS.streamCursor("mailbox"));
|
|
12972
13025
|
let basis = record !== null && record.syncEpoch === deps.syncEpoch() ? record : null;
|
|
12973
13026
|
for (let pass = 0; pass < 2; pass++) {
|
|
12974
|
-
|
|
12975
|
-
const storedBefore = stored.length;
|
|
12976
|
-
await this.processEntry(deps, engine, entry, pending, stored);
|
|
12977
|
-
if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
|
|
12978
|
-
if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
|
|
12979
|
-
}
|
|
12980
|
-
await flushAcks(deps, pending, pageEpoch);
|
|
13027
|
+
await this.drainPages({ deps, engine, pending, stored, pageEpoch }, basis);
|
|
12981
13028
|
const served = deps.delivery.incomingEpoch();
|
|
12982
13029
|
if (basis === null || served === null || served === basis.syncEpoch) break;
|
|
12983
13030
|
await deps.kv.remove(STORE_KEYS.streamCursor("mailbox"));
|
|
@@ -12985,10 +13032,12 @@ var Receive = class {
|
|
|
12985
13032
|
}
|
|
12986
13033
|
} catch (err) {
|
|
12987
13034
|
logger.warn("PaymentsV2", "receive drain interrupted \u2014 unacked entries retry next drain:", err);
|
|
13035
|
+
if (isRetryableAckError(err)) return stored;
|
|
12988
13036
|
await flushAcks(deps, pending, pageEpoch).catch((flushErr) => {
|
|
12989
13037
|
logger.warn("PaymentsV2", "receive ack flush failed \u2014 cursor holds at the acked prefix:", flushErr);
|
|
12990
13038
|
});
|
|
12991
13039
|
}
|
|
13040
|
+
if (stored.length > 0) deps.refreshView?.();
|
|
12992
13041
|
return stored;
|
|
12993
13042
|
}
|
|
12994
13043
|
async processEntry(deps, engine, entry, pending, stored) {
|
|
@@ -13059,14 +13108,18 @@ async function announce(deps, entry, record) {
|
|
|
13059
13108
|
};
|
|
13060
13109
|
}
|
|
13061
13110
|
async function flushAcks(deps, pending, epochOf) {
|
|
13111
|
+
if (pending.length === 0) return;
|
|
13062
13112
|
let lastAcked = null;
|
|
13063
13113
|
try {
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
lastAcked =
|
|
13068
|
-
|
|
13114
|
+
const settled = await settleAcks(deps, pending);
|
|
13115
|
+
let i = 0;
|
|
13116
|
+
while (i < pending.length && settled.has(pending[i].deliveryId)) {
|
|
13117
|
+
lastAcked = pending[i].cursor;
|
|
13118
|
+
i += 1;
|
|
13069
13119
|
}
|
|
13120
|
+
const stuck = pending.filter((p) => !settled.has(p.deliveryId));
|
|
13121
|
+
pending.length = 0;
|
|
13122
|
+
pending.push(...stuck);
|
|
13070
13123
|
} finally {
|
|
13071
13124
|
if (lastAcked !== null) {
|
|
13072
13125
|
const record = { cursor: lastAcked, syncEpoch: epochOf() };
|
|
@@ -13074,14 +13127,65 @@ async function flushAcks(deps, pending, epochOf) {
|
|
|
13074
13127
|
}
|
|
13075
13128
|
}
|
|
13076
13129
|
}
|
|
13130
|
+
async function settleAcks(deps, pending) {
|
|
13131
|
+
const batch = deps.delivery.ackBatch?.bind(deps.delivery);
|
|
13132
|
+
if (batch === void 0) return settleOneByOne(deps, pending);
|
|
13133
|
+
let outcomes;
|
|
13134
|
+
try {
|
|
13135
|
+
outcomes = await batch(pending.map(toAckRequest));
|
|
13136
|
+
} catch (err) {
|
|
13137
|
+
if (isRetryableAckError(err)) throw err;
|
|
13138
|
+
logger.warn("PaymentsV2", "batched mailbox ack failed \u2014 settling one at a time:", err);
|
|
13139
|
+
return settleOneByOne(deps, pending);
|
|
13140
|
+
}
|
|
13141
|
+
const settled = new Set(outcomes.filter((o) => o.status === "settled").map((o) => o.deliveryId));
|
|
13142
|
+
const conflicts = outcomes.filter((o) => o.status === "conflict").map((o) => o.deliveryId);
|
|
13143
|
+
if (conflicts.length > 0) await resolveConflicts(deps, pending, conflicts, settled);
|
|
13144
|
+
return settled;
|
|
13145
|
+
}
|
|
13146
|
+
async function resolveConflicts(deps, pending, conflicts, settled) {
|
|
13147
|
+
for (const deliveryId of conflicts) {
|
|
13148
|
+
const entry = pending.find((p) => p.deliveryId === deliveryId);
|
|
13149
|
+
try {
|
|
13150
|
+
await rejectStaleClaim(deps, deliveryId, entry?.transferId);
|
|
13151
|
+
} catch (err) {
|
|
13152
|
+
logger.warn("PaymentsV2", `stale-reject failed for ${deliveryId} \u2014 cursor holds here:`, err);
|
|
13153
|
+
continue;
|
|
13154
|
+
}
|
|
13155
|
+
settled.add(deliveryId);
|
|
13156
|
+
}
|
|
13157
|
+
}
|
|
13158
|
+
async function rejectStaleClaim(deps, deliveryId, transferId) {
|
|
13159
|
+
logger.warn("PaymentsV2", `mailbox claim CONFLICT for ${deliveryId} \u2014 rejected('other') as stale`);
|
|
13160
|
+
await deps.delivery.ack(deliveryId, "rejected", "other");
|
|
13161
|
+
deps.attention(transferId ?? "", ATTENTION_CLAIM_CONFLICT, deliveryId);
|
|
13162
|
+
}
|
|
13163
|
+
async function settleOneByOne(deps, pending) {
|
|
13164
|
+
const settled = /* @__PURE__ */ new Set();
|
|
13165
|
+
for (const ack of pending) {
|
|
13166
|
+
try {
|
|
13167
|
+
await ackOne(deps, ack);
|
|
13168
|
+
} catch (err) {
|
|
13169
|
+
logger.warn("PaymentsV2", `mailbox ack failed for ${ack.deliveryId} \u2014 cursor holds here:`, err);
|
|
13170
|
+
break;
|
|
13171
|
+
}
|
|
13172
|
+
settled.add(ack.deliveryId);
|
|
13173
|
+
}
|
|
13174
|
+
return settled;
|
|
13175
|
+
}
|
|
13176
|
+
function toAckRequest(ack) {
|
|
13177
|
+
return {
|
|
13178
|
+
deliveryId: ack.deliveryId,
|
|
13179
|
+
disposition: ack.disposition,
|
|
13180
|
+
...ack.reason !== void 0 ? { reason: ack.reason } : {}
|
|
13181
|
+
};
|
|
13182
|
+
}
|
|
13077
13183
|
async function ackOne(deps, ack) {
|
|
13078
13184
|
try {
|
|
13079
13185
|
await deps.delivery.ack(ack.deliveryId, ack.disposition, ack.reason);
|
|
13080
13186
|
} catch (err) {
|
|
13081
13187
|
if (ack.disposition !== "claimed" || !isClaimConflict(err)) throw err;
|
|
13082
|
-
|
|
13083
|
-
await deps.delivery.ack(ack.deliveryId, "rejected", "other");
|
|
13084
|
-
deps.attention(ack.transferId ?? "", ATTENTION_CLAIM_CONFLICT, ack.deliveryId);
|
|
13188
|
+
await rejectStaleClaim(deps, ack.deliveryId, ack.transferId);
|
|
13085
13189
|
}
|
|
13086
13190
|
}
|
|
13087
13191
|
function claimAck(entry) {
|
|
@@ -13835,26 +13939,6 @@ function parseAmount(raw) {
|
|
|
13835
13939
|
function supportsDeterministicMint(engine) {
|
|
13836
13940
|
return engine.deterministicMint === true;
|
|
13837
13941
|
}
|
|
13838
|
-
function makeCoalescedRefresh(refresh) {
|
|
13839
|
-
let inFlight = false;
|
|
13840
|
-
let queued = false;
|
|
13841
|
-
const run = () => {
|
|
13842
|
-
inFlight = true;
|
|
13843
|
-
void refresh().catch(() => void 0).finally(() => {
|
|
13844
|
-
inFlight = false;
|
|
13845
|
-
if (!queued) return;
|
|
13846
|
-
queued = false;
|
|
13847
|
-
run();
|
|
13848
|
-
});
|
|
13849
|
-
};
|
|
13850
|
-
return () => {
|
|
13851
|
-
if (inFlight) {
|
|
13852
|
-
queued = true;
|
|
13853
|
-
return;
|
|
13854
|
-
}
|
|
13855
|
-
run();
|
|
13856
|
-
};
|
|
13857
|
-
}
|
|
13858
13942
|
function composeFacadeParts(deps, hooks) {
|
|
13859
13943
|
const ownPubkeyBytes = hexToBytes4(deps.ownPubkey);
|
|
13860
13944
|
const ledger = new ReservationLedger();
|
|
@@ -13884,9 +13968,11 @@ function composeFacadeParts(deps, hooks) {
|
|
|
13884
13968
|
const machineDeps = buildMachineDeps(deps, hooks, historyStore);
|
|
13885
13969
|
const machineStores = createMachineStores(deps.kv);
|
|
13886
13970
|
const heldStates = /* @__PURE__ */ new Map();
|
|
13971
|
+
const refreshView = coalesced(() => view.delta(), hooks.track);
|
|
13887
13972
|
return {
|
|
13888
13973
|
ownPubkeyBytes,
|
|
13889
13974
|
view,
|
|
13975
|
+
refreshView,
|
|
13890
13976
|
ledger,
|
|
13891
13977
|
pins: buildPins(deps, hooks, { ledger, view, machineStores, machineDeps }),
|
|
13892
13978
|
queue,
|
|
@@ -13895,7 +13981,7 @@ function composeFacadeParts(deps, hooks) {
|
|
|
13895
13981
|
machineDeps,
|
|
13896
13982
|
machine: new TransferMachine(machineDeps),
|
|
13897
13983
|
heldStates,
|
|
13898
|
-
receiveLoop: buildReceive(deps, hooks, historyStore, heldStates,
|
|
13984
|
+
receiveLoop: buildReceive(deps, hooks, historyStore, heldStates, refreshView),
|
|
13899
13985
|
requests: buildRequests(deps, hooks),
|
|
13900
13986
|
restoreDeps: buildRestoreDeps(deps, machineDeps, machineStores, view)
|
|
13901
13987
|
};
|
|
@@ -13962,7 +14048,7 @@ function buildMachineDeps(deps, hooks, historyStore) {
|
|
|
13962
14048
|
}
|
|
13963
14049
|
};
|
|
13964
14050
|
}
|
|
13965
|
-
function buildReceive(deps, hooks, historyStore, heldStates,
|
|
14051
|
+
function buildReceive(deps, hooks, historyStore, heldStates, refreshView) {
|
|
13966
14052
|
return new Receive({
|
|
13967
14053
|
delivery: deps.deliveryPort,
|
|
13968
14054
|
engine: () => hooks.engine(),
|
|
@@ -13976,8 +14062,7 @@ function buildReceive(deps, hooks, historyStore, heldStates, view) {
|
|
|
13976
14062
|
registry: deps.registry,
|
|
13977
14063
|
recordReceived: (record) => recordReceived(historyStore, record),
|
|
13978
14064
|
emit: (event, transfer) => deps.emit(event, transfer),
|
|
13979
|
-
|
|
13980
|
-
refreshView: makeCoalescedRefresh(() => view.delta()),
|
|
14065
|
+
refreshView,
|
|
13981
14066
|
attention: (transferId, code, detail) => {
|
|
13982
14067
|
deps.emit(
|
|
13983
14068
|
"transfer:attention",
|
|
@@ -14026,10 +14111,11 @@ var PaymentsFacade = class {
|
|
|
14026
14111
|
const parts = composeFacadeParts(deps, {
|
|
14027
14112
|
engine: () => this.engine(),
|
|
14028
14113
|
send: (request) => this.send(request),
|
|
14029
|
-
isActiveOp: (id) => this.activeMoneyOps.has(id)
|
|
14114
|
+
isActiveOp: (id) => this.activeMoneyOps.has(id),
|
|
14115
|
+
track: (op) => this.trackTail(op)
|
|
14030
14116
|
});
|
|
14031
14117
|
this.view = parts.view;
|
|
14032
|
-
this.wakeRefresh =
|
|
14118
|
+
this.wakeRefresh = parts.refreshView;
|
|
14033
14119
|
this.ledger = parts.ledger;
|
|
14034
14120
|
this.queue = parts.queue;
|
|
14035
14121
|
this.machine = parts.machine;
|
|
@@ -14166,7 +14252,6 @@ var PaymentsFacade = class {
|
|
|
14166
14252
|
}
|
|
14167
14253
|
async receive() {
|
|
14168
14254
|
const transfers = await this.track(this.receiveLoop.drainOnce());
|
|
14169
|
-
if (transfers.length > 0) this.trackTail(this.view.delta());
|
|
14170
14255
|
return { transfers };
|
|
14171
14256
|
}
|
|
14172
14257
|
mint(coinId, amount) {
|
|
@@ -14362,7 +14447,7 @@ var PaymentsFacade = class {
|
|
|
14362
14447
|
...spend.plan.direct,
|
|
14363
14448
|
...spend.plan.split !== void 0 ? [spend.plan.split.tokenId] : []
|
|
14364
14449
|
];
|
|
14365
|
-
|
|
14450
|
+
this.view.markInFlightMany(sourceIds);
|
|
14366
14451
|
if (spend.plan.split !== void 0) {
|
|
14367
14452
|
this.queue.declareExpectedChange(transferId, coinId, spend.plan.split.remainderAmount);
|
|
14368
14453
|
}
|
|
@@ -14648,6 +14733,10 @@ var WalletApiHttpError = class extends Error {
|
|
|
14648
14733
|
if (retryAfter !== void 0) this.retryAfter = retryAfter;
|
|
14649
14734
|
}
|
|
14650
14735
|
};
|
|
14736
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([0, 408, 425, 429, 500, 502, 503, 504]);
|
|
14737
|
+
function isRetryableStatus(err) {
|
|
14738
|
+
return err instanceof WalletApiHttpError && RETRYABLE_STATUSES.has(err.status);
|
|
14739
|
+
}
|
|
14651
14740
|
function isWalletApiHttpError(err, status) {
|
|
14652
14741
|
return err instanceof WalletApiHttpError && (status === void 0 || err.status === status);
|
|
14653
14742
|
}
|
|
@@ -15360,6 +15449,23 @@ function computeDeliveryId(tokenIdHex, stateHashHex) {
|
|
|
15360
15449
|
return bytesToHex3(sha256(joined));
|
|
15361
15450
|
}
|
|
15362
15451
|
var DELIVERY_SEEN_KEY = "delivery:seen";
|
|
15452
|
+
var ACK_CHUNK = 50;
|
|
15453
|
+
function chunked(items, size) {
|
|
15454
|
+
const out = [];
|
|
15455
|
+
for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
|
|
15456
|
+
return out;
|
|
15457
|
+
}
|
|
15458
|
+
var RetryableAckFailure = class extends Error {
|
|
15459
|
+
retryable = true;
|
|
15460
|
+
constructor(cause) {
|
|
15461
|
+
super(`mailbox ack batch could not be attempted: ${String(cause)}`);
|
|
15462
|
+
this.name = "RetryableAckFailure";
|
|
15463
|
+
this.cause = cause;
|
|
15464
|
+
}
|
|
15465
|
+
};
|
|
15466
|
+
function asRetryable(err) {
|
|
15467
|
+
return isRetryableStatus(err) ? new RetryableAckFailure(err) : err;
|
|
15468
|
+
}
|
|
15363
15469
|
var WalletApiDeliveryPort = class {
|
|
15364
15470
|
custody;
|
|
15365
15471
|
client;
|
|
@@ -15525,7 +15631,54 @@ var WalletApiDeliveryPort = class {
|
|
|
15525
15631
|
} else {
|
|
15526
15632
|
await this.client.reject([deliveryId], reason);
|
|
15527
15633
|
}
|
|
15528
|
-
await this.
|
|
15634
|
+
await this.addSeenAll([deliveryId]);
|
|
15635
|
+
}
|
|
15636
|
+
/**
|
|
15637
|
+
* §5.7/#757 batched settle. Claims go out grouped, rejects grouped by reason
|
|
15638
|
+
* (the endpoint takes one reason per call), and the seen-set is written ONCE
|
|
15639
|
+
* after every HTTP call has succeeded — never on a throw, so an aborted batch
|
|
15640
|
+
* re-lists rather than being silently forgotten.
|
|
15641
|
+
*/
|
|
15642
|
+
async ackBatch(acks) {
|
|
15643
|
+
const settled = [];
|
|
15644
|
+
const outcomes = [];
|
|
15645
|
+
try {
|
|
15646
|
+
await this.settleClaims(acks, settled, outcomes);
|
|
15647
|
+
await this.settleRejects(acks, settled);
|
|
15648
|
+
} catch (err) {
|
|
15649
|
+
await this.addSeenAll(settled).catch(() => void 0);
|
|
15650
|
+
throw asRetryable(err);
|
|
15651
|
+
}
|
|
15652
|
+
await this.addSeenAll(settled);
|
|
15653
|
+
return [...outcomes, ...settled.map((deliveryId) => ({ deliveryId, status: "settled" }))];
|
|
15654
|
+
}
|
|
15655
|
+
async settleClaims(acks, settled, outcomes) {
|
|
15656
|
+
const ids = acks.filter((a) => a.disposition === "claimed").map((a) => a.deliveryId);
|
|
15657
|
+
for (const chunk of chunked(ids, ACK_CHUNK)) {
|
|
15658
|
+
const result = await this.client.claim(chunk, this.custody === "inventory");
|
|
15659
|
+
settled.push(...result.claimed);
|
|
15660
|
+
settled.push(...result.alreadyClaimed.map((e) => e.entryId));
|
|
15661
|
+
for (const f of result.failed) {
|
|
15662
|
+
if (f.code === "CONFLICT") outcomes.push({ deliveryId: f.entryId, status: "conflict" });
|
|
15663
|
+
else throw new MailboxClaimFailedError(f.entryId, f.code);
|
|
15664
|
+
}
|
|
15665
|
+
}
|
|
15666
|
+
}
|
|
15667
|
+
async settleRejects(acks, settled) {
|
|
15668
|
+
const byReason = /* @__PURE__ */ new Map();
|
|
15669
|
+
for (const a of acks) {
|
|
15670
|
+
if (a.disposition !== "rejected") continue;
|
|
15671
|
+
const key = a.reason ?? "";
|
|
15672
|
+
const group = byReason.get(key) ?? [];
|
|
15673
|
+
group.push(a.deliveryId);
|
|
15674
|
+
byReason.set(key, group);
|
|
15675
|
+
}
|
|
15676
|
+
for (const [reason, group] of byReason) {
|
|
15677
|
+
for (const chunk of chunked(group, ACK_CHUNK)) {
|
|
15678
|
+
await this.client.reject(chunk, reason === "" ? void 0 : reason);
|
|
15679
|
+
settled.push(...chunk);
|
|
15680
|
+
}
|
|
15681
|
+
}
|
|
15529
15682
|
}
|
|
15530
15683
|
onWake(cb) {
|
|
15531
15684
|
if (this.wake === null) return () => void 0;
|
|
@@ -15536,10 +15689,12 @@ var WalletApiDeliveryPort = class {
|
|
|
15536
15689
|
const raw = await this.kv.get(DELIVERY_SEEN_KEY);
|
|
15537
15690
|
return new Set(raw ?? []);
|
|
15538
15691
|
}
|
|
15539
|
-
|
|
15692
|
+
/** SerialChain settles-not-fulfills: a rejected write never bricks later acks. */
|
|
15693
|
+
addSeenAll(deliveryIds) {
|
|
15694
|
+
if (deliveryIds.length === 0) return Promise.resolve();
|
|
15540
15695
|
return this.seenChain.enqueue(async () => {
|
|
15541
15696
|
const seen = await this.readSeen();
|
|
15542
|
-
seen.add(
|
|
15697
|
+
for (const id of deliveryIds) seen.add(id);
|
|
15543
15698
|
await this.kv.set(DELIVERY_SEEN_KEY, [...seen]);
|
|
15544
15699
|
});
|
|
15545
15700
|
}
|