routstrd 0.4.8 → 0.4.9
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/README.md +96 -6
- package/SKILL.md +341 -0
- package/dist/daemon/index.js +598 -390
- package/dist/index.js +162637 -14155
- package/package.json +9 -4
- package/src/cli.ts +279 -110
- package/src/daemon/args.ts +4 -5
- package/src/daemon/http/index.ts +37 -2
- package/src/daemon/index.ts +94 -33
- package/src/daemon/wallet/auto-refill.ts +1 -1
- package/src/daemon/wallet/coco-client.ts +205 -3
- package/src/daemon/wallet/cocod-client.ts +19 -3
- package/src/daemon/wallet/index.ts +1 -1
- package/src/index.ts +9 -1
- package/src/runtime.ts +55 -0
- package/src/start-daemon.ts +4 -8
- package/src/utils/clients.ts +74 -1
- package/src/utils/config.ts +14 -0
- package/src/utils/daemon-stop.ts +125 -0
- package/src/utils/standalone-update.ts +214 -0
- package/src/utils/update-checker.ts +81 -18
- package/src/version.ts +3 -0
- package/src/cli.test.ts +0 -192
- package/src/daemon/fatal-error.test.ts +0 -104
- package/src/daemon/http/usage-summary.test.ts +0 -272
- package/src/daemon/models.test.ts +0 -81
- package/src/daemon/wallet/cleanup.test.ts +0 -168
- package/src/daemon/wallet/coco-client.npc.test.ts +0 -252
- package/src/daemon/wallet/coco-client.test.ts +0 -669
- package/src/daemon/wallet/diagnostics.test.ts +0 -378
- package/src/daemon/wallet/fixtures/cocod-0.0.24-wallet.db.gz +0 -0
- package/src/daemon/wallet/migration.test.ts +0 -171
- package/src/daemon/wallet/receive-dedup.test.ts +0 -238
package/dist/daemon/index.js
CHANGED
|
@@ -36717,10 +36717,10 @@ function invert4(number6, modulo) {
|
|
|
36717
36717
|
let b = modulo;
|
|
36718
36718
|
let x2 = _0n19, y = _1n19, u = _1n19, v3 = _0n19;
|
|
36719
36719
|
while (a !== _0n19) {
|
|
36720
|
-
const
|
|
36720
|
+
const q2 = b / a;
|
|
36721
36721
|
const r = b % a;
|
|
36722
|
-
const m = x2 - u *
|
|
36723
|
-
const n = y - v3 *
|
|
36722
|
+
const m = x2 - u * q2;
|
|
36723
|
+
const n = y - v3 * q2;
|
|
36724
36724
|
b = a, a = r, x2 = u, y = v3, u = m, v3 = n;
|
|
36725
36725
|
}
|
|
36726
36726
|
const gcd4 = b;
|
|
@@ -38003,14 +38003,14 @@ function ecdsa2(Point4, hash5, ecdsaOpts = {}) {
|
|
|
38003
38003
|
if (!Fn3.isValidNot0(k2))
|
|
38004
38004
|
return;
|
|
38005
38005
|
const ik = Fn3.inv(k2);
|
|
38006
|
-
const
|
|
38007
|
-
const r = Fn3.create(
|
|
38006
|
+
const q2 = Point4.BASE.multiply(k2).toAffine();
|
|
38007
|
+
const r = Fn3.create(q2.x);
|
|
38008
38008
|
if (r === _0n21)
|
|
38009
38009
|
return;
|
|
38010
38010
|
const s = Fn3.create(ik * Fn3.create(m + r * d));
|
|
38011
38011
|
if (s === _0n21)
|
|
38012
38012
|
return;
|
|
38013
|
-
let recovery = (
|
|
38013
|
+
let recovery = (q2.x === r ? 0 : 2) | Number(q2.y & _1n21);
|
|
38014
38014
|
let normS = s;
|
|
38015
38015
|
if (lowS && isBiggerThanHalfOrder(s)) {
|
|
38016
38016
|
normS = Fn3.neg(s);
|
|
@@ -65238,10 +65238,10 @@ function invert5(number10, modulo) {
|
|
|
65238
65238
|
let b = modulo;
|
|
65239
65239
|
let x2 = _0n25, y = _1n25, u = _1n25, v3 = _0n25;
|
|
65240
65240
|
while (a !== _0n25) {
|
|
65241
|
-
const
|
|
65241
|
+
const q2 = b / a;
|
|
65242
65242
|
const r = b % a;
|
|
65243
|
-
const m = x2 - u *
|
|
65244
|
-
const n = y - v3 *
|
|
65243
|
+
const m = x2 - u * q2;
|
|
65244
|
+
const n = y - v3 * q2;
|
|
65245
65245
|
b = a, a = r, x2 = u, y = v3, u = m, v3 = n;
|
|
65246
65246
|
}
|
|
65247
65247
|
const gcd4 = b;
|
|
@@ -66159,14 +66159,14 @@ function weierstrass5(curveDef) {
|
|
|
66159
66159
|
if (!isWithinCurveOrder(k2))
|
|
66160
66160
|
return;
|
|
66161
66161
|
const ik = invN(k2);
|
|
66162
|
-
const
|
|
66163
|
-
const r = modN3(
|
|
66162
|
+
const q2 = Point4.BASE.multiply(k2).toAffine();
|
|
66163
|
+
const r = modN3(q2.x);
|
|
66164
66164
|
if (r === _0n27)
|
|
66165
66165
|
return;
|
|
66166
66166
|
const s = modN3(ik * modN3(m + r * d));
|
|
66167
66167
|
if (s === _0n27)
|
|
66168
66168
|
return;
|
|
66169
|
-
let recovery = (
|
|
66169
|
+
let recovery = (q2.x === r ? 0 : 2) | Number(q2.y & _1n27);
|
|
66170
66170
|
let normS = s;
|
|
66171
66171
|
if (lowS && isBiggerThanHalfOrder(s)) {
|
|
66172
66172
|
normS = normalizeS(s);
|
|
@@ -88410,9 +88410,22 @@ function cr(t) {
|
|
|
88410
88410
|
};
|
|
88411
88411
|
return t.d && (r.memo = t.d), r;
|
|
88412
88412
|
}
|
|
88413
|
-
function
|
|
88414
|
-
|
|
88415
|
-
|
|
88413
|
+
function ur(e2) {
|
|
88414
|
+
e2 = Or(e2);
|
|
88415
|
+
let t = dr(e2);
|
|
88416
|
+
return {
|
|
88417
|
+
unit: t.unit || "sat",
|
|
88418
|
+
mint: t.mint,
|
|
88419
|
+
amount: q(t.proofs),
|
|
88420
|
+
...t.memo && { memo: t.memo },
|
|
88421
|
+
incompleteProofs: t.proofs.map((e3) => ({
|
|
88422
|
+
secret: e3.secret,
|
|
88423
|
+
C: e3.C,
|
|
88424
|
+
amount: e3.amount,
|
|
88425
|
+
...e3.dleq && { dleq: e3.dleq },
|
|
88426
|
+
...e3.witness && { witness: e3.witness }
|
|
88427
|
+
}))
|
|
88428
|
+
};
|
|
88416
88429
|
}
|
|
88417
88430
|
function dr(e2) {
|
|
88418
88431
|
let t = e2.slice(0, 1), n = e2.slice(1);
|
|
@@ -88469,6 +88482,9 @@ function K2(...e2) {
|
|
|
88469
88482
|
function gr(e2) {
|
|
88470
88483
|
return e2.replace(/\/$/, "");
|
|
88471
88484
|
}
|
|
88485
|
+
function q(e2) {
|
|
88486
|
+
return D.sum(e2.map((e3) => e3.amount)).toNumber();
|
|
88487
|
+
}
|
|
88472
88488
|
var vr = class {
|
|
88473
88489
|
get value() {
|
|
88474
88490
|
return this._value;
|
|
@@ -88519,32 +88535,6 @@ var yr = class {
|
|
|
88519
88535
|
return this._first = e2.next, e2.next = null, this._size--, e2.value;
|
|
88520
88536
|
}
|
|
88521
88537
|
};
|
|
88522
|
-
function Sr(e2, n) {
|
|
88523
|
-
let r = (n ?? []).map((e3) => typeof e3 == "string" ? e3 : e3.id), i4 = [];
|
|
88524
|
-
for (let n2 of e2) {
|
|
88525
|
-
let e3;
|
|
88526
|
-
try {
|
|
88527
|
-
e3 = hexToBytes7(n2.id);
|
|
88528
|
-
} catch {
|
|
88529
|
-
i4.push(n2);
|
|
88530
|
-
continue;
|
|
88531
|
-
}
|
|
88532
|
-
if (e3[0] === 0)
|
|
88533
|
-
i4.push(n2);
|
|
88534
|
-
else if (e3[0] === 1) {
|
|
88535
|
-
if (!r)
|
|
88536
|
-
throw Error("A short keyset ID v2 was encountered, but got no keysets to map it to.");
|
|
88537
|
-
let e4 = r.filter((e5) => n2.id === e5.slice(0, n2.id.length));
|
|
88538
|
-
if (e4.length > 1)
|
|
88539
|
-
throw Error(`Short keyset ID ${n2.id} is ambiguous.`);
|
|
88540
|
-
if (e4.length === 0)
|
|
88541
|
-
throw Error(`Couldn't map short keyset ID ${n2.id} to any known keysets of the current Mint`);
|
|
88542
|
-
n2.id = e4[0], i4.push(n2);
|
|
88543
|
-
} else
|
|
88544
|
-
throw Error(`Unknown keyset ID version: ${e3[0]}`);
|
|
88545
|
-
}
|
|
88546
|
-
return i4;
|
|
88547
|
-
}
|
|
88548
88538
|
function Cr(e2, n) {
|
|
88549
88539
|
if (e2.dleq == null)
|
|
88550
88540
|
return false;
|
|
@@ -90844,6 +90834,7 @@ var ModelManager = class _ModelManager {
|
|
|
90844
90834
|
this.logger = (config2.logger ?? consoleLogger).child("ModelManager");
|
|
90845
90835
|
this.eventStoreDbPath = config2.eventStoreDbPath;
|
|
90846
90836
|
this.persistentEventDatabaseFactory = config2.persistentEventDatabaseFactory;
|
|
90837
|
+
this.eventStore = config2.eventStore ?? null;
|
|
90847
90838
|
}
|
|
90848
90839
|
adapter;
|
|
90849
90840
|
cacheTTL;
|
|
@@ -90857,6 +90848,8 @@ var ModelManager = class _ModelManager {
|
|
|
90857
90848
|
providerNodePubkeysByUrl = /* @__PURE__ */ new Map;
|
|
90858
90849
|
relayPool = null;
|
|
90859
90850
|
eventStore = null;
|
|
90851
|
+
memoryEventStore = new EventStore({ verifyEvent });
|
|
90852
|
+
queryLastUpdate = /* @__PURE__ */ new Map;
|
|
90860
90853
|
eventStoreDb = null;
|
|
90861
90854
|
eventStoreInitPromise = null;
|
|
90862
90855
|
eventStoreDbPath;
|
|
@@ -90865,17 +90858,16 @@ var ModelManager = class _ModelManager {
|
|
|
90865
90858
|
return this.adapter.getBaseUrlsList();
|
|
90866
90859
|
}
|
|
90867
90860
|
async ensureEventStore() {
|
|
90868
|
-
if (!this.eventStoreDbPath)
|
|
90869
|
-
return null;
|
|
90870
90861
|
if (this.eventStore)
|
|
90871
90862
|
return this.eventStore;
|
|
90863
|
+
if (!this.eventStoreDbPath)
|
|
90864
|
+
return null;
|
|
90872
90865
|
if (!this.eventStoreInitPromise) {
|
|
90873
90866
|
this.eventStoreInitPromise = (async () => {
|
|
90874
90867
|
try {
|
|
90875
90868
|
const db = await this.createPersistentEventDatabase();
|
|
90876
90869
|
this.eventStoreDb = db;
|
|
90877
90870
|
this.eventStore = new EventStore({ database: db });
|
|
90878
|
-
this.initializeEventStoreMetadata();
|
|
90879
90871
|
this.logger.log(`Persistent event store initialized at ${this.eventStoreDbPath}`);
|
|
90880
90872
|
return this.eventStore;
|
|
90881
90873
|
} catch (error53) {
|
|
@@ -90904,34 +90896,40 @@ var ModelManager = class _ModelManager {
|
|
|
90904
90896
|
this.eventStoreDb = null;
|
|
90905
90897
|
this.eventStoreInitPromise = null;
|
|
90906
90898
|
}
|
|
90907
|
-
|
|
90908
|
-
|
|
90909
|
-
|
|
90910
|
-
|
|
90911
|
-
|
|
90912
|
-
|
|
90913
|
-
|
|
90914
|
-
const
|
|
90915
|
-
if (!
|
|
90916
|
-
|
|
90917
|
-
|
|
90918
|
-
|
|
90919
|
-
|
|
90920
|
-
|
|
90921
|
-
|
|
90922
|
-
|
|
90923
|
-
|
|
90924
|
-
|
|
90925
|
-
|
|
90926
|
-
|
|
90927
|
-
|
|
90928
|
-
|
|
90929
|
-
|
|
90930
|
-
|
|
90931
|
-
|
|
90932
|
-
|
|
90933
|
-
|
|
90934
|
-
|
|
90899
|
+
async getNostrEvents(filter10, forceRefresh = false, onEvent) {
|
|
90900
|
+
const eventStore = await this.ensureEventStore() ?? this.memoryEventStore;
|
|
90901
|
+
const query2 = JSON.stringify(filter10);
|
|
90902
|
+
const lastUpdate = this.queryLastUpdate.get(query2) ?? this.adapter.getNostrQueryLastUpdate?.()?.[query2];
|
|
90903
|
+
const now2 = Date.now();
|
|
90904
|
+
const cacheValid = typeof lastUpdate === "number" && lastUpdate <= now2 && now2 - lastUpdate <= this.cacheTTL;
|
|
90905
|
+
const received = /* @__PURE__ */ new Set;
|
|
90906
|
+
const cached2 = forceRefresh ? [] : eventStore.getTimeline(filter10).filter((event3) => this.isNostrEventTrustworthy(event3));
|
|
90907
|
+
if (forceRefresh || cached2.length === 0 || !cacheValid) {
|
|
90908
|
+
await this.collectNostrEvents(filter10, this.getNostrRelays(), NOSTR_QUERY_TIMEOUT_MS, (event3) => {
|
|
90909
|
+
const stored = eventStore.add(event3);
|
|
90910
|
+
if (!stored || stored.id !== event3.id)
|
|
90911
|
+
return;
|
|
90912
|
+
received.add(event3.id);
|
|
90913
|
+
onEvent?.(event3);
|
|
90914
|
+
});
|
|
90915
|
+
if (received.size > 0) {
|
|
90916
|
+
this.queryLastUpdate.set(query2, Date.now());
|
|
90917
|
+
this.adapter.setNostrQueryLastUpdate?.({
|
|
90918
|
+
...this.adapter.getNostrQueryLastUpdate?.(),
|
|
90919
|
+
...Object.fromEntries(this.queryLastUpdate)
|
|
90920
|
+
});
|
|
90921
|
+
}
|
|
90922
|
+
const events = eventStore.getTimeline(filter10).filter((event3) => this.isNostrEventTrustworthy(event3));
|
|
90923
|
+
for (const event3 of events) {
|
|
90924
|
+
if (!received.has(event3.id))
|
|
90925
|
+
onEvent?.(event3);
|
|
90926
|
+
}
|
|
90927
|
+
return events;
|
|
90928
|
+
}
|
|
90929
|
+
for (const event3 of cached2) {
|
|
90930
|
+
onEvent?.(event3);
|
|
90931
|
+
}
|
|
90932
|
+
return cached2;
|
|
90935
90933
|
}
|
|
90936
90934
|
async refreshNostrEvents() {
|
|
90937
90935
|
const eventStore = await this.ensureEventStore();
|
|
@@ -90939,23 +90937,12 @@ var ModelManager = class _ModelManager {
|
|
|
90939
90937
|
this.logger.warn("refreshNostrEvents: no event store configured, skipping");
|
|
90940
90938
|
return;
|
|
90941
90939
|
}
|
|
90942
|
-
|
|
90943
|
-
|
|
90944
|
-
await this.
|
|
90945
|
-
await this.fetchLiveIntoStore({ kinds: [38425], limit: 500, authors: [this.routstrPubkey] }, relays2, timeoutMs);
|
|
90946
|
-
await this.fetchLiveIntoStore({ kinds: [38423], "#d": ["routstr-21-models"], authors: [this.routstrModelsPubkey] }, relays2, timeoutMs);
|
|
90940
|
+
await this.getNostrEvents({ kinds: [38421], limit: 100 }, true);
|
|
90941
|
+
await this.getNostrEvents({ kinds: [38425], limit: 500, authors: [this.routstrPubkey] }, true);
|
|
90942
|
+
await this.getNostrEvents({ kinds: [38423], "#d": ["routstr-21-models"], authors: [this.routstrModelsPubkey] }, true);
|
|
90947
90943
|
this.logger.log("refreshNostrEvents: live fetch complete");
|
|
90948
90944
|
await this.syncReviewedProvidersFromNostr();
|
|
90949
90945
|
}
|
|
90950
|
-
async fetchLiveIntoStore(filter10, relays2, timeoutMs) {
|
|
90951
|
-
const eventStore = await this.ensureEventStore();
|
|
90952
|
-
if (!eventStore)
|
|
90953
|
-
return;
|
|
90954
|
-
await this.collectNostrEvents(filter10, relays2, timeoutMs, (event3) => {
|
|
90955
|
-
eventStore.add(event3);
|
|
90956
|
-
this.markEventFetched(event3);
|
|
90957
|
-
});
|
|
90958
|
-
}
|
|
90959
90946
|
static async init(adapter, config2 = {}, options = {}) {
|
|
90960
90947
|
const manager = new _ModelManager(adapter, config2);
|
|
90961
90948
|
const torMode = options.torMode ?? false;
|
|
@@ -90974,7 +90961,7 @@ var ModelManager = class _ModelManager {
|
|
|
90974
90961
|
const filteredCachedUrls = this.filterBaseUrlsForTor(cachedUrls, torMode);
|
|
90975
90962
|
await Promise.all([
|
|
90976
90963
|
this.fetchRoutstr21Models(forceRefresh),
|
|
90977
|
-
this.syncReviewedProvidersFromNostr(filteredCachedUrls
|
|
90964
|
+
this.syncReviewedProvidersFromNostr(filteredCachedUrls)
|
|
90978
90965
|
]);
|
|
90979
90966
|
return filteredCachedUrls;
|
|
90980
90967
|
}
|
|
@@ -91056,7 +91043,6 @@ var ModelManager = class _ModelManager {
|
|
|
91056
91043
|
});
|
|
91057
91044
|
}
|
|
91058
91045
|
async bootstrapFromNostr(kind, torMode, forceRefresh = false, options = {}) {
|
|
91059
|
-
const relays2 = this.getNostrRelays();
|
|
91060
91046
|
const bases = /* @__PURE__ */ new Set;
|
|
91061
91047
|
this.providerNodePubkeysByUrl = /* @__PURE__ */ new Map;
|
|
91062
91048
|
const excluded = new Set(this.excludeProviderUrls.map((url3) => this.normalizeUrl(url3)));
|
|
@@ -91112,19 +91098,7 @@ var ModelManager = class _ModelManager {
|
|
|
91112
91098
|
}
|
|
91113
91099
|
}
|
|
91114
91100
|
};
|
|
91115
|
-
|
|
91116
|
-
if (cached2.length > 0) {
|
|
91117
|
-
this.logger.log(`Using ${cached2.length} cached kind ${kind} events from persistent store`);
|
|
91118
|
-
for (const event3 of cached2) {
|
|
91119
|
-
collectFromEvent(event3);
|
|
91120
|
-
}
|
|
91121
|
-
} else {
|
|
91122
|
-
await this.collectNostrEvents({ kinds: [kind], limit: 100 }, relays2, NOSTR_QUERY_TIMEOUT_MS, (event3) => {
|
|
91123
|
-
this.eventStore?.add(event3);
|
|
91124
|
-
this.markEventFetched(event3);
|
|
91125
|
-
collectFromEvent(event3);
|
|
91126
|
-
});
|
|
91127
|
-
}
|
|
91101
|
+
await this.getNostrEvents({ kinds: [kind], limit: 100 }, forceRefresh, collectFromEvent);
|
|
91128
91102
|
for (const url3 of this.includeProviderUrls) {
|
|
91129
91103
|
const normalized = this.normalizeUrl(url3);
|
|
91130
91104
|
if (!torMode || normalized.includes(".onion")) {
|
|
@@ -91173,25 +91147,25 @@ var ModelManager = class _ModelManager {
|
|
|
91173
91147
|
throw new ProviderBootstrapError([], `Provider bootstrap failed: ${e13}`);
|
|
91174
91148
|
}
|
|
91175
91149
|
}
|
|
91176
|
-
async syncReviewedProvidersFromNostr(baseUrls = this.adapter.getBaseUrlsList(), providerNodes
|
|
91150
|
+
async syncReviewedProvidersFromNostr(baseUrls = this.adapter.getBaseUrlsList(), providerNodes, forceRefresh = false) {
|
|
91177
91151
|
if (baseUrls.length === 0)
|
|
91178
91152
|
return null;
|
|
91179
91153
|
if (!this.adapter.setDisabledProviders) {
|
|
91180
91154
|
this.logger.warn("NostrReviews: adapter does not support setDisabledProviders; skipping provider disable sync");
|
|
91181
91155
|
return null;
|
|
91182
91156
|
}
|
|
91183
|
-
if (providerNodes.size === 0) {
|
|
91184
|
-
providerNodes = await this.rebuildProviderNodesFromStore();
|
|
91157
|
+
if (!providerNodes || providerNodes.size === 0) {
|
|
91158
|
+
providerNodes = await this.rebuildProviderNodesFromStore(forceRefresh);
|
|
91159
|
+
if (!forceRefresh && providerNodes.size > 0 && baseUrls.some((url3) => !providerNodes.has(this.normalizeUrl(url3)))) {
|
|
91160
|
+
providerNodes = await this.rebuildProviderNodesFromStore(true);
|
|
91161
|
+
}
|
|
91185
91162
|
this.providerNodePubkeysByUrl = providerNodes;
|
|
91186
91163
|
}
|
|
91187
91164
|
const reviewLabels = await this.fetchReviewLabels(forceRefresh);
|
|
91188
91165
|
return this.applyReviewDisables(baseUrls, providerNodes, reviewLabels);
|
|
91189
91166
|
}
|
|
91190
|
-
async rebuildProviderNodesFromStore() {
|
|
91167
|
+
async rebuildProviderNodesFromStore(forceRefresh) {
|
|
91191
91168
|
const map14 = /* @__PURE__ */ new Map;
|
|
91192
|
-
const eventStore = await this.ensureEventStore();
|
|
91193
|
-
if (!eventStore)
|
|
91194
|
-
return map14;
|
|
91195
91169
|
const addNode = (url3, pubkey) => {
|
|
91196
91170
|
if (!pubkey)
|
|
91197
91171
|
return;
|
|
@@ -91200,7 +91174,7 @@ var ModelManager = class _ModelManager {
|
|
|
91200
91174
|
existing.add(pubkey);
|
|
91201
91175
|
map14.set(normalized, existing);
|
|
91202
91176
|
};
|
|
91203
|
-
const events =
|
|
91177
|
+
const events = await this.getNostrEvents({ kinds: [38421], limit: 100 }, forceRefresh);
|
|
91204
91178
|
for (const event3 of events) {
|
|
91205
91179
|
const eventUrls = [];
|
|
91206
91180
|
for (const tag2 of event3.tags) {
|
|
@@ -91218,7 +91192,10 @@ var ModelManager = class _ModelManager {
|
|
|
91218
91192
|
const content2 = JSON.parse(event3.content);
|
|
91219
91193
|
const providers = Array.isArray(content2) ? content2 : content2.providers || [];
|
|
91220
91194
|
for (const p of providers) {
|
|
91221
|
-
const endpoints =
|
|
91195
|
+
const endpoints = [
|
|
91196
|
+
...this.getProviderEndpoints(p, false),
|
|
91197
|
+
...this.getProviderEndpoints(p, true)
|
|
91198
|
+
];
|
|
91222
91199
|
for (const endpoint of endpoints) {
|
|
91223
91200
|
addNode(endpoint, p?.pubkey || event3.pubkey);
|
|
91224
91201
|
}
|
|
@@ -91243,23 +91220,9 @@ var ModelManager = class _ModelManager {
|
|
|
91243
91220
|
}
|
|
91244
91221
|
}
|
|
91245
91222
|
};
|
|
91246
|
-
const
|
|
91247
|
-
|
|
91248
|
-
|
|
91249
|
-
for (const event3 of cached2) {
|
|
91250
|
-
collectFromEvent(event3);
|
|
91251
|
-
}
|
|
91252
|
-
} else {
|
|
91253
|
-
await this.collectNostrEvents({
|
|
91254
|
-
kinds: [38425],
|
|
91255
|
-
limit: 500,
|
|
91256
|
-
authors: [this.routstrPubkey]
|
|
91257
|
-
}, this.getNostrRelays(), NOSTR_QUERY_TIMEOUT_MS, (event3) => {
|
|
91258
|
-
this.eventStore?.add(event3);
|
|
91259
|
-
this.markEventFetched(event3);
|
|
91260
|
-
collectFromEvent(event3);
|
|
91261
|
-
});
|
|
91262
|
-
}
|
|
91223
|
+
const events = await this.getNostrEvents({ kinds: [38425], limit: 500, authors: [this.routstrPubkey] }, forceRefresh);
|
|
91224
|
+
for (const event3 of events)
|
|
91225
|
+
collectFromEvent(event3);
|
|
91263
91226
|
const labels = /* @__PURE__ */ new Map;
|
|
91264
91227
|
for (const [node, event3] of latestByNode) {
|
|
91265
91228
|
const label = event3.tags.find((tag2) => tag2[0] === "t" && typeof tag2[1] === "string" && tag2[1])?.[1]?.toLowerCase();
|
|
@@ -91473,24 +91436,8 @@ var ModelManager = class _ModelManager {
|
|
|
91473
91436
|
return cachedModels;
|
|
91474
91437
|
}
|
|
91475
91438
|
}
|
|
91476
|
-
const
|
|
91477
|
-
const
|
|
91478
|
-
let event3 = null;
|
|
91479
|
-
if (cached2.length === 0) {
|
|
91480
|
-
await this.collectNostrEvents({
|
|
91481
|
-
kinds: [38423],
|
|
91482
|
-
"#d": ["routstr-21-models"],
|
|
91483
|
-
authors: [this.routstrModelsPubkey]
|
|
91484
|
-
}, relays2, NOSTR_QUERY_TIMEOUT_MS, (e13) => {
|
|
91485
|
-
this.eventStore?.add(e13);
|
|
91486
|
-
this.markEventFetched(e13);
|
|
91487
|
-
if (!event3 || e13.created_at > event3.created_at)
|
|
91488
|
-
event3 = e13;
|
|
91489
|
-
});
|
|
91490
|
-
} else {
|
|
91491
|
-
this.logger.log(`Using ${cached2.length} cached kind 38423 events from persistent store`);
|
|
91492
|
-
event3 = cached2.reduce((latest, e13) => e13.created_at > latest.created_at ? e13 : latest, cached2[0]);
|
|
91493
|
-
}
|
|
91439
|
+
const events = await this.getNostrEvents({ kinds: [38423], "#d": ["routstr-21-models"], authors: [this.routstrModelsPubkey] }, forceRefresh);
|
|
91440
|
+
const event3 = events.reduce((latest, event22) => !latest || event22.created_at > latest.created_at ? event22 : latest, null);
|
|
91494
91441
|
if (!event3) {
|
|
91495
91442
|
return cachedModels.length > 0 ? cachedModels : [];
|
|
91496
91443
|
}
|
|
@@ -91613,10 +91560,9 @@ var CashuSpender = class _CashuSpender {
|
|
|
91613
91560
|
}
|
|
91614
91561
|
_decodeTokenAmount(token) {
|
|
91615
91562
|
try {
|
|
91616
|
-
const
|
|
91617
|
-
const
|
|
91618
|
-
|
|
91619
|
-
return { amount, unit };
|
|
91563
|
+
const metadata = ur(token);
|
|
91564
|
+
const unit = metadata.unit || "sat";
|
|
91565
|
+
return { amount: metadata.amount, unit };
|
|
91620
91566
|
} catch {
|
|
91621
91567
|
return { amount: 0, unit: "sat" };
|
|
91622
91568
|
}
|
|
@@ -92023,7 +91969,8 @@ var CashuSpender = class _CashuSpender {
|
|
|
92023
91969
|
}
|
|
92024
91970
|
if (balanceResult.amount >= 0 && !balanceResult.balanceUnknown) {
|
|
92025
91971
|
const balanceSat = balanceResult.unit === "msat" ? Math.floor(balanceResult.amount / 1000) : balanceResult.amount;
|
|
92026
|
-
|
|
91972
|
+
const reservedSat = balanceResult.unit === "msat" ? Math.floor(balanceResult.reserved / 1000) : balanceResult.reserved;
|
|
91973
|
+
this.storageAdapter.updateApiKeyBalance(apiKeyEntry.baseUrl, balanceSat, reservedSat);
|
|
92027
91974
|
} else {
|
|
92028
91975
|
this.logger.warn(`refundProviders: balance refresh for ${apiKeyEntry.baseUrl} returned negative amount; keeping stale local balance=${apiKeyEntryFull.balance}`);
|
|
92029
91976
|
}
|
|
@@ -93628,11 +93575,7 @@ var ProviderManager = class _ProviderManager {
|
|
|
93628
93575
|
getProviderPriceRankingForModel(modelId, options = {}) {
|
|
93629
93576
|
const includeDisabled = options.includeDisabled ?? false;
|
|
93630
93577
|
const torMode = options.torMode ?? false;
|
|
93631
|
-
const
|
|
93632
|
-
const disabledProviders = new Set(disabledProviderList);
|
|
93633
|
-
if (disabledProviderList.length > 0) {
|
|
93634
|
-
this.logger.log(`getProviderPriceRankingForModel: disabled providers (${disabledProviderList.length}): ${disabledProviderList.join(", ")}`);
|
|
93635
|
-
}
|
|
93578
|
+
const disabledProviders = new Set(this.discoveryAdapter.getDisabledProviders());
|
|
93636
93579
|
const allModels = this.discoveryAdapter.getCachedModels();
|
|
93637
93580
|
const results = [];
|
|
93638
93581
|
for (const [baseUrl, models] of Object.entries(allModels)) {
|
|
@@ -93842,6 +93785,7 @@ var createMemoryDriver = (seed) => {
|
|
|
93842
93785
|
};
|
|
93843
93786
|
};
|
|
93844
93787
|
var SDK_STORAGE_KEYS = {
|
|
93788
|
+
NOSTR_QUERY_LAST_UPDATE: "nostr_query_last_update",
|
|
93845
93789
|
MODELS_FROM_ALL_PROVIDERS: "modelsFromAllProviders",
|
|
93846
93790
|
LAST_USED_MODEL: "lastUsedModel",
|
|
93847
93791
|
BASE_URLS_LIST: "base_urls_list",
|
|
@@ -94220,6 +94164,11 @@ var createMemoryUsageTrackingDriver = (seed = []) => {
|
|
|
94220
94164
|
};
|
|
94221
94165
|
var normalizeBaseUrl5 = (baseUrl) => baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
94222
94166
|
var createEmptyStore = (driver) => createStore((set2, get) => ({
|
|
94167
|
+
nostrQueryLastUpdate: {},
|
|
94168
|
+
setNostrQueryLastUpdate: (value) => {
|
|
94169
|
+
driver.setItem(SDK_STORAGE_KEYS.NOSTR_QUERY_LAST_UPDATE, value);
|
|
94170
|
+
set2({ nostrQueryLastUpdate: value });
|
|
94171
|
+
},
|
|
94223
94172
|
modelsFromAllProviders: {},
|
|
94224
94173
|
lastUsedModel: null,
|
|
94225
94174
|
baseUrlsList: [],
|
|
@@ -94307,6 +94256,7 @@ var createEmptyStore = (driver) => createStore((set2, get) => ({
|
|
|
94307
94256
|
...entry,
|
|
94308
94257
|
baseUrl: normalizeBaseUrl5(entry.baseUrl),
|
|
94309
94258
|
balance: entry.balance ?? 0,
|
|
94259
|
+
reserved: entry.reserved ?? 0,
|
|
94310
94260
|
lastUsed: entry.lastUsed ?? null
|
|
94311
94261
|
}));
|
|
94312
94262
|
driver.setItem(SDK_STORAGE_KEYS.API_KEYS, normalized);
|
|
@@ -94447,6 +94397,7 @@ var createEmptyStore = (driver) => createStore((set2, get) => ({
|
|
|
94447
94397
|
}));
|
|
94448
94398
|
var hydrateStoreFromDriver = async (store, driver) => {
|
|
94449
94399
|
const [
|
|
94400
|
+
nostrQueryLastUpdate,
|
|
94450
94401
|
rawModels,
|
|
94451
94402
|
lastUsedModel,
|
|
94452
94403
|
rawBaseUrls,
|
|
@@ -94468,6 +94419,7 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
94468
94419
|
rawLastFailed,
|
|
94469
94420
|
rawProvidersOnCooldown
|
|
94470
94421
|
] = await Promise.all([
|
|
94422
|
+
driver.getItem(SDK_STORAGE_KEYS.NOSTR_QUERY_LAST_UPDATE, {}),
|
|
94471
94423
|
driver.getItem(SDK_STORAGE_KEYS.MODELS_FROM_ALL_PROVIDERS, {}),
|
|
94472
94424
|
driver.getItem(SDK_STORAGE_KEYS.LAST_USED_MODEL, null),
|
|
94473
94425
|
driver.getItem(SDK_STORAGE_KEYS.BASE_URLS_LIST, []),
|
|
@@ -94513,6 +94465,7 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
94513
94465
|
...entry,
|
|
94514
94466
|
baseUrl: normalizeBaseUrl5(entry.baseUrl),
|
|
94515
94467
|
balance: entry.balance ?? 0,
|
|
94468
|
+
reserved: entry.reserved ?? 0,
|
|
94516
94469
|
lastUsed: entry.lastUsed ?? null
|
|
94517
94470
|
}));
|
|
94518
94471
|
const childKeys = rawChildKeys.map((entry) => ({
|
|
@@ -94555,6 +94508,7 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
94555
94508
|
timestamp: entry.timestamp
|
|
94556
94509
|
}));
|
|
94557
94510
|
store.setState({
|
|
94511
|
+
nostrQueryLastUpdate,
|
|
94558
94512
|
modelsFromAllProviders,
|
|
94559
94513
|
lastUsedModel,
|
|
94560
94514
|
baseUrlsList,
|
|
@@ -94591,10 +94545,15 @@ var createStorageAdapterFromStore = (store) => ({
|
|
|
94591
94545
|
const apiKeys = store.getState().apiKeys;
|
|
94592
94546
|
const distributionMap = {};
|
|
94593
94547
|
for (const entry of apiKeys) {
|
|
94594
|
-
const
|
|
94595
|
-
|
|
94548
|
+
const snapshot = distributionMap[entry.baseUrl] ?? {
|
|
94549
|
+
amount: 0,
|
|
94550
|
+
reserved: 0
|
|
94551
|
+
};
|
|
94552
|
+
snapshot.amount += entry.balance || 0;
|
|
94553
|
+
snapshot.reserved += entry.reserved || 0;
|
|
94554
|
+
distributionMap[entry.baseUrl] = snapshot;
|
|
94596
94555
|
}
|
|
94597
|
-
return Object.entries(distributionMap).map(([baseUrl,
|
|
94556
|
+
return Object.entries(distributionMap).map(([baseUrl, snapshot]) => ({ baseUrl, ...snapshot })).sort((a, b) => b.amount - a.amount);
|
|
94598
94557
|
},
|
|
94599
94558
|
saveProviderInfo: (baseUrl, info) => {
|
|
94600
94559
|
const normalized = normalizeBaseUrl5(baseUrl);
|
|
@@ -94625,14 +94584,19 @@ var createStorageAdapterFromStore = (store) => ({
|
|
|
94625
94584
|
baseUrl: normalized,
|
|
94626
94585
|
key,
|
|
94627
94586
|
balance: 0,
|
|
94587
|
+
reserved: 0,
|
|
94628
94588
|
lastUsed: Date.now()
|
|
94629
94589
|
});
|
|
94630
94590
|
store.getState().setApiKeys(next);
|
|
94631
94591
|
},
|
|
94632
|
-
updateApiKeyBalance: (baseUrl, balance) => {
|
|
94592
|
+
updateApiKeyBalance: (baseUrl, balance, reserved) => {
|
|
94633
94593
|
const normalized = normalizeBaseUrl5(baseUrl);
|
|
94634
94594
|
const keys2 = store.getState().apiKeys;
|
|
94635
|
-
const next = keys2.map((entry) => entry.baseUrl === normalized ? {
|
|
94595
|
+
const next = keys2.map((entry) => entry.baseUrl === normalized ? {
|
|
94596
|
+
...entry,
|
|
94597
|
+
balance,
|
|
94598
|
+
reserved: reserved ?? entry.reserved ?? 0
|
|
94599
|
+
} : entry);
|
|
94636
94600
|
store.getState().setApiKeys(next);
|
|
94637
94601
|
},
|
|
94638
94602
|
touchApiKeyLastUsed: (baseUrl) => {
|
|
@@ -94651,6 +94615,7 @@ var createStorageAdapterFromStore = (store) => ({
|
|
|
94651
94615
|
baseUrl: entry.baseUrl,
|
|
94652
94616
|
key: entry.key,
|
|
94653
94617
|
balance: entry.balance,
|
|
94618
|
+
reserved: entry.reserved ?? 0,
|
|
94654
94619
|
lastUsed: entry.lastUsed
|
|
94655
94620
|
}));
|
|
94656
94621
|
},
|
|
@@ -95042,7 +95007,8 @@ async function inspectSSEWebStream(stream2, onUsage, onResponseId, options) {
|
|
|
95042
95007
|
capturedResponseId
|
|
95043
95008
|
};
|
|
95044
95009
|
}
|
|
95045
|
-
var TOPUP_MARGIN = 1.
|
|
95010
|
+
var TOPUP_MARGIN = 1.4;
|
|
95011
|
+
var PROACTIVE_TOPUP_MIN_FRACTION = 0.21;
|
|
95046
95012
|
var RoutstrClient = class {
|
|
95047
95013
|
constructor(walletAdapter, storageAdapter, discoveryAdapter, alertLevel, mode = "xcashu", options = {}) {
|
|
95048
95014
|
this.walletAdapter = walletAdapter;
|
|
@@ -95075,6 +95041,7 @@ var RoutstrClient = class {
|
|
|
95075
95041
|
requestResponseLogSink;
|
|
95076
95042
|
userCacheSecret;
|
|
95077
95043
|
tinfoilCacheSecretPath;
|
|
95044
|
+
_inflightTopups = /* @__PURE__ */ new Map;
|
|
95078
95045
|
getMode() {
|
|
95079
95046
|
return this.mode;
|
|
95080
95047
|
}
|
|
@@ -95214,10 +95181,21 @@ var RoutstrClient = class {
|
|
|
95214
95181
|
const {
|
|
95215
95182
|
token,
|
|
95216
95183
|
tokenBalance,
|
|
95184
|
+
tokenReserved,
|
|
95217
95185
|
tokenBalanceUnit,
|
|
95218
95186
|
tokenBalanceUnknown,
|
|
95219
95187
|
selectedMintUrl
|
|
95220
95188
|
} = spendResult;
|
|
95189
|
+
this._spinOffTopupIfNeeded({
|
|
95190
|
+
token,
|
|
95191
|
+
baseUrl,
|
|
95192
|
+
mintUrl,
|
|
95193
|
+
requiredSats,
|
|
95194
|
+
tokenBalance,
|
|
95195
|
+
tokenReserved,
|
|
95196
|
+
tokenBalanceUnit,
|
|
95197
|
+
tokenBalanceUnknown
|
|
95198
|
+
});
|
|
95221
95199
|
const finalHeaders = this._withAuthAndTinfoilHeaders(baseHeaders, token, tinfoilEnabled, modelId);
|
|
95222
95200
|
const response = await this._makeRequest({
|
|
95223
95201
|
path: requestPath,
|
|
@@ -95524,12 +95502,12 @@ var RoutstrClient = class {
|
|
|
95524
95502
|
if (!balanceValidated) {
|
|
95525
95503
|
tryNextProvider = true;
|
|
95526
95504
|
} else {
|
|
95527
|
-
const topupResult = await this.balanceManager.topUp({
|
|
95505
|
+
const topupResult = await this._topUpOnce(`${baseUrl}:${params.token}`, () => this.balanceManager.topUp({
|
|
95528
95506
|
mintUrl,
|
|
95529
95507
|
baseUrl,
|
|
95530
95508
|
amount: topupAmount * TOPUP_MARGIN,
|
|
95531
95509
|
token: params.token
|
|
95532
|
-
});
|
|
95510
|
+
}));
|
|
95533
95511
|
this._log("DEBUG", `[RoutstrClient] _handleErrorResponse: Topup result for ${baseUrl}: success=${topupResult.success}, message=${topupResult.message}`);
|
|
95534
95512
|
if (!topupResult.success) {
|
|
95535
95513
|
const message = topupResult.message || "";
|
|
@@ -95574,6 +95552,7 @@ var RoutstrClient = class {
|
|
|
95574
95552
|
tryNextProvider = true;
|
|
95575
95553
|
} else {
|
|
95576
95554
|
const latestTokenBalance = latestBalanceInfo.balanceUnknown ? undefined : latestBalanceInfo.unit === "msat" ? latestBalanceInfo.amount / 1000 : latestBalanceInfo.amount;
|
|
95555
|
+
const latestReservedBalance = latestBalanceInfo.balanceUnknown ? undefined : latestBalanceInfo.unit === "msat" ? latestBalanceInfo.reserved / 1000 : latestBalanceInfo.reserved;
|
|
95577
95556
|
if (latestBalanceInfo.apiKey) {
|
|
95578
95557
|
const storedApiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
|
|
95579
95558
|
if (storedApiKeyEntry?.key !== latestBalanceInfo.apiKey) {
|
|
@@ -95585,7 +95564,7 @@ var RoutstrClient = class {
|
|
|
95585
95564
|
retryToken = latestBalanceInfo.apiKey;
|
|
95586
95565
|
}
|
|
95587
95566
|
if (latestTokenBalance !== undefined && latestTokenBalance >= 0) {
|
|
95588
|
-
this.storageAdapter.updateApiKeyBalance(baseUrl, latestTokenBalance);
|
|
95567
|
+
this.storageAdapter.updateApiKeyBalance(baseUrl, latestTokenBalance, latestReservedBalance);
|
|
95589
95568
|
this.storageAdapter.touchApiKeyLastUsed(baseUrl);
|
|
95590
95569
|
}
|
|
95591
95570
|
}
|
|
@@ -95839,13 +95818,14 @@ var RoutstrClient = class {
|
|
|
95839
95818
|
const latestBalanceInfo = await this.balanceManager.getTokenBalance(token, baseUrl);
|
|
95840
95819
|
this._log("DEBUG", "LATEST Balance", latestBalanceInfo.amount, latestBalanceInfo.reserved, latestBalanceInfo.apiKey, baseUrl);
|
|
95841
95820
|
const latestTokenBalance = latestBalanceInfo.balanceUnknown ? undefined : latestBalanceInfo.unit === "msat" ? latestBalanceInfo.amount / 1000 : latestBalanceInfo.amount;
|
|
95821
|
+
const latestReservedBalance = latestBalanceInfo.balanceUnknown ? undefined : latestBalanceInfo.unit === "msat" ? latestBalanceInfo.reserved / 1000 : latestBalanceInfo.reserved;
|
|
95842
95822
|
const storedApiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
|
|
95843
95823
|
if (storedApiKeyEntry?.key.startsWith("cashu") && latestBalanceInfo.apiKey) {
|
|
95844
95824
|
this.storageAdapter.removeApiKey(baseUrl);
|
|
95845
95825
|
this.storageAdapter.setApiKey(baseUrl, latestBalanceInfo.apiKey);
|
|
95846
95826
|
}
|
|
95847
95827
|
if (latestTokenBalance !== undefined) {
|
|
95848
|
-
this.storageAdapter.updateApiKeyBalance(baseUrl, latestTokenBalance);
|
|
95828
|
+
this.storageAdapter.updateApiKeyBalance(baseUrl, latestTokenBalance, latestReservedBalance);
|
|
95849
95829
|
this.storageAdapter.touchApiKeyLastUsed(baseUrl);
|
|
95850
95830
|
}
|
|
95851
95831
|
satsSpent = latestTokenBalance !== undefined && !initialTokenBalanceUnknown ? Math.max(0, initialTokenBalance - latestTokenBalance) : fallbackSatsSpent ?? usage?.satsCost ?? this._headerSatsCost(response) ?? 0;
|
|
@@ -95961,6 +95941,72 @@ var RoutstrClient = class {
|
|
|
95961
95941
|
throw new InsufficientBalanceError(1, 0);
|
|
95962
95942
|
}
|
|
95963
95943
|
}
|
|
95944
|
+
_spinOffTopupIfNeeded(snapshot) {
|
|
95945
|
+
if (this.mode !== "apikeys" || !snapshot.token)
|
|
95946
|
+
return;
|
|
95947
|
+
if (snapshot.tokenBalanceUnknown)
|
|
95948
|
+
return;
|
|
95949
|
+
const snapshotSats = snapshot.tokenBalanceUnit === "msat" ? snapshot.tokenBalance / 1000 : snapshot.tokenBalance;
|
|
95950
|
+
const tokenReserved = snapshot.tokenReserved ?? 0;
|
|
95951
|
+
const snapshotReservedSats = snapshot.tokenBalanceUnit === "msat" ? tokenReserved / 1000 : tokenReserved;
|
|
95952
|
+
const snapshotAvailableSats = snapshotSats - snapshotReservedSats;
|
|
95953
|
+
const targetSats = snapshot.requiredSats * TOPUP_MARGIN;
|
|
95954
|
+
if (snapshotAvailableSats >= targetSats)
|
|
95955
|
+
return;
|
|
95956
|
+
const key = `${snapshot.baseUrl}:${snapshot.token}`;
|
|
95957
|
+
if (this._inflightTopups.has(key))
|
|
95958
|
+
return;
|
|
95959
|
+
this._log("DEBUG", `[RoutstrClient] _spinOffTopupIfNeeded: snapshot total=${snapshotSats} sat, reserved=${snapshotReservedSats} sat, available=${snapshotAvailableSats} sat < target=${targetSats} sat (required=${snapshot.requiredSats} x ${TOPUP_MARGIN}) for ${snapshot.baseUrl}; spinning off background topup`);
|
|
95960
|
+
this._topUpOnce(key, () => this._runProactiveTopup(snapshot)).catch((e13) => {
|
|
95961
|
+
this._log("WARN", `[RoutstrClient] _spinOffTopupIfNeeded: background topup crashed for ${snapshot.baseUrl}`, e13);
|
|
95962
|
+
});
|
|
95963
|
+
}
|
|
95964
|
+
async _runProactiveTopup(snapshot) {
|
|
95965
|
+
try {
|
|
95966
|
+
const tokenReserved = snapshot.tokenReserved ?? 0;
|
|
95967
|
+
const snapshotSats = snapshot.tokenBalanceUnit === "msat" ? snapshot.tokenBalance / 1000 : snapshot.tokenBalance;
|
|
95968
|
+
const reservedSats = snapshot.tokenBalanceUnit === "msat" ? tokenReserved / 1000 : tokenReserved;
|
|
95969
|
+
const availableSats = snapshotSats - reservedSats;
|
|
95970
|
+
const targetSats = snapshot.requiredSats * TOPUP_MARGIN;
|
|
95971
|
+
const shortfall = Math.max(0, targetSats - availableSats);
|
|
95972
|
+
if (shortfall <= 0) {
|
|
95973
|
+
this._log("DEBUG", `[RoutstrClient] _runProactiveTopup: snapshot for ${snapshot.baseUrl} is sufficient (available=${availableSats} sat >= target=${targetSats} sat); no topup needed`);
|
|
95974
|
+
return {
|
|
95975
|
+
success: true,
|
|
95976
|
+
message: "proactive topup skipped: balance sufficient on snapshot"
|
|
95977
|
+
};
|
|
95978
|
+
}
|
|
95979
|
+
const topupAmount = Math.max(shortfall, PROACTIVE_TOPUP_MIN_FRACTION * snapshot.requiredSats);
|
|
95980
|
+
const result = await this.balanceManager.topUp({
|
|
95981
|
+
mintUrl: snapshot.mintUrl,
|
|
95982
|
+
baseUrl: snapshot.baseUrl,
|
|
95983
|
+
amount: topupAmount,
|
|
95984
|
+
token: snapshot.token
|
|
95985
|
+
});
|
|
95986
|
+
this._log("DEBUG", `[RoutstrClient] _runProactiveTopup: result for ${snapshot.baseUrl}: success=${result.success}, amount=${topupAmount}, message=${result.message}`);
|
|
95987
|
+
if (result.success) {
|
|
95988
|
+
const added = result.toppedUpAmount ?? topupAmount;
|
|
95989
|
+
this.storageAdapter.updateApiKeyBalance(snapshot.baseUrl, Math.floor(snapshotSats + added), Math.floor(reservedSats));
|
|
95990
|
+
}
|
|
95991
|
+
return result;
|
|
95992
|
+
} catch (e13) {
|
|
95993
|
+
this._log("WARN", `[RoutstrClient] _runProactiveTopup: failed for ${snapshot.baseUrl}`, e13);
|
|
95994
|
+
return {
|
|
95995
|
+
success: false,
|
|
95996
|
+
message: `proactive topup failed: ${e13 instanceof Error ? e13.message : String(e13)}`
|
|
95997
|
+
};
|
|
95998
|
+
}
|
|
95999
|
+
}
|
|
96000
|
+
_topUpOnce(key, start) {
|
|
96001
|
+
const existing = this._inflightTopups.get(key);
|
|
96002
|
+
if (existing)
|
|
96003
|
+
return existing;
|
|
96004
|
+
const promise2 = start().finally(() => {
|
|
96005
|
+
this._inflightTopups.delete(key);
|
|
96006
|
+
});
|
|
96007
|
+
this._inflightTopups.set(key, promise2);
|
|
96008
|
+
return promise2;
|
|
96009
|
+
}
|
|
95964
96010
|
async _spendToken(params) {
|
|
95965
96011
|
const { mintUrl, amount, baseUrl, excludeMints = [] } = params;
|
|
95966
96012
|
this._log("DEBUG", `[RoutstrClient] _spendToken: mode=${this.mode}, amount=${amount}, baseUrl=${baseUrl}, mintUrl=${mintUrl}`);
|
|
@@ -96018,27 +96064,31 @@ var RoutstrClient = class {
|
|
|
96018
96064
|
this._log("DEBUG", `[RoutstrClient] _spendToken: Using existing API key for ${baseUrl}, key preview: ${parentApiKey.key}`);
|
|
96019
96065
|
}
|
|
96020
96066
|
let tokenBalance = 0;
|
|
96067
|
+
let tokenReserved = 0;
|
|
96021
96068
|
let tokenBalanceUnit = "sat";
|
|
96022
96069
|
let tokenBalanceUnknown = false;
|
|
96023
96070
|
const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
|
|
96024
96071
|
const distributionForBaseUrl = apiKeyDistribution.find((d) => d.baseUrl === baseUrl);
|
|
96025
96072
|
if (distributionForBaseUrl) {
|
|
96026
96073
|
tokenBalance = distributionForBaseUrl.amount;
|
|
96074
|
+
tokenReserved = distributionForBaseUrl.reserved ?? 0;
|
|
96027
96075
|
}
|
|
96028
96076
|
if (tokenBalance === 0 && parentApiKey) {
|
|
96029
96077
|
try {
|
|
96030
96078
|
const balanceInfo = await this.balanceManager.getTokenBalance(parentApiKey.key, baseUrl);
|
|
96031
96079
|
tokenBalance = balanceInfo.amount;
|
|
96080
|
+
tokenReserved = balanceInfo.reserved;
|
|
96032
96081
|
tokenBalanceUnit = balanceInfo.unit;
|
|
96033
96082
|
tokenBalanceUnknown = Boolean(balanceInfo.balanceUnknown);
|
|
96034
96083
|
} catch (e13) {
|
|
96035
96084
|
this._log("WARN", "Could not get initial API key balance:", e13);
|
|
96036
96085
|
}
|
|
96037
96086
|
}
|
|
96038
|
-
this._log("DEBUG", `[RoutstrClient] _spendToken: Returning token with balance=${tokenBalance} ${tokenBalanceUnit}`);
|
|
96087
|
+
this._log("DEBUG", `[RoutstrClient] _spendToken: Returning token with balance=${tokenBalance}, reserved=${tokenReserved} ${tokenBalanceUnit}`);
|
|
96039
96088
|
return {
|
|
96040
96089
|
token: parentApiKey?.key ?? "",
|
|
96041
96090
|
tokenBalance,
|
|
96091
|
+
tokenReserved,
|
|
96042
96092
|
tokenBalanceUnit,
|
|
96043
96093
|
tokenBalanceUnknown,
|
|
96044
96094
|
selectedMintUrl
|
|
@@ -96061,6 +96111,7 @@ var RoutstrClient = class {
|
|
|
96061
96111
|
return {
|
|
96062
96112
|
token: spendResult.token,
|
|
96063
96113
|
tokenBalance: spendResult.balance,
|
|
96114
|
+
tokenReserved: 0,
|
|
96064
96115
|
tokenBalanceUnit: spendResult.unit ?? "sat",
|
|
96065
96116
|
tokenBalanceUnknown: false,
|
|
96066
96117
|
selectedMintUrl: spendResult.selectedMintUrl
|
|
@@ -96341,6 +96392,7 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96341
96392
|
this.logger = (config2.logger ?? consoleLogger2).child("ModelManager");
|
|
96342
96393
|
this.eventStoreDbPath = config2.eventStoreDbPath;
|
|
96343
96394
|
this.persistentEventDatabaseFactory = config2.persistentEventDatabaseFactory;
|
|
96395
|
+
this.eventStore = config2.eventStore ?? null;
|
|
96344
96396
|
}
|
|
96345
96397
|
adapter;
|
|
96346
96398
|
cacheTTL;
|
|
@@ -96354,6 +96406,8 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96354
96406
|
providerNodePubkeysByUrl = /* @__PURE__ */ new Map;
|
|
96355
96407
|
relayPool = null;
|
|
96356
96408
|
eventStore = null;
|
|
96409
|
+
memoryEventStore = new EventStore({ verifyEvent });
|
|
96410
|
+
queryLastUpdate = /* @__PURE__ */ new Map;
|
|
96357
96411
|
eventStoreDb = null;
|
|
96358
96412
|
eventStoreInitPromise = null;
|
|
96359
96413
|
eventStoreDbPath;
|
|
@@ -96362,17 +96416,16 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96362
96416
|
return this.adapter.getBaseUrlsList();
|
|
96363
96417
|
}
|
|
96364
96418
|
async ensureEventStore() {
|
|
96365
|
-
if (!this.eventStoreDbPath)
|
|
96366
|
-
return null;
|
|
96367
96419
|
if (this.eventStore)
|
|
96368
96420
|
return this.eventStore;
|
|
96421
|
+
if (!this.eventStoreDbPath)
|
|
96422
|
+
return null;
|
|
96369
96423
|
if (!this.eventStoreInitPromise) {
|
|
96370
96424
|
this.eventStoreInitPromise = (async () => {
|
|
96371
96425
|
try {
|
|
96372
96426
|
const db = await this.createPersistentEventDatabase();
|
|
96373
96427
|
this.eventStoreDb = db;
|
|
96374
96428
|
this.eventStore = new EventStore({ database: db });
|
|
96375
|
-
this.initializeEventStoreMetadata();
|
|
96376
96429
|
this.logger.log(`Persistent event store initialized at ${this.eventStoreDbPath}`);
|
|
96377
96430
|
return this.eventStore;
|
|
96378
96431
|
} catch (error53) {
|
|
@@ -96401,34 +96454,40 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96401
96454
|
this.eventStoreDb = null;
|
|
96402
96455
|
this.eventStoreInitPromise = null;
|
|
96403
96456
|
}
|
|
96404
|
-
|
|
96405
|
-
|
|
96406
|
-
|
|
96407
|
-
|
|
96408
|
-
|
|
96409
|
-
|
|
96410
|
-
|
|
96411
|
-
const
|
|
96412
|
-
if (!
|
|
96413
|
-
|
|
96414
|
-
|
|
96415
|
-
|
|
96416
|
-
|
|
96417
|
-
|
|
96418
|
-
|
|
96419
|
-
|
|
96420
|
-
|
|
96421
|
-
|
|
96422
|
-
|
|
96423
|
-
|
|
96424
|
-
|
|
96425
|
-
|
|
96426
|
-
|
|
96427
|
-
|
|
96428
|
-
|
|
96429
|
-
|
|
96430
|
-
|
|
96431
|
-
|
|
96457
|
+
async getNostrEvents(filter16, forceRefresh = false, onEvent) {
|
|
96458
|
+
const eventStore = await this.ensureEventStore() ?? this.memoryEventStore;
|
|
96459
|
+
const query2 = JSON.stringify(filter16);
|
|
96460
|
+
const lastUpdate = this.queryLastUpdate.get(query2) ?? this.adapter.getNostrQueryLastUpdate?.()?.[query2];
|
|
96461
|
+
const now3 = Date.now();
|
|
96462
|
+
const cacheValid = typeof lastUpdate === "number" && lastUpdate <= now3 && now3 - lastUpdate <= this.cacheTTL;
|
|
96463
|
+
const received = /* @__PURE__ */ new Set;
|
|
96464
|
+
const cached2 = forceRefresh ? [] : eventStore.getTimeline(filter16).filter((event7) => this.isNostrEventTrustworthy(event7));
|
|
96465
|
+
if (forceRefresh || cached2.length === 0 || !cacheValid) {
|
|
96466
|
+
await this.collectNostrEvents(filter16, this.getNostrRelays(), NOSTR_QUERY_TIMEOUT_MS2, (event7) => {
|
|
96467
|
+
const stored = eventStore.add(event7);
|
|
96468
|
+
if (!stored || stored.id !== event7.id)
|
|
96469
|
+
return;
|
|
96470
|
+
received.add(event7.id);
|
|
96471
|
+
onEvent?.(event7);
|
|
96472
|
+
});
|
|
96473
|
+
if (received.size > 0) {
|
|
96474
|
+
this.queryLastUpdate.set(query2, Date.now());
|
|
96475
|
+
this.adapter.setNostrQueryLastUpdate?.({
|
|
96476
|
+
...this.adapter.getNostrQueryLastUpdate?.(),
|
|
96477
|
+
...Object.fromEntries(this.queryLastUpdate)
|
|
96478
|
+
});
|
|
96479
|
+
}
|
|
96480
|
+
const events = eventStore.getTimeline(filter16).filter((event7) => this.isNostrEventTrustworthy(event7));
|
|
96481
|
+
for (const event7 of events) {
|
|
96482
|
+
if (!received.has(event7.id))
|
|
96483
|
+
onEvent?.(event7);
|
|
96484
|
+
}
|
|
96485
|
+
return events;
|
|
96486
|
+
}
|
|
96487
|
+
for (const event7 of cached2) {
|
|
96488
|
+
onEvent?.(event7);
|
|
96489
|
+
}
|
|
96490
|
+
return cached2;
|
|
96432
96491
|
}
|
|
96433
96492
|
async refreshNostrEvents() {
|
|
96434
96493
|
const eventStore = await this.ensureEventStore();
|
|
@@ -96436,23 +96495,12 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96436
96495
|
this.logger.warn("refreshNostrEvents: no event store configured, skipping");
|
|
96437
96496
|
return;
|
|
96438
96497
|
}
|
|
96439
|
-
|
|
96440
|
-
|
|
96441
|
-
await this.
|
|
96442
|
-
await this.fetchLiveIntoStore({ kinds: [38425], limit: 500, authors: [this.routstrPubkey] }, relays3, timeoutMs);
|
|
96443
|
-
await this.fetchLiveIntoStore({ kinds: [38423], "#d": ["routstr-21-models"], authors: [this.routstrModelsPubkey] }, relays3, timeoutMs);
|
|
96498
|
+
await this.getNostrEvents({ kinds: [38421], limit: 100 }, true);
|
|
96499
|
+
await this.getNostrEvents({ kinds: [38425], limit: 500, authors: [this.routstrPubkey] }, true);
|
|
96500
|
+
await this.getNostrEvents({ kinds: [38423], "#d": ["routstr-21-models"], authors: [this.routstrModelsPubkey] }, true);
|
|
96444
96501
|
this.logger.log("refreshNostrEvents: live fetch complete");
|
|
96445
96502
|
await this.syncReviewedProvidersFromNostr();
|
|
96446
96503
|
}
|
|
96447
|
-
async fetchLiveIntoStore(filter16, relays3, timeoutMs) {
|
|
96448
|
-
const eventStore = await this.ensureEventStore();
|
|
96449
|
-
if (!eventStore)
|
|
96450
|
-
return;
|
|
96451
|
-
await this.collectNostrEvents(filter16, relays3, timeoutMs, (event7) => {
|
|
96452
|
-
eventStore.add(event7);
|
|
96453
|
-
this.markEventFetched(event7);
|
|
96454
|
-
});
|
|
96455
|
-
}
|
|
96456
96504
|
static async init(adapter, config2 = {}, options = {}) {
|
|
96457
96505
|
const manager = new _ModelManager2(adapter, config2);
|
|
96458
96506
|
const torMode = options.torMode ?? false;
|
|
@@ -96471,7 +96519,7 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96471
96519
|
const filteredCachedUrls = this.filterBaseUrlsForTor(cachedUrls, torMode);
|
|
96472
96520
|
await Promise.all([
|
|
96473
96521
|
this.fetchRoutstr21Models(forceRefresh),
|
|
96474
|
-
this.syncReviewedProvidersFromNostr(filteredCachedUrls
|
|
96522
|
+
this.syncReviewedProvidersFromNostr(filteredCachedUrls)
|
|
96475
96523
|
]);
|
|
96476
96524
|
return filteredCachedUrls;
|
|
96477
96525
|
}
|
|
@@ -96553,7 +96601,6 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96553
96601
|
});
|
|
96554
96602
|
}
|
|
96555
96603
|
async bootstrapFromNostr(kind, torMode, forceRefresh = false, options = {}) {
|
|
96556
|
-
const relays3 = this.getNostrRelays();
|
|
96557
96604
|
const bases = /* @__PURE__ */ new Set;
|
|
96558
96605
|
this.providerNodePubkeysByUrl = /* @__PURE__ */ new Map;
|
|
96559
96606
|
const excluded = new Set(this.excludeProviderUrls.map((url4) => this.normalizeUrl(url4)));
|
|
@@ -96609,19 +96656,7 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96609
96656
|
}
|
|
96610
96657
|
}
|
|
96611
96658
|
};
|
|
96612
|
-
|
|
96613
|
-
if (cached2.length > 0) {
|
|
96614
|
-
this.logger.log(`Using ${cached2.length} cached kind ${kind} events from persistent store`);
|
|
96615
|
-
for (const event7 of cached2) {
|
|
96616
|
-
collectFromEvent(event7);
|
|
96617
|
-
}
|
|
96618
|
-
} else {
|
|
96619
|
-
await this.collectNostrEvents({ kinds: [kind], limit: 100 }, relays3, NOSTR_QUERY_TIMEOUT_MS2, (event7) => {
|
|
96620
|
-
this.eventStore?.add(event7);
|
|
96621
|
-
this.markEventFetched(event7);
|
|
96622
|
-
collectFromEvent(event7);
|
|
96623
|
-
});
|
|
96624
|
-
}
|
|
96659
|
+
await this.getNostrEvents({ kinds: [kind], limit: 100 }, forceRefresh, collectFromEvent);
|
|
96625
96660
|
for (const url4 of this.includeProviderUrls) {
|
|
96626
96661
|
const normalized = this.normalizeUrl(url4);
|
|
96627
96662
|
if (!torMode || normalized.includes(".onion")) {
|
|
@@ -96670,25 +96705,25 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96670
96705
|
throw new ProviderBootstrapError2([], `Provider bootstrap failed: ${e13}`);
|
|
96671
96706
|
}
|
|
96672
96707
|
}
|
|
96673
|
-
async syncReviewedProvidersFromNostr(baseUrls = this.adapter.getBaseUrlsList(), providerNodes
|
|
96708
|
+
async syncReviewedProvidersFromNostr(baseUrls = this.adapter.getBaseUrlsList(), providerNodes, forceRefresh = false) {
|
|
96674
96709
|
if (baseUrls.length === 0)
|
|
96675
96710
|
return null;
|
|
96676
96711
|
if (!this.adapter.setDisabledProviders) {
|
|
96677
96712
|
this.logger.warn("NostrReviews: adapter does not support setDisabledProviders; skipping provider disable sync");
|
|
96678
96713
|
return null;
|
|
96679
96714
|
}
|
|
96680
|
-
if (providerNodes.size === 0) {
|
|
96681
|
-
providerNodes = await this.rebuildProviderNodesFromStore();
|
|
96715
|
+
if (!providerNodes || providerNodes.size === 0) {
|
|
96716
|
+
providerNodes = await this.rebuildProviderNodesFromStore(forceRefresh);
|
|
96717
|
+
if (!forceRefresh && providerNodes.size > 0 && baseUrls.some((url4) => !providerNodes.has(this.normalizeUrl(url4)))) {
|
|
96718
|
+
providerNodes = await this.rebuildProviderNodesFromStore(true);
|
|
96719
|
+
}
|
|
96682
96720
|
this.providerNodePubkeysByUrl = providerNodes;
|
|
96683
96721
|
}
|
|
96684
96722
|
const reviewLabels = await this.fetchReviewLabels(forceRefresh);
|
|
96685
96723
|
return this.applyReviewDisables(baseUrls, providerNodes, reviewLabels);
|
|
96686
96724
|
}
|
|
96687
|
-
async rebuildProviderNodesFromStore() {
|
|
96725
|
+
async rebuildProviderNodesFromStore(forceRefresh) {
|
|
96688
96726
|
const map23 = /* @__PURE__ */ new Map;
|
|
96689
|
-
const eventStore = await this.ensureEventStore();
|
|
96690
|
-
if (!eventStore)
|
|
96691
|
-
return map23;
|
|
96692
96727
|
const addNode = (url4, pubkey2) => {
|
|
96693
96728
|
if (!pubkey2)
|
|
96694
96729
|
return;
|
|
@@ -96697,7 +96732,7 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96697
96732
|
existing.add(pubkey2);
|
|
96698
96733
|
map23.set(normalized, existing);
|
|
96699
96734
|
};
|
|
96700
|
-
const events =
|
|
96735
|
+
const events = await this.getNostrEvents({ kinds: [38421], limit: 100 }, forceRefresh);
|
|
96701
96736
|
for (const event7 of events) {
|
|
96702
96737
|
const eventUrls = [];
|
|
96703
96738
|
for (const tag2 of event7.tags) {
|
|
@@ -96715,7 +96750,10 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96715
96750
|
const content3 = JSON.parse(event7.content);
|
|
96716
96751
|
const providers = Array.isArray(content3) ? content3 : content3.providers || [];
|
|
96717
96752
|
for (const p of providers) {
|
|
96718
|
-
const endpoints =
|
|
96753
|
+
const endpoints = [
|
|
96754
|
+
...this.getProviderEndpoints(p, false),
|
|
96755
|
+
...this.getProviderEndpoints(p, true)
|
|
96756
|
+
];
|
|
96719
96757
|
for (const endpoint of endpoints) {
|
|
96720
96758
|
addNode(endpoint, p?.pubkey || event7.pubkey);
|
|
96721
96759
|
}
|
|
@@ -96740,23 +96778,9 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96740
96778
|
}
|
|
96741
96779
|
}
|
|
96742
96780
|
};
|
|
96743
|
-
const
|
|
96744
|
-
|
|
96745
|
-
|
|
96746
|
-
for (const event7 of cached2) {
|
|
96747
|
-
collectFromEvent(event7);
|
|
96748
|
-
}
|
|
96749
|
-
} else {
|
|
96750
|
-
await this.collectNostrEvents({
|
|
96751
|
-
kinds: [38425],
|
|
96752
|
-
limit: 500,
|
|
96753
|
-
authors: [this.routstrPubkey]
|
|
96754
|
-
}, this.getNostrRelays(), NOSTR_QUERY_TIMEOUT_MS2, (event7) => {
|
|
96755
|
-
this.eventStore?.add(event7);
|
|
96756
|
-
this.markEventFetched(event7);
|
|
96757
|
-
collectFromEvent(event7);
|
|
96758
|
-
});
|
|
96759
|
-
}
|
|
96781
|
+
const events = await this.getNostrEvents({ kinds: [38425], limit: 500, authors: [this.routstrPubkey] }, forceRefresh);
|
|
96782
|
+
for (const event7 of events)
|
|
96783
|
+
collectFromEvent(event7);
|
|
96760
96784
|
const labels = /* @__PURE__ */ new Map;
|
|
96761
96785
|
for (const [node, event7] of latestByNode) {
|
|
96762
96786
|
const label = event7.tags.find((tag2) => tag2[0] === "t" && typeof tag2[1] === "string" && tag2[1])?.[1]?.toLowerCase();
|
|
@@ -96970,24 +96994,8 @@ var ModelManager2 = class _ModelManager2 {
|
|
|
96970
96994
|
return cachedModels;
|
|
96971
96995
|
}
|
|
96972
96996
|
}
|
|
96973
|
-
const
|
|
96974
|
-
const
|
|
96975
|
-
let event7 = null;
|
|
96976
|
-
if (cached2.length === 0) {
|
|
96977
|
-
await this.collectNostrEvents({
|
|
96978
|
-
kinds: [38423],
|
|
96979
|
-
"#d": ["routstr-21-models"],
|
|
96980
|
-
authors: [this.routstrModelsPubkey]
|
|
96981
|
-
}, relays3, NOSTR_QUERY_TIMEOUT_MS2, (e13) => {
|
|
96982
|
-
this.eventStore?.add(e13);
|
|
96983
|
-
this.markEventFetched(e13);
|
|
96984
|
-
if (!event7 || e13.created_at > event7.created_at)
|
|
96985
|
-
event7 = e13;
|
|
96986
|
-
});
|
|
96987
|
-
} else {
|
|
96988
|
-
this.logger.log(`Using ${cached2.length} cached kind 38423 events from persistent store`);
|
|
96989
|
-
event7 = cached2.reduce((latest, e13) => e13.created_at > latest.created_at ? e13 : latest, cached2[0]);
|
|
96990
|
-
}
|
|
96997
|
+
const events = await this.getNostrEvents({ kinds: [38423], "#d": ["routstr-21-models"], authors: [this.routstrModelsPubkey] }, forceRefresh);
|
|
96998
|
+
const event7 = events.reduce((latest, event22) => !latest || event22.created_at > latest.created_at ? event22 : latest, null);
|
|
96991
96999
|
if (!event7) {
|
|
96992
97000
|
return cachedModels.length > 0 ? cachedModels : [];
|
|
96993
97001
|
}
|
|
@@ -97141,7 +97149,9 @@ function parseArgs(argv) {
|
|
|
97141
97149
|
const portFlagIndex = argv.findIndex((arg) => arg === "--port");
|
|
97142
97150
|
const hostFlagIndex = argv.findIndex((arg) => arg === "--host");
|
|
97143
97151
|
const providerFlagIndex = argv.findIndex((arg) => arg === "--provider" || arg === "-p");
|
|
97144
|
-
const
|
|
97152
|
+
const portValue = portFlagIndex !== -1 ? argv[portFlagIndex + 1] : undefined;
|
|
97153
|
+
const parsedPort = portValue ? Number.parseInt(portValue, 10) : Number.NaN;
|
|
97154
|
+
const port = Number.isInteger(parsedPort) ? parsedPort : null;
|
|
97145
97155
|
const hostValue = hostFlagIndex !== -1 ? argv[hostFlagIndex + 1] : undefined;
|
|
97146
97156
|
const host = hostValue?.trim() || null;
|
|
97147
97157
|
const providerValue = providerFlagIndex !== -1 ? argv[providerFlagIndex + 1] : undefined;
|
|
@@ -97241,6 +97251,7 @@ function saveDaemonConfig(config2) {
|
|
|
97241
97251
|
|
|
97242
97252
|
// node_modules/@routstr/sdk/dist/storage/bun.mjs
|
|
97243
97253
|
var SDK_STORAGE_KEYS2 = {
|
|
97254
|
+
NOSTR_QUERY_LAST_UPDATE: "nostr_query_last_update",
|
|
97244
97255
|
MODELS_FROM_ALL_PROVIDERS: "modelsFromAllProviders",
|
|
97245
97256
|
LAST_USED_MODEL: "lastUsedModel",
|
|
97246
97257
|
BASE_URLS_LIST: "base_urls_list",
|
|
@@ -97350,6 +97361,7 @@ var createShardedDiscoveryAdapter = async (options) => {
|
|
|
97350
97361
|
}
|
|
97351
97362
|
await driver.setItem(MIGRATION_MARKER_KEY2, true);
|
|
97352
97363
|
const [
|
|
97364
|
+
rawNostrQueryLastUpdate,
|
|
97353
97365
|
rawMints,
|
|
97354
97366
|
rawInfo,
|
|
97355
97367
|
lastUsedModel,
|
|
@@ -97361,6 +97373,7 @@ var createShardedDiscoveryAdapter = async (options) => {
|
|
|
97361
97373
|
rawRoutstr21Models,
|
|
97362
97374
|
lastRoutstr21ModelsUpdate
|
|
97363
97375
|
] = await Promise.all([
|
|
97376
|
+
driver.getItem(SDK_STORAGE_KEYS2.NOSTR_QUERY_LAST_UPDATE, {}).catch(() => ({})),
|
|
97364
97377
|
driver.getItem(SDK_STORAGE_KEYS2.MINTS_FROM_ALL_PROVIDERS, {}),
|
|
97365
97378
|
driver.getItem(SDK_STORAGE_KEYS2.INFO_FROM_ALL_PROVIDERS, {}),
|
|
97366
97379
|
driver.getItem(SDK_STORAGE_KEYS2.LAST_USED_MODEL, null),
|
|
@@ -97420,6 +97433,7 @@ var createShardedDiscoveryAdapter = async (options) => {
|
|
|
97420
97433
|
entry
|
|
97421
97434
|
]));
|
|
97422
97435
|
let _lastUsedModel = lastUsedModel;
|
|
97436
|
+
let nostrQueryLastUpdate = rawNostrQueryLastUpdate;
|
|
97423
97437
|
let _disabledProviders = rawDisabled.map(normalizeBaseUrl42);
|
|
97424
97438
|
let _manuallyDisabledProviders = rawManuallyDisabled.map(normalizeBaseUrl42);
|
|
97425
97439
|
let _manuallyEnabledProviders = rawManuallyEnabled.map(normalizeBaseUrl42);
|
|
@@ -97431,6 +97445,11 @@ var createShardedDiscoveryAdapter = async (options) => {
|
|
|
97431
97445
|
driver.setItem(PROVIDER_INDEX_KEY, [...providerIndex]);
|
|
97432
97446
|
};
|
|
97433
97447
|
return {
|
|
97448
|
+
getNostrQueryLastUpdate: () => nostrQueryLastUpdate,
|
|
97449
|
+
setNostrQueryLastUpdate: (timestamps) => {
|
|
97450
|
+
nostrQueryLastUpdate = timestamps;
|
|
97451
|
+
driver.setItem(SDK_STORAGE_KEYS2.NOSTR_QUERY_LAST_UPDATE, timestamps).catch((error53) => console.warn("Failed to persist discovery query times", error53));
|
|
97452
|
+
},
|
|
97434
97453
|
getCachedModels: () => {
|
|
97435
97454
|
const result = {};
|
|
97436
97455
|
for (const [baseUrl, models] of modelsByBaseUrl.entries()) {
|
|
@@ -99117,7 +99136,7 @@ function Gr2(e22) {
|
|
|
99117
99136
|
return {
|
|
99118
99137
|
unit: t.unit || "sat",
|
|
99119
99138
|
mint: t.mint,
|
|
99120
|
-
amount:
|
|
99139
|
+
amount: q2(t.proofs),
|
|
99121
99140
|
...t.memo && { memo: t.memo },
|
|
99122
99141
|
incompleteProofs: t.proofs.map((e23) => {
|
|
99123
99142
|
let { id: t2, ...n } = e23;
|
|
@@ -99202,7 +99221,7 @@ function Zr2(e22) {
|
|
|
99202
99221
|
throw new _2("Mint URL path must not contain percent-encoded characters");
|
|
99203
99222
|
return t.href.replace(/\/+$/, "");
|
|
99204
99223
|
}
|
|
99205
|
-
function
|
|
99224
|
+
function q2(e22) {
|
|
99206
99225
|
return k2.sum(e22.map((e23) => e23.amount));
|
|
99207
99226
|
}
|
|
99208
99227
|
function ri2(e22, t, r) {
|
|
@@ -101691,10 +101710,10 @@ function invert6(number13, modulo) {
|
|
|
101691
101710
|
let b2 = modulo;
|
|
101692
101711
|
let x3 = _0n30, y2 = _1n30, u = _1n30, v4 = _0n30;
|
|
101693
101712
|
while (a !== _0n30) {
|
|
101694
|
-
const
|
|
101713
|
+
const q3 = b2 / a;
|
|
101695
101714
|
const r = b2 % a;
|
|
101696
|
-
const m = x3 - u *
|
|
101697
|
-
const n = y2 - v4 *
|
|
101715
|
+
const m = x3 - u * q3;
|
|
101716
|
+
const n = y2 - v4 * q3;
|
|
101698
101717
|
b2 = a, a = r, x3 = u, y2 = v4, u = m, v4 = n;
|
|
101699
101718
|
}
|
|
101700
101719
|
const gcd5 = b2;
|
|
@@ -102651,14 +102670,14 @@ function weierstrass6(curveDef) {
|
|
|
102651
102670
|
if (!isWithinCurveOrder(k3))
|
|
102652
102671
|
return;
|
|
102653
102672
|
const ik = invN(k3);
|
|
102654
|
-
const
|
|
102655
|
-
const r = modN4(
|
|
102673
|
+
const q3 = Point5.BASE.multiply(k3).toAffine();
|
|
102674
|
+
const r = modN4(q3.x);
|
|
102656
102675
|
if (r === _0n32)
|
|
102657
102676
|
return;
|
|
102658
102677
|
const s = modN4(ik * modN4(m + r * d));
|
|
102659
102678
|
if (s === _0n32)
|
|
102660
102679
|
return;
|
|
102661
|
-
let recovery = (
|
|
102680
|
+
let recovery = (q3.x === r ? 0 : 2) | Number(q3.y & _1n32);
|
|
102662
102681
|
let normS = s;
|
|
102663
102682
|
if (lowS && isBiggerThanHalfOrder(s)) {
|
|
102664
102683
|
normS = normalizeS(s);
|
|
@@ -112433,7 +112452,7 @@ function createCocodClient(options = {}) {
|
|
|
112433
112452
|
return message;
|
|
112434
112453
|
},
|
|
112435
112454
|
async receiveBolt11(amount, mintUrl) {
|
|
112436
|
-
return post("/receive/bolt11", { amount, mintUrl });
|
|
112455
|
+
return { invoice: await post("/receive/bolt11", { amount, mintUrl }) };
|
|
112437
112456
|
},
|
|
112438
112457
|
async sendCashu(amount, mintUrl) {
|
|
112439
112458
|
return post("/send/cashu", { amount, mintUrl });
|
|
@@ -112538,7 +112557,7 @@ function startAutoRefillLoop(cocod, getWallet, getConfig, intervalMs = 5000) {
|
|
|
112538
112557
|
return;
|
|
112539
112558
|
}
|
|
112540
112559
|
logger5.log(`[auto-refill] Creating BOLT-11 invoice for ${config2.amount} sats via ${mintUrl}...`);
|
|
112541
|
-
const invoice = await cocod.receiveBolt11(config2.amount, mintUrl);
|
|
112560
|
+
const { invoice } = await cocod.receiveBolt11(config2.amount, mintUrl);
|
|
112542
112561
|
logger5.log(`[auto-refill] Paying invoice via NWC...`);
|
|
112543
112562
|
const currentWallet = getWallet();
|
|
112544
112563
|
if (!currentWallet?.service) {
|
|
@@ -112691,7 +112710,7 @@ async function createWalletAdapter(options = {}) {
|
|
|
112691
112710
|
logger5.log("[nwc] Could not retrieve initial balance");
|
|
112692
112711
|
}
|
|
112693
112712
|
logger5.log(`[nwc] Creating ${amount}-sat Lightning invoice via cocod...`);
|
|
112694
|
-
const invoice = await client4.receiveBolt11(amount, mintUrl);
|
|
112713
|
+
const { invoice } = await client4.receiveBolt11(amount, mintUrl);
|
|
112695
112714
|
logger5.log(`[nwc] Invoice: ${invoice}`);
|
|
112696
112715
|
logger5.log("[nwc] Paying invoice via NWC...");
|
|
112697
112716
|
const { preimage, fees_paid } = await wallet.payInvoice(invoice);
|
|
@@ -113958,10 +113977,10 @@ var radixBaseN = (BASE, GROUP) => ({
|
|
|
113958
113977
|
let carry = 0;
|
|
113959
113978
|
for (let i8 = pos;i8 < nlimbs; i8++) {
|
|
113960
113979
|
const cur = carry * 65536 + limbs[i8];
|
|
113961
|
-
const
|
|
113962
|
-
carry = cur -
|
|
113963
|
-
limbs[i8] =
|
|
113964
|
-
if (
|
|
113980
|
+
const q3 = Math.floor(cur / GROUP);
|
|
113981
|
+
carry = cur - q3 * GROUP;
|
|
113982
|
+
limbs[i8] = q3;
|
|
113983
|
+
if (q3 === 0 && i8 === pos)
|
|
113965
113984
|
pos++;
|
|
113966
113985
|
}
|
|
113967
113986
|
groups.push(carry);
|
|
@@ -114301,9 +114320,9 @@ function invert7(number15, modulo) {
|
|
|
114301
114320
|
let b2 = modulo;
|
|
114302
114321
|
let x3 = _0n35, u = _1n35;
|
|
114303
114322
|
while (a !== _0n35) {
|
|
114304
|
-
const
|
|
114305
|
-
const r = b2 - a *
|
|
114306
|
-
const m = x3 - u *
|
|
114323
|
+
const q3 = b2 / a;
|
|
114324
|
+
const r = b2 - a * q3;
|
|
114325
|
+
const m = x3 - u * q3;
|
|
114307
114326
|
b2 = a, a = r, x3 = u, u = m;
|
|
114308
114327
|
}
|
|
114309
114328
|
const gcd6 = b2;
|
|
@@ -115908,8 +115927,8 @@ function ecdsa3(Point6, hash10, ecdsaOpts = {}) {
|
|
|
115908
115927
|
const k3 = bits2int(kBytes);
|
|
115909
115928
|
if (!Fn4.isValidNot0(k3))
|
|
115910
115929
|
return;
|
|
115911
|
-
const
|
|
115912
|
-
const r = Fn4.create(
|
|
115930
|
+
const q3 = Point6.BASE.multiply(k3).toAffine();
|
|
115931
|
+
const r = Fn4.create(q3.x);
|
|
115913
115932
|
if (r === _0n38)
|
|
115914
115933
|
return;
|
|
115915
115934
|
let s;
|
|
@@ -115925,7 +115944,7 @@ function ecdsa3(Point6, hash10, ecdsaOpts = {}) {
|
|
|
115925
115944
|
}
|
|
115926
115945
|
if (s === _0n38)
|
|
115927
115946
|
return;
|
|
115928
|
-
let recovery = getRecoveryBit(
|
|
115947
|
+
let recovery = getRecoveryBit(q3.x, q3.y, r);
|
|
115929
115948
|
let normS = s;
|
|
115930
115949
|
if (lowS && isBiggerThanHalfOrder(s)) {
|
|
115931
115950
|
normS = Fn4.neg(s);
|
|
@@ -115965,11 +115984,11 @@ function ecdsa3(Point6, hash10, ecdsaOpts = {}) {
|
|
|
115965
115984
|
const R = Point6.BASE.mulAddUnsafe(u1, P2, u2);
|
|
115966
115985
|
if (R.is0())
|
|
115967
115986
|
return false;
|
|
115968
|
-
const
|
|
115969
|
-
const v4 = Fn4.create(
|
|
115987
|
+
const q3 = R.toAffine();
|
|
115988
|
+
const v4 = Fn4.create(q3.x);
|
|
115970
115989
|
if (v4 !== r)
|
|
115971
115990
|
return false;
|
|
115972
|
-
if (format === "recovered" && sig.recovery !== getRecoveryBit(
|
|
115991
|
+
if (format === "recovered" && sig.recovery !== getRecoveryBit(q3.x, q3.y, r))
|
|
115973
115992
|
return false;
|
|
115974
115993
|
return true;
|
|
115975
115994
|
} catch (e29) {
|
|
@@ -118280,17 +118299,17 @@ function cr2(t) {
|
|
|
118280
118299
|
};
|
|
118281
118300
|
return t.d && (r.memo = t.d), r;
|
|
118282
118301
|
}
|
|
118283
|
-
function
|
|
118302
|
+
function lr(e31, t) {
|
|
118284
118303
|
let n = (t ?? []).map((e32) => typeof e32 == "string" ? e32 : e32.id), r = dr2(Or2(e31));
|
|
118285
|
-
return n && (r.proofs =
|
|
118304
|
+
return n && (r.proofs = Sr(r.proofs, n)), r;
|
|
118286
118305
|
}
|
|
118287
|
-
function
|
|
118306
|
+
function ur2(e31) {
|
|
118288
118307
|
e31 = Or2(e31);
|
|
118289
118308
|
let t = dr2(e31);
|
|
118290
118309
|
return {
|
|
118291
118310
|
unit: t.unit || "sat",
|
|
118292
118311
|
mint: t.mint,
|
|
118293
|
-
amount:
|
|
118312
|
+
amount: q3(t.proofs),
|
|
118294
118313
|
...t.memo && { memo: t.memo },
|
|
118295
118314
|
incompleteProofs: t.proofs.map((e32) => ({
|
|
118296
118315
|
secret: e32.secret,
|
|
@@ -118356,7 +118375,7 @@ function K5(...e31) {
|
|
|
118356
118375
|
function gr2(e31) {
|
|
118357
118376
|
return e31.replace(/\/$/, "");
|
|
118358
118377
|
}
|
|
118359
|
-
function
|
|
118378
|
+
function q3(e31) {
|
|
118360
118379
|
return D3.sum(e31.map((e32) => e32.amount)).toNumber();
|
|
118361
118380
|
}
|
|
118362
118381
|
var vr2 = class {
|
|
@@ -118415,7 +118434,7 @@ function br(e31) {
|
|
|
118415
118434
|
return delete t.dleq, t;
|
|
118416
118435
|
});
|
|
118417
118436
|
}
|
|
118418
|
-
function
|
|
118437
|
+
function Sr(e31, n) {
|
|
118419
118438
|
let r = (n ?? []).map((e32) => typeof e32 == "string" ? e32 : e32.id), i8 = [];
|
|
118420
118439
|
for (let n2 of e31) {
|
|
118421
118440
|
let e32;
|
|
@@ -121267,7 +121286,7 @@ var Xi = class e41 {
|
|
|
121267
121286
|
});
|
|
121268
121287
|
let l = [];
|
|
121269
121288
|
({ proofs: l } = s);
|
|
121270
|
-
let u = this.parseAmount(
|
|
121289
|
+
let u = this.parseAmount(q3(l), "prepareSwapToReceive", true);
|
|
121271
121290
|
this.failIf(u.isZero(), "Token contains no proofs", { proofs: l });
|
|
121272
121291
|
let d = this.getKeyset(r);
|
|
121273
121292
|
if (i8)
|
|
@@ -121289,7 +121308,7 @@ var Xi = class e41 {
|
|
|
121289
121308
|
}
|
|
121290
121309
|
sendOffline(e42, t, n) {
|
|
121291
121310
|
let r = this.normalizeAmount(e42, "sendOffline"), { requireDleq: i8 = false, includeFees: a = false, exactMatch: o = true } = n || {};
|
|
121292
|
-
i8 && (t = t.filter((e43) => e43.dleq != null)), this.failIf(
|
|
121311
|
+
i8 && (t = t.filter((e43) => e43.dleq != null)), this.failIf(q3(t) < r, "Not enough funds available to send");
|
|
121293
121312
|
let { keep: s, send: c } = this.selectProofsToSend(t, r, a, o);
|
|
121294
121313
|
return {
|
|
121295
121314
|
keep: s,
|
|
@@ -121313,7 +121332,7 @@ var Xi = class e41 {
|
|
|
121313
121332
|
exactMatch: true,
|
|
121314
121333
|
requireDleq: false
|
|
121315
121334
|
}), l = o ? this.getFeesForProofs(c) : 0;
|
|
121316
|
-
if (
|
|
121335
|
+
if (q3(c) === i8 + l)
|
|
121317
121336
|
return this._logger.info("Successful exactMatch offline selection!"), {
|
|
121318
121337
|
keep: s2,
|
|
121319
121338
|
send: c
|
|
@@ -121334,7 +121353,7 @@ var Xi = class e41 {
|
|
|
121334
121353
|
let c = this.getKeyset(a), l = this.configureOutputs(i8, c, r.send ?? this.defaultOutputType(), o), u = this.preparedTotal(l), { keep: d, send: f } = this.selectProofsToSend(t, u, true);
|
|
121335
121354
|
if (f.length === 0)
|
|
121336
121355
|
throw Error("Not enough funds available to send");
|
|
121337
|
-
let p = D3.from(
|
|
121356
|
+
let p = D3.from(q3(f)), m = this.getFeesForProofs(f), h3 = u.add(m);
|
|
121338
121357
|
p.lessThan(h3) && this.failIf(true, "Not enough funds available for swap", {
|
|
121339
121358
|
selectedSum: p.toString(),
|
|
121340
121359
|
required: h3.toString()
|
|
@@ -121434,7 +121453,7 @@ var Xi = class e41 {
|
|
|
121434
121453
|
});
|
|
121435
121454
|
}
|
|
121436
121455
|
decodeToken(e42) {
|
|
121437
|
-
return
|
|
121456
|
+
return lr(e42, this._keyChain.getAllKeysetIds());
|
|
121438
121457
|
}
|
|
121439
121458
|
async batchRestore(e42 = 300, t = 100, n = 0, r) {
|
|
121440
121459
|
let i8 = Math.ceil(e42 / t), a = [], o, s = 0;
|
|
@@ -121634,7 +121653,7 @@ var Xi = class e41 {
|
|
|
121634
121653
|
}
|
|
121635
121654
|
async prepareMelt(e42, t, n, r, i8) {
|
|
121636
121655
|
i8 = i8 ?? this.defaultOutputType();
|
|
121637
|
-
let { keysetId: a, onChangeOutputsCreated: o, onCountersReserved: s } = r || {}, c = this.getKeyset(a), l =
|
|
121656
|
+
let { keysetId: a, onChangeOutputsCreated: o, onCountersReserved: s } = r || {}, c = this.getKeyset(a), l = q3(n), u = l - t.amount, d = [];
|
|
121638
121657
|
if (this.failIf(u < 0, "Not enough proofs to cover amount + fee reserve", {
|
|
121639
121658
|
sendAmount: l,
|
|
121640
121659
|
quoteAmount: t.amount
|
|
@@ -125386,7 +125405,7 @@ var TokenService = class {
|
|
|
125386
125405
|
}
|
|
125387
125406
|
try {
|
|
125388
125407
|
const keysetIds = mintKeysets.map((keyset) => keyset.id);
|
|
125389
|
-
return typeof token === "string" ?
|
|
125408
|
+
return typeof token === "string" ? lr(token, keysetIds) : token;
|
|
125390
125409
|
} catch (err) {
|
|
125391
125410
|
const errMsg = err instanceof Error ? err.message : "Unknown error during token decoding";
|
|
125392
125411
|
this.logger?.warn("Failed to decode token", {
|
|
@@ -127612,7 +127631,7 @@ var ReceiveOperationService = class {
|
|
|
127612
127631
|
}
|
|
127613
127632
|
extractMintUrl(token) {
|
|
127614
127633
|
try {
|
|
127615
|
-
return normalizeMintUrl(typeof token === "string" ?
|
|
127634
|
+
return normalizeMintUrl(typeof token === "string" ? ur2(token).mint : token.mint);
|
|
127616
127635
|
} catch (err) {
|
|
127617
127636
|
this.logger?.warn("Failed to decode token for receive", { err });
|
|
127618
127637
|
throw new ProofValidationError("Invalid token");
|
|
@@ -127997,10 +128016,10 @@ var PollingTransport = class {
|
|
|
127997
128016
|
subToYs = /* @__PURE__ */ new Map;
|
|
127998
128017
|
this.subToYsByMint.set(mintUrl, subToYs);
|
|
127999
128018
|
}
|
|
128000
|
-
let
|
|
128001
|
-
if (!
|
|
128002
|
-
|
|
128003
|
-
this.proofQueueByMint.set(mintUrl,
|
|
128019
|
+
let q4 = this.proofQueueByMint.get(mintUrl);
|
|
128020
|
+
if (!q4) {
|
|
128021
|
+
q4 = [];
|
|
128022
|
+
this.proofQueueByMint.set(mintUrl, q4);
|
|
128004
128023
|
}
|
|
128005
128024
|
let set2 = this.proofSetByMint.get(mintUrl);
|
|
128006
128025
|
if (!set2) {
|
|
@@ -128022,7 +128041,7 @@ var PollingTransport = class {
|
|
|
128022
128041
|
subs.add(subId);
|
|
128023
128042
|
if (!set2.has(y2)) {
|
|
128024
128043
|
set2.add(y2);
|
|
128025
|
-
|
|
128044
|
+
q4.push(y2);
|
|
128026
128045
|
}
|
|
128027
128046
|
}
|
|
128028
128047
|
if (!scheduler.hasProofBatchTask) {
|
|
@@ -128071,7 +128090,7 @@ var PollingTransport = class {
|
|
|
128071
128090
|
unsubscribed.add(subId);
|
|
128072
128091
|
const subToYs = this.subToYsByMint.get(mintUrl);
|
|
128073
128092
|
const yToSubs = this.yToSubsByMint.get(mintUrl);
|
|
128074
|
-
const
|
|
128093
|
+
const q4 = this.proofQueueByMint.get(mintUrl);
|
|
128075
128094
|
const set2 = this.proofSetByMint.get(mintUrl);
|
|
128076
128095
|
if (subToYs && yToSubs) {
|
|
128077
128096
|
const ys = subToYs.get(subId);
|
|
@@ -128084,10 +128103,10 @@ var PollingTransport = class {
|
|
|
128084
128103
|
yToSubs.delete(y2);
|
|
128085
128104
|
if (set2)
|
|
128086
128105
|
set2.delete(y2);
|
|
128087
|
-
if (
|
|
128088
|
-
const idx =
|
|
128106
|
+
if (q4) {
|
|
128107
|
+
const idx = q4.indexOf(y2);
|
|
128089
128108
|
if (idx >= 0)
|
|
128090
|
-
|
|
128109
|
+
q4.splice(idx, 1);
|
|
128091
128110
|
}
|
|
128092
128111
|
}
|
|
128093
128112
|
}
|
|
@@ -130271,7 +130290,7 @@ var WalletApi = class {
|
|
|
130271
130290
|
async decodeToken(tokenString, mintUrl) {
|
|
130272
130291
|
if (mintUrl)
|
|
130273
130292
|
return await this.tokenService.decodeToken(tokenString, mintUrl);
|
|
130274
|
-
const metadata =
|
|
130293
|
+
const metadata = ur2(tokenString);
|
|
130275
130294
|
return (await this.walletService.getWallet(metadata.mint)).decodeToken(tokenString);
|
|
130276
130295
|
}
|
|
130277
130296
|
encodeToken(token, opts) {
|
|
@@ -132285,10 +132304,10 @@ function invert8(number15, modulo) {
|
|
|
132285
132304
|
let b2 = modulo;
|
|
132286
132305
|
let x4 = _0n41, y2 = _1n39, u = _1n39, v4 = _0n41;
|
|
132287
132306
|
while (a !== _0n41) {
|
|
132288
|
-
const
|
|
132307
|
+
const q4 = b2 / a;
|
|
132289
132308
|
const r = b2 % a;
|
|
132290
|
-
const m = x4 - u *
|
|
132291
|
-
const n = y2 - v4 *
|
|
132309
|
+
const m = x4 - u * q4;
|
|
132310
|
+
const n = y2 - v4 * q4;
|
|
132292
132311
|
b2 = a, a = r, x4 = u, y2 = v4, u = m, v4 = n;
|
|
132293
132312
|
}
|
|
132294
132313
|
const gcd6 = b2;
|
|
@@ -133662,14 +133681,14 @@ function ecdsa4(Point7, hash10, ecdsaOpts = {}) {
|
|
|
133662
133681
|
if (!Fn6.isValidNot0(k4))
|
|
133663
133682
|
return;
|
|
133664
133683
|
const ik = Fn6.inv(k4);
|
|
133665
|
-
const
|
|
133666
|
-
const r = Fn6.create(
|
|
133684
|
+
const q4 = Point7.BASE.multiply(k4).toAffine();
|
|
133685
|
+
const r = Fn6.create(q4.x);
|
|
133667
133686
|
if (r === _0n43)
|
|
133668
133687
|
return;
|
|
133669
133688
|
const s = Fn6.create(ik * Fn6.create(m + r * d));
|
|
133670
133689
|
if (s === _0n43)
|
|
133671
133690
|
return;
|
|
133672
|
-
let recovery = (
|
|
133691
|
+
let recovery = (q4.x === r ? 0 : 2) | Number(q4.y & _1n41);
|
|
133673
133692
|
let normS = s;
|
|
133674
133693
|
if (lowS && isBiggerThanHalfOrder(s)) {
|
|
133675
133694
|
normS = Fn6.neg(s);
|
|
@@ -139832,8 +139851,19 @@ function createDaemonRequestHandler(deps) {
|
|
|
139832
139851
|
const body = await readJsonBody(req);
|
|
139833
139852
|
const amount = getRequiredPositiveNumberField(body, "amount");
|
|
139834
139853
|
const mintUrl = optionalStringField(body, "mintUrl");
|
|
139835
|
-
const invoice = await deps.walletClient.receiveBolt11(amount, mintUrl);
|
|
139836
|
-
return { output: { invoice, amount, mintUrl } };
|
|
139854
|
+
const { invoice, operationId } = await deps.walletClient.receiveBolt11(amount, mintUrl);
|
|
139855
|
+
return { output: { invoice, operationId, amount, mintUrl } };
|
|
139856
|
+
});
|
|
139857
|
+
return;
|
|
139858
|
+
}
|
|
139859
|
+
const mintQuoteMatch = url5.pathname.match(/^\/wallet\/receive\/bolt11\/([^/]+)$/);
|
|
139860
|
+
if (req.method === "GET" && mintQuoteMatch?.[1]) {
|
|
139861
|
+
const operationId = decodeURIComponent(mintQuoteMatch[1]);
|
|
139862
|
+
await respond(res, async () => {
|
|
139863
|
+
const quote = await deps.walletClient.getMintQuote?.(operationId);
|
|
139864
|
+
if (!quote)
|
|
139865
|
+
throw new CocodHttpError(404, "Mint quote not found");
|
|
139866
|
+
return { output: quote };
|
|
139837
139867
|
});
|
|
139838
139868
|
return;
|
|
139839
139869
|
}
|
|
@@ -140069,6 +140099,22 @@ function createDaemonRequestHandler(deps) {
|
|
|
140069
140099
|
});
|
|
140070
140100
|
return;
|
|
140071
140101
|
}
|
|
140102
|
+
if (req.method === "POST" && url5.pathname === "/settings/auto-refresh") {
|
|
140103
|
+
await respond(res, async () => {
|
|
140104
|
+
const body = await readJsonBody(req);
|
|
140105
|
+
const enabled = body.enabled === true || body.enabled === "true";
|
|
140106
|
+
const config2 = await loadDaemonConfig();
|
|
140107
|
+
config2.autoRefresh = { ...config2.autoRefresh, enabled };
|
|
140108
|
+
saveDaemonConfig(config2);
|
|
140109
|
+
return {
|
|
140110
|
+
output: {
|
|
140111
|
+
message: `Automatic refresh ${enabled ? "enabled" : "disabled"}.`,
|
|
140112
|
+
autoRefresh: config2.autoRefresh
|
|
140113
|
+
}
|
|
140114
|
+
};
|
|
140115
|
+
});
|
|
140116
|
+
return;
|
|
140117
|
+
}
|
|
140072
140118
|
if (req.method === "GET" && url5.pathname === "/models") {
|
|
140073
140119
|
try {
|
|
140074
140120
|
const forceRefresh = url5.searchParams.get("refresh")?.toLowerCase() === "true";
|
|
@@ -144748,10 +144794,10 @@ function invert9(number15, modulo) {
|
|
|
144748
144794
|
let b2 = modulo;
|
|
144749
144795
|
let x4 = _0n46, y2 = _1n43, u = _1n43, v4 = _0n46;
|
|
144750
144796
|
while (a !== _0n46) {
|
|
144751
|
-
const
|
|
144797
|
+
const q4 = b2 / a;
|
|
144752
144798
|
const r = b2 % a;
|
|
144753
|
-
const m = x4 - u *
|
|
144754
|
-
const n = y2 - v4 *
|
|
144799
|
+
const m = x4 - u * q4;
|
|
144800
|
+
const n = y2 - v4 * q4;
|
|
144755
144801
|
b2 = a, a = r, x4 = u, y2 = v4, u = m, v4 = n;
|
|
144756
144802
|
}
|
|
144757
144803
|
const gcd8 = b2;
|
|
@@ -146249,7 +146295,7 @@ class E3 {
|
|
|
146249
146295
|
return e43.length - t.length;
|
|
146250
146296
|
}
|
|
146251
146297
|
}
|
|
146252
|
-
function
|
|
146298
|
+
function q4(r) {
|
|
146253
146299
|
return E3.fromBase64(r);
|
|
146254
146300
|
}
|
|
146255
146301
|
function $2(r) {
|
|
@@ -146539,7 +146585,7 @@ class w4 {
|
|
|
146539
146585
|
throw new Error("unsupported pr: invalid prefix");
|
|
146540
146586
|
if (e43[4] !== "A")
|
|
146541
146587
|
throw new Error("unsupported pr version");
|
|
146542
|
-
const t = e43.slice(5), n =
|
|
146588
|
+
const t = e43.slice(5), n = q4(t), s = B3(n);
|
|
146543
146589
|
return this.fromRawRequest(s);
|
|
146544
146590
|
}
|
|
146545
146591
|
}
|
|
@@ -148210,17 +148256,17 @@ function cr3(t) {
|
|
|
148210
148256
|
};
|
|
148211
148257
|
return t.d && (r.memo = t.d), r;
|
|
148212
148258
|
}
|
|
148213
|
-
function
|
|
148259
|
+
function lr2(e45, t) {
|
|
148214
148260
|
let n = (t ?? []).map((e46) => typeof e46 == "string" ? e46 : e46.id), r = dr3(Or3(e45));
|
|
148215
|
-
return n && (r.proofs =
|
|
148261
|
+
return n && (r.proofs = Sr2(r.proofs, n)), r;
|
|
148216
148262
|
}
|
|
148217
|
-
function
|
|
148263
|
+
function ur3(e45) {
|
|
148218
148264
|
e45 = Or3(e45);
|
|
148219
148265
|
let t = dr3(e45);
|
|
148220
148266
|
return {
|
|
148221
148267
|
unit: t.unit || "sat",
|
|
148222
148268
|
mint: t.mint,
|
|
148223
|
-
amount:
|
|
148269
|
+
amount: q5(t.proofs),
|
|
148224
148270
|
...t.memo && { memo: t.memo },
|
|
148225
148271
|
incompleteProofs: t.proofs.map((e46) => ({
|
|
148226
148272
|
secret: e46.secret,
|
|
@@ -148286,7 +148332,7 @@ function K7(...e45) {
|
|
|
148286
148332
|
function gr3(e45) {
|
|
148287
148333
|
return e45.replace(/\/$/, "");
|
|
148288
148334
|
}
|
|
148289
|
-
function
|
|
148335
|
+
function q5(e45) {
|
|
148290
148336
|
return D5.sum(e45.map((e46) => e46.amount)).toNumber();
|
|
148291
148337
|
}
|
|
148292
148338
|
var vr3 = class {
|
|
@@ -148345,7 +148391,7 @@ function br2(e45) {
|
|
|
148345
148391
|
return delete t.dleq, t;
|
|
148346
148392
|
});
|
|
148347
148393
|
}
|
|
148348
|
-
function
|
|
148394
|
+
function Sr2(e45, n) {
|
|
148349
148395
|
let r = (n ?? []).map((e46) => typeof e46 == "string" ? e46 : e46.id), i10 = [];
|
|
148350
148396
|
for (let n2 of e45) {
|
|
148351
148397
|
let e46;
|
|
@@ -151197,7 +151243,7 @@ var Xi2 = class e55 {
|
|
|
151197
151243
|
});
|
|
151198
151244
|
let l2 = [];
|
|
151199
151245
|
({ proofs: l2 } = s);
|
|
151200
|
-
let u = this.parseAmount(
|
|
151246
|
+
let u = this.parseAmount(q5(l2), "prepareSwapToReceive", true);
|
|
151201
151247
|
this.failIf(u.isZero(), "Token contains no proofs", { proofs: l2 });
|
|
151202
151248
|
let d2 = this.getKeyset(r);
|
|
151203
151249
|
if (i10)
|
|
@@ -151219,7 +151265,7 @@ var Xi2 = class e55 {
|
|
|
151219
151265
|
}
|
|
151220
151266
|
sendOffline(e56, t, n) {
|
|
151221
151267
|
let r = this.normalizeAmount(e56, "sendOffline"), { requireDleq: i10 = false, includeFees: a = false, exactMatch: o = true } = n || {};
|
|
151222
|
-
i10 && (t = t.filter((e57) => e57.dleq != null)), this.failIf(
|
|
151268
|
+
i10 && (t = t.filter((e57) => e57.dleq != null)), this.failIf(q5(t) < r, "Not enough funds available to send");
|
|
151223
151269
|
let { keep: s, send: c } = this.selectProofsToSend(t, r, a, o);
|
|
151224
151270
|
return {
|
|
151225
151271
|
keep: s,
|
|
@@ -151243,7 +151289,7 @@ var Xi2 = class e55 {
|
|
|
151243
151289
|
exactMatch: true,
|
|
151244
151290
|
requireDleq: false
|
|
151245
151291
|
}), l2 = o ? this.getFeesForProofs(c) : 0;
|
|
151246
|
-
if (
|
|
151292
|
+
if (q5(c) === i10 + l2)
|
|
151247
151293
|
return this._logger.info("Successful exactMatch offline selection!"), {
|
|
151248
151294
|
keep: s2,
|
|
151249
151295
|
send: c
|
|
@@ -151264,7 +151310,7 @@ var Xi2 = class e55 {
|
|
|
151264
151310
|
let c = this.getKeyset(a), l2 = this.configureOutputs(i10, c, r.send ?? this.defaultOutputType(), o), u = this.preparedTotal(l2), { keep: d2, send: f2 } = this.selectProofsToSend(t, u, true);
|
|
151265
151311
|
if (f2.length === 0)
|
|
151266
151312
|
throw Error("Not enough funds available to send");
|
|
151267
|
-
let p2 = D5.from(
|
|
151313
|
+
let p2 = D5.from(q5(f2)), m2 = this.getFeesForProofs(f2), h5 = u.add(m2);
|
|
151268
151314
|
p2.lessThan(h5) && this.failIf(true, "Not enough funds available for swap", {
|
|
151269
151315
|
selectedSum: p2.toString(),
|
|
151270
151316
|
required: h5.toString()
|
|
@@ -151364,7 +151410,7 @@ var Xi2 = class e55 {
|
|
|
151364
151410
|
});
|
|
151365
151411
|
}
|
|
151366
151412
|
decodeToken(e56) {
|
|
151367
|
-
return
|
|
151413
|
+
return lr2(e56, this._keyChain.getAllKeysetIds());
|
|
151368
151414
|
}
|
|
151369
151415
|
async batchRestore(e56 = 300, t = 100, n = 0, r) {
|
|
151370
151416
|
let i10 = Math.ceil(e56 / t), a = [], o, s = 0;
|
|
@@ -151564,7 +151610,7 @@ var Xi2 = class e55 {
|
|
|
151564
151610
|
}
|
|
151565
151611
|
async prepareMelt(e56, t, n, r, i10) {
|
|
151566
151612
|
i10 = i10 ?? this.defaultOutputType();
|
|
151567
|
-
let { keysetId: a, onChangeOutputsCreated: o, onCountersReserved: s } = r || {}, c = this.getKeyset(a), l2 =
|
|
151613
|
+
let { keysetId: a, onChangeOutputsCreated: o, onCountersReserved: s } = r || {}, c = this.getKeyset(a), l2 = q5(n), u = l2 - t.amount, d2 = [];
|
|
151568
151614
|
if (this.failIf(u < 0, "Not enough proofs to cover amount + fee reserve", {
|
|
151569
151615
|
sendAmount: l2,
|
|
151570
151616
|
quoteAmount: t.amount
|
|
@@ -154084,7 +154130,7 @@ var TransactionService = class {
|
|
|
154084
154130
|
async receive(token) {
|
|
154085
154131
|
let mint;
|
|
154086
154132
|
try {
|
|
154087
|
-
mint = typeof token === "string" ?
|
|
154133
|
+
mint = typeof token === "string" ? ur3(token).mint : token.mint;
|
|
154088
154134
|
} catch (err) {
|
|
154089
154135
|
this.logger?.warn("Failed to decode token for receive", { err });
|
|
154090
154136
|
throw new ProofValidationError2("Invalid token");
|
|
@@ -154095,7 +154141,7 @@ var TransactionService = class {
|
|
|
154095
154141
|
const { keysets } = await this.mintService.ensureUpdatedMint(mint);
|
|
154096
154142
|
const { wallet } = await this.walletService.getWalletWithActiveKeysetId(mint);
|
|
154097
154143
|
const keysetIds = keysets.map((keyset) => keyset.id);
|
|
154098
|
-
let proofs = typeof token === "string" ?
|
|
154144
|
+
let proofs = typeof token === "string" ? lr2(token, keysetIds).proofs : token.proofs;
|
|
154099
154145
|
proofs = await this.proofService.prepareProofsForReceiving(proofs);
|
|
154100
154146
|
if (!Array.isArray(proofs) || proofs.length === 0) {
|
|
154101
154147
|
this.logger?.warn("Token contains no proofs", { mint });
|
|
@@ -155373,7 +155419,7 @@ var TokenService2 = class {
|
|
|
155373
155419
|
}
|
|
155374
155420
|
try {
|
|
155375
155421
|
const keysetIds = mintKeysets.map((keyset) => keyset.id);
|
|
155376
|
-
return typeof token === "string" ?
|
|
155422
|
+
return typeof token === "string" ? lr2(token, keysetIds) : token;
|
|
155377
155423
|
} catch (err) {
|
|
155378
155424
|
const errMsg = err instanceof Error ? err.message : "Unknown error during token decoding";
|
|
155379
155425
|
this.logger?.warn("Failed to decode token", {
|
|
@@ -157543,7 +157589,7 @@ var ReceiveOperationService2 = class {
|
|
|
157543
157589
|
}
|
|
157544
157590
|
extractMintUrl(token) {
|
|
157545
157591
|
try {
|
|
157546
|
-
return normalizeMintUrl2(typeof token === "string" ?
|
|
157592
|
+
return normalizeMintUrl2(typeof token === "string" ? ur3(token).mint : token.mint);
|
|
157547
157593
|
} catch (err) {
|
|
157548
157594
|
this.logger?.warn("Failed to decode token for receive", { err });
|
|
157549
157595
|
throw new ProofValidationError2("Invalid token");
|
|
@@ -157928,10 +157974,10 @@ var PollingTransport2 = class {
|
|
|
157928
157974
|
subToYs = /* @__PURE__ */ new Map;
|
|
157929
157975
|
this.subToYsByMint.set(mintUrl, subToYs);
|
|
157930
157976
|
}
|
|
157931
|
-
let
|
|
157932
|
-
if (!
|
|
157933
|
-
|
|
157934
|
-
this.proofQueueByMint.set(mintUrl,
|
|
157977
|
+
let q6 = this.proofQueueByMint.get(mintUrl);
|
|
157978
|
+
if (!q6) {
|
|
157979
|
+
q6 = [];
|
|
157980
|
+
this.proofQueueByMint.set(mintUrl, q6);
|
|
157935
157981
|
}
|
|
157936
157982
|
let set2 = this.proofSetByMint.get(mintUrl);
|
|
157937
157983
|
if (!set2) {
|
|
@@ -157953,7 +157999,7 @@ var PollingTransport2 = class {
|
|
|
157953
157999
|
subs.add(subId);
|
|
157954
158000
|
if (!set2.has(y2)) {
|
|
157955
158001
|
set2.add(y2);
|
|
157956
|
-
|
|
158002
|
+
q6.push(y2);
|
|
157957
158003
|
}
|
|
157958
158004
|
}
|
|
157959
158005
|
if (!scheduler.hasProofBatchTask) {
|
|
@@ -158002,7 +158048,7 @@ var PollingTransport2 = class {
|
|
|
158002
158048
|
unsubscribed.add(subId);
|
|
158003
158049
|
const subToYs = this.subToYsByMint.get(mintUrl);
|
|
158004
158050
|
const yToSubs = this.yToSubsByMint.get(mintUrl);
|
|
158005
|
-
const
|
|
158051
|
+
const q6 = this.proofQueueByMint.get(mintUrl);
|
|
158006
158052
|
const set2 = this.proofSetByMint.get(mintUrl);
|
|
158007
158053
|
if (subToYs && yToSubs) {
|
|
158008
158054
|
const ys = subToYs.get(subId);
|
|
@@ -158015,10 +158061,10 @@ var PollingTransport2 = class {
|
|
|
158015
158061
|
yToSubs.delete(y2);
|
|
158016
158062
|
if (set2)
|
|
158017
158063
|
set2.delete(y2);
|
|
158018
|
-
if (
|
|
158019
|
-
const idx =
|
|
158064
|
+
if (q6) {
|
|
158065
|
+
const idx = q6.indexOf(y2);
|
|
158020
158066
|
if (idx >= 0)
|
|
158021
|
-
|
|
158067
|
+
q6.splice(idx, 1);
|
|
158022
158068
|
}
|
|
158023
158069
|
}
|
|
158024
158070
|
}
|
|
@@ -160210,7 +160256,7 @@ var WalletApi2 = class {
|
|
|
160210
160256
|
async decodeToken(tokenString, mintUrl) {
|
|
160211
160257
|
if (mintUrl)
|
|
160212
160258
|
return await this.tokenService.decodeToken(tokenString, mintUrl);
|
|
160213
|
-
const metadata =
|
|
160259
|
+
const metadata = ur3(tokenString);
|
|
160214
160260
|
return (await this.walletService.getWallet(metadata.mint)).decodeToken(tokenString);
|
|
160215
160261
|
}
|
|
160216
160262
|
encodeToken(token, opts) {
|
|
@@ -161385,8 +161431,8 @@ var QUOTE_DEFAULTS = {
|
|
|
161385
161431
|
function isValidQuote(quote) {
|
|
161386
161432
|
if (!quote || typeof quote !== "object")
|
|
161387
161433
|
return false;
|
|
161388
|
-
const
|
|
161389
|
-
return typeof
|
|
161434
|
+
const q6 = quote;
|
|
161435
|
+
return typeof q6.quoteId === "string" && typeof q6.mintUrl === "string" && typeof q6.paidAt === "number";
|
|
161390
161436
|
}
|
|
161391
161437
|
function isValidUrl(url5) {
|
|
161392
161438
|
try {
|
|
@@ -162723,6 +162769,9 @@ var SAFE_COCO_LOG_FIELDS = new Set([
|
|
|
162723
162769
|
"operationId",
|
|
162724
162770
|
"quoteId",
|
|
162725
162771
|
"state",
|
|
162772
|
+
"code",
|
|
162773
|
+
"detail",
|
|
162774
|
+
"status",
|
|
162726
162775
|
"count",
|
|
162727
162776
|
"total",
|
|
162728
162777
|
"filterCount",
|
|
@@ -163042,6 +163091,107 @@ async function settleExpiredMintQuotes(source, nowMs, deadlineMs = EXPIRED_MINT_
|
|
|
163042
163091
|
}
|
|
163043
163092
|
return settlement;
|
|
163044
163093
|
}
|
|
163094
|
+
var PENDING_MINT_SWEEP_INTERVAL_MS = 15000;
|
|
163095
|
+
var PENDING_MINT_CHECK_TIMEOUT_MS = 1e4;
|
|
163096
|
+
var PENDING_MINT_SWEEP_DEADLINE_MS = 30000;
|
|
163097
|
+
var PENDING_MINT_STOP_DRAIN_MS = 1e4;
|
|
163098
|
+
async function settlePendingMintQuotes(source, nowMs, options = {}) {
|
|
163099
|
+
const deadlineMs = options.deadlineMs ?? PENDING_MINT_SWEEP_DEADLINE_MS;
|
|
163100
|
+
const checkTimeoutMs = options.checkTimeoutMs ?? PENDING_MINT_CHECK_TIMEOUT_MS;
|
|
163101
|
+
const state = options.state ?? { outstanding: new Map };
|
|
163102
|
+
let unreachable = 0;
|
|
163103
|
+
const pending = await source.ops.mint.listPending();
|
|
163104
|
+
const resumeAt = pending.findIndex((op) => op.id === state.after) + 1;
|
|
163105
|
+
const ordered = [...pending.slice(resumeAt), ...pending.slice(0, resumeAt)];
|
|
163106
|
+
const startedAt = Date.now();
|
|
163107
|
+
for (const op of ordered) {
|
|
163108
|
+
const remainingMs = deadlineMs - (Date.now() - startedAt);
|
|
163109
|
+
if (state.outstanding.has(op.id) || remainingMs <= 0) {
|
|
163110
|
+
unreachable++;
|
|
163111
|
+
continue;
|
|
163112
|
+
}
|
|
163113
|
+
state.after = op.id;
|
|
163114
|
+
const settled = source.ops.mint.refresh(op.id).then((result) => reportPendingMintRefresh(source, op, result, nowMs), (error53) => reportPendingMintRefreshError(source, op, error53)).finally(() => state.outstanding.delete(op.id));
|
|
163115
|
+
state.outstanding.set(op.id, settled);
|
|
163116
|
+
try {
|
|
163117
|
+
const outcome = await withTimeout(settled, Math.min(checkTimeoutMs, remainingMs));
|
|
163118
|
+
if (outcome === "unreachable")
|
|
163119
|
+
unreachable++;
|
|
163120
|
+
} catch {
|
|
163121
|
+
unreachable++;
|
|
163122
|
+
}
|
|
163123
|
+
}
|
|
163124
|
+
return { unreachable };
|
|
163125
|
+
}
|
|
163126
|
+
async function reportPendingMintRefresh(source, op, result, nowMs) {
|
|
163127
|
+
const quote = `Mint quote ${op.quoteId} at ${op.mintUrl}`;
|
|
163128
|
+
if (result.state === "finalized") {
|
|
163129
|
+
if (result.error) {
|
|
163130
|
+
logger5.warn(`${quote}: ${result.error}`);
|
|
163131
|
+
return "other";
|
|
163132
|
+
}
|
|
163133
|
+
const balance = (await source.wallet.balances.byMint())[op.mintUrl]?.spendable;
|
|
163134
|
+
logger5.log(`${quote}: paid, ${op.amount} sat minted` + (balance === undefined ? "" : `, balance now ${balance} sat`));
|
|
163135
|
+
return "other";
|
|
163136
|
+
}
|
|
163137
|
+
if (result.state === "failed") {
|
|
163138
|
+
logger5.warn(`${quote}: failed at the mint: ${result.error ?? "unknown reason"}`);
|
|
163139
|
+
return "other";
|
|
163140
|
+
}
|
|
163141
|
+
const expired = op.expiry > 0 && op.expiry * 1000 <= nowMs;
|
|
163142
|
+
if (expired && result.state === "pending" && result.lastObservedRemoteState === "UNPAID") {
|
|
163143
|
+
await source.mintOperationService.failPendingOperation({ id: op.id }, {
|
|
163144
|
+
reason: "Expired mint quote confirmed unpaid by mint",
|
|
163145
|
+
retryable: false,
|
|
163146
|
+
observedAt: Date.now()
|
|
163147
|
+
});
|
|
163148
|
+
}
|
|
163149
|
+
return "other";
|
|
163150
|
+
}
|
|
163151
|
+
async function reportPendingMintRefreshError(source, op, error53) {
|
|
163152
|
+
if (error53 instanceof OperationInProgressError)
|
|
163153
|
+
return "other";
|
|
163154
|
+
const current = await source.ops.mint.get(op.id);
|
|
163155
|
+
if (current?.state === "pending" && current.lastObservedRemoteState === "PAID") {
|
|
163156
|
+
if (op.lastObservedRemoteState !== "PAID" || current.error !== op.error) {
|
|
163157
|
+
logger5.warn(`Mint quote ${op.quoteId} at ${op.mintUrl}: paid (${op.amount} sat) but proofs not minted yet: ${current.error ?? String(error53)}; will retry`);
|
|
163158
|
+
}
|
|
163159
|
+
return "other";
|
|
163160
|
+
}
|
|
163161
|
+
return "unreachable";
|
|
163162
|
+
}
|
|
163163
|
+
function startPendingMintSweep(source) {
|
|
163164
|
+
let stopped = false;
|
|
163165
|
+
let timer6;
|
|
163166
|
+
let inFlight = Promise.resolve();
|
|
163167
|
+
let unreachableBefore = 0;
|
|
163168
|
+
const state = { outstanding: new Map };
|
|
163169
|
+
const tick = async () => {
|
|
163170
|
+
if (stopped)
|
|
163171
|
+
return;
|
|
163172
|
+
inFlight = settlePendingMintQuotes(source, Date.now(), { state }).then(({ unreachable }) => {
|
|
163173
|
+
if (unreachable > 0 && unreachableBefore === 0) {
|
|
163174
|
+
logger5.warn(`Could not check ${unreachable} pending mint quote(s); will keep retrying`);
|
|
163175
|
+
} else if (unreachable === 0 && unreachableBefore > 0) {
|
|
163176
|
+
logger5.log("Pending mint quote checks are reaching the mint again");
|
|
163177
|
+
}
|
|
163178
|
+
unreachableBefore = unreachable;
|
|
163179
|
+
}, (error53) => {
|
|
163180
|
+
logger5.warn(`Pending mint quote sweep failed: ${error53 instanceof Error ? error53.message : String(error53)}`);
|
|
163181
|
+
});
|
|
163182
|
+
await inFlight;
|
|
163183
|
+
if (!stopped)
|
|
163184
|
+
timer6 = setTimeout(tick, PENDING_MINT_SWEEP_INTERVAL_MS);
|
|
163185
|
+
};
|
|
163186
|
+
timer6 = setTimeout(tick, PENDING_MINT_SWEEP_INTERVAL_MS);
|
|
163187
|
+
return async () => {
|
|
163188
|
+
stopped = true;
|
|
163189
|
+
if (timer6 !== undefined)
|
|
163190
|
+
clearTimeout(timer6);
|
|
163191
|
+
await inFlight;
|
|
163192
|
+
await withTimeout(Promise.allSettled(state.outstanding.values()), PENDING_MINT_STOP_DRAIN_MS).catch(() => {});
|
|
163193
|
+
};
|
|
163194
|
+
}
|
|
163045
163195
|
async function reconcileDuplicateReceiveOperations(coco, repo) {
|
|
163046
163196
|
const internals = coco;
|
|
163047
163197
|
const unavailableMints = new Set;
|
|
@@ -163165,6 +163315,7 @@ async function createCocoClient(options = {}) {
|
|
|
163165
163315
|
pendingMints: 0
|
|
163166
163316
|
};
|
|
163167
163317
|
let recoveryResolve;
|
|
163318
|
+
let stopPendingMintSweep;
|
|
163168
163319
|
const recoveryPromise = new Promise((resolve) => {
|
|
163169
163320
|
recoveryResolve = resolve;
|
|
163170
163321
|
});
|
|
@@ -163291,6 +163442,11 @@ async function createCocoClient(options = {}) {
|
|
|
163291
163442
|
recoveryPhase = "done";
|
|
163292
163443
|
recoveryResolve?.();
|
|
163293
163444
|
startupProgress("Wallet recovery complete.");
|
|
163445
|
+
stopPendingMintSweep = startPendingMintSweep({
|
|
163446
|
+
ops: coco.ops,
|
|
163447
|
+
wallet: coco.wallet,
|
|
163448
|
+
mintOperationService: coco.mintOperationService
|
|
163449
|
+
});
|
|
163294
163450
|
}).catch((error53) => {
|
|
163295
163451
|
recoveryDone = true;
|
|
163296
163452
|
recoveryPhase = "error";
|
|
@@ -163488,7 +163644,20 @@ async function createCocoClient(options = {}) {
|
|
|
163488
163644
|
if (!("request" in op)) {
|
|
163489
163645
|
throw new Error("mint prepare did not return a payment request");
|
|
163490
163646
|
}
|
|
163491
|
-
return op.request;
|
|
163647
|
+
return { invoice: op.request, operationId: op.id };
|
|
163648
|
+
},
|
|
163649
|
+
async getMintQuote(operationId) {
|
|
163650
|
+
const op = await coco.ops.mint.get(operationId);
|
|
163651
|
+
if (!op || op.state === "init")
|
|
163652
|
+
return null;
|
|
163653
|
+
return {
|
|
163654
|
+
operationId: op.id,
|
|
163655
|
+
state: op.state,
|
|
163656
|
+
mintState: op.lastObservedRemoteState,
|
|
163657
|
+
amount: op.amount,
|
|
163658
|
+
mintUrl: op.mintUrl,
|
|
163659
|
+
error: op.error
|
|
163660
|
+
};
|
|
163492
163661
|
},
|
|
163493
163662
|
async sendCashu(amount, mintUrl) {
|
|
163494
163663
|
await waitForRecovery();
|
|
@@ -163550,6 +163719,7 @@ async function createCocoClient(options = {}) {
|
|
|
163550
163719
|
disposed = true;
|
|
163551
163720
|
try {
|
|
163552
163721
|
await recoveryPromise;
|
|
163722
|
+
await stopPendingMintSweep?.();
|
|
163553
163723
|
await coco.dispose();
|
|
163554
163724
|
} finally {
|
|
163555
163725
|
try {
|
|
@@ -164096,8 +164266,8 @@ function startupProgress2(message) {
|
|
|
164096
164266
|
logger5.info(message);
|
|
164097
164267
|
console.log(`${STARTUP_LOG_PREFIX2} ${message}`);
|
|
164098
164268
|
}
|
|
164099
|
-
|
|
164100
|
-
|
|
164269
|
+
async function runDaemon(argv = process.argv) {
|
|
164270
|
+
installGlobalErrorHandlers();
|
|
164101
164271
|
let shutdownDaemon = () => process.exit(0);
|
|
164102
164272
|
const shutdownForSignal = (signal) => {
|
|
164103
164273
|
logger5.log(`Received ${signal}; shutting down...`);
|
|
@@ -164106,9 +164276,9 @@ async function main() {
|
|
|
164106
164276
|
process.once("SIGINT", shutdownForSignal);
|
|
164107
164277
|
process.once("SIGTERM", shutdownForSignal);
|
|
164108
164278
|
startupProgress2("Loading configuration...");
|
|
164109
|
-
const args = parseArgs(
|
|
164279
|
+
const args = parseArgs(argv);
|
|
164110
164280
|
const config2 = await loadDaemonConfig();
|
|
164111
|
-
const port = args.port;
|
|
164281
|
+
const port = args.port ?? config2.port ?? 8008;
|
|
164112
164282
|
const host = args.host || config2.host || "127.0.0.1";
|
|
164113
164283
|
const provider = args.provider || config2.provider;
|
|
164114
164284
|
const requestResponseLogDir = process.env.ROUTSTRD_REQUEST_RESPONSE_LOG_DIR || (config2.requestResponseLogging?.enabled ? config2.requestResponseLogging.dir || REQUEST_RESPONSE_LOGS_DIR : undefined);
|
|
@@ -164211,31 +164381,61 @@ async function main() {
|
|
|
164211
164381
|
unlinkSync4(SOCKET_PATH);
|
|
164212
164382
|
}
|
|
164213
164383
|
} catch {}
|
|
164214
|
-
const
|
|
164215
|
-
|
|
164384
|
+
const DEFAULT_REFRESH_INTERVAL_MS = 21 * 60 * 1000;
|
|
164385
|
+
const DISABLED_REFRESH_POLL_MS = 60 * 1000;
|
|
164386
|
+
const readAutoRefreshSettings = () => {
|
|
164387
|
+
const autoRefresh = loadDaemonConfigSync().autoRefresh;
|
|
164388
|
+
const intervalMs = typeof autoRefresh?.intervalMs === "number" && autoRefresh.intervalMs > 0 ? autoRefresh.intervalMs : DEFAULT_REFRESH_INTERVAL_MS;
|
|
164389
|
+
return { enabled: autoRefresh?.enabled !== false, intervalMs };
|
|
164390
|
+
};
|
|
164391
|
+
let refreshTimer = null;
|
|
164392
|
+
let refreshJobActive = false;
|
|
164393
|
+
let disabledNoticeLogged = false;
|
|
164394
|
+
const runScheduledRefresh = async () => {
|
|
164395
|
+
logger5.log("Running scheduled Nostr event refresh...");
|
|
164396
|
+
try {
|
|
164397
|
+
await modelManager.refreshNostrEvents();
|
|
164398
|
+
} catch (error53) {
|
|
164399
|
+
logger5.error("Scheduled Nostr event refresh failed:", error53);
|
|
164400
|
+
}
|
|
164401
|
+
logger5.log("Running scheduled model refresh...");
|
|
164402
|
+
try {
|
|
164403
|
+
await refreshModelsAndIntegrations(getRoutstr21Models, updatedConfig, "Scheduled");
|
|
164404
|
+
} catch (error53) {
|
|
164405
|
+
logger5.error("Scheduled model refresh failed:", error53);
|
|
164406
|
+
}
|
|
164407
|
+
};
|
|
164408
|
+
const scheduleNextRefresh = () => {
|
|
164409
|
+
if (!refreshJobActive)
|
|
164410
|
+
return;
|
|
164411
|
+
const { enabled, intervalMs } = readAutoRefreshSettings();
|
|
164412
|
+
if (!enabled) {
|
|
164413
|
+
if (!disabledNoticeLogged) {
|
|
164414
|
+
logger5.log("Scheduled refresh job is disabled (autoRefresh.enabled=false). Polling for re-enable every 60s.");
|
|
164415
|
+
disabledNoticeLogged = true;
|
|
164416
|
+
}
|
|
164417
|
+
refreshTimer = setTimeout(scheduleNextRefresh, Math.min(intervalMs, DISABLED_REFRESH_POLL_MS));
|
|
164418
|
+
return;
|
|
164419
|
+
}
|
|
164420
|
+
if (disabledNoticeLogged) {
|
|
164421
|
+
logger5.log("Scheduled refresh job re-enabled.");
|
|
164422
|
+
disabledNoticeLogged = false;
|
|
164423
|
+
}
|
|
164424
|
+
refreshTimer = setTimeout(() => {
|
|
164425
|
+
runScheduledRefresh().catch((error53) => logger5.error("Model refresh interval escaped:", error53)).finally(() => scheduleNextRefresh());
|
|
164426
|
+
}, intervalMs);
|
|
164427
|
+
};
|
|
164216
164428
|
const startModelRefreshJob = () => {
|
|
164217
|
-
|
|
164218
|
-
|
|
164219
|
-
|
|
164220
|
-
|
|
164221
|
-
try {
|
|
164222
|
-
await modelManager.refreshNostrEvents();
|
|
164223
|
-
} catch (error53) {
|
|
164224
|
-
logger5.error("Scheduled Nostr event refresh failed:", error53);
|
|
164225
|
-
}
|
|
164226
|
-
logger5.log("Running scheduled model refresh...");
|
|
164227
|
-
try {
|
|
164228
|
-
await refreshModelsAndIntegrations(getRoutstr21Models, updatedConfig, "Scheduled");
|
|
164229
|
-
} catch (error53) {
|
|
164230
|
-
logger5.error("Scheduled model refresh failed:", error53);
|
|
164231
|
-
}
|
|
164232
|
-
})().catch((error53) => logger5.error("Model refresh interval escaped:", error53));
|
|
164233
|
-
}, REFRESH_INTERVAL_MS);
|
|
164429
|
+
refreshJobActive = true;
|
|
164430
|
+
const { enabled, intervalMs } = readAutoRefreshSettings();
|
|
164431
|
+
logger5.log(enabled ? `Starting recurring model refresh job (every ${Math.round(intervalMs / 60000)} minutes)` : "Recurring model refresh job is disabled (autoRefresh.enabled=false).");
|
|
164432
|
+
scheduleNextRefresh();
|
|
164234
164433
|
};
|
|
164235
164434
|
const stopModelRefreshJob = () => {
|
|
164236
|
-
|
|
164237
|
-
|
|
164238
|
-
|
|
164435
|
+
refreshJobActive = false;
|
|
164436
|
+
if (refreshTimer) {
|
|
164437
|
+
clearTimeout(refreshTimer);
|
|
164438
|
+
refreshTimer = null;
|
|
164239
164439
|
logger5.log("Stopped recurring model refresh job.");
|
|
164240
164440
|
}
|
|
164241
164441
|
};
|
|
@@ -164315,8 +164515,13 @@ async function main() {
|
|
|
164315
164515
|
await modelManager.refreshNostrEvents();
|
|
164316
164516
|
startModelRefreshJob();
|
|
164317
164517
|
startRefundJob();
|
|
164318
|
-
|
|
164319
|
-
|
|
164518
|
+
if (readAutoRefreshSettings().enabled) {
|
|
164519
|
+
logger5.log("Running initial model refresh...");
|
|
164520
|
+
await refreshModelsAndIntegrations(getRoutstr21Models, updatedConfig, "Initial");
|
|
164521
|
+
} else {
|
|
164522
|
+
logger5.log("Running initial model refresh (client integrations skipped)...");
|
|
164523
|
+
await getRoutstr21Models(true);
|
|
164524
|
+
}
|
|
164320
164525
|
}).catch((error53) => {
|
|
164321
164526
|
logger5.error("Initial model refresh failed:", error53);
|
|
164322
164527
|
startModelRefreshJob();
|
|
@@ -164325,9 +164530,12 @@ async function main() {
|
|
|
164325
164530
|
});
|
|
164326
164531
|
}
|
|
164327
164532
|
if (import.meta.main) {
|
|
164328
|
-
|
|
164533
|
+
runDaemon().catch((error53) => {
|
|
164329
164534
|
logger5.error("Failed to start Routstr daemon:", error53);
|
|
164330
164535
|
console.error("Failed to start Routstr daemon:", error53 instanceof Error ? error53.message : error53);
|
|
164331
164536
|
process.exit(1);
|
|
164332
164537
|
});
|
|
164333
164538
|
}
|
|
164539
|
+
export {
|
|
164540
|
+
runDaemon
|
|
164541
|
+
};
|