@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.js
CHANGED
|
@@ -11217,6 +11217,33 @@ var SerialChain = class {
|
|
|
11217
11217
|
return run;
|
|
11218
11218
|
}
|
|
11219
11219
|
};
|
|
11220
|
+
function coalesced(run, observe) {
|
|
11221
|
+
let inFlight = false;
|
|
11222
|
+
let queued = false;
|
|
11223
|
+
const start = () => {
|
|
11224
|
+
inFlight = true;
|
|
11225
|
+
let running;
|
|
11226
|
+
try {
|
|
11227
|
+
running = run();
|
|
11228
|
+
} catch {
|
|
11229
|
+
running = Promise.resolve();
|
|
11230
|
+
}
|
|
11231
|
+
observe?.(running);
|
|
11232
|
+
void running.catch(() => void 0).finally(() => {
|
|
11233
|
+
inFlight = false;
|
|
11234
|
+
if (!queued) return;
|
|
11235
|
+
queued = false;
|
|
11236
|
+
start();
|
|
11237
|
+
});
|
|
11238
|
+
};
|
|
11239
|
+
return () => {
|
|
11240
|
+
if (inFlight) {
|
|
11241
|
+
queued = true;
|
|
11242
|
+
return;
|
|
11243
|
+
}
|
|
11244
|
+
start();
|
|
11245
|
+
};
|
|
11246
|
+
}
|
|
11220
11247
|
|
|
11221
11248
|
// modules/payments-v2/stores.ts
|
|
11222
11249
|
function createScopedKV(storage, network, chainPubkey) {
|
|
@@ -12664,6 +12691,16 @@ var InventoryView = class {
|
|
|
12664
12691
|
this.inFlight.add(tokenId);
|
|
12665
12692
|
this.deps.emit("inventory:updated");
|
|
12666
12693
|
}
|
|
12694
|
+
/** Reserve a whole plan as ONE change — per token emitted 54 events per send. */
|
|
12695
|
+
markInFlightMany(tokenIds) {
|
|
12696
|
+
let changed = false;
|
|
12697
|
+
for (const tokenId of tokenIds) {
|
|
12698
|
+
if (this.inFlight.has(tokenId)) continue;
|
|
12699
|
+
this.inFlight.add(tokenId);
|
|
12700
|
+
changed = true;
|
|
12701
|
+
}
|
|
12702
|
+
if (changed) this.deps.emit("inventory:updated");
|
|
12703
|
+
}
|
|
12667
12704
|
release(tokenId) {
|
|
12668
12705
|
if (this.inFlight.delete(tokenId)) this.deps.emit("inventory:updated");
|
|
12669
12706
|
}
|
|
@@ -12888,6 +12925,11 @@ var InventoryView = class {
|
|
|
12888
12925
|
}
|
|
12889
12926
|
};
|
|
12890
12927
|
|
|
12928
|
+
// modules/payments-v2/ports.ts
|
|
12929
|
+
function isRetryableAckError(err) {
|
|
12930
|
+
return err !== null && typeof err === "object" && err.retryable === true;
|
|
12931
|
+
}
|
|
12932
|
+
|
|
12891
12933
|
// modules/payments-v2/receive/Receive.ts
|
|
12892
12934
|
var ACK_BATCH_SIZE = 200;
|
|
12893
12935
|
var REFRESH_INTERVAL_MS = 2500;
|
|
@@ -12944,6 +12986,17 @@ var Receive = class {
|
|
|
12944
12986
|
await flushAcks(deps, pending, epochOf);
|
|
12945
12987
|
deps.refreshView();
|
|
12946
12988
|
}
|
|
12989
|
+
/** One listing pass: process each entry, flushing and refreshing as it goes. */
|
|
12990
|
+
async drainPages(ctx, basis) {
|
|
12991
|
+
const { deps, engine, pending, stored, pageEpoch } = ctx;
|
|
12992
|
+
for await (const entry of deps.delivery.incoming(basis === null ? void 0 : String(basis.cursor))) {
|
|
12993
|
+
const storedBefore = stored.length;
|
|
12994
|
+
await this.processEntry(deps, engine, entry, pending, stored);
|
|
12995
|
+
if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
|
|
12996
|
+
if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
|
|
12997
|
+
}
|
|
12998
|
+
await flushAcks(deps, pending, pageEpoch);
|
|
12999
|
+
}
|
|
12947
13000
|
async doDrain() {
|
|
12948
13001
|
const deps = this.deps;
|
|
12949
13002
|
this.lastRefreshAt = deps.now?.() ?? Date.now();
|
|
@@ -12955,13 +13008,7 @@ var Receive = class {
|
|
|
12955
13008
|
const record = await deps.kv.get(STORE_KEYS.streamCursor("mailbox"));
|
|
12956
13009
|
let basis = record !== null && record.syncEpoch === deps.syncEpoch() ? record : null;
|
|
12957
13010
|
for (let pass = 0; pass < 2; pass++) {
|
|
12958
|
-
|
|
12959
|
-
const storedBefore = stored.length;
|
|
12960
|
-
await this.processEntry(deps, engine, entry, pending, stored);
|
|
12961
|
-
if (pending.length >= ACK_BATCH_SIZE) await flushAcks(deps, pending, pageEpoch);
|
|
12962
|
-
if (stored.length > storedBefore) await this.maybeRefresh(deps, pending, pageEpoch);
|
|
12963
|
-
}
|
|
12964
|
-
await flushAcks(deps, pending, pageEpoch);
|
|
13011
|
+
await this.drainPages({ deps, engine, pending, stored, pageEpoch }, basis);
|
|
12965
13012
|
const served = deps.delivery.incomingEpoch();
|
|
12966
13013
|
if (basis === null || served === null || served === basis.syncEpoch) break;
|
|
12967
13014
|
await deps.kv.remove(STORE_KEYS.streamCursor("mailbox"));
|
|
@@ -12969,10 +13016,12 @@ var Receive = class {
|
|
|
12969
13016
|
}
|
|
12970
13017
|
} catch (err) {
|
|
12971
13018
|
logger.warn("PaymentsV2", "receive drain interrupted \u2014 unacked entries retry next drain:", err);
|
|
13019
|
+
if (isRetryableAckError(err)) return stored;
|
|
12972
13020
|
await flushAcks(deps, pending, pageEpoch).catch((flushErr) => {
|
|
12973
13021
|
logger.warn("PaymentsV2", "receive ack flush failed \u2014 cursor holds at the acked prefix:", flushErr);
|
|
12974
13022
|
});
|
|
12975
13023
|
}
|
|
13024
|
+
if (stored.length > 0) deps.refreshView?.();
|
|
12976
13025
|
return stored;
|
|
12977
13026
|
}
|
|
12978
13027
|
async processEntry(deps, engine, entry, pending, stored) {
|
|
@@ -13043,14 +13092,18 @@ async function announce(deps, entry, record) {
|
|
|
13043
13092
|
};
|
|
13044
13093
|
}
|
|
13045
13094
|
async function flushAcks(deps, pending, epochOf) {
|
|
13095
|
+
if (pending.length === 0) return;
|
|
13046
13096
|
let lastAcked = null;
|
|
13047
13097
|
try {
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
lastAcked =
|
|
13052
|
-
|
|
13098
|
+
const settled = await settleAcks(deps, pending);
|
|
13099
|
+
let i = 0;
|
|
13100
|
+
while (i < pending.length && settled.has(pending[i].deliveryId)) {
|
|
13101
|
+
lastAcked = pending[i].cursor;
|
|
13102
|
+
i += 1;
|
|
13053
13103
|
}
|
|
13104
|
+
const stuck = pending.filter((p) => !settled.has(p.deliveryId));
|
|
13105
|
+
pending.length = 0;
|
|
13106
|
+
pending.push(...stuck);
|
|
13054
13107
|
} finally {
|
|
13055
13108
|
if (lastAcked !== null) {
|
|
13056
13109
|
const record = { cursor: lastAcked, syncEpoch: epochOf() };
|
|
@@ -13058,14 +13111,65 @@ async function flushAcks(deps, pending, epochOf) {
|
|
|
13058
13111
|
}
|
|
13059
13112
|
}
|
|
13060
13113
|
}
|
|
13114
|
+
async function settleAcks(deps, pending) {
|
|
13115
|
+
const batch = deps.delivery.ackBatch?.bind(deps.delivery);
|
|
13116
|
+
if (batch === void 0) return settleOneByOne(deps, pending);
|
|
13117
|
+
let outcomes;
|
|
13118
|
+
try {
|
|
13119
|
+
outcomes = await batch(pending.map(toAckRequest));
|
|
13120
|
+
} catch (err) {
|
|
13121
|
+
if (isRetryableAckError(err)) throw err;
|
|
13122
|
+
logger.warn("PaymentsV2", "batched mailbox ack failed \u2014 settling one at a time:", err);
|
|
13123
|
+
return settleOneByOne(deps, pending);
|
|
13124
|
+
}
|
|
13125
|
+
const settled = new Set(outcomes.filter((o) => o.status === "settled").map((o) => o.deliveryId));
|
|
13126
|
+
const conflicts = outcomes.filter((o) => o.status === "conflict").map((o) => o.deliveryId);
|
|
13127
|
+
if (conflicts.length > 0) await resolveConflicts(deps, pending, conflicts, settled);
|
|
13128
|
+
return settled;
|
|
13129
|
+
}
|
|
13130
|
+
async function resolveConflicts(deps, pending, conflicts, settled) {
|
|
13131
|
+
for (const deliveryId of conflicts) {
|
|
13132
|
+
const entry = pending.find((p) => p.deliveryId === deliveryId);
|
|
13133
|
+
try {
|
|
13134
|
+
await rejectStaleClaim(deps, deliveryId, entry?.transferId);
|
|
13135
|
+
} catch (err) {
|
|
13136
|
+
logger.warn("PaymentsV2", `stale-reject failed for ${deliveryId} \u2014 cursor holds here:`, err);
|
|
13137
|
+
continue;
|
|
13138
|
+
}
|
|
13139
|
+
settled.add(deliveryId);
|
|
13140
|
+
}
|
|
13141
|
+
}
|
|
13142
|
+
async function rejectStaleClaim(deps, deliveryId, transferId) {
|
|
13143
|
+
logger.warn("PaymentsV2", `mailbox claim CONFLICT for ${deliveryId} \u2014 rejected('other') as stale`);
|
|
13144
|
+
await deps.delivery.ack(deliveryId, "rejected", "other");
|
|
13145
|
+
deps.attention(transferId ?? "", ATTENTION_CLAIM_CONFLICT, deliveryId);
|
|
13146
|
+
}
|
|
13147
|
+
async function settleOneByOne(deps, pending) {
|
|
13148
|
+
const settled = /* @__PURE__ */ new Set();
|
|
13149
|
+
for (const ack of pending) {
|
|
13150
|
+
try {
|
|
13151
|
+
await ackOne(deps, ack);
|
|
13152
|
+
} catch (err) {
|
|
13153
|
+
logger.warn("PaymentsV2", `mailbox ack failed for ${ack.deliveryId} \u2014 cursor holds here:`, err);
|
|
13154
|
+
break;
|
|
13155
|
+
}
|
|
13156
|
+
settled.add(ack.deliveryId);
|
|
13157
|
+
}
|
|
13158
|
+
return settled;
|
|
13159
|
+
}
|
|
13160
|
+
function toAckRequest(ack) {
|
|
13161
|
+
return {
|
|
13162
|
+
deliveryId: ack.deliveryId,
|
|
13163
|
+
disposition: ack.disposition,
|
|
13164
|
+
...ack.reason !== void 0 ? { reason: ack.reason } : {}
|
|
13165
|
+
};
|
|
13166
|
+
}
|
|
13061
13167
|
async function ackOne(deps, ack) {
|
|
13062
13168
|
try {
|
|
13063
13169
|
await deps.delivery.ack(ack.deliveryId, ack.disposition, ack.reason);
|
|
13064
13170
|
} catch (err) {
|
|
13065
13171
|
if (ack.disposition !== "claimed" || !isClaimConflict(err)) throw err;
|
|
13066
|
-
|
|
13067
|
-
await deps.delivery.ack(ack.deliveryId, "rejected", "other");
|
|
13068
|
-
deps.attention(ack.transferId ?? "", ATTENTION_CLAIM_CONFLICT, ack.deliveryId);
|
|
13172
|
+
await rejectStaleClaim(deps, ack.deliveryId, ack.transferId);
|
|
13069
13173
|
}
|
|
13070
13174
|
}
|
|
13071
13175
|
function claimAck(entry) {
|
|
@@ -13819,26 +13923,6 @@ function parseAmount(raw) {
|
|
|
13819
13923
|
function supportsDeterministicMint(engine) {
|
|
13820
13924
|
return engine.deterministicMint === true;
|
|
13821
13925
|
}
|
|
13822
|
-
function makeCoalescedRefresh(refresh) {
|
|
13823
|
-
let inFlight = false;
|
|
13824
|
-
let queued = false;
|
|
13825
|
-
const run = () => {
|
|
13826
|
-
inFlight = true;
|
|
13827
|
-
void refresh().catch(() => void 0).finally(() => {
|
|
13828
|
-
inFlight = false;
|
|
13829
|
-
if (!queued) return;
|
|
13830
|
-
queued = false;
|
|
13831
|
-
run();
|
|
13832
|
-
});
|
|
13833
|
-
};
|
|
13834
|
-
return () => {
|
|
13835
|
-
if (inFlight) {
|
|
13836
|
-
queued = true;
|
|
13837
|
-
return;
|
|
13838
|
-
}
|
|
13839
|
-
run();
|
|
13840
|
-
};
|
|
13841
|
-
}
|
|
13842
13926
|
function composeFacadeParts(deps, hooks) {
|
|
13843
13927
|
const ownPubkeyBytes = hexToBytes4(deps.ownPubkey);
|
|
13844
13928
|
const ledger = new ReservationLedger();
|
|
@@ -13868,9 +13952,11 @@ function composeFacadeParts(deps, hooks) {
|
|
|
13868
13952
|
const machineDeps = buildMachineDeps(deps, hooks, historyStore);
|
|
13869
13953
|
const machineStores = createMachineStores(deps.kv);
|
|
13870
13954
|
const heldStates = /* @__PURE__ */ new Map();
|
|
13955
|
+
const refreshView = coalesced(() => view.delta(), hooks.track);
|
|
13871
13956
|
return {
|
|
13872
13957
|
ownPubkeyBytes,
|
|
13873
13958
|
view,
|
|
13959
|
+
refreshView,
|
|
13874
13960
|
ledger,
|
|
13875
13961
|
pins: buildPins(deps, hooks, { ledger, view, machineStores, machineDeps }),
|
|
13876
13962
|
queue,
|
|
@@ -13879,7 +13965,7 @@ function composeFacadeParts(deps, hooks) {
|
|
|
13879
13965
|
machineDeps,
|
|
13880
13966
|
machine: new TransferMachine(machineDeps),
|
|
13881
13967
|
heldStates,
|
|
13882
|
-
receiveLoop: buildReceive(deps, hooks, historyStore, heldStates,
|
|
13968
|
+
receiveLoop: buildReceive(deps, hooks, historyStore, heldStates, refreshView),
|
|
13883
13969
|
requests: buildRequests(deps, hooks),
|
|
13884
13970
|
restoreDeps: buildRestoreDeps(deps, machineDeps, machineStores, view)
|
|
13885
13971
|
};
|
|
@@ -13946,7 +14032,7 @@ function buildMachineDeps(deps, hooks, historyStore) {
|
|
|
13946
14032
|
}
|
|
13947
14033
|
};
|
|
13948
14034
|
}
|
|
13949
|
-
function buildReceive(deps, hooks, historyStore, heldStates,
|
|
14035
|
+
function buildReceive(deps, hooks, historyStore, heldStates, refreshView) {
|
|
13950
14036
|
return new Receive({
|
|
13951
14037
|
delivery: deps.deliveryPort,
|
|
13952
14038
|
engine: () => hooks.engine(),
|
|
@@ -13960,8 +14046,7 @@ function buildReceive(deps, hooks, historyStore, heldStates, view) {
|
|
|
13960
14046
|
registry: deps.registry,
|
|
13961
14047
|
recordReceived: (record) => recordReceived(historyStore, record),
|
|
13962
14048
|
emit: (event, transfer) => deps.emit(event, transfer),
|
|
13963
|
-
|
|
13964
|
-
refreshView: makeCoalescedRefresh(() => view.delta()),
|
|
14049
|
+
refreshView,
|
|
13965
14050
|
attention: (transferId, code, detail) => {
|
|
13966
14051
|
deps.emit(
|
|
13967
14052
|
"transfer:attention",
|
|
@@ -14010,10 +14095,11 @@ var PaymentsFacade = class {
|
|
|
14010
14095
|
const parts = composeFacadeParts(deps, {
|
|
14011
14096
|
engine: () => this.engine(),
|
|
14012
14097
|
send: (request) => this.send(request),
|
|
14013
|
-
isActiveOp: (id) => this.activeMoneyOps.has(id)
|
|
14098
|
+
isActiveOp: (id) => this.activeMoneyOps.has(id),
|
|
14099
|
+
track: (op) => this.trackTail(op)
|
|
14014
14100
|
});
|
|
14015
14101
|
this.view = parts.view;
|
|
14016
|
-
this.wakeRefresh =
|
|
14102
|
+
this.wakeRefresh = parts.refreshView;
|
|
14017
14103
|
this.ledger = parts.ledger;
|
|
14018
14104
|
this.queue = parts.queue;
|
|
14019
14105
|
this.machine = parts.machine;
|
|
@@ -14150,7 +14236,6 @@ var PaymentsFacade = class {
|
|
|
14150
14236
|
}
|
|
14151
14237
|
async receive() {
|
|
14152
14238
|
const transfers = await this.track(this.receiveLoop.drainOnce());
|
|
14153
|
-
if (transfers.length > 0) this.trackTail(this.view.delta());
|
|
14154
14239
|
return { transfers };
|
|
14155
14240
|
}
|
|
14156
14241
|
mint(coinId, amount) {
|
|
@@ -14346,7 +14431,7 @@ var PaymentsFacade = class {
|
|
|
14346
14431
|
...spend.plan.direct,
|
|
14347
14432
|
...spend.plan.split !== void 0 ? [spend.plan.split.tokenId] : []
|
|
14348
14433
|
];
|
|
14349
|
-
|
|
14434
|
+
this.view.markInFlightMany(sourceIds);
|
|
14350
14435
|
if (spend.plan.split !== void 0) {
|
|
14351
14436
|
this.queue.declareExpectedChange(transferId, coinId, spend.plan.split.remainderAmount);
|
|
14352
14437
|
}
|
|
@@ -14632,6 +14717,10 @@ var WalletApiHttpError = class extends Error {
|
|
|
14632
14717
|
if (retryAfter !== void 0) this.retryAfter = retryAfter;
|
|
14633
14718
|
}
|
|
14634
14719
|
};
|
|
14720
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([0, 408, 425, 429, 500, 502, 503, 504]);
|
|
14721
|
+
function isRetryableStatus(err) {
|
|
14722
|
+
return err instanceof WalletApiHttpError && RETRYABLE_STATUSES.has(err.status);
|
|
14723
|
+
}
|
|
14635
14724
|
function isWalletApiHttpError(err, status) {
|
|
14636
14725
|
return err instanceof WalletApiHttpError && (status === void 0 || err.status === status);
|
|
14637
14726
|
}
|
|
@@ -15344,6 +15433,23 @@ function computeDeliveryId(tokenIdHex, stateHashHex) {
|
|
|
15344
15433
|
return bytesToHex3(sha256(joined));
|
|
15345
15434
|
}
|
|
15346
15435
|
var DELIVERY_SEEN_KEY = "delivery:seen";
|
|
15436
|
+
var ACK_CHUNK = 50;
|
|
15437
|
+
function chunked(items, size) {
|
|
15438
|
+
const out = [];
|
|
15439
|
+
for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
|
|
15440
|
+
return out;
|
|
15441
|
+
}
|
|
15442
|
+
var RetryableAckFailure = class extends Error {
|
|
15443
|
+
retryable = true;
|
|
15444
|
+
constructor(cause) {
|
|
15445
|
+
super(`mailbox ack batch could not be attempted: ${String(cause)}`);
|
|
15446
|
+
this.name = "RetryableAckFailure";
|
|
15447
|
+
this.cause = cause;
|
|
15448
|
+
}
|
|
15449
|
+
};
|
|
15450
|
+
function asRetryable(err) {
|
|
15451
|
+
return isRetryableStatus(err) ? new RetryableAckFailure(err) : err;
|
|
15452
|
+
}
|
|
15347
15453
|
var WalletApiDeliveryPort = class {
|
|
15348
15454
|
custody;
|
|
15349
15455
|
client;
|
|
@@ -15509,7 +15615,54 @@ var WalletApiDeliveryPort = class {
|
|
|
15509
15615
|
} else {
|
|
15510
15616
|
await this.client.reject([deliveryId], reason);
|
|
15511
15617
|
}
|
|
15512
|
-
await this.
|
|
15618
|
+
await this.addSeenAll([deliveryId]);
|
|
15619
|
+
}
|
|
15620
|
+
/**
|
|
15621
|
+
* §5.7/#757 batched settle. Claims go out grouped, rejects grouped by reason
|
|
15622
|
+
* (the endpoint takes one reason per call), and the seen-set is written ONCE
|
|
15623
|
+
* after every HTTP call has succeeded — never on a throw, so an aborted batch
|
|
15624
|
+
* re-lists rather than being silently forgotten.
|
|
15625
|
+
*/
|
|
15626
|
+
async ackBatch(acks) {
|
|
15627
|
+
const settled = [];
|
|
15628
|
+
const outcomes = [];
|
|
15629
|
+
try {
|
|
15630
|
+
await this.settleClaims(acks, settled, outcomes);
|
|
15631
|
+
await this.settleRejects(acks, settled);
|
|
15632
|
+
} catch (err) {
|
|
15633
|
+
await this.addSeenAll(settled).catch(() => void 0);
|
|
15634
|
+
throw asRetryable(err);
|
|
15635
|
+
}
|
|
15636
|
+
await this.addSeenAll(settled);
|
|
15637
|
+
return [...outcomes, ...settled.map((deliveryId) => ({ deliveryId, status: "settled" }))];
|
|
15638
|
+
}
|
|
15639
|
+
async settleClaims(acks, settled, outcomes) {
|
|
15640
|
+
const ids = acks.filter((a) => a.disposition === "claimed").map((a) => a.deliveryId);
|
|
15641
|
+
for (const chunk of chunked(ids, ACK_CHUNK)) {
|
|
15642
|
+
const result = await this.client.claim(chunk, this.custody === "inventory");
|
|
15643
|
+
settled.push(...result.claimed);
|
|
15644
|
+
settled.push(...result.alreadyClaimed.map((e) => e.entryId));
|
|
15645
|
+
for (const f of result.failed) {
|
|
15646
|
+
if (f.code === "CONFLICT") outcomes.push({ deliveryId: f.entryId, status: "conflict" });
|
|
15647
|
+
else throw new MailboxClaimFailedError(f.entryId, f.code);
|
|
15648
|
+
}
|
|
15649
|
+
}
|
|
15650
|
+
}
|
|
15651
|
+
async settleRejects(acks, settled) {
|
|
15652
|
+
const byReason = /* @__PURE__ */ new Map();
|
|
15653
|
+
for (const a of acks) {
|
|
15654
|
+
if (a.disposition !== "rejected") continue;
|
|
15655
|
+
const key = a.reason ?? "";
|
|
15656
|
+
const group = byReason.get(key) ?? [];
|
|
15657
|
+
group.push(a.deliveryId);
|
|
15658
|
+
byReason.set(key, group);
|
|
15659
|
+
}
|
|
15660
|
+
for (const [reason, group] of byReason) {
|
|
15661
|
+
for (const chunk of chunked(group, ACK_CHUNK)) {
|
|
15662
|
+
await this.client.reject(chunk, reason === "" ? void 0 : reason);
|
|
15663
|
+
settled.push(...chunk);
|
|
15664
|
+
}
|
|
15665
|
+
}
|
|
15513
15666
|
}
|
|
15514
15667
|
onWake(cb) {
|
|
15515
15668
|
if (this.wake === null) return () => void 0;
|
|
@@ -15520,10 +15673,12 @@ var WalletApiDeliveryPort = class {
|
|
|
15520
15673
|
const raw = await this.kv.get(DELIVERY_SEEN_KEY);
|
|
15521
15674
|
return new Set(raw ?? []);
|
|
15522
15675
|
}
|
|
15523
|
-
|
|
15676
|
+
/** SerialChain settles-not-fulfills: a rejected write never bricks later acks. */
|
|
15677
|
+
addSeenAll(deliveryIds) {
|
|
15678
|
+
if (deliveryIds.length === 0) return Promise.resolve();
|
|
15524
15679
|
return this.seenChain.enqueue(async () => {
|
|
15525
15680
|
const seen = await this.readSeen();
|
|
15526
|
-
seen.add(
|
|
15681
|
+
for (const id of deliveryIds) seen.add(id);
|
|
15527
15682
|
await this.kv.set(DELIVERY_SEEN_KEY, [...seen]);
|
|
15528
15683
|
});
|
|
15529
15684
|
}
|