@unicitylabs/sphere-sdk 0.14.11-dev.6 → 0.14.11-dev.7
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 +178 -37
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +178 -37
- 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 +72 -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 +72 -3
- package/dist/impl/wallet-api-v2/index.js.map +1 -1
- package/dist/index.cjs +178 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +178 -37
- package/dist/index.js.map +1 -1
- package/dist/modules/payments-v2/index.cjs +106 -34
- 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 +106 -34
- package/dist/modules/payments-v2/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -340,8 +340,22 @@ interface DeliveryPort {
|
|
|
340
340
|
*/
|
|
341
341
|
incomingEpoch(): string | null;
|
|
342
342
|
ack(deliveryId: string, disposition: 'claimed' | 'rejected', reason?: 'invalid' | 'not-owned' | 'storage-rejected' | 'other'): Promise<void>;
|
|
343
|
+
/** Settle many acks at once (#757). Contract pinned by the delivery-port contract suite. */
|
|
344
|
+
ackBatch?(acks: readonly AckRequest[]): Promise<readonly AckOutcome[]>;
|
|
343
345
|
onWake?(cb: () => void): () => void;
|
|
344
346
|
}
|
|
347
|
+
interface AckRequest {
|
|
348
|
+
readonly deliveryId: string;
|
|
349
|
+
readonly disposition: 'claimed' | 'rejected';
|
|
350
|
+
readonly reason?: 'invalid' | 'not-owned' | 'storage-rejected' | 'other';
|
|
351
|
+
}
|
|
352
|
+
type AckOutcome = {
|
|
353
|
+
readonly deliveryId: string;
|
|
354
|
+
readonly status: 'settled';
|
|
355
|
+
} | {
|
|
356
|
+
readonly deliveryId: string;
|
|
357
|
+
readonly status: 'conflict';
|
|
358
|
+
};
|
|
345
359
|
|
|
346
360
|
interface IntentPayload {
|
|
347
361
|
v: 2;
|
|
@@ -340,8 +340,22 @@ interface DeliveryPort {
|
|
|
340
340
|
*/
|
|
341
341
|
incomingEpoch(): string | null;
|
|
342
342
|
ack(deliveryId: string, disposition: 'claimed' | 'rejected', reason?: 'invalid' | 'not-owned' | 'storage-rejected' | 'other'): Promise<void>;
|
|
343
|
+
/** Settle many acks at once (#757). Contract pinned by the delivery-port contract suite. */
|
|
344
|
+
ackBatch?(acks: readonly AckRequest[]): Promise<readonly AckOutcome[]>;
|
|
343
345
|
onWake?(cb: () => void): () => void;
|
|
344
346
|
}
|
|
347
|
+
interface AckRequest {
|
|
348
|
+
readonly deliveryId: string;
|
|
349
|
+
readonly disposition: 'claimed' | 'rejected';
|
|
350
|
+
readonly reason?: 'invalid' | 'not-owned' | 'storage-rejected' | 'other';
|
|
351
|
+
}
|
|
352
|
+
type AckOutcome = {
|
|
353
|
+
readonly deliveryId: string;
|
|
354
|
+
readonly status: 'settled';
|
|
355
|
+
} | {
|
|
356
|
+
readonly deliveryId: string;
|
|
357
|
+
readonly status: 'conflict';
|
|
358
|
+
};
|
|
345
359
|
|
|
346
360
|
interface IntentPayload {
|
|
347
361
|
v: 2;
|
|
@@ -536,6 +536,26 @@ var SerialChain = class {
|
|
|
536
536
|
return run;
|
|
537
537
|
}
|
|
538
538
|
};
|
|
539
|
+
function coalesced(run) {
|
|
540
|
+
let inFlight = false;
|
|
541
|
+
let queued = false;
|
|
542
|
+
const start = () => {
|
|
543
|
+
inFlight = true;
|
|
544
|
+
void run().catch(() => void 0).finally(() => {
|
|
545
|
+
inFlight = false;
|
|
546
|
+
if (!queued) return;
|
|
547
|
+
queued = false;
|
|
548
|
+
start();
|
|
549
|
+
});
|
|
550
|
+
};
|
|
551
|
+
return () => {
|
|
552
|
+
if (inFlight) {
|
|
553
|
+
queued = true;
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
start();
|
|
557
|
+
};
|
|
558
|
+
}
|
|
539
559
|
|
|
540
560
|
// modules/payments-v2/machine/journal.ts
|
|
541
561
|
var MAX_DELIVERY_ATTEMPTS = 6;
|
|
@@ -2841,6 +2861,16 @@ var InventoryView = class {
|
|
|
2841
2861
|
this.inFlight.add(tokenId);
|
|
2842
2862
|
this.deps.emit("inventory:updated");
|
|
2843
2863
|
}
|
|
2864
|
+
/** Reserve a whole plan as ONE change — per token emitted 54 events per send. */
|
|
2865
|
+
markInFlightMany(tokenIds) {
|
|
2866
|
+
let changed = false;
|
|
2867
|
+
for (const tokenId of tokenIds) {
|
|
2868
|
+
if (this.inFlight.has(tokenId)) continue;
|
|
2869
|
+
this.inFlight.add(tokenId);
|
|
2870
|
+
changed = true;
|
|
2871
|
+
}
|
|
2872
|
+
if (changed) this.deps.emit("inventory:updated");
|
|
2873
|
+
}
|
|
2844
2874
|
release(tokenId) {
|
|
2845
2875
|
if (this.inFlight.delete(tokenId)) this.deps.emit("inventory:updated");
|
|
2846
2876
|
}
|
|
@@ -3157,6 +3187,11 @@ var logger = {
|
|
|
3157
3187
|
}
|
|
3158
3188
|
};
|
|
3159
3189
|
|
|
3190
|
+
// modules/payments-v2/ports.ts
|
|
3191
|
+
function isRetryableAckError(err) {
|
|
3192
|
+
return err !== null && typeof err === "object" && err.retryable === true;
|
|
3193
|
+
}
|
|
3194
|
+
|
|
3160
3195
|
// modules/payments-v2/receive/Receive.ts
|
|
3161
3196
|
var ACK_BATCH_SIZE = 200;
|
|
3162
3197
|
var REFRESH_INTERVAL_MS = 2500;
|
|
@@ -3238,6 +3273,7 @@ var Receive = class {
|
|
|
3238
3273
|
}
|
|
3239
3274
|
} catch (err) {
|
|
3240
3275
|
logger.warn("PaymentsV2", "receive drain interrupted \u2014 unacked entries retry next drain:", err);
|
|
3276
|
+
if (isRetryableAckError(err)) return stored;
|
|
3241
3277
|
await flushAcks(deps, pending, pageEpoch).catch((flushErr) => {
|
|
3242
3278
|
logger.warn("PaymentsV2", "receive ack flush failed \u2014 cursor holds at the acked prefix:", flushErr);
|
|
3243
3279
|
});
|
|
@@ -3312,14 +3348,18 @@ async function announce(deps, entry, record) {
|
|
|
3312
3348
|
};
|
|
3313
3349
|
}
|
|
3314
3350
|
async function flushAcks(deps, pending, epochOf) {
|
|
3351
|
+
if (pending.length === 0) return;
|
|
3315
3352
|
let lastAcked = null;
|
|
3316
3353
|
try {
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
lastAcked =
|
|
3321
|
-
|
|
3354
|
+
const settled = await settleAcks(deps, pending);
|
|
3355
|
+
let i = 0;
|
|
3356
|
+
while (i < pending.length && settled.has(pending[i].deliveryId)) {
|
|
3357
|
+
lastAcked = pending[i].cursor;
|
|
3358
|
+
i += 1;
|
|
3322
3359
|
}
|
|
3360
|
+
const stuck = pending.filter((p) => !settled.has(p.deliveryId));
|
|
3361
|
+
pending.length = 0;
|
|
3362
|
+
pending.push(...stuck);
|
|
3323
3363
|
} finally {
|
|
3324
3364
|
if (lastAcked !== null) {
|
|
3325
3365
|
const record = { cursor: lastAcked, syncEpoch: epochOf() };
|
|
@@ -3327,14 +3367,65 @@ async function flushAcks(deps, pending, epochOf) {
|
|
|
3327
3367
|
}
|
|
3328
3368
|
}
|
|
3329
3369
|
}
|
|
3370
|
+
async function settleAcks(deps, pending) {
|
|
3371
|
+
const batch = deps.delivery.ackBatch?.bind(deps.delivery);
|
|
3372
|
+
if (batch === void 0) return settleOneByOne(deps, pending);
|
|
3373
|
+
let outcomes;
|
|
3374
|
+
try {
|
|
3375
|
+
outcomes = await batch(pending.map(toAckRequest));
|
|
3376
|
+
} catch (err) {
|
|
3377
|
+
if (isRetryableAckError(err)) throw err;
|
|
3378
|
+
logger.warn("PaymentsV2", "batched mailbox ack failed \u2014 settling one at a time:", err);
|
|
3379
|
+
return settleOneByOne(deps, pending);
|
|
3380
|
+
}
|
|
3381
|
+
const settled = new Set(outcomes.filter((o) => o.status === "settled").map((o) => o.deliveryId));
|
|
3382
|
+
const conflicts = outcomes.filter((o) => o.status === "conflict").map((o) => o.deliveryId);
|
|
3383
|
+
if (conflicts.length > 0) await resolveConflicts(deps, pending, conflicts, settled);
|
|
3384
|
+
return settled;
|
|
3385
|
+
}
|
|
3386
|
+
async function resolveConflicts(deps, pending, conflicts, settled) {
|
|
3387
|
+
for (const deliveryId of conflicts) {
|
|
3388
|
+
const entry = pending.find((p) => p.deliveryId === deliveryId);
|
|
3389
|
+
try {
|
|
3390
|
+
await rejectStaleClaim(deps, deliveryId, entry?.transferId);
|
|
3391
|
+
} catch (err) {
|
|
3392
|
+
logger.warn("PaymentsV2", `stale-reject failed for ${deliveryId} \u2014 cursor holds here:`, err);
|
|
3393
|
+
continue;
|
|
3394
|
+
}
|
|
3395
|
+
settled.add(deliveryId);
|
|
3396
|
+
}
|
|
3397
|
+
}
|
|
3398
|
+
async function rejectStaleClaim(deps, deliveryId, transferId) {
|
|
3399
|
+
logger.warn("PaymentsV2", `mailbox claim CONFLICT for ${deliveryId} \u2014 rejected('other') as stale`);
|
|
3400
|
+
await deps.delivery.ack(deliveryId, "rejected", "other");
|
|
3401
|
+
deps.attention(transferId ?? "", ATTENTION_CLAIM_CONFLICT, deliveryId);
|
|
3402
|
+
}
|
|
3403
|
+
async function settleOneByOne(deps, pending) {
|
|
3404
|
+
const settled = /* @__PURE__ */ new Set();
|
|
3405
|
+
for (const ack of pending) {
|
|
3406
|
+
try {
|
|
3407
|
+
await ackOne(deps, ack);
|
|
3408
|
+
} catch (err) {
|
|
3409
|
+
logger.warn("PaymentsV2", `mailbox ack failed for ${ack.deliveryId} \u2014 cursor holds here:`, err);
|
|
3410
|
+
break;
|
|
3411
|
+
}
|
|
3412
|
+
settled.add(ack.deliveryId);
|
|
3413
|
+
}
|
|
3414
|
+
return settled;
|
|
3415
|
+
}
|
|
3416
|
+
function toAckRequest(ack) {
|
|
3417
|
+
return {
|
|
3418
|
+
deliveryId: ack.deliveryId,
|
|
3419
|
+
disposition: ack.disposition,
|
|
3420
|
+
...ack.reason !== void 0 ? { reason: ack.reason } : {}
|
|
3421
|
+
};
|
|
3422
|
+
}
|
|
3330
3423
|
async function ackOne(deps, ack) {
|
|
3331
3424
|
try {
|
|
3332
3425
|
await deps.delivery.ack(ack.deliveryId, ack.disposition, ack.reason);
|
|
3333
3426
|
} catch (err) {
|
|
3334
3427
|
if (ack.disposition !== "claimed" || !isClaimConflict(err)) throw err;
|
|
3335
|
-
|
|
3336
|
-
await deps.delivery.ack(ack.deliveryId, "rejected", "other");
|
|
3337
|
-
deps.attention(ack.transferId ?? "", ATTENTION_CLAIM_CONFLICT, ack.deliveryId);
|
|
3428
|
+
await rejectStaleClaim(deps, ack.deliveryId, ack.transferId);
|
|
3338
3429
|
}
|
|
3339
3430
|
}
|
|
3340
3431
|
function claimAck(entry) {
|
|
@@ -4088,26 +4179,6 @@ function parseAmount(raw) {
|
|
|
4088
4179
|
function supportsDeterministicMint(engine) {
|
|
4089
4180
|
return engine.deterministicMint === true;
|
|
4090
4181
|
}
|
|
4091
|
-
function makeCoalescedRefresh(refresh) {
|
|
4092
|
-
let inFlight = false;
|
|
4093
|
-
let queued = false;
|
|
4094
|
-
const run = () => {
|
|
4095
|
-
inFlight = true;
|
|
4096
|
-
void refresh().catch(() => void 0).finally(() => {
|
|
4097
|
-
inFlight = false;
|
|
4098
|
-
if (!queued) return;
|
|
4099
|
-
queued = false;
|
|
4100
|
-
run();
|
|
4101
|
-
});
|
|
4102
|
-
};
|
|
4103
|
-
return () => {
|
|
4104
|
-
if (inFlight) {
|
|
4105
|
-
queued = true;
|
|
4106
|
-
return;
|
|
4107
|
-
}
|
|
4108
|
-
run();
|
|
4109
|
-
};
|
|
4110
|
-
}
|
|
4111
4182
|
function composeFacadeParts(deps, hooks) {
|
|
4112
4183
|
const ownPubkeyBytes = hexToBytes(deps.ownPubkey);
|
|
4113
4184
|
const ledger = new ReservationLedger();
|
|
@@ -4137,9 +4208,11 @@ function composeFacadeParts(deps, hooks) {
|
|
|
4137
4208
|
const machineDeps = buildMachineDeps(deps, hooks, historyStore);
|
|
4138
4209
|
const machineStores = createMachineStores(deps.kv);
|
|
4139
4210
|
const heldStates = /* @__PURE__ */ new Map();
|
|
4211
|
+
const refreshView = coalesced(() => view.delta());
|
|
4140
4212
|
return {
|
|
4141
4213
|
ownPubkeyBytes,
|
|
4142
4214
|
view,
|
|
4215
|
+
refreshView,
|
|
4143
4216
|
ledger,
|
|
4144
4217
|
pins: buildPins(deps, hooks, { ledger, view, machineStores, machineDeps }),
|
|
4145
4218
|
queue,
|
|
@@ -4148,7 +4221,7 @@ function composeFacadeParts(deps, hooks) {
|
|
|
4148
4221
|
machineDeps,
|
|
4149
4222
|
machine: new TransferMachine(machineDeps),
|
|
4150
4223
|
heldStates,
|
|
4151
|
-
receiveLoop: buildReceive(deps, hooks, historyStore, heldStates,
|
|
4224
|
+
receiveLoop: buildReceive(deps, hooks, historyStore, heldStates, refreshView),
|
|
4152
4225
|
requests: buildRequests(deps, hooks),
|
|
4153
4226
|
restoreDeps: buildRestoreDeps(deps, machineDeps, machineStores, view)
|
|
4154
4227
|
};
|
|
@@ -4215,7 +4288,7 @@ function buildMachineDeps(deps, hooks, historyStore) {
|
|
|
4215
4288
|
}
|
|
4216
4289
|
};
|
|
4217
4290
|
}
|
|
4218
|
-
function buildReceive(deps, hooks, historyStore, heldStates,
|
|
4291
|
+
function buildReceive(deps, hooks, historyStore, heldStates, refreshView) {
|
|
4219
4292
|
return new Receive({
|
|
4220
4293
|
delivery: deps.deliveryPort,
|
|
4221
4294
|
engine: () => hooks.engine(),
|
|
@@ -4229,8 +4302,7 @@ function buildReceive(deps, hooks, historyStore, heldStates, view) {
|
|
|
4229
4302
|
registry: deps.registry,
|
|
4230
4303
|
recordReceived: (record) => recordReceived(historyStore, record),
|
|
4231
4304
|
emit: (event, transfer) => deps.emit(event, transfer),
|
|
4232
|
-
|
|
4233
|
-
refreshView: makeCoalescedRefresh(() => view.delta()),
|
|
4305
|
+
refreshView,
|
|
4234
4306
|
attention: (transferId, code, detail) => {
|
|
4235
4307
|
deps.emit(
|
|
4236
4308
|
"transfer:attention",
|
|
@@ -4282,7 +4354,7 @@ var PaymentsFacade = class {
|
|
|
4282
4354
|
isActiveOp: (id) => this.activeMoneyOps.has(id)
|
|
4283
4355
|
});
|
|
4284
4356
|
this.view = parts.view;
|
|
4285
|
-
this.wakeRefresh =
|
|
4357
|
+
this.wakeRefresh = parts.refreshView;
|
|
4286
4358
|
this.ledger = parts.ledger;
|
|
4287
4359
|
this.queue = parts.queue;
|
|
4288
4360
|
this.machine = parts.machine;
|
|
@@ -4615,7 +4687,7 @@ var PaymentsFacade = class {
|
|
|
4615
4687
|
...spend.plan.direct,
|
|
4616
4688
|
...spend.plan.split !== void 0 ? [spend.plan.split.tokenId] : []
|
|
4617
4689
|
];
|
|
4618
|
-
|
|
4690
|
+
this.view.markInFlightMany(sourceIds);
|
|
4619
4691
|
if (spend.plan.split !== void 0) {
|
|
4620
4692
|
this.queue.declareExpectedChange(transferId, coinId, spend.plan.split.remainderAmount);
|
|
4621
4693
|
}
|