@routstr/sdk 0.3.8 → 0.3.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/dist/client/index.js +80 -25
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +80 -25
- package/dist/client/index.mjs.map +1 -1
- package/dist/discovery/index.d.mts +37 -3
- package/dist/discovery/index.d.ts +37 -3
- package/dist/discovery/index.js +231 -75
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +231 -75
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +592 -102
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +591 -103
- package/dist/index.mjs.map +1 -1
- package/dist/storage/index.d.mts +27 -1
- package/dist/storage/index.d.ts +27 -1
- package/dist/storage/index.js +281 -2
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/index.mjs +280 -3
- package/dist/storage/index.mjs.map +1 -1
- package/dist/wallet/index.d.mts +4 -0
- package/dist/wallet/index.d.ts +4 -0
- package/dist/wallet/index.js +11 -4
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +11 -4
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.mjs
CHANGED
|
@@ -137,6 +137,9 @@ var MintDiscoveryError = class extends Error {
|
|
|
137
137
|
}
|
|
138
138
|
baseUrl;
|
|
139
139
|
};
|
|
140
|
+
function isBunRuntime() {
|
|
141
|
+
return typeof Bun !== "undefined";
|
|
142
|
+
}
|
|
140
143
|
var ModelManager = class _ModelManager {
|
|
141
144
|
constructor(adapter, config = {}) {
|
|
142
145
|
this.adapter = adapter;
|
|
@@ -146,6 +149,7 @@ var ModelManager = class _ModelManager {
|
|
|
146
149
|
this.excludeProviderUrls = config.excludeProviderUrls || [];
|
|
147
150
|
this.routstrPubkey = config.routstrPubkey || "4ad6fa2d16e2a9b576c863b4cf7404a70d4dc320c0c447d10ad6ff58993eacc8";
|
|
148
151
|
this.logger = (config.logger ?? consoleLogger).child("ModelManager");
|
|
152
|
+
this.eventStoreDbPath = config.eventStoreDbPath;
|
|
149
153
|
}
|
|
150
154
|
adapter;
|
|
151
155
|
cacheTTL;
|
|
@@ -155,6 +159,11 @@ var ModelManager = class _ModelManager {
|
|
|
155
159
|
routstrPubkey;
|
|
156
160
|
logger;
|
|
157
161
|
providerNodePubkeysByUrl = /* @__PURE__ */ new Map();
|
|
162
|
+
/** Persistent event store for relay-fetched events (null if not configured/initialized) */
|
|
163
|
+
eventStore = null;
|
|
164
|
+
eventStoreDb = null;
|
|
165
|
+
eventStoreInitPromise = null;
|
|
166
|
+
eventStoreDbPath;
|
|
158
167
|
/**
|
|
159
168
|
* Get the list of bootstrapped provider base URLs
|
|
160
169
|
* @returns Array of provider base URLs
|
|
@@ -162,6 +171,104 @@ var ModelManager = class _ModelManager {
|
|
|
162
171
|
getBaseUrls() {
|
|
163
172
|
return this.adapter.getBaseUrlsList();
|
|
164
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Lazily initialize the persistent event store.
|
|
176
|
+
* Returns null if no eventStoreDbPath was provided.
|
|
177
|
+
*/
|
|
178
|
+
async ensureEventStore() {
|
|
179
|
+
if (!this.eventStoreDbPath) return null;
|
|
180
|
+
if (this.eventStore) return this.eventStore;
|
|
181
|
+
if (!this.eventStoreInitPromise) {
|
|
182
|
+
this.eventStoreInitPromise = (async () => {
|
|
183
|
+
try {
|
|
184
|
+
const db = await this.createPersistentEventDatabase();
|
|
185
|
+
this.eventStoreDb = db;
|
|
186
|
+
this.eventStore = new EventStore({ database: db });
|
|
187
|
+
this.initializeEventStoreMetadata();
|
|
188
|
+
this.logger.log(
|
|
189
|
+
`Persistent event store initialized at ${this.eventStoreDbPath}`
|
|
190
|
+
);
|
|
191
|
+
return this.eventStore;
|
|
192
|
+
} catch (error) {
|
|
193
|
+
this.eventStoreInitPromise = null;
|
|
194
|
+
throw new Error(
|
|
195
|
+
`applesauce-sqlite with a supported SQLite driver is required for persistent Nostr event storage. Bun uses bun:sqlite; Node.js uses better-sqlite3. Install optional dependencies or omit eventStoreDbPath. (${error})`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
})();
|
|
199
|
+
}
|
|
200
|
+
return this.eventStoreInitPromise;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get the persistent event store, initializing it if configured.
|
|
204
|
+
* Returns null if no eventStoreDbPath was provided.
|
|
205
|
+
*/
|
|
206
|
+
async getEventStore() {
|
|
207
|
+
return this.ensureEventStore();
|
|
208
|
+
}
|
|
209
|
+
async createPersistentEventDatabase() {
|
|
210
|
+
if (isBunRuntime()) {
|
|
211
|
+
const { BunSqliteEventDatabase } = await import('applesauce-sqlite/bun');
|
|
212
|
+
return new BunSqliteEventDatabase(
|
|
213
|
+
this.eventStoreDbPath
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
const { BetterSqlite3EventDatabase } = await import('applesauce-sqlite/better-sqlite3');
|
|
217
|
+
return new BetterSqlite3EventDatabase(
|
|
218
|
+
this.eventStoreDbPath
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
/** Close the persistent event store database handle, if configured. */
|
|
222
|
+
closeEventStore() {
|
|
223
|
+
this.eventStoreDb?.close?.();
|
|
224
|
+
this.eventStore = null;
|
|
225
|
+
this.eventStoreDb = null;
|
|
226
|
+
this.eventStoreInitPromise = null;
|
|
227
|
+
}
|
|
228
|
+
initializeEventStoreMetadata() {
|
|
229
|
+
this.eventStoreDb?.db?.exec(
|
|
230
|
+
`CREATE TABLE IF NOT EXISTS routstr_event_cache_metadata (
|
|
231
|
+
event_id TEXT PRIMARY KEY,
|
|
232
|
+
fetched_at INTEGER NOT NULL
|
|
233
|
+
)`
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
markEventFetched(event, fetchedAt = Date.now()) {
|
|
237
|
+
const db = this.eventStoreDb?.db;
|
|
238
|
+
if (!db) return;
|
|
239
|
+
db.prepare(
|
|
240
|
+
`INSERT INTO routstr_event_cache_metadata (event_id, fetched_at)
|
|
241
|
+
VALUES (?, ?)
|
|
242
|
+
ON CONFLICT(event_id) DO UPDATE SET fetched_at = excluded.fetched_at`
|
|
243
|
+
).run?.(event.id, fetchedAt);
|
|
244
|
+
}
|
|
245
|
+
getEventFetchedAt(event) {
|
|
246
|
+
const db = this.eventStoreDb?.db;
|
|
247
|
+
if (!db) return void 0;
|
|
248
|
+
const row = db.prepare(
|
|
249
|
+
`SELECT fetched_at FROM routstr_event_cache_metadata WHERE event_id = ?`
|
|
250
|
+
).get?.(event.id);
|
|
251
|
+
return typeof row?.fetched_at === "number" ? row.fetched_at : void 0;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Check the persistent event store for fresh cached events.
|
|
255
|
+
* Returns events from SQLite if they were fetched within `maxAge`, otherwise
|
|
256
|
+
* returns empty array (caller should hit relays). Events without local fetch
|
|
257
|
+
* metadata fall back to Nostr created_at for backwards compatibility.
|
|
258
|
+
*/
|
|
259
|
+
async getCachedNostrEvents(filter, maxAge, forceRefresh = false) {
|
|
260
|
+
const eventStore = await this.ensureEventStore();
|
|
261
|
+
if (forceRefresh) return [];
|
|
262
|
+
if (!eventStore) return [];
|
|
263
|
+
const timeline = eventStore.getTimeline(filter);
|
|
264
|
+
if (timeline.length === 0) return [];
|
|
265
|
+
const cutoff = Date.now() - maxAge;
|
|
266
|
+
const freshest = Math.max(
|
|
267
|
+
...timeline.map((e) => this.getEventFetchedAt(e) ?? e.created_at * 1e3)
|
|
268
|
+
);
|
|
269
|
+
if (freshest < cutoff) return [];
|
|
270
|
+
return timeline;
|
|
271
|
+
}
|
|
165
272
|
static async init(adapter, config = {}, options = {}) {
|
|
166
273
|
const manager = new _ModelManager(adapter, config);
|
|
167
274
|
const torMode = options.torMode ?? false;
|
|
@@ -190,19 +297,31 @@ var ModelManager = class _ModelManager {
|
|
|
190
297
|
torMode
|
|
191
298
|
);
|
|
192
299
|
await this.fetchRoutstr21Models(forceRefresh);
|
|
193
|
-
await this.syncReviewedProvidersFromNostr(
|
|
300
|
+
await this.syncReviewedProvidersFromNostr(
|
|
301
|
+
filteredCachedUrls,
|
|
302
|
+
this.providerNodePubkeysByUrl,
|
|
303
|
+
forceRefresh
|
|
304
|
+
);
|
|
194
305
|
return filteredCachedUrls;
|
|
195
306
|
}
|
|
196
307
|
}
|
|
197
308
|
}
|
|
198
309
|
try {
|
|
199
|
-
const nostrProviders = await this.bootstrapFromNostr(
|
|
310
|
+
const nostrProviders = await this.bootstrapFromNostr(
|
|
311
|
+
38421,
|
|
312
|
+
torMode,
|
|
313
|
+
forceRefresh
|
|
314
|
+
);
|
|
200
315
|
if (nostrProviders.length > 0) {
|
|
201
316
|
const filtered = this.filterBaseUrlsForTor(nostrProviders, torMode);
|
|
202
317
|
this.adapter.setBaseUrlsList(filtered);
|
|
203
318
|
this.adapter.setBaseUrlsLastUpdate(Date.now());
|
|
204
319
|
await this.fetchRoutstr21Models(forceRefresh);
|
|
205
|
-
await this.syncReviewedProvidersFromNostr(
|
|
320
|
+
await this.syncReviewedProvidersFromNostr(
|
|
321
|
+
filtered,
|
|
322
|
+
this.providerNodePubkeysByUrl,
|
|
323
|
+
forceRefresh
|
|
324
|
+
);
|
|
206
325
|
return filtered;
|
|
207
326
|
}
|
|
208
327
|
} catch (e) {
|
|
@@ -211,42 +330,52 @@ var ModelManager = class _ModelManager {
|
|
|
211
330
|
return this.bootstrapFromHttp(torMode, forceRefresh);
|
|
212
331
|
}
|
|
213
332
|
/**
|
|
214
|
-
* Bootstrap providers from Nostr network (kind
|
|
333
|
+
* Bootstrap providers from Nostr network (kind 38421)
|
|
215
334
|
* @param kind The Nostr kind to fetch
|
|
216
335
|
* @param torMode Whether running in Tor context
|
|
217
336
|
* @returns Array of provider base URLs
|
|
218
337
|
*/
|
|
219
|
-
async bootstrapFromNostr(kind, torMode) {
|
|
338
|
+
async bootstrapFromNostr(kind, torMode, forceRefresh = false) {
|
|
220
339
|
const DEFAULT_RELAYS = [
|
|
221
340
|
"wss://relay.primal.net",
|
|
222
341
|
"wss://nos.lol",
|
|
223
342
|
"wss://relay.damus.io"
|
|
224
343
|
];
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
344
|
+
const cached = await this.getCachedNostrEvents(
|
|
345
|
+
{ kinds: [kind] },
|
|
346
|
+
this.cacheTTL,
|
|
347
|
+
forceRefresh
|
|
348
|
+
);
|
|
349
|
+
let sessionEvents = cached;
|
|
350
|
+
if (cached.length === 0) {
|
|
351
|
+
const pool = new RelayPool();
|
|
352
|
+
const timeoutMs = 5e3;
|
|
353
|
+
await new Promise((resolve) => {
|
|
354
|
+
pool.req(DEFAULT_RELAYS, {
|
|
355
|
+
kinds: [kind],
|
|
356
|
+
limit: 100
|
|
357
|
+
}).pipe(
|
|
358
|
+
onlyEvents(),
|
|
359
|
+
tap((event) => {
|
|
360
|
+
sessionEvents.push(event);
|
|
361
|
+
this.eventStore?.add(event);
|
|
362
|
+
this.markEventFetched(event);
|
|
363
|
+
})
|
|
364
|
+
).subscribe({
|
|
365
|
+
complete: () => {
|
|
366
|
+
resolve();
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
setTimeout(() => {
|
|
239
370
|
resolve();
|
|
240
|
-
}
|
|
371
|
+
}, timeoutMs);
|
|
241
372
|
});
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
});
|
|
246
|
-
const timeline = localEventStore.getTimeline({ kinds: [kind] });
|
|
373
|
+
} else {
|
|
374
|
+
this.logger.log(`Using ${cached.length} cached kind ${kind} events from persistent store`);
|
|
375
|
+
}
|
|
247
376
|
const bases = /* @__PURE__ */ new Set();
|
|
248
377
|
this.providerNodePubkeysByUrl = /* @__PURE__ */ new Map();
|
|
249
|
-
for (const event of
|
|
378
|
+
for (const event of sessionEvents) {
|
|
250
379
|
const eventUrls = [];
|
|
251
380
|
for (const tag of event.tags) {
|
|
252
381
|
if (tag[0] === "u" && typeof tag[1] === "string") {
|
|
@@ -354,7 +483,11 @@ var ModelManager = class _ModelManager {
|
|
|
354
483
|
this.adapter.setBaseUrlsList(list);
|
|
355
484
|
this.adapter.setBaseUrlsLastUpdate(Date.now());
|
|
356
485
|
await this.fetchRoutstr21Models(forceRefresh);
|
|
357
|
-
await this.syncReviewedProvidersFromNostr(
|
|
486
|
+
await this.syncReviewedProvidersFromNostr(
|
|
487
|
+
list,
|
|
488
|
+
this.providerNodePubkeysByUrl,
|
|
489
|
+
forceRefresh
|
|
490
|
+
);
|
|
358
491
|
}
|
|
359
492
|
return list;
|
|
360
493
|
} catch (e) {
|
|
@@ -373,7 +506,7 @@ var ModelManager = class _ModelManager {
|
|
|
373
506
|
* @param baseUrls Current provider base URLs to evaluate
|
|
374
507
|
* @returns Array of provider base URLs disabled by the review set
|
|
375
508
|
*/
|
|
376
|
-
async syncReviewedProvidersFromNostr(baseUrls = this.adapter.getBaseUrlsList(), providerNodes = this.providerNodePubkeysByUrl) {
|
|
509
|
+
async syncReviewedProvidersFromNostr(baseUrls = this.adapter.getBaseUrlsList(), providerNodes = this.providerNodePubkeysByUrl, forceRefresh = false) {
|
|
377
510
|
if (baseUrls.length === 0) return [];
|
|
378
511
|
if (!this.adapter.setDisabledProviders) {
|
|
379
512
|
this.logger.warn(
|
|
@@ -381,30 +514,43 @@ var ModelManager = class _ModelManager {
|
|
|
381
514
|
);
|
|
382
515
|
return [];
|
|
383
516
|
}
|
|
384
|
-
const LGTM_RELAYS = [
|
|
385
|
-
"wss://relay.primal.net",
|
|
386
|
-
"wss://nos.lol",
|
|
387
|
-
"wss://relay.damus.io",
|
|
388
|
-
"wss://relay.routstr.com"
|
|
389
|
-
];
|
|
390
517
|
const reviewedNodePubkeys = /* @__PURE__ */ new Set();
|
|
391
518
|
{
|
|
392
|
-
const
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
519
|
+
const cached = await this.getCachedNostrEvents(
|
|
520
|
+
{ kinds: [38425], "#t": ["lgtm"], authors: [this.routstrPubkey] },
|
|
521
|
+
this.cacheTTL,
|
|
522
|
+
forceRefresh
|
|
523
|
+
);
|
|
524
|
+
let sessionEvents = cached;
|
|
525
|
+
if (cached.length === 0) {
|
|
526
|
+
const LGTM_RELAYS = [
|
|
527
|
+
"wss://relay.primal.net",
|
|
528
|
+
"wss://nos.lol",
|
|
529
|
+
"wss://relay.damus.io",
|
|
530
|
+
"wss://relay.routstr.com"
|
|
531
|
+
];
|
|
532
|
+
const pool = new RelayPool();
|
|
533
|
+
const timeoutMs = 5e3;
|
|
534
|
+
await new Promise((resolve) => {
|
|
535
|
+
pool.req(LGTM_RELAYS, {
|
|
536
|
+
kinds: [38425],
|
|
537
|
+
"#t": ["lgtm"],
|
|
538
|
+
limit: 500,
|
|
539
|
+
authors: [this.routstrPubkey]
|
|
540
|
+
}).pipe(
|
|
541
|
+
onlyEvents(),
|
|
542
|
+
tap((event) => {
|
|
543
|
+
sessionEvents.push(event);
|
|
544
|
+
this.eventStore?.add(event);
|
|
545
|
+
this.markEventFetched(event);
|
|
546
|
+
})
|
|
547
|
+
).subscribe({ complete: () => resolve() });
|
|
548
|
+
setTimeout(() => resolve(), timeoutMs);
|
|
549
|
+
});
|
|
550
|
+
} else {
|
|
551
|
+
this.logger.log(`Using ${cached.length} cached kind 38425 events from persistent store`);
|
|
552
|
+
}
|
|
553
|
+
for (const event of sessionEvents) {
|
|
408
554
|
const hasLgtmTag = event.tags.some(
|
|
409
555
|
(tag) => tag[0] === "t" && tag[1]?.toLowerCase() === "lgtm"
|
|
410
556
|
);
|
|
@@ -513,7 +659,7 @@ var ModelManager = class _ModelManager {
|
|
|
513
659
|
if (this.isProviderDownError(error)) {
|
|
514
660
|
this.logger.warn(`Provider ${base} is down right now.`);
|
|
515
661
|
} else {
|
|
516
|
-
this.logger.warn(`
|
|
662
|
+
this.logger.warn(`Provider ${base} unreachable: ${error.message}`);
|
|
517
663
|
}
|
|
518
664
|
this.adapter.setProviderLastUpdate(base, Date.now());
|
|
519
665
|
return { success: false, base };
|
|
@@ -633,34 +779,44 @@ var ModelManager = class _ModelManager {
|
|
|
633
779
|
"wss://nos.lol",
|
|
634
780
|
"wss://relay.routstr.com"
|
|
635
781
|
];
|
|
636
|
-
const
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
782
|
+
const cached = await this.getCachedNostrEvents(
|
|
783
|
+
{ kinds: [38423], "#d": ["routstr-21-models"], authors: [this.routstrPubkey] },
|
|
784
|
+
this.cacheTTL,
|
|
785
|
+
forceRefresh
|
|
786
|
+
);
|
|
787
|
+
let sessionEvents = cached;
|
|
788
|
+
if (cached.length === 0) {
|
|
789
|
+
const pool = new RelayPool();
|
|
790
|
+
const timeoutMs = 5e3;
|
|
791
|
+
await new Promise((resolve) => {
|
|
792
|
+
pool.req(DEFAULT_RELAYS, {
|
|
793
|
+
kinds: [38423],
|
|
794
|
+
"#d": ["routstr-21-models"],
|
|
795
|
+
limit: 1,
|
|
796
|
+
authors: [this.routstrPubkey]
|
|
797
|
+
}).pipe(
|
|
798
|
+
onlyEvents(),
|
|
799
|
+
tap((event2) => {
|
|
800
|
+
sessionEvents.push(event2);
|
|
801
|
+
this.eventStore?.add(event2);
|
|
802
|
+
this.markEventFetched(event2);
|
|
803
|
+
})
|
|
804
|
+
).subscribe({
|
|
805
|
+
complete: () => {
|
|
806
|
+
resolve();
|
|
807
|
+
}
|
|
808
|
+
});
|
|
809
|
+
setTimeout(() => {
|
|
652
810
|
resolve();
|
|
653
|
-
}
|
|
811
|
+
}, timeoutMs);
|
|
654
812
|
});
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
const timeline = localEventStore.getTimeline({ kinds: [38423] });
|
|
660
|
-
if (timeline.length === 0) {
|
|
813
|
+
} else {
|
|
814
|
+
this.logger.log(`Using ${cached.length} cached kind 38423 events from persistent store`);
|
|
815
|
+
}
|
|
816
|
+
if (sessionEvents.length === 0) {
|
|
661
817
|
return cachedModels.length > 0 ? cachedModels : [];
|
|
662
818
|
}
|
|
663
|
-
const event =
|
|
819
|
+
const event = sessionEvents[0];
|
|
664
820
|
try {
|
|
665
821
|
const content = JSON.parse(event.content);
|
|
666
822
|
const models = Array.isArray(content?.models) ? content.models : [];
|
|
@@ -1378,7 +1534,7 @@ var CashuSpender = class {
|
|
|
1378
1534
|
});
|
|
1379
1535
|
continue;
|
|
1380
1536
|
}
|
|
1381
|
-
if (balanceResult.amount >= 0) {
|
|
1537
|
+
if (balanceResult.amount >= 0 && !balanceResult.balanceUnknown) {
|
|
1382
1538
|
const balanceSat = balanceResult.unit === "msat" ? Math.floor(balanceResult.amount / 1e3) : balanceResult.amount;
|
|
1383
1539
|
this.storageAdapter.updateApiKeyBalance(
|
|
1384
1540
|
apiKeyEntry.baseUrl,
|
|
@@ -2127,17 +2283,24 @@ var BalanceManager = class _BalanceManager {
|
|
|
2127
2283
|
this.logger.warn("getTokenBalance: FAILED", data);
|
|
2128
2284
|
const isInvalidApiKey = response.status === 401 && data?.detail?.error?.code === "invalid_api_key" && data?.detail?.error?.message?.includes("proofs already spent");
|
|
2129
2285
|
return {
|
|
2130
|
-
amount:
|
|
2286
|
+
amount: 0,
|
|
2131
2287
|
reserved: data.reserved ?? 0,
|
|
2132
2288
|
unit: "msat",
|
|
2133
2289
|
apiKey: data.api_key,
|
|
2134
|
-
isInvalidApiKey
|
|
2290
|
+
isInvalidApiKey,
|
|
2291
|
+
balanceUnknown: true
|
|
2135
2292
|
};
|
|
2136
2293
|
}
|
|
2137
2294
|
} catch (error) {
|
|
2138
2295
|
this.logger.error("getTokenBalance error", error);
|
|
2139
2296
|
}
|
|
2140
|
-
return {
|
|
2297
|
+
return {
|
|
2298
|
+
amount: 0,
|
|
2299
|
+
reserved: 0,
|
|
2300
|
+
unit: "sat",
|
|
2301
|
+
apiKey: "",
|
|
2302
|
+
balanceUnknown: true
|
|
2303
|
+
};
|
|
2141
2304
|
}
|
|
2142
2305
|
/**
|
|
2143
2306
|
* Handle topup errors with specific error types
|
|
@@ -4684,6 +4847,277 @@ var createProviderRegistryFromStore = (store, logger) => {
|
|
|
4684
4847
|
};
|
|
4685
4848
|
};
|
|
4686
4849
|
|
|
4850
|
+
// storage/shardedDiscoveryAdapter.ts
|
|
4851
|
+
var MODEL_KEY_PREFIX = "models:provider:";
|
|
4852
|
+
var MODEL_TS_KEY_PREFIX = "models:provider_timestamp:";
|
|
4853
|
+
var PROVIDER_INDEX_KEY = "models:provider_index";
|
|
4854
|
+
var MIGRATION_MARKER_KEY4 = "models_sharded_migration_v1";
|
|
4855
|
+
var encodeBaseUrl = (baseUrl) => encodeURIComponent(baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`);
|
|
4856
|
+
var modelKey = (baseUrl) => `${MODEL_KEY_PREFIX}${encodeBaseUrl(baseUrl)}`;
|
|
4857
|
+
var modelTsKey = (baseUrl) => `${MODEL_TS_KEY_PREFIX}${encodeBaseUrl(baseUrl)}`;
|
|
4858
|
+
var normalizeBaseUrl6 = (baseUrl) => baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
4859
|
+
var createShardedDiscoveryAdapter = async (options) => {
|
|
4860
|
+
const { driver } = options;
|
|
4861
|
+
const legacyModels = await driver.getItem(SDK_STORAGE_KEYS.MODELS_FROM_ALL_PROVIDERS, {});
|
|
4862
|
+
const legacyTimestamps = await driver.getItem(SDK_STORAGE_KEYS.LAST_MODELS_UPDATE, {});
|
|
4863
|
+
if (Object.keys(legacyModels).length > 0) {
|
|
4864
|
+
const migratedProviders = [];
|
|
4865
|
+
for (const [baseUrl, models] of Object.entries(legacyModels)) {
|
|
4866
|
+
const normalized = normalizeBaseUrl6(baseUrl);
|
|
4867
|
+
await driver.setItem(modelKey(normalized), models);
|
|
4868
|
+
const ts = legacyTimestamps[normalized] ?? Date.now();
|
|
4869
|
+
await driver.setItem(modelTsKey(normalized), ts);
|
|
4870
|
+
migratedProviders.push(normalized);
|
|
4871
|
+
}
|
|
4872
|
+
const existingIndex = await driver.getItem(
|
|
4873
|
+
PROVIDER_INDEX_KEY,
|
|
4874
|
+
[]
|
|
4875
|
+
);
|
|
4876
|
+
const merged = [.../* @__PURE__ */ new Set([...existingIndex, ...migratedProviders])];
|
|
4877
|
+
await driver.setItem(PROVIDER_INDEX_KEY, merged);
|
|
4878
|
+
await driver.removeItem(SDK_STORAGE_KEYS.MODELS_FROM_ALL_PROVIDERS);
|
|
4879
|
+
await driver.removeItem(SDK_STORAGE_KEYS.LAST_MODELS_UPDATE);
|
|
4880
|
+
}
|
|
4881
|
+
await driver.setItem(MIGRATION_MARKER_KEY4, true);
|
|
4882
|
+
const [
|
|
4883
|
+
rawMints,
|
|
4884
|
+
rawInfo,
|
|
4885
|
+
lastUsedModel,
|
|
4886
|
+
rawDisabled,
|
|
4887
|
+
rawBaseUrls,
|
|
4888
|
+
lastBaseUrlsUpdate,
|
|
4889
|
+
rawRoutstr21Models,
|
|
4890
|
+
lastRoutstr21ModelsUpdate
|
|
4891
|
+
] = await Promise.all([
|
|
4892
|
+
driver.getItem(
|
|
4893
|
+
SDK_STORAGE_KEYS.MINTS_FROM_ALL_PROVIDERS,
|
|
4894
|
+
{}
|
|
4895
|
+
),
|
|
4896
|
+
driver.getItem(
|
|
4897
|
+
SDK_STORAGE_KEYS.INFO_FROM_ALL_PROVIDERS,
|
|
4898
|
+
{}
|
|
4899
|
+
),
|
|
4900
|
+
driver.getItem(SDK_STORAGE_KEYS.LAST_USED_MODEL, null),
|
|
4901
|
+
driver.getItem(SDK_STORAGE_KEYS.DISABLED_PROVIDERS, []),
|
|
4902
|
+
driver.getItem(SDK_STORAGE_KEYS.BASE_URLS_LIST, []),
|
|
4903
|
+
driver.getItem(SDK_STORAGE_KEYS.LAST_BASE_URLS_UPDATE, null),
|
|
4904
|
+
driver.getItem(SDK_STORAGE_KEYS.ROUTSTR21_MODELS, []),
|
|
4905
|
+
driver.getItem(
|
|
4906
|
+
SDK_STORAGE_KEYS.LAST_ROUTSTR21_MODELS_UPDATE,
|
|
4907
|
+
null
|
|
4908
|
+
)
|
|
4909
|
+
]);
|
|
4910
|
+
const modelsByBaseUrl = /* @__PURE__ */ new Map();
|
|
4911
|
+
const timestampsByBaseUrl = /* @__PURE__ */ new Map();
|
|
4912
|
+
const providerIndex = /* @__PURE__ */ new Set();
|
|
4913
|
+
const knownProviders = /* @__PURE__ */ new Set();
|
|
4914
|
+
for (const baseUrl of Object.keys(rawInfo)) {
|
|
4915
|
+
knownProviders.add(normalizeBaseUrl6(baseUrl));
|
|
4916
|
+
}
|
|
4917
|
+
for (const baseUrl of Object.keys(rawMints)) {
|
|
4918
|
+
knownProviders.add(normalizeBaseUrl6(baseUrl));
|
|
4919
|
+
}
|
|
4920
|
+
for (const baseUrl of rawBaseUrls) {
|
|
4921
|
+
knownProviders.add(normalizeBaseUrl6(baseUrl));
|
|
4922
|
+
}
|
|
4923
|
+
for (const baseUrl of rawDisabled) {
|
|
4924
|
+
knownProviders.add(normalizeBaseUrl6(baseUrl));
|
|
4925
|
+
}
|
|
4926
|
+
for (const baseUrl of Object.keys(legacyModels)) {
|
|
4927
|
+
knownProviders.add(normalizeBaseUrl6(baseUrl));
|
|
4928
|
+
}
|
|
4929
|
+
const indexProviders = await driver.getItem(
|
|
4930
|
+
PROVIDER_INDEX_KEY,
|
|
4931
|
+
[]
|
|
4932
|
+
);
|
|
4933
|
+
for (const baseUrl of indexProviders) {
|
|
4934
|
+
const normalized = normalizeBaseUrl6(baseUrl);
|
|
4935
|
+
providerIndex.add(normalized);
|
|
4936
|
+
knownProviders.add(normalized);
|
|
4937
|
+
}
|
|
4938
|
+
for (const baseUrl of knownProviders) {
|
|
4939
|
+
const normalized = normalizeBaseUrl6(baseUrl);
|
|
4940
|
+
const models = await driver.getItem(
|
|
4941
|
+
modelKey(normalized),
|
|
4942
|
+
null
|
|
4943
|
+
);
|
|
4944
|
+
const ts = await driver.getItem(
|
|
4945
|
+
modelTsKey(normalized),
|
|
4946
|
+
null
|
|
4947
|
+
);
|
|
4948
|
+
if (models !== null) {
|
|
4949
|
+
modelsByBaseUrl.set(normalized, models);
|
|
4950
|
+
}
|
|
4951
|
+
if (ts !== null) {
|
|
4952
|
+
timestampsByBaseUrl.set(normalized, ts);
|
|
4953
|
+
}
|
|
4954
|
+
if (models !== null || ts !== null) {
|
|
4955
|
+
providerIndex.add(normalized);
|
|
4956
|
+
}
|
|
4957
|
+
}
|
|
4958
|
+
let mints = Object.fromEntries(
|
|
4959
|
+
Object.entries(rawMints).map(([baseUrl, mintList]) => [
|
|
4960
|
+
normalizeBaseUrl6(baseUrl),
|
|
4961
|
+
mintList.map((mint) => mint.endsWith("/") ? mint.slice(0, -1) : mint)
|
|
4962
|
+
])
|
|
4963
|
+
);
|
|
4964
|
+
let info = Object.fromEntries(
|
|
4965
|
+
Object.entries(rawInfo).map(([baseUrl, entry]) => [
|
|
4966
|
+
normalizeBaseUrl6(baseUrl),
|
|
4967
|
+
entry
|
|
4968
|
+
])
|
|
4969
|
+
);
|
|
4970
|
+
let _lastUsedModel = lastUsedModel;
|
|
4971
|
+
let _disabledProviders = rawDisabled.map(normalizeBaseUrl6);
|
|
4972
|
+
let _baseUrlsList = rawBaseUrls.map(normalizeBaseUrl6);
|
|
4973
|
+
let _lastBaseUrlsUpdate = lastBaseUrlsUpdate;
|
|
4974
|
+
let _routstr21Models = rawRoutstr21Models;
|
|
4975
|
+
let _lastRoutstr21ModelsUpdate = lastRoutstr21ModelsUpdate;
|
|
4976
|
+
const persistProviderIndex = () => {
|
|
4977
|
+
void driver.setItem(PROVIDER_INDEX_KEY, [...providerIndex]);
|
|
4978
|
+
};
|
|
4979
|
+
return {
|
|
4980
|
+
// -- Models (sharded kv) --
|
|
4981
|
+
getCachedModels: () => {
|
|
4982
|
+
const result = {};
|
|
4983
|
+
for (const [baseUrl, models] of modelsByBaseUrl.entries()) {
|
|
4984
|
+
result[baseUrl] = models;
|
|
4985
|
+
}
|
|
4986
|
+
return result;
|
|
4987
|
+
},
|
|
4988
|
+
setCachedModels: (models) => {
|
|
4989
|
+
const nextKeys = new Set(
|
|
4990
|
+
Object.keys(models).map((baseUrl) => normalizeBaseUrl6(baseUrl))
|
|
4991
|
+
);
|
|
4992
|
+
for (const baseUrl of [...modelsByBaseUrl.keys()]) {
|
|
4993
|
+
if (!nextKeys.has(normalizeBaseUrl6(baseUrl))) {
|
|
4994
|
+
providerIndex.delete(baseUrl);
|
|
4995
|
+
modelsByBaseUrl.delete(baseUrl);
|
|
4996
|
+
timestampsByBaseUrl.delete(baseUrl);
|
|
4997
|
+
void driver.removeItem(modelKey(baseUrl));
|
|
4998
|
+
void driver.removeItem(modelTsKey(baseUrl));
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
for (const [baseUrl, modelList] of Object.entries(models)) {
|
|
5002
|
+
const normalized = normalizeBaseUrl6(baseUrl);
|
|
5003
|
+
providerIndex.add(normalized);
|
|
5004
|
+
modelsByBaseUrl.set(normalized, modelList);
|
|
5005
|
+
const ts = timestampsByBaseUrl.get(normalized) ?? Date.now();
|
|
5006
|
+
timestampsByBaseUrl.set(normalized, ts);
|
|
5007
|
+
void driver.setItem(modelKey(normalized), modelList);
|
|
5008
|
+
void driver.setItem(modelTsKey(normalized), ts);
|
|
5009
|
+
}
|
|
5010
|
+
persistProviderIndex();
|
|
5011
|
+
},
|
|
5012
|
+
getProviderLastUpdate: (baseUrl) => {
|
|
5013
|
+
return timestampsByBaseUrl.get(normalizeBaseUrl6(baseUrl)) ?? null;
|
|
5014
|
+
},
|
|
5015
|
+
setProviderLastUpdate: (baseUrl, timestamp) => {
|
|
5016
|
+
const normalized = normalizeBaseUrl6(baseUrl);
|
|
5017
|
+
providerIndex.add(normalized);
|
|
5018
|
+
timestampsByBaseUrl.set(normalized, timestamp);
|
|
5019
|
+
void driver.setItem(modelTsKey(normalized), timestamp);
|
|
5020
|
+
persistProviderIndex();
|
|
5021
|
+
},
|
|
5022
|
+
// -- Mints (kv) --
|
|
5023
|
+
getCachedMints: () => mints,
|
|
5024
|
+
setCachedMints: (value) => {
|
|
5025
|
+
const normalized = {};
|
|
5026
|
+
for (const [baseUrl, mintList] of Object.entries(value)) {
|
|
5027
|
+
normalized[normalizeBaseUrl6(baseUrl)] = mintList.map(
|
|
5028
|
+
(mint) => mint.endsWith("/") ? mint.slice(0, -1) : mint
|
|
5029
|
+
);
|
|
5030
|
+
}
|
|
5031
|
+
mints = normalized;
|
|
5032
|
+
void driver.setItem(SDK_STORAGE_KEYS.MINTS_FROM_ALL_PROVIDERS, normalized);
|
|
5033
|
+
},
|
|
5034
|
+
// -- Provider info (kv) --
|
|
5035
|
+
getCachedProviderInfo: () => info,
|
|
5036
|
+
setCachedProviderInfo: (value) => {
|
|
5037
|
+
const normalized = {};
|
|
5038
|
+
for (const [baseUrl, entry] of Object.entries(value)) {
|
|
5039
|
+
normalized[normalizeBaseUrl6(baseUrl)] = entry;
|
|
5040
|
+
}
|
|
5041
|
+
info = normalized;
|
|
5042
|
+
void driver.setItem(SDK_STORAGE_KEYS.INFO_FROM_ALL_PROVIDERS, normalized);
|
|
5043
|
+
},
|
|
5044
|
+
// -- Last used model (kv) --
|
|
5045
|
+
getLastUsedModel: () => _lastUsedModel,
|
|
5046
|
+
setLastUsedModel: (modelId) => {
|
|
5047
|
+
_lastUsedModel = modelId;
|
|
5048
|
+
void driver.setItem(SDK_STORAGE_KEYS.LAST_USED_MODEL, modelId);
|
|
5049
|
+
},
|
|
5050
|
+
// -- Disabled providers (kv) --
|
|
5051
|
+
getDisabledProviders: () => _disabledProviders,
|
|
5052
|
+
setDisabledProviders: (urls) => {
|
|
5053
|
+
const normalized = urls.map(normalizeBaseUrl6);
|
|
5054
|
+
_disabledProviders = normalized;
|
|
5055
|
+
void driver.setItem(SDK_STORAGE_KEYS.DISABLED_PROVIDERS, normalized);
|
|
5056
|
+
},
|
|
5057
|
+
// -- Base URLs (kv) --
|
|
5058
|
+
getBaseUrlsList: () => _baseUrlsList,
|
|
5059
|
+
getBaseUrlsLastUpdate: () => _lastBaseUrlsUpdate,
|
|
5060
|
+
setBaseUrlsList: (urls) => {
|
|
5061
|
+
const normalized = urls.map(normalizeBaseUrl6);
|
|
5062
|
+
_baseUrlsList = normalized;
|
|
5063
|
+
void driver.setItem(SDK_STORAGE_KEYS.BASE_URLS_LIST, normalized);
|
|
5064
|
+
},
|
|
5065
|
+
setBaseUrlsLastUpdate: (timestamp) => {
|
|
5066
|
+
_lastBaseUrlsUpdate = timestamp;
|
|
5067
|
+
void driver.setItem(SDK_STORAGE_KEYS.LAST_BASE_URLS_UPDATE, timestamp);
|
|
5068
|
+
},
|
|
5069
|
+
// -- Routstr21 models (kv) --
|
|
5070
|
+
getRoutstr21Models: () => _routstr21Models,
|
|
5071
|
+
setRoutstr21Models: (models) => {
|
|
5072
|
+
_routstr21Models = models;
|
|
5073
|
+
void driver.setItem(SDK_STORAGE_KEYS.ROUTSTR21_MODELS, models);
|
|
5074
|
+
},
|
|
5075
|
+
getRoutstr21ModelsLastUpdate: () => _lastRoutstr21ModelsUpdate,
|
|
5076
|
+
setRoutstr21ModelsLastUpdate: (timestamp) => {
|
|
5077
|
+
_lastRoutstr21ModelsUpdate = timestamp;
|
|
5078
|
+
void driver.setItem(
|
|
5079
|
+
SDK_STORAGE_KEYS.LAST_ROUTSTR21_MODELS_UPDATE,
|
|
5080
|
+
timestamp
|
|
5081
|
+
);
|
|
5082
|
+
}
|
|
5083
|
+
};
|
|
5084
|
+
};
|
|
5085
|
+
var createProviderRegistryFromDiscoveryAdapter = (adapter, logger) => {
|
|
5086
|
+
const log = (logger ?? consoleLogger).child("ProviderRegistry");
|
|
5087
|
+
return {
|
|
5088
|
+
getModelsForProvider: (baseUrl) => {
|
|
5089
|
+
const normalized = normalizeBaseUrl6(baseUrl);
|
|
5090
|
+
return adapter.getCachedModels()[normalized] || [];
|
|
5091
|
+
},
|
|
5092
|
+
getDisabledProviders: () => adapter.getDisabledProviders(),
|
|
5093
|
+
getProviderMints: (baseUrl) => {
|
|
5094
|
+
const normalized = normalizeBaseUrl6(baseUrl);
|
|
5095
|
+
return adapter.getCachedMints()[normalized] || [];
|
|
5096
|
+
},
|
|
5097
|
+
getProviderInfo: async (baseUrl) => {
|
|
5098
|
+
const normalized = normalizeBaseUrl6(baseUrl);
|
|
5099
|
+
const cached = adapter.getCachedProviderInfo()[normalized];
|
|
5100
|
+
if (cached) return cached;
|
|
5101
|
+
try {
|
|
5102
|
+
const response = await fetch(`${normalized}v1/info`);
|
|
5103
|
+
if (!response.ok) {
|
|
5104
|
+
throw new Error(`Failed ${response.status}`);
|
|
5105
|
+
}
|
|
5106
|
+
const info = await response.json();
|
|
5107
|
+
adapter.setCachedProviderInfo({
|
|
5108
|
+
...adapter.getCachedProviderInfo(),
|
|
5109
|
+
[normalized]: info
|
|
5110
|
+
});
|
|
5111
|
+
return info;
|
|
5112
|
+
} catch (error) {
|
|
5113
|
+
log.warn(`Failed to fetch provider info from ${normalized}:`, error);
|
|
5114
|
+
return null;
|
|
5115
|
+
}
|
|
5116
|
+
},
|
|
5117
|
+
getAllProvidersModels: () => adapter.getCachedModels()
|
|
5118
|
+
};
|
|
5119
|
+
};
|
|
5120
|
+
|
|
4687
5121
|
// storage/index.ts
|
|
4688
5122
|
var isBrowser3 = () => {
|
|
4689
5123
|
try {
|
|
@@ -4753,9 +5187,15 @@ var getDefaultUsageTrackingDriver = () => {
|
|
|
4753
5187
|
var setDefaultUsageTrackingDriver = (driver) => {
|
|
4754
5188
|
defaultUsageTrackingDriver = driver;
|
|
4755
5189
|
};
|
|
4756
|
-
var
|
|
5190
|
+
var defaultDiscoveryAdapter = null;
|
|
5191
|
+
var getDefaultDiscoveryAdapter = async () => {
|
|
5192
|
+
if (defaultDiscoveryAdapter) return defaultDiscoveryAdapter;
|
|
5193
|
+
const driver = getDefaultSdkDriver();
|
|
5194
|
+
defaultDiscoveryAdapter = await createShardedDiscoveryAdapter({ driver });
|
|
5195
|
+
return defaultDiscoveryAdapter;
|
|
5196
|
+
};
|
|
4757
5197
|
var getDefaultStorageAdapter = async () => createStorageAdapterFromStore(await getDefaultSdkStore());
|
|
4758
|
-
var getDefaultProviderRegistry = async () =>
|
|
5198
|
+
var getDefaultProviderRegistry = async () => createProviderRegistryFromDiscoveryAdapter(await getDefaultDiscoveryAdapter());
|
|
4759
5199
|
function mergeUsage(previous, next) {
|
|
4760
5200
|
if (!previous) return next;
|
|
4761
5201
|
return {
|
|
@@ -5065,6 +5505,8 @@ var RoutstrClient = class {
|
|
|
5065
5505
|
baseUrl: prepared.baseUrlUsed,
|
|
5066
5506
|
mintUrl: params.mintUrl,
|
|
5067
5507
|
initialTokenBalance: prepared.tokenBalanceInSats,
|
|
5508
|
+
initialTokenBalanceUnknown: prepared.tokenBalanceUnknown,
|
|
5509
|
+
fallbackSatsSpent: usage?.satsCost,
|
|
5068
5510
|
response: prepared.response,
|
|
5069
5511
|
modelId: prepared.modelId,
|
|
5070
5512
|
usage,
|
|
@@ -5129,7 +5571,7 @@ var RoutstrClient = class {
|
|
|
5129
5571
|
);
|
|
5130
5572
|
}
|
|
5131
5573
|
}
|
|
5132
|
-
const { token, tokenBalance, tokenBalanceUnit } = await this._spendToken({
|
|
5574
|
+
const { token, tokenBalance, tokenBalanceUnit, tokenBalanceUnknown } = await this._spendToken({
|
|
5133
5575
|
mintUrl,
|
|
5134
5576
|
amount: requiredSats,
|
|
5135
5577
|
baseUrl
|
|
@@ -5155,9 +5597,20 @@ var RoutstrClient = class {
|
|
|
5155
5597
|
baseHeaders,
|
|
5156
5598
|
selectedModel
|
|
5157
5599
|
});
|
|
5158
|
-
|
|
5600
|
+
let tokenBalanceInSats = tokenBalanceUnit === "msat" ? tokenBalance / 1e3 : tokenBalance;
|
|
5601
|
+
let initialTokenBalanceUnknown = tokenBalanceUnknown;
|
|
5159
5602
|
const baseUrlUsed = response.baseUrl || baseUrl;
|
|
5160
5603
|
const tokenUsed = response.token || token;
|
|
5604
|
+
if (baseUrlUsed !== baseUrl || tokenUsed !== token) {
|
|
5605
|
+
if (typeof response.initialTokenBalanceInSats === "number") {
|
|
5606
|
+
tokenBalanceInSats = response.initialTokenBalanceInSats;
|
|
5607
|
+
initialTokenBalanceUnknown = Boolean(
|
|
5608
|
+
response.initialTokenBalanceUnknown
|
|
5609
|
+
);
|
|
5610
|
+
} else {
|
|
5611
|
+
initialTokenBalanceUnknown = true;
|
|
5612
|
+
}
|
|
5613
|
+
}
|
|
5161
5614
|
const contentType = response.headers.get("content-type") || "";
|
|
5162
5615
|
let processedResponse = response;
|
|
5163
5616
|
let capturedUsage;
|
|
@@ -5190,6 +5643,7 @@ var RoutstrClient = class {
|
|
|
5190
5643
|
tokenUsed,
|
|
5191
5644
|
baseUrlUsed,
|
|
5192
5645
|
tokenBalanceInSats,
|
|
5646
|
+
tokenBalanceUnknown: initialTokenBalanceUnknown,
|
|
5193
5647
|
modelId,
|
|
5194
5648
|
capturedUsage,
|
|
5195
5649
|
capturedResponseId,
|
|
@@ -5239,7 +5693,8 @@ var RoutstrClient = class {
|
|
|
5239
5693
|
let token = spendResult.token;
|
|
5240
5694
|
let tokenBalance = spendResult.tokenBalance;
|
|
5241
5695
|
let tokenBalanceUnit = spendResult.tokenBalanceUnit;
|
|
5242
|
-
|
|
5696
|
+
let tokenBalanceInSats = tokenBalanceUnit === "msat" ? tokenBalance / 1e3 : tokenBalance;
|
|
5697
|
+
let initialTokenBalanceUnknown = spendResult.tokenBalanceUnknown;
|
|
5243
5698
|
callbacks.onTokenCreated?.(this._getPendingCashuTokenAmount());
|
|
5244
5699
|
const baseHeaders = this._buildBaseHeaders(headers);
|
|
5245
5700
|
const requestHeaders = this._withAuthHeader(baseHeaders, token);
|
|
@@ -5282,6 +5737,18 @@ var RoutstrClient = class {
|
|
|
5282
5737
|
}
|
|
5283
5738
|
if (response.status === 200) {
|
|
5284
5739
|
const baseUrlUsed = response.baseUrl || baseUrl;
|
|
5740
|
+
const responseToken = response.token || token;
|
|
5741
|
+
if (baseUrlUsed !== baseUrl || responseToken !== token) {
|
|
5742
|
+
token = responseToken;
|
|
5743
|
+
if (typeof response.initialTokenBalanceInSats === "number") {
|
|
5744
|
+
tokenBalanceInSats = response.initialTokenBalanceInSats;
|
|
5745
|
+
initialTokenBalanceUnknown = Boolean(
|
|
5746
|
+
response.initialTokenBalanceUnknown
|
|
5747
|
+
);
|
|
5748
|
+
} else {
|
|
5749
|
+
initialTokenBalanceUnknown = true;
|
|
5750
|
+
}
|
|
5751
|
+
}
|
|
5285
5752
|
const streamingResult = await this.streamProcessor.process(
|
|
5286
5753
|
response,
|
|
5287
5754
|
{
|
|
@@ -5312,6 +5779,7 @@ var RoutstrClient = class {
|
|
|
5312
5779
|
baseUrl: baseUrlUsed,
|
|
5313
5780
|
mintUrl,
|
|
5314
5781
|
initialTokenBalance: tokenBalanceInSats,
|
|
5782
|
+
initialTokenBalanceUnknown,
|
|
5315
5783
|
fallbackSatsSpent: isApikeysEstimate ? this._getEstimatedCosts(selectedModel, streamingResult) : void 0,
|
|
5316
5784
|
response,
|
|
5317
5785
|
modelId: selectedModel.id,
|
|
@@ -5468,14 +5936,24 @@ var RoutstrClient = class {
|
|
|
5468
5936
|
params.token,
|
|
5469
5937
|
baseUrl
|
|
5470
5938
|
);
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5939
|
+
if (currentBalanceInfo.balanceUnknown) {
|
|
5940
|
+
this._log(
|
|
5941
|
+
"DEBUG",
|
|
5942
|
+
`[RoutstrClient] _handleErrorResponse: Current balance unknown for ${baseUrl}; using default topup amount=${topupAmount}`
|
|
5943
|
+
);
|
|
5944
|
+
} else {
|
|
5945
|
+
const currentBalance = currentBalanceInfo.unit === "msat" ? currentBalanceInfo.amount / 1e3 : currentBalanceInfo.amount;
|
|
5946
|
+
const reservedBalance = currentBalanceInfo.unit === "msat" ? (currentBalanceInfo.reserved ?? 0) / 1e3 : currentBalanceInfo.reserved ?? 0;
|
|
5947
|
+
const shortfall = Math.max(
|
|
5948
|
+
0,
|
|
5949
|
+
params.requiredSats - currentBalance + reservedBalance
|
|
5950
|
+
);
|
|
5951
|
+
topupAmount = shortfall > 0.21 * params.requiredSats ? shortfall : 0.21 * params.requiredSats;
|
|
5952
|
+
this._log(
|
|
5953
|
+
"DEBUG",
|
|
5954
|
+
`The shortfall is: ${shortfall}. requiredSats: ${params.requiredSats}. Current Balance: ${currentBalance}. Reserved Balance: ${reservedBalance}. Available Balance: ${currentBalance - reservedBalance}`
|
|
5955
|
+
);
|
|
5956
|
+
}
|
|
5479
5957
|
} catch (e) {
|
|
5480
5958
|
this._log(
|
|
5481
5959
|
"WARN",
|
|
@@ -5561,7 +6039,7 @@ var RoutstrClient = class {
|
|
|
5561
6039
|
this.storageAdapter.removeApiKey(baseUrl);
|
|
5562
6040
|
tryNextProvider = true;
|
|
5563
6041
|
} else {
|
|
5564
|
-
const latestTokenBalance = latestBalanceInfo.unit === "msat" ? latestBalanceInfo.amount / 1e3 : latestBalanceInfo.amount;
|
|
6042
|
+
const latestTokenBalance = latestBalanceInfo.balanceUnknown ? void 0 : latestBalanceInfo.unit === "msat" ? latestBalanceInfo.amount / 1e3 : latestBalanceInfo.amount;
|
|
5565
6043
|
if (latestBalanceInfo.apiKey) {
|
|
5566
6044
|
const storedApiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
|
|
5567
6045
|
if (storedApiKeyEntry?.key !== latestBalanceInfo.apiKey) {
|
|
@@ -5572,7 +6050,7 @@ var RoutstrClient = class {
|
|
|
5572
6050
|
}
|
|
5573
6051
|
retryToken = latestBalanceInfo.apiKey;
|
|
5574
6052
|
}
|
|
5575
|
-
if (latestTokenBalance >= 0) {
|
|
6053
|
+
if (latestTokenBalance !== void 0 && latestTokenBalance >= 0) {
|
|
5576
6054
|
this.storageAdapter.updateApiKeyBalance(
|
|
5577
6055
|
baseUrl,
|
|
5578
6056
|
latestTokenBalance
|
|
@@ -5647,7 +6125,7 @@ var RoutstrClient = class {
|
|
|
5647
6125
|
"DEBUG",
|
|
5648
6126
|
`[RoutstrClient] _handleErrorResponse: API key refund result: success=${refundResult.success}, message=${refundResult.message}`
|
|
5649
6127
|
);
|
|
5650
|
-
if (!refundResult.success && latestBalanceInfo.amount > 0) {
|
|
6128
|
+
if (!refundResult.success && latestBalanceInfo.amount > 0 && !latestBalanceInfo.balanceUnknown) {
|
|
5651
6129
|
throw new ProviderError(
|
|
5652
6130
|
baseUrl,
|
|
5653
6131
|
status,
|
|
@@ -5698,7 +6176,7 @@ var RoutstrClient = class {
|
|
|
5698
6176
|
amount: newRequiredSats,
|
|
5699
6177
|
baseUrl: nextProvider
|
|
5700
6178
|
});
|
|
5701
|
-
|
|
6179
|
+
const retryResponse = await this._makeRequest({
|
|
5702
6180
|
...params,
|
|
5703
6181
|
path,
|
|
5704
6182
|
method,
|
|
@@ -5710,6 +6188,9 @@ var RoutstrClient = class {
|
|
|
5710
6188
|
headers: this._withAuthHeader(params.baseHeaders, spendResult.token),
|
|
5711
6189
|
retryCount: 0
|
|
5712
6190
|
});
|
|
6191
|
+
retryResponse.initialTokenBalanceInSats = spendResult.tokenBalanceUnit === "msat" ? spendResult.tokenBalance / 1e3 : spendResult.tokenBalance;
|
|
6192
|
+
retryResponse.initialTokenBalanceUnknown = spendResult.tokenBalanceUnknown;
|
|
6193
|
+
return retryResponse;
|
|
5713
6194
|
}
|
|
5714
6195
|
throw new FailoverError(
|
|
5715
6196
|
baseUrl,
|
|
@@ -5725,6 +6206,7 @@ var RoutstrClient = class {
|
|
|
5725
6206
|
baseUrl,
|
|
5726
6207
|
mintUrl,
|
|
5727
6208
|
initialTokenBalance,
|
|
6209
|
+
initialTokenBalanceUnknown,
|
|
5728
6210
|
fallbackSatsSpent,
|
|
5729
6211
|
response,
|
|
5730
6212
|
modelId,
|
|
@@ -5761,17 +6243,19 @@ var RoutstrClient = class {
|
|
|
5761
6243
|
latestBalanceInfo.apiKey,
|
|
5762
6244
|
baseUrl
|
|
5763
6245
|
);
|
|
5764
|
-
const latestTokenBalance = latestBalanceInfo.unit === "msat" ? latestBalanceInfo.amount / 1e3 : latestBalanceInfo.amount;
|
|
6246
|
+
const latestTokenBalance = latestBalanceInfo.balanceUnknown ? void 0 : latestBalanceInfo.unit === "msat" ? latestBalanceInfo.amount / 1e3 : latestBalanceInfo.amount;
|
|
5765
6247
|
const storedApiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
|
|
5766
6248
|
if (storedApiKeyEntry?.key.startsWith("cashu") && latestBalanceInfo.apiKey) {
|
|
5767
6249
|
this.storageAdapter.removeApiKey(baseUrl);
|
|
5768
6250
|
this.storageAdapter.setApiKey(baseUrl, latestBalanceInfo.apiKey);
|
|
5769
6251
|
}
|
|
5770
|
-
|
|
5771
|
-
|
|
6252
|
+
if (latestTokenBalance !== void 0) {
|
|
6253
|
+
this.storageAdapter.updateApiKeyBalance(baseUrl, latestTokenBalance);
|
|
6254
|
+
}
|
|
6255
|
+
satsSpent = latestTokenBalance !== void 0 && !initialTokenBalanceUnknown ? Math.max(0, initialTokenBalance - latestTokenBalance) : fallbackSatsSpent ?? usage?.satsCost ?? 0;
|
|
5772
6256
|
} catch (e) {
|
|
5773
6257
|
this._log("WARN", "Could not get updated API key balance:", e);
|
|
5774
|
-
satsSpent = fallbackSatsSpent ??
|
|
6258
|
+
satsSpent = fallbackSatsSpent ?? usage?.satsCost ?? 0;
|
|
5775
6259
|
}
|
|
5776
6260
|
}
|
|
5777
6261
|
await this._trackResponseUsage({
|
|
@@ -6021,6 +6505,7 @@ var RoutstrClient = class {
|
|
|
6021
6505
|
}
|
|
6022
6506
|
let tokenBalance = 0;
|
|
6023
6507
|
let tokenBalanceUnit = "sat";
|
|
6508
|
+
let tokenBalanceUnknown = false;
|
|
6024
6509
|
const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
|
|
6025
6510
|
const distributionForBaseUrl = apiKeyDistribution.find(
|
|
6026
6511
|
(d) => d.baseUrl === baseUrl
|
|
@@ -6036,6 +6521,7 @@ var RoutstrClient = class {
|
|
|
6036
6521
|
);
|
|
6037
6522
|
tokenBalance = balanceInfo.amount;
|
|
6038
6523
|
tokenBalanceUnit = balanceInfo.unit;
|
|
6524
|
+
tokenBalanceUnknown = Boolean(balanceInfo.balanceUnknown);
|
|
6039
6525
|
} catch (e) {
|
|
6040
6526
|
this._log("WARN", "Could not get initial API key balance:", e);
|
|
6041
6527
|
}
|
|
@@ -6047,7 +6533,8 @@ var RoutstrClient = class {
|
|
|
6047
6533
|
return {
|
|
6048
6534
|
token: parentApiKey?.key ?? "",
|
|
6049
6535
|
tokenBalance,
|
|
6050
|
-
tokenBalanceUnit
|
|
6536
|
+
tokenBalanceUnit,
|
|
6537
|
+
tokenBalanceUnknown
|
|
6051
6538
|
};
|
|
6052
6539
|
}
|
|
6053
6540
|
this._log(
|
|
@@ -6076,7 +6563,8 @@ var RoutstrClient = class {
|
|
|
6076
6563
|
return {
|
|
6077
6564
|
token: spendResult.token,
|
|
6078
6565
|
tokenBalance: spendResult.balance,
|
|
6079
|
-
tokenBalanceUnit: spendResult.unit ?? "sat"
|
|
6566
|
+
tokenBalanceUnit: spendResult.unit ?? "sat",
|
|
6567
|
+
tokenBalanceUnknown: false
|
|
6080
6568
|
};
|
|
6081
6569
|
}
|
|
6082
6570
|
/**
|
|
@@ -6253,6 +6741,6 @@ function extractStream(requestBody) {
|
|
|
6253
6741
|
return typeof stream === "boolean" ? stream : void 0;
|
|
6254
6742
|
}
|
|
6255
6743
|
|
|
6256
|
-
export { BalanceManager, CashuSpender, FailoverError, InsufficientBalanceError, MintDiscovery, MintDiscoveryError, MintUnreachableError, ModelManager, ModelNotFoundError, NoProvidersAvailableError, ProviderBootstrapError, ProviderError, ProviderManager, RoutstrClient, SDK_STORAGE_KEYS, StreamProcessor, StreamingError, TokenOperationError, consoleLogger, createBunSqliteDriver, createBunSqliteUsageTrackingDriver, createDiscoveryAdapterFromStore, createIndexedDBDriver, createIndexedDBUsageTrackingDriver, createMemoryDriver, createMemoryUsageTrackingDriver, createProviderRegistryFromStore, createSSEParserTransform, createSdkStore, createSqliteDriver, createSqliteUsageTrackingDriver, createStorageAdapterFromStore, filterBaseUrlsForTor, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultSdkDriver, getDefaultSdkStore, getDefaultStorageAdapter, getDefaultUsageTrackingDriver, getProviderEndpoints, inspectSSEWebStream, isOnionUrl, isTorContext, localStorageDriver, noopLogger, normalizeProviderUrl, routeRequests, setDefaultUsageTrackingDriver };
|
|
6744
|
+
export { BalanceManager, CashuSpender, FailoverError, InsufficientBalanceError, MintDiscovery, MintDiscoveryError, MintUnreachableError, ModelManager, ModelNotFoundError, NoProvidersAvailableError, ProviderBootstrapError, ProviderError, ProviderManager, RoutstrClient, SDK_STORAGE_KEYS, StreamProcessor, StreamingError, TokenOperationError, consoleLogger, createBunSqliteDriver, createBunSqliteUsageTrackingDriver, createDiscoveryAdapterFromStore, createIndexedDBDriver, createIndexedDBUsageTrackingDriver, createMemoryDriver, createMemoryUsageTrackingDriver, createProviderRegistryFromDiscoveryAdapter, createProviderRegistryFromStore, createSSEParserTransform, createSdkStore, createShardedDiscoveryAdapter, createSqliteDriver, createSqliteUsageTrackingDriver, createStorageAdapterFromStore, filterBaseUrlsForTor, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultSdkDriver, getDefaultSdkStore, getDefaultStorageAdapter, getDefaultUsageTrackingDriver, getProviderEndpoints, inspectSSEWebStream, isOnionUrl, isTorContext, localStorageDriver, noopLogger, normalizeProviderUrl, routeRequests, setDefaultUsageTrackingDriver };
|
|
6257
6745
|
//# sourceMappingURL=index.mjs.map
|
|
6258
6746
|
//# sourceMappingURL=index.mjs.map
|