@unicitylabs/sphere-sdk 0.14.10 → 0.14.11-dev.1
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 +139 -16
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +2 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +139 -16
- 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/index.cjs +139 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +139 -16
- package/dist/index.js.map +1 -1
- package/dist/modules/payments-v2/index.cjs +139 -16
- package/dist/modules/payments-v2/index.cjs.map +1 -1
- package/dist/modules/payments-v2/index.d.cts +6 -2
- package/dist/modules/payments-v2/index.d.ts +6 -2
- package/dist/modules/payments-v2/index.js +139 -16
- package/dist/modules/payments-v2/index.js.map +1 -1
- package/package.json +1 -1
package/dist/core/index.d.cts
CHANGED
|
@@ -167,6 +167,8 @@ interface PendingTransfer {
|
|
|
167
167
|
}
|
|
168
168
|
type ConnectionStatus$1 = 'connected' | 'degraded' | 'offline';
|
|
169
169
|
interface PaymentsV2 {
|
|
170
|
+
prewarmSend(request: SendRequest): Promise<void>;
|
|
171
|
+
discardPrewarm(): void;
|
|
170
172
|
assets(coinId?: string): Promise<Asset[]>;
|
|
171
173
|
tokens(filter?: {
|
|
172
174
|
coinId?: string;
|
package/dist/core/index.d.ts
CHANGED
|
@@ -167,6 +167,8 @@ interface PendingTransfer {
|
|
|
167
167
|
}
|
|
168
168
|
type ConnectionStatus$1 = 'connected' | 'degraded' | 'offline';
|
|
169
169
|
interface PaymentsV2 {
|
|
170
|
+
prewarmSend(request: SendRequest): Promise<void>;
|
|
171
|
+
discardPrewarm(): void;
|
|
170
172
|
assets(coinId?: string): Promise<Asset[]>;
|
|
171
173
|
tokens(filter?: {
|
|
172
174
|
coinId?: string;
|
package/dist/core/index.js
CHANGED
|
@@ -12273,6 +12273,90 @@ async function splitOpIndex(deps, envelope) {
|
|
|
12273
12273
|
return Array.isArray(payload.direct) ? payload.direct.length : 0;
|
|
12274
12274
|
}
|
|
12275
12275
|
|
|
12276
|
+
// modules/payments-v2/mint-params.ts
|
|
12277
|
+
function mintParams(recipientPubkey, coinId, amount) {
|
|
12278
|
+
return { recipientPubkey, value: { assets: [{ coinId, amount }] } };
|
|
12279
|
+
}
|
|
12280
|
+
|
|
12281
|
+
// modules/payments-v2/prewarm-cache.ts
|
|
12282
|
+
var PrewarmCache = class _PrewarmCache {
|
|
12283
|
+
entries = /* @__PURE__ */ new Map();
|
|
12284
|
+
generation = 0;
|
|
12285
|
+
static key(tokenId, stateHash) {
|
|
12286
|
+
return `${tokenId}:${stateHash}`;
|
|
12287
|
+
}
|
|
12288
|
+
/** Claim the cache for a warm about to start; supersedes any warm already running. */
|
|
12289
|
+
begin() {
|
|
12290
|
+
this.entries.clear();
|
|
12291
|
+
this.generation += 1;
|
|
12292
|
+
return this.generation;
|
|
12293
|
+
}
|
|
12294
|
+
/**
|
|
12295
|
+
* Publish a warm's result, unless it was cancelled or superseded while its
|
|
12296
|
+
* fetch was in flight — a cancel that only cleared what had landed so far
|
|
12297
|
+
* would be undone by the continuation of the very warm it cancelled.
|
|
12298
|
+
*/
|
|
12299
|
+
commit(generation, warmed) {
|
|
12300
|
+
if (generation !== this.generation) return;
|
|
12301
|
+
for (const [tokenId, stateHash, bytes] of warmed) {
|
|
12302
|
+
this.entries.set(_PrewarmCache.key(tokenId, stateHash), bytes);
|
|
12303
|
+
}
|
|
12304
|
+
}
|
|
12305
|
+
get(tokenId, stateHash) {
|
|
12306
|
+
if (stateHash === void 0) return void 0;
|
|
12307
|
+
return this.entries.get(_PrewarmCache.key(tokenId, stateHash));
|
|
12308
|
+
}
|
|
12309
|
+
clear() {
|
|
12310
|
+
this.entries.clear();
|
|
12311
|
+
this.generation += 1;
|
|
12312
|
+
}
|
|
12313
|
+
get size() {
|
|
12314
|
+
return this.entries.size;
|
|
12315
|
+
}
|
|
12316
|
+
};
|
|
12317
|
+
async function warmSendSources(deps, request) {
|
|
12318
|
+
const ids = deps.queue.previewSelection(request);
|
|
12319
|
+
if (ids.length === 0) return;
|
|
12320
|
+
const generation = deps.cache.begin();
|
|
12321
|
+
const at = new Map(ids.map((id) => [id, deps.view.stateHashOf(id)]));
|
|
12322
|
+
let blobs;
|
|
12323
|
+
try {
|
|
12324
|
+
blobs = await deps.storagePort.getBlobs([...ids]);
|
|
12325
|
+
} catch {
|
|
12326
|
+
return;
|
|
12327
|
+
}
|
|
12328
|
+
const warmed = [];
|
|
12329
|
+
for (const [tokenId, bytes] of blobs) {
|
|
12330
|
+
const stateHash = at.get(tokenId);
|
|
12331
|
+
if (stateHash !== void 0) warmed.push([tokenId, stateHash, bytes]);
|
|
12332
|
+
}
|
|
12333
|
+
deps.cache.commit(generation, warmed);
|
|
12334
|
+
}
|
|
12335
|
+
async function takeSourceBlobs(deps, sourceIds) {
|
|
12336
|
+
const blobs = /* @__PURE__ */ new Map();
|
|
12337
|
+
const missing = [];
|
|
12338
|
+
let trustCache = deps.cache.size > 0;
|
|
12339
|
+
if (trustCache) {
|
|
12340
|
+
try {
|
|
12341
|
+
await deps.view.delta();
|
|
12342
|
+
} catch {
|
|
12343
|
+
trustCache = false;
|
|
12344
|
+
}
|
|
12345
|
+
}
|
|
12346
|
+
for (const tokenId of sourceIds) {
|
|
12347
|
+
const warm = trustCache ? deps.cache.get(tokenId, deps.view.stateHashOf(tokenId)) : void 0;
|
|
12348
|
+
if (warm === void 0) missing.push(tokenId);
|
|
12349
|
+
else blobs.set(tokenId, warm);
|
|
12350
|
+
}
|
|
12351
|
+
deps.cache.clear();
|
|
12352
|
+
if (missing.length > 0) {
|
|
12353
|
+
for (const [tokenId, bytes] of await deps.storagePort.getBlobs(missing)) {
|
|
12354
|
+
blobs.set(tokenId, bytes);
|
|
12355
|
+
}
|
|
12356
|
+
}
|
|
12357
|
+
return blobs;
|
|
12358
|
+
}
|
|
12359
|
+
|
|
12276
12360
|
// modules/payments-v2/inventory/presentation.ts
|
|
12277
12361
|
function toToken(tokenId, snapshot, asset, registry, flags) {
|
|
12278
12362
|
const iconUrl = registry.getIconUrl(asset.coinId);
|
|
@@ -12359,6 +12443,13 @@ function priceOne(asset, quote) {
|
|
|
12359
12443
|
fiatValueEur: quote.priceEur != null ? human * quote.priceEur : null
|
|
12360
12444
|
};
|
|
12361
12445
|
}
|
|
12446
|
+
function transferringToken(tokenId, coinId, amount, registry, now) {
|
|
12447
|
+
const snapshot = { assets: [], createdAt: now, updatedAt: now };
|
|
12448
|
+
return toToken(tokenId, snapshot, { coinId, amount: amount.toString() }, registry, {
|
|
12449
|
+
transferring: true,
|
|
12450
|
+
suspectedSpent: false
|
|
12451
|
+
});
|
|
12452
|
+
}
|
|
12362
12453
|
|
|
12363
12454
|
// modules/payments-v2/machine/payload.ts
|
|
12364
12455
|
function buildPayload(recipientPubkey, request, spend, spentStates) {
|
|
@@ -12597,6 +12688,15 @@ var InventoryView = class {
|
|
|
12597
12688
|
}
|
|
12598
12689
|
return out;
|
|
12599
12690
|
}
|
|
12691
|
+
/**
|
|
12692
|
+
* Current mirrored state of an ACTIVE token, or undefined when it is unknown
|
|
12693
|
+
* or tombstoned. Exists so a cached blob can be state-scoped (F6): a blob is
|
|
12694
|
+
* only reusable while the token still sits at the state it was fetched at.
|
|
12695
|
+
*/
|
|
12696
|
+
stateHashOf(tokenId) {
|
|
12697
|
+
const entry = this.mirror.get(tokenId);
|
|
12698
|
+
return entry !== void 0 && entry.status === "active" ? entry.stateHash : void 0;
|
|
12699
|
+
}
|
|
12600
12700
|
tokens(registry, filter) {
|
|
12601
12701
|
const out = [];
|
|
12602
12702
|
for (const [tokenId, entry] of this.mirror) {
|
|
@@ -13516,6 +13616,31 @@ var SpendQueue = class {
|
|
|
13516
13616
|
}
|
|
13517
13617
|
return { kind: "queued", settled: this.enqueue(reservationId, request.coinId, amount) };
|
|
13518
13618
|
}
|
|
13619
|
+
/**
|
|
13620
|
+
* The sources `plan()` WOULD pick right now, reserving nothing and queueing
|
|
13621
|
+
* nothing — a read-only probe used to warm blobs while the user is still
|
|
13622
|
+
* looking at the confirm screen.
|
|
13623
|
+
*
|
|
13624
|
+
* Deliberately side-effect free: reserving here would pin the user's balance
|
|
13625
|
+
* across think-time and strand it if they never press send. The consequence is
|
|
13626
|
+
* that the real `plan()` may pick differently (inventory moves, another send
|
|
13627
|
+
* reserves first); callers must treat the result as a HINT and tolerate a miss,
|
|
13628
|
+
* never as a commitment that these sources will be spent.
|
|
13629
|
+
*/
|
|
13630
|
+
previewSelection(request) {
|
|
13631
|
+
if (this.destroyed) return [];
|
|
13632
|
+
let amount;
|
|
13633
|
+
try {
|
|
13634
|
+
amount = parseAmount(request.amount);
|
|
13635
|
+
} catch {
|
|
13636
|
+
return [];
|
|
13637
|
+
}
|
|
13638
|
+
const { freeView, freeTotal } = this.freeView(request.coinId);
|
|
13639
|
+
if (freeTotal < amount) return [];
|
|
13640
|
+
const plan = selectCoins(freeView, amount, { workBudget: this.deps.workBudget });
|
|
13641
|
+
if (plan === null) return [];
|
|
13642
|
+
return [...plan.direct, ...plan.split !== void 0 ? [plan.split.tokenId] : []];
|
|
13643
|
+
}
|
|
13519
13644
|
// Coverage math: free + Σ declared expected change of in-flight sends —
|
|
13520
13645
|
// never the full amount of in-flight sources (§5.3).
|
|
13521
13646
|
declareExpectedChange(transferId, coinId, amount) {
|
|
@@ -13865,6 +13990,7 @@ var PaymentsFacade = class {
|
|
|
13865
13990
|
now: () => this.nowMs()
|
|
13866
13991
|
});
|
|
13867
13992
|
}
|
|
13993
|
+
prewarmed = new PrewarmCache();
|
|
13868
13994
|
view;
|
|
13869
13995
|
ledger;
|
|
13870
13996
|
queue;
|
|
@@ -13958,6 +14084,15 @@ var PaymentsFacade = class {
|
|
|
13958
14084
|
return derivePendingTransfers(this.machineStores, this.machineDeps.decryptPayload);
|
|
13959
14085
|
}
|
|
13960
14086
|
// ── money movement ─────────────────────────────────────────────────────────
|
|
14087
|
+
async prewarmSend(request) {
|
|
14088
|
+
await warmSendSources(this.warmDeps(), request);
|
|
14089
|
+
}
|
|
14090
|
+
discardPrewarm() {
|
|
14091
|
+
this.prewarmed.clear();
|
|
14092
|
+
}
|
|
14093
|
+
warmDeps() {
|
|
14094
|
+
return { queue: this.queue, view: this.view, storagePort: this.deps.storagePort, cache: this.prewarmed };
|
|
14095
|
+
}
|
|
13961
14096
|
send(request) {
|
|
13962
14097
|
return this.track(this.sendOutcome(request));
|
|
13963
14098
|
}
|
|
@@ -14167,7 +14302,7 @@ var PaymentsFacade = class {
|
|
|
14167
14302
|
}
|
|
14168
14303
|
async materialize(transferId, recipientPubkey, request, spend, sourceIds) {
|
|
14169
14304
|
const engine = this.engine();
|
|
14170
|
-
const blobs = await this.
|
|
14305
|
+
const blobs = await takeSourceBlobs(this.warmDeps(), sourceIds);
|
|
14171
14306
|
const sources = /* @__PURE__ */ new Map();
|
|
14172
14307
|
const sourceTokens = [];
|
|
14173
14308
|
const spentStates = {};
|
|
@@ -14180,7 +14315,7 @@ var PaymentsFacade = class {
|
|
|
14180
14315
|
const keys = await engine.deliveryKeys(bytes);
|
|
14181
14316
|
spentStates[tokenId] = { local: keys.stateHash, protocol: keys.stateHash };
|
|
14182
14317
|
sources.set(tokenId, token);
|
|
14183
|
-
sourceTokens.push(
|
|
14318
|
+
sourceTokens.push(transferringToken(tokenId, request.coinId, engine.balanceOf(token, request.coinId), this.deps.registry, this.nowMs()));
|
|
14184
14319
|
}
|
|
14185
14320
|
const payload = buildPayload(recipientPubkey, request, spend, spentStates);
|
|
14186
14321
|
const plan = {
|
|
@@ -14324,7 +14459,7 @@ var PaymentsFacade = class {
|
|
|
14324
14459
|
await this.machineStores.mintJournal.upsert(entry);
|
|
14325
14460
|
let token;
|
|
14326
14461
|
try {
|
|
14327
|
-
token = await engine.mint(this.
|
|
14462
|
+
token = await engine.mint(mintParams(this.ownPubkeyBytes, coinId, amount), { transferId: mintId });
|
|
14328
14463
|
} catch (err) {
|
|
14329
14464
|
this.heartbeat.arm();
|
|
14330
14465
|
return { success: false, error: messageOf(err) };
|
|
@@ -14383,7 +14518,7 @@ var PaymentsFacade = class {
|
|
|
14383
14518
|
});
|
|
14384
14519
|
return false;
|
|
14385
14520
|
}
|
|
14386
|
-
const token = await engine.mint(this.
|
|
14521
|
+
const token = await engine.mint(mintParams(this.ownPubkeyBytes, entry.coinId, BigInt(entry.amount)), {
|
|
14387
14522
|
transferId: entry.mintId
|
|
14388
14523
|
});
|
|
14389
14524
|
if (token.blob.tokenId !== entry.tokenId) {
|
|
@@ -14392,12 +14527,6 @@ var PaymentsFacade = class {
|
|
|
14392
14527
|
await this.finalizeMint(engine, entry.mintId, token, entry.coinId, entry.amount);
|
|
14393
14528
|
return true;
|
|
14394
14529
|
}
|
|
14395
|
-
mintParams(coinId, amount) {
|
|
14396
|
-
return {
|
|
14397
|
-
recipientPubkey: this.ownPubkeyBytes,
|
|
14398
|
-
value: { assets: [{ coinId, amount }] }
|
|
14399
|
-
};
|
|
14400
|
-
}
|
|
14401
14530
|
async tokenInServerInventory(tokenId) {
|
|
14402
14531
|
let page = await this.deps.storagePort.listInventory();
|
|
14403
14532
|
for (let i = 0; i < INVENTORY_SCAN_PAGE_LIMIT; i++) {
|
|
@@ -14426,12 +14555,6 @@ var PaymentsFacade = class {
|
|
|
14426
14555
|
page = await this.deps.storagePort.listInventory(page.cursor);
|
|
14427
14556
|
}
|
|
14428
14557
|
}
|
|
14429
|
-
toUiToken(tokenId, coinId, amount) {
|
|
14430
|
-
const now = this.nowMs();
|
|
14431
|
-
const snapshot = { assets: [], createdAt: now, updatedAt: now };
|
|
14432
|
-
const flags = { transferring: true, suspectedSpent: false };
|
|
14433
|
-
return toToken(tokenId, snapshot, { coinId, amount: amount.toString() }, this.deps.registry, flags);
|
|
14434
|
-
}
|
|
14435
14558
|
track(op) {
|
|
14436
14559
|
const settled = op.then(() => void 0, () => void 0);
|
|
14437
14560
|
this.pendingOps.add(settled);
|