@routstr/sdk 0.2.4 → 0.2.6

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.
Files changed (40) hide show
  1. package/README.md +10 -2
  2. package/dist/client/index.d.mts +38 -11
  3. package/dist/client/index.d.ts +38 -11
  4. package/dist/client/index.js +1771 -391
  5. package/dist/client/index.js.map +1 -1
  6. package/dist/client/index.mjs +1771 -392
  7. package/dist/client/index.mjs.map +1 -1
  8. package/dist/discovery/index.d.mts +2 -2
  9. package/dist/discovery/index.d.ts +2 -2
  10. package/dist/discovery/index.js +1 -4
  11. package/dist/discovery/index.js.map +1 -1
  12. package/dist/discovery/index.mjs +1 -4
  13. package/dist/discovery/index.mjs.map +1 -1
  14. package/dist/index.d.mts +26 -22
  15. package/dist/index.d.ts +26 -22
  16. package/dist/index.js +3005 -2107
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.mjs +2997 -2108
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/{interfaces-B85Wx7ni.d.mts → interfaces-B62Rw-dd.d.ts} +20 -15
  21. package/dist/{interfaces-DGdP8fQp.d.mts → interfaces-BWJJTCXO.d.mts} +1 -1
  22. package/dist/{interfaces-CC0LT9p9.d.ts → interfaces-BxDEka72.d.ts} +1 -1
  23. package/dist/{interfaces-BVNyAmKu.d.ts → interfaces-C5fLD3jB.d.mts} +20 -15
  24. package/dist/storage/index.d.mts +38 -142
  25. package/dist/storage/index.d.ts +38 -142
  26. package/dist/storage/index.js +852 -158
  27. package/dist/storage/index.js.map +1 -1
  28. package/dist/storage/index.mjs +846 -159
  29. package/dist/storage/index.mjs.map +1 -1
  30. package/dist/store-BJlwiDX5.d.ts +151 -0
  31. package/dist/store-C5lnyX8k.d.mts +151 -0
  32. package/dist/{types-BlHjmWRK.d.mts → types-BYj_8c5c.d.mts} +3 -0
  33. package/dist/{types-BlHjmWRK.d.ts → types-BYj_8c5c.d.ts} +3 -0
  34. package/dist/wallet/index.d.mts +24 -26
  35. package/dist/wallet/index.d.ts +24 -26
  36. package/dist/wallet/index.js +130 -259
  37. package/dist/wallet/index.js.map +1 -1
  38. package/dist/wallet/index.mjs +130 -259
  39. package/dist/wallet/index.mjs.map +1 -1
  40. package/package.json +1 -1
@@ -1,14 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  var vanilla = require('zustand/vanilla');
4
- var cashuTs = require('@cashu/cashu-ts');
5
-
6
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
- }) : x)(function(x) {
9
- if (typeof require !== "undefined") return require.apply(this, arguments);
10
- throw Error('Dynamic require of "' + x + '" is not supported');
11
- });
12
4
 
13
5
  // storage/drivers/localStorage.ts
14
6
  var canUseLocalStorage = () => {
@@ -122,38 +114,54 @@ var createMemoryDriver = (seed) => {
122
114
  var isBun = () => {
123
115
  return typeof process.versions.bun !== "undefined";
124
116
  };
125
- var createDatabase = (dbPath) => {
117
+ var cachedDbModule = null;
118
+ var loadDatabase = async (dbPath) => {
126
119
  if (isBun()) {
127
120
  throw new Error(
128
- "SQLite driver not supported in Bun. Use createMemoryDriver() instead."
121
+ "SQLite driver not supported in Bun. Use createBunSqliteDriver() instead."
129
122
  );
130
123
  }
131
- let Database = null;
132
124
  try {
133
- Database = __require("better-sqlite3");
125
+ if (!cachedDbModule) {
126
+ cachedDbModule = (await import('better-sqlite3')).default;
127
+ }
128
+ return new cachedDbModule(dbPath);
134
129
  } catch (error) {
135
130
  throw new Error(
136
131
  `better-sqlite3 is required for sqlite storage. Install it to use sqlite storage. (${error})`
137
132
  );
138
133
  }
139
- return new Database(dbPath);
140
134
  };
141
135
  var createSqliteDriver = (options = {}) => {
142
136
  const dbPath = options.dbPath || "routstr.sqlite";
143
137
  const tableName = options.tableName || "sdk_storage";
144
- const db = createDatabase(dbPath);
145
- db.exec(
146
- `CREATE TABLE IF NOT EXISTS ${tableName} (key TEXT PRIMARY KEY, value TEXT NOT NULL)`
147
- );
148
- const selectStmt = db.prepare(`SELECT value FROM ${tableName} WHERE key = ?`);
149
- const upsertStmt = db.prepare(
150
- `INSERT INTO ${tableName} (key, value) VALUES (?, ?)
138
+ let db;
139
+ let selectStmt;
140
+ let upsertStmt;
141
+ let deleteStmt;
142
+ const initDb = async () => {
143
+ if (!db) {
144
+ db = await loadDatabase(dbPath);
145
+ db.exec(
146
+ `CREATE TABLE IF NOT EXISTS ${tableName} (key TEXT PRIMARY KEY, value TEXT NOT NULL)`
147
+ );
148
+ selectStmt = db.prepare(`SELECT value FROM ${tableName} WHERE key = ?`);
149
+ upsertStmt = db.prepare(
150
+ `INSERT INTO ${tableName} (key, value) VALUES (?, ?)
151
151
  ON CONFLICT(key) DO UPDATE SET value = excluded.value`
152
- );
153
- const deleteStmt = db.prepare(`DELETE FROM ${tableName} WHERE key = ?`);
152
+ );
153
+ deleteStmt = db.prepare(`DELETE FROM ${tableName} WHERE key = ?`);
154
+ }
155
+ };
156
+ const ensureInit = async () => {
157
+ if (!db) {
158
+ await initDb();
159
+ }
160
+ };
154
161
  return {
155
162
  async getItem(key, defaultValue) {
156
163
  try {
164
+ await ensureInit();
157
165
  const row = selectStmt.get(key);
158
166
  if (!row || typeof row.value !== "string") return defaultValue;
159
167
  try {
@@ -171,6 +179,7 @@ var createSqliteDriver = (options = {}) => {
171
179
  },
172
180
  async setItem(key, value) {
173
181
  try {
182
+ await ensureInit();
174
183
  upsertStmt.run(key, JSON.stringify(value));
175
184
  } catch (error) {
176
185
  console.error(`SQLite setItem failed for key "${key}":`, error);
@@ -178,6 +187,7 @@ var createSqliteDriver = (options = {}) => {
178
187
  },
179
188
  async removeItem(key) {
180
189
  try {
190
+ await ensureInit();
181
191
  deleteStmt.run(key);
182
192
  } catch (error) {
183
193
  console.error(`SQLite removeItem failed for key "${key}":`, error);
@@ -185,6 +195,54 @@ var createSqliteDriver = (options = {}) => {
185
195
  }
186
196
  };
187
197
  };
198
+ async function createBunSqliteDriver(dbPath) {
199
+ const SQLite = (await import(
200
+ /* webpackIgnore: true */
201
+ 'bun:sqlite'
202
+ )).default;
203
+ const db = new SQLite(dbPath);
204
+ db.run(`
205
+ CREATE TABLE IF NOT EXISTS sdk_storage (
206
+ key TEXT PRIMARY KEY,
207
+ value TEXT NOT NULL
208
+ )
209
+ `);
210
+ return {
211
+ async getItem(key, defaultValue) {
212
+ try {
213
+ const row = db.query("SELECT value FROM sdk_storage WHERE key = ?").get(key);
214
+ if (!row || typeof row.value !== "string") return defaultValue;
215
+ try {
216
+ return JSON.parse(row.value);
217
+ } catch (parseError) {
218
+ if (typeof defaultValue === "string") {
219
+ return row.value;
220
+ }
221
+ throw parseError;
222
+ }
223
+ } catch (error) {
224
+ console.error(`SQLite getItem failed for key "${key}":`, error);
225
+ return defaultValue;
226
+ }
227
+ },
228
+ async setItem(key, value) {
229
+ try {
230
+ db.query(
231
+ "INSERT INTO sdk_storage (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value"
232
+ ).run(key, JSON.stringify(value));
233
+ } catch (error) {
234
+ console.error(`SQLite setItem failed for key "${key}":`, error);
235
+ }
236
+ },
237
+ async removeItem(key) {
238
+ try {
239
+ db.query("DELETE FROM sdk_storage WHERE key = ?").run(key);
240
+ } catch (error) {
241
+ console.error(`SQLite removeItem failed for key "${key}":`, error);
242
+ }
243
+ }
244
+ };
245
+ }
188
246
 
189
247
  // storage/drivers/indexedDB.ts
190
248
  var isBrowser = typeof indexedDB !== "undefined";
@@ -290,9 +348,9 @@ var SDK_STORAGE_KEYS = {
290
348
  INFO_FROM_ALL_PROVIDERS: "info_from_all_providers",
291
349
  LAST_MODELS_UPDATE: "lastModelsUpdate",
292
350
  LAST_BASE_URLS_UPDATE: "lastBaseUrlsUpdate",
293
- LOCAL_CASHU_TOKENS: "local_cashu_tokens",
294
351
  API_KEYS: "api_keys",
295
352
  CHILD_KEYS: "child_keys",
353
+ XCASHU_TOKENS: "xcashu_tokens",
296
354
  ROUTSTR21_MODELS: "routstr21Models",
297
355
  LAST_ROUTSTR21_MODELS_UPDATE: "lastRoutstr21ModelsUpdate",
298
356
  CACHED_RECEIVE_TOKENS: "cached_receive_tokens",
@@ -300,21 +358,634 @@ var SDK_STORAGE_KEYS = {
300
358
  CLIENT_IDS: "client_ids"
301
359
  };
302
360
 
303
- // storage/store.ts
361
+ // storage/usageTracking/indexedDB.ts
362
+ var DEFAULT_DB_NAME = "routstr-sdk";
363
+ var DEFAULT_STORE_NAME = "usage_tracking";
364
+ var MIGRATION_MARKER_KEY = "usage_tracking_migration_v1";
365
+ var isBrowser2 = typeof indexedDB !== "undefined";
304
366
  var normalizeBaseUrl = (baseUrl) => baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
305
- var getCashuTokenBalance = (token) => {
367
+ var openDatabase2 = (dbName, storeName) => {
368
+ if (!isBrowser2) {
369
+ return Promise.reject(new Error("IndexedDB is not available"));
370
+ }
371
+ return new Promise((resolve, reject) => {
372
+ const request = indexedDB.open(dbName, 1);
373
+ request.onupgradeneeded = () => {
374
+ const db = request.result;
375
+ if (!db.objectStoreNames.contains(storeName)) {
376
+ const store = db.createObjectStore(storeName, { keyPath: "id" });
377
+ store.createIndex("timestamp", "timestamp", { unique: false });
378
+ store.createIndex("modelId", "modelId", { unique: false });
379
+ store.createIndex("baseUrl", "baseUrl", { unique: false });
380
+ store.createIndex("sessionId", "sessionId", { unique: false });
381
+ store.createIndex("client", "client", { unique: false });
382
+ }
383
+ };
384
+ request.onsuccess = () => resolve(request.result);
385
+ request.onerror = () => reject(request.error);
386
+ });
387
+ };
388
+ var matchesFilters = (entry, options = {}) => {
389
+ if (typeof options.before === "number" && entry.timestamp >= options.before) {
390
+ return false;
391
+ }
392
+ if (typeof options.after === "number" && entry.timestamp <= options.after) {
393
+ return false;
394
+ }
395
+ if (options.modelId && entry.modelId !== options.modelId) {
396
+ return false;
397
+ }
398
+ if (options.baseUrl && normalizeBaseUrl(entry.baseUrl) !== normalizeBaseUrl(options.baseUrl)) {
399
+ return false;
400
+ }
401
+ if (options.sessionId && entry.sessionId !== options.sessionId) {
402
+ return false;
403
+ }
404
+ if (options.client && entry.client !== options.client) {
405
+ return false;
406
+ }
407
+ return true;
408
+ };
409
+ var createIndexedDBUsageTrackingDriver = (options = {}) => {
410
+ const dbName = options.dbName || DEFAULT_DB_NAME;
411
+ const storeName = options.storeName || DEFAULT_STORE_NAME;
412
+ const legacyStorageDriver = options.legacyStorageDriver;
413
+ let dbPromise = null;
414
+ let migrationPromise = null;
415
+ const getDb = () => {
416
+ if (!dbPromise) {
417
+ dbPromise = openDatabase2(dbName, storeName);
418
+ }
419
+ return dbPromise;
420
+ };
421
+ const putMany = async (entries) => {
422
+ if (entries.length === 0) return;
423
+ const db = await getDb();
424
+ await new Promise((resolve, reject) => {
425
+ const tx = db.transaction(storeName, "readwrite");
426
+ const store = tx.objectStore(storeName);
427
+ for (const entry of entries) {
428
+ store.put({ ...entry, baseUrl: normalizeBaseUrl(entry.baseUrl) });
429
+ }
430
+ tx.oncomplete = () => resolve();
431
+ tx.onerror = () => reject(tx.error);
432
+ });
433
+ };
434
+ const ensureMigrated = async () => {
435
+ if (!legacyStorageDriver) return;
436
+ if (!migrationPromise) {
437
+ migrationPromise = (async () => {
438
+ const migrated = await legacyStorageDriver.getItem(
439
+ MIGRATION_MARKER_KEY,
440
+ false
441
+ );
442
+ if (migrated) return;
443
+ const legacyEntries = await legacyStorageDriver.getItem(
444
+ SDK_STORAGE_KEYS.USAGE_TRACKING,
445
+ []
446
+ );
447
+ if (legacyEntries.length > 0) {
448
+ await putMany(legacyEntries);
449
+ await legacyStorageDriver.removeItem(SDK_STORAGE_KEYS.USAGE_TRACKING);
450
+ }
451
+ await legacyStorageDriver.setItem(MIGRATION_MARKER_KEY, true);
452
+ })();
453
+ }
454
+ await migrationPromise;
455
+ };
456
+ return {
457
+ async migrate() {
458
+ await ensureMigrated();
459
+ },
460
+ async append(entry) {
461
+ await ensureMigrated();
462
+ await putMany([entry]);
463
+ },
464
+ async appendMany(entries) {
465
+ await ensureMigrated();
466
+ await putMany(entries);
467
+ },
468
+ async list(options2 = {}) {
469
+ await ensureMigrated();
470
+ const db = await getDb();
471
+ return new Promise((resolve, reject) => {
472
+ const tx = db.transaction(storeName, "readonly");
473
+ const store = tx.objectStore(storeName);
474
+ const index = store.index("timestamp");
475
+ const direction = "prev";
476
+ const request = index.openCursor(null, direction);
477
+ const results = [];
478
+ const limit = options2.limit;
479
+ request.onsuccess = () => {
480
+ const cursor = request.result;
481
+ if (!cursor) {
482
+ resolve(results);
483
+ return;
484
+ }
485
+ const value = cursor.value;
486
+ if (matchesFilters(value, options2)) {
487
+ results.push(value);
488
+ if (typeof limit === "number" && results.length >= limit) {
489
+ resolve(results);
490
+ return;
491
+ }
492
+ }
493
+ cursor.continue();
494
+ };
495
+ request.onerror = () => reject(request.error);
496
+ });
497
+ },
498
+ async count(options2 = {}) {
499
+ const results = await this.list(options2);
500
+ return results.length;
501
+ },
502
+ async deleteOlderThan(timestamp) {
503
+ await ensureMigrated();
504
+ const db = await getDb();
505
+ return new Promise((resolve, reject) => {
506
+ const tx = db.transaction(storeName, "readwrite");
507
+ const store = tx.objectStore(storeName);
508
+ const index = store.index("timestamp");
509
+ const range = IDBKeyRange.upperBound(timestamp, true);
510
+ const request = index.openCursor(range);
511
+ let deleted = 0;
512
+ request.onsuccess = () => {
513
+ const cursor = request.result;
514
+ if (!cursor) {
515
+ resolve(deleted);
516
+ return;
517
+ }
518
+ deleted += 1;
519
+ cursor.delete();
520
+ cursor.continue();
521
+ };
522
+ request.onerror = () => reject(request.error);
523
+ });
524
+ },
525
+ async clear() {
526
+ await ensureMigrated();
527
+ const db = await getDb();
528
+ await new Promise((resolve, reject) => {
529
+ const tx = db.transaction(storeName, "readwrite");
530
+ tx.objectStore(storeName).clear();
531
+ tx.oncomplete = () => resolve();
532
+ tx.onerror = () => reject(tx.error);
533
+ });
534
+ }
535
+ };
536
+ };
537
+
538
+ // storage/usageTracking/sqlite.ts
539
+ var MIGRATION_MARKER_KEY2 = "usage_tracking_migration_v1";
540
+ var normalizeBaseUrl2 = (baseUrl) => baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
541
+ var isBun2 = () => {
542
+ return typeof process.versions.bun !== "undefined";
543
+ };
544
+ var cachedDbModule2 = null;
545
+ var loadDatabase2 = async (dbPath) => {
546
+ if (isBun2()) {
547
+ throw new Error(
548
+ "SQLite driver not supported in Bun. Use createMemoryDriver() instead."
549
+ );
550
+ }
306
551
  try {
307
- const decoded = cashuTs.getDecodedToken(token);
308
- const unitDivisor = decoded.unit === "msat" ? 1e3 : 1;
309
- let sum = 0;
310
- for (const proof of decoded.proofs) {
311
- sum += proof.amount / unitDivisor;
552
+ if (!cachedDbModule2) {
553
+ cachedDbModule2 = (await import('better-sqlite3')).default;
312
554
  }
313
- return sum;
314
- } catch {
315
- return 0;
555
+ return new cachedDbModule2(dbPath);
556
+ } catch (error) {
557
+ throw new Error(
558
+ `better-sqlite3 is required for sqlite usage tracking. Install it to use sqlite storage. (${error})`
559
+ );
560
+ }
561
+ };
562
+ var buildWhereClause = (options = {}) => {
563
+ const clauses = [];
564
+ const params = [];
565
+ if (typeof options.before === "number") {
566
+ clauses.push("timestamp < ?");
567
+ params.push(options.before);
568
+ }
569
+ if (typeof options.after === "number") {
570
+ clauses.push("timestamp > ?");
571
+ params.push(options.after);
572
+ }
573
+ if (options.modelId) {
574
+ clauses.push("model_id = ?");
575
+ params.push(options.modelId);
576
+ }
577
+ if (options.baseUrl) {
578
+ clauses.push("base_url = ?");
579
+ params.push(normalizeBaseUrl2(options.baseUrl));
580
+ }
581
+ if (options.sessionId) {
582
+ clauses.push("session_id = ?");
583
+ params.push(options.sessionId);
584
+ }
585
+ if (options.client) {
586
+ clauses.push("client = ?");
587
+ params.push(options.client);
588
+ }
589
+ return {
590
+ sql: clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "",
591
+ params
592
+ };
593
+ };
594
+ var createSqliteUsageTrackingDriver = (options = {}) => {
595
+ const dbPath = options.dbPath || "routstr.sqlite";
596
+ const tableName = options.tableName || "usage_tracking";
597
+ const legacyStorageDriver = options.legacyStorageDriver;
598
+ let db;
599
+ let insertStmt;
600
+ let migrationComplete = false;
601
+ const initDb = async () => {
602
+ if (!db) {
603
+ db = await loadDatabase2(dbPath);
604
+ db.exec(`
605
+ CREATE TABLE IF NOT EXISTS ${tableName} (
606
+ id TEXT PRIMARY KEY,
607
+ timestamp INTEGER NOT NULL,
608
+ model_id TEXT NOT NULL,
609
+ base_url TEXT NOT NULL,
610
+ request_id TEXT NOT NULL,
611
+ cost REAL NOT NULL,
612
+ sats_cost REAL NOT NULL,
613
+ prompt_tokens INTEGER NOT NULL,
614
+ completion_tokens INTEGER NOT NULL,
615
+ total_tokens INTEGER NOT NULL,
616
+ client TEXT,
617
+ session_id TEXT,
618
+ tags TEXT
619
+ );
620
+ CREATE INDEX IF NOT EXISTS idx_${tableName}_timestamp ON ${tableName}(timestamp);
621
+ CREATE INDEX IF NOT EXISTS idx_${tableName}_model_id ON ${tableName}(model_id);
622
+ CREATE INDEX IF NOT EXISTS idx_${tableName}_base_url ON ${tableName}(base_url);
623
+ CREATE INDEX IF NOT EXISTS idx_${tableName}_session_id ON ${tableName}(session_id);
624
+ CREATE INDEX IF NOT EXISTS idx_${tableName}_client ON ${tableName}(client);
625
+ `);
626
+ insertStmt = db.prepare(`
627
+ INSERT OR REPLACE INTO ${tableName} (
628
+ id, timestamp, model_id, base_url, request_id,
629
+ cost, sats_cost, prompt_tokens, completion_tokens, total_tokens,
630
+ client, session_id, tags
631
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
632
+ `);
633
+ }
634
+ };
635
+ const ensureInit = async () => {
636
+ if (!db) {
637
+ await initDb();
638
+ }
639
+ };
640
+ const appendOne = (entry) => {
641
+ insertStmt.run(
642
+ entry.id,
643
+ entry.timestamp,
644
+ entry.modelId,
645
+ normalizeBaseUrl2(entry.baseUrl),
646
+ entry.requestId,
647
+ entry.cost,
648
+ entry.satsCost,
649
+ entry.promptTokens,
650
+ entry.completionTokens,
651
+ entry.totalTokens,
652
+ entry.client ?? null,
653
+ entry.sessionId ?? null,
654
+ JSON.stringify(entry.tags ?? [])
655
+ );
656
+ };
657
+ const ensureMigrated = async () => {
658
+ if (!legacyStorageDriver || migrationComplete) return;
659
+ const migrated = await legacyStorageDriver.getItem(
660
+ MIGRATION_MARKER_KEY2,
661
+ false
662
+ );
663
+ if (migrated) {
664
+ migrationComplete = true;
665
+ return;
666
+ }
667
+ const legacyEntries = await legacyStorageDriver.getItem(
668
+ SDK_STORAGE_KEYS.USAGE_TRACKING,
669
+ []
670
+ );
671
+ for (const entry of legacyEntries) {
672
+ appendOne(entry);
673
+ }
674
+ if (legacyEntries.length > 0) {
675
+ await legacyStorageDriver.removeItem(SDK_STORAGE_KEYS.USAGE_TRACKING);
676
+ }
677
+ await legacyStorageDriver.setItem(MIGRATION_MARKER_KEY2, true);
678
+ migrationComplete = true;
679
+ };
680
+ const mapRow = (row) => ({
681
+ id: row.id,
682
+ timestamp: row.timestamp,
683
+ modelId: row.model_id,
684
+ baseUrl: row.base_url,
685
+ requestId: row.request_id,
686
+ cost: row.cost,
687
+ satsCost: row.sats_cost,
688
+ promptTokens: row.prompt_tokens,
689
+ completionTokens: row.completion_tokens,
690
+ totalTokens: row.total_tokens,
691
+ client: row.client ?? void 0,
692
+ sessionId: row.session_id ?? void 0,
693
+ tags: typeof row.tags === "string" ? JSON.parse(row.tags) : void 0
694
+ });
695
+ return {
696
+ async migrate() {
697
+ await ensureInit();
698
+ await ensureMigrated();
699
+ },
700
+ async append(entry) {
701
+ await ensureInit();
702
+ await ensureMigrated();
703
+ appendOne(entry);
704
+ },
705
+ async appendMany(entries) {
706
+ await ensureInit();
707
+ await ensureMigrated();
708
+ for (const entry of entries) {
709
+ appendOne(entry);
710
+ }
711
+ },
712
+ async list(options2 = {}) {
713
+ await ensureInit();
714
+ await ensureMigrated();
715
+ const { sql, params } = buildWhereClause(options2);
716
+ const limitSql = typeof options2.limit === "number" ? " LIMIT ?" : "";
717
+ const stmt = db.prepare(
718
+ `SELECT * FROM ${tableName} ${sql} ORDER BY timestamp DESC${limitSql}`
719
+ );
720
+ const rows = stmt.all(
721
+ ...typeof options2.limit === "number" ? [...params, options2.limit] : params
722
+ );
723
+ return rows.map(mapRow);
724
+ },
725
+ async count(options2 = {}) {
726
+ await ensureInit();
727
+ await ensureMigrated();
728
+ const { sql, params } = buildWhereClause(options2);
729
+ const stmt = db.prepare(`SELECT COUNT(*) as count FROM ${tableName} ${sql}`);
730
+ const row = stmt.get(...params);
731
+ return Number(row?.count ?? 0);
732
+ },
733
+ async deleteOlderThan(timestamp) {
734
+ await ensureInit();
735
+ await ensureMigrated();
736
+ const stmt = db.prepare(`DELETE FROM ${tableName} WHERE timestamp < ?`);
737
+ const result = stmt.run(timestamp);
738
+ return result.changes;
739
+ },
740
+ async clear() {
741
+ await ensureInit();
742
+ await ensureMigrated();
743
+ db.prepare(`DELETE FROM ${tableName}`).run();
744
+ }
745
+ };
746
+ };
747
+
748
+ // storage/usageTracking/bunSqlite.ts
749
+ var MIGRATION_MARKER_KEY3 = "usage_tracking_migration_v1";
750
+ var normalizeBaseUrl3 = (baseUrl) => baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
751
+ var buildWhereClause2 = (options = {}) => {
752
+ const clauses = [];
753
+ const params = [];
754
+ if (typeof options.before === "number") {
755
+ clauses.push("timestamp < ?");
756
+ params.push(options.before);
757
+ }
758
+ if (typeof options.after === "number") {
759
+ clauses.push("timestamp > ?");
760
+ params.push(options.after);
761
+ }
762
+ if (options.modelId) {
763
+ clauses.push("model_id = ?");
764
+ params.push(options.modelId);
765
+ }
766
+ if (options.baseUrl) {
767
+ clauses.push("base_url = ?");
768
+ params.push(normalizeBaseUrl3(options.baseUrl));
769
+ }
770
+ if (options.sessionId) {
771
+ clauses.push("session_id = ?");
772
+ params.push(options.sessionId);
773
+ }
774
+ if (options.client) {
775
+ clauses.push("client = ?");
776
+ params.push(options.client);
777
+ }
778
+ return {
779
+ sql: clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "",
780
+ params
781
+ };
782
+ };
783
+ var createBunSqliteUsageTrackingDriver = (options = {}) => {
784
+ const dbPath = options.dbPath || "routstr.sqlite";
785
+ const tableName = options.tableName || "usage_tracking";
786
+ const legacyStorageDriver = options.legacyStorageDriver;
787
+ const SQLiteDatabase = options.sqlite?.Database;
788
+ let migrationPromise = null;
789
+ if (!SQLiteDatabase) {
790
+ throw new Error(
791
+ "Bun SQLite Database constructor is required. Pass { sqlite: { Database } } when creating the driver."
792
+ );
793
+ }
794
+ const db = new SQLiteDatabase(dbPath);
795
+ db.run(`
796
+ CREATE TABLE IF NOT EXISTS ${tableName} (
797
+ id TEXT PRIMARY KEY,
798
+ timestamp INTEGER NOT NULL,
799
+ model_id TEXT NOT NULL,
800
+ base_url TEXT NOT NULL,
801
+ request_id TEXT NOT NULL,
802
+ cost REAL NOT NULL,
803
+ sats_cost REAL NOT NULL,
804
+ prompt_tokens INTEGER NOT NULL,
805
+ completion_tokens INTEGER NOT NULL,
806
+ total_tokens INTEGER NOT NULL,
807
+ client TEXT,
808
+ session_id TEXT,
809
+ tags TEXT
810
+ )
811
+ `);
812
+ db.run(`CREATE INDEX IF NOT EXISTS idx_${tableName}_timestamp ON ${tableName}(timestamp)`);
813
+ db.run(`CREATE INDEX IF NOT EXISTS idx_${tableName}_model_id ON ${tableName}(model_id)`);
814
+ db.run(`CREATE INDEX IF NOT EXISTS idx_${tableName}_base_url ON ${tableName}(base_url)`);
815
+ const appendOne = (entry) => {
816
+ db.query(`
817
+ INSERT OR REPLACE INTO ${tableName} (
818
+ id, timestamp, model_id, base_url, request_id,
819
+ cost, sats_cost, prompt_tokens, completion_tokens, total_tokens,
820
+ client, session_id, tags
821
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
822
+ `).run(
823
+ entry.id,
824
+ entry.timestamp,
825
+ entry.modelId,
826
+ normalizeBaseUrl3(entry.baseUrl),
827
+ entry.requestId,
828
+ entry.cost,
829
+ entry.satsCost,
830
+ entry.promptTokens,
831
+ entry.completionTokens,
832
+ entry.totalTokens,
833
+ entry.client ?? null,
834
+ entry.sessionId ?? null,
835
+ JSON.stringify(entry.tags ?? [])
836
+ );
837
+ };
838
+ const mapRow = (row) => ({
839
+ id: row.id,
840
+ timestamp: row.timestamp,
841
+ modelId: row.model_id,
842
+ baseUrl: row.base_url,
843
+ requestId: row.request_id,
844
+ cost: row.cost,
845
+ satsCost: row.sats_cost,
846
+ promptTokens: row.prompt_tokens,
847
+ completionTokens: row.completion_tokens,
848
+ totalTokens: row.total_tokens,
849
+ client: row.client ?? void 0,
850
+ sessionId: row.session_id ?? void 0,
851
+ tags: typeof row.tags === "string" ? JSON.parse(row.tags) : void 0
852
+ });
853
+ const ensureMigrated = async () => {
854
+ if (!legacyStorageDriver) return;
855
+ if (!migrationPromise) {
856
+ migrationPromise = (async () => {
857
+ const migrated = await legacyStorageDriver.getItem(
858
+ MIGRATION_MARKER_KEY3,
859
+ false
860
+ );
861
+ if (migrated) return;
862
+ const legacyEntries = await legacyStorageDriver.getItem(
863
+ SDK_STORAGE_KEYS.USAGE_TRACKING,
864
+ []
865
+ );
866
+ if (legacyEntries.length > 0) {
867
+ for (const entry of legacyEntries) {
868
+ appendOne(entry);
869
+ }
870
+ await legacyStorageDriver.removeItem(SDK_STORAGE_KEYS.USAGE_TRACKING);
871
+ }
872
+ await legacyStorageDriver.setItem(MIGRATION_MARKER_KEY3, true);
873
+ })();
874
+ }
875
+ await migrationPromise;
876
+ };
877
+ return {
878
+ async migrate() {
879
+ await ensureMigrated();
880
+ },
881
+ async append(entry) {
882
+ await ensureMigrated();
883
+ appendOne(entry);
884
+ },
885
+ async appendMany(entries) {
886
+ await ensureMigrated();
887
+ for (const entry of entries) {
888
+ appendOne(entry);
889
+ }
890
+ },
891
+ async list(options2 = {}) {
892
+ await ensureMigrated();
893
+ const { sql, params } = buildWhereClause2(options2);
894
+ const limitSql = typeof options2.limit === "number" ? " LIMIT ?" : "";
895
+ const query = `SELECT * FROM ${tableName} ${sql} ORDER BY timestamp DESC${limitSql}`;
896
+ let rows;
897
+ if (typeof options2.limit === "number") {
898
+ rows = db.query(query).all(...params, options2.limit);
899
+ } else {
900
+ rows = db.query(query).all(...params);
901
+ }
902
+ return rows.map(mapRow);
903
+ },
904
+ async count(options2 = {}) {
905
+ const { sql, params } = buildWhereClause2(options2);
906
+ const query = `SELECT COUNT(*) as count FROM ${tableName} ${sql}`;
907
+ const row = db.query(query).get(...params);
908
+ return Number(row?.count ?? 0);
909
+ },
910
+ async deleteOlderThan(timestamp) {
911
+ await ensureMigrated();
912
+ const before = timestamp;
913
+ const result = db.query(`DELETE FROM ${tableName} WHERE timestamp < ?`).run(before);
914
+ return result.changes ?? 0;
915
+ },
916
+ async clear() {
917
+ await ensureMigrated();
918
+ db.query(`DELETE FROM ${tableName}`).run();
919
+ }
920
+ };
921
+ };
922
+
923
+ // storage/usageTracking/memory.ts
924
+ var normalizeBaseUrl4 = (baseUrl) => baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
925
+ var matchesFilters2 = (entry, options = {}) => {
926
+ if (typeof options.before === "number" && entry.timestamp >= options.before) {
927
+ return false;
928
+ }
929
+ if (typeof options.after === "number" && entry.timestamp <= options.after) {
930
+ return false;
931
+ }
932
+ if (options.modelId && entry.modelId !== options.modelId) {
933
+ return false;
934
+ }
935
+ if (options.baseUrl && normalizeBaseUrl4(entry.baseUrl) !== normalizeBaseUrl4(options.baseUrl)) {
936
+ return false;
937
+ }
938
+ if (options.sessionId && entry.sessionId !== options.sessionId) {
939
+ return false;
316
940
  }
941
+ if (options.client && entry.client !== options.client) {
942
+ return false;
943
+ }
944
+ return true;
945
+ };
946
+ var createMemoryUsageTrackingDriver = (seed = []) => {
947
+ const store = /* @__PURE__ */ new Map();
948
+ for (const entry of seed) {
949
+ store.set(entry.id, { ...entry, baseUrl: normalizeBaseUrl4(entry.baseUrl) });
950
+ }
951
+ return {
952
+ async migrate() {
953
+ return;
954
+ },
955
+ async append(entry) {
956
+ store.set(entry.id, { ...entry, baseUrl: normalizeBaseUrl4(entry.baseUrl) });
957
+ },
958
+ async appendMany(entries) {
959
+ for (const entry of entries) {
960
+ store.set(entry.id, { ...entry, baseUrl: normalizeBaseUrl4(entry.baseUrl) });
961
+ }
962
+ },
963
+ async list(options = {}) {
964
+ const entries = [...store.values()].filter((entry) => matchesFilters2(entry, options)).sort((a, b) => b.timestamp - a.timestamp);
965
+ if (typeof options.limit === "number") {
966
+ return entries.slice(0, options.limit);
967
+ }
968
+ return entries;
969
+ },
970
+ async count(options = {}) {
971
+ return (await this.list(options)).length;
972
+ },
973
+ async deleteOlderThan(timestamp) {
974
+ let deleted = 0;
975
+ for (const [id, entry] of store.entries()) {
976
+ if (entry.timestamp < timestamp) {
977
+ store.delete(id);
978
+ deleted += 1;
979
+ }
980
+ }
981
+ return deleted;
982
+ },
983
+ async clear() {
984
+ store.clear();
985
+ }
986
+ };
317
987
  };
988
+ var normalizeBaseUrl5 = (baseUrl) => baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
318
989
  var createEmptyStore = (driver) => vanilla.createStore((set, get) => ({
319
990
  modelsFromAllProviders: {},
320
991
  lastUsedModel: null,
@@ -324,18 +995,17 @@ var createEmptyStore = (driver) => vanilla.createStore((set, get) => ({
324
995
  mintsFromAllProviders: {},
325
996
  infoFromAllProviders: {},
326
997
  lastModelsUpdate: {},
327
- cachedTokens: [],
328
998
  apiKeys: [],
329
999
  childKeys: [],
1000
+ xcashuTokens: {},
330
1001
  routstr21Models: [],
331
1002
  lastRoutstr21ModelsUpdate: null,
332
1003
  cachedReceiveTokens: [],
333
- usageTracking: [],
334
1004
  clientIds: [],
335
1005
  setModelsFromAllProviders: (value) => {
336
1006
  const normalized = {};
337
1007
  for (const [baseUrl, models] of Object.entries(value)) {
338
- normalized[normalizeBaseUrl(baseUrl)] = models;
1008
+ normalized[normalizeBaseUrl5(baseUrl)] = models;
339
1009
  }
340
1010
  void driver.setItem(
341
1011
  SDK_STORAGE_KEYS.MODELS_FROM_ALL_PROVIDERS,
@@ -348,7 +1018,7 @@ var createEmptyStore = (driver) => vanilla.createStore((set, get) => ({
348
1018
  set({ lastUsedModel: value });
349
1019
  },
350
1020
  setBaseUrlsList: (value) => {
351
- const normalized = value.map((url) => normalizeBaseUrl(url));
1021
+ const normalized = value.map((url) => normalizeBaseUrl5(url));
352
1022
  void driver.setItem(SDK_STORAGE_KEYS.BASE_URLS_LIST, normalized);
353
1023
  set({ baseUrlsList: normalized });
354
1024
  },
@@ -357,14 +1027,14 @@ var createEmptyStore = (driver) => vanilla.createStore((set, get) => ({
357
1027
  set({ lastBaseUrlsUpdate: value });
358
1028
  },
359
1029
  setDisabledProviders: (value) => {
360
- const normalized = value.map((url) => normalizeBaseUrl(url));
1030
+ const normalized = value.map((url) => normalizeBaseUrl5(url));
361
1031
  void driver.setItem(SDK_STORAGE_KEYS.DISABLED_PROVIDERS, normalized);
362
1032
  set({ disabledProviders: normalized });
363
1033
  },
364
1034
  setMintsFromAllProviders: (value) => {
365
1035
  const normalized = {};
366
1036
  for (const [baseUrl, mints] of Object.entries(value)) {
367
- normalized[normalizeBaseUrl(baseUrl)] = mints.map(
1037
+ normalized[normalizeBaseUrl5(baseUrl)] = mints.map(
368
1038
  (mint) => mint.endsWith("/") ? mint.slice(0, -1) : mint
369
1039
  );
370
1040
  }
@@ -377,7 +1047,7 @@ var createEmptyStore = (driver) => vanilla.createStore((set, get) => ({
377
1047
  setInfoFromAllProviders: (value) => {
378
1048
  const normalized = {};
379
1049
  for (const [baseUrl, info] of Object.entries(value)) {
380
- normalized[normalizeBaseUrl(baseUrl)] = info;
1050
+ normalized[normalizeBaseUrl5(baseUrl)] = info;
381
1051
  }
382
1052
  void driver.setItem(SDK_STORAGE_KEYS.INFO_FROM_ALL_PROVIDERS, normalized);
383
1053
  set({ infoFromAllProviders: normalized });
@@ -385,30 +1055,17 @@ var createEmptyStore = (driver) => vanilla.createStore((set, get) => ({
385
1055
  setLastModelsUpdate: (value) => {
386
1056
  const normalized = {};
387
1057
  for (const [baseUrl, timestamp] of Object.entries(value)) {
388
- normalized[normalizeBaseUrl(baseUrl)] = timestamp;
1058
+ normalized[normalizeBaseUrl5(baseUrl)] = timestamp;
389
1059
  }
390
1060
  void driver.setItem(SDK_STORAGE_KEYS.LAST_MODELS_UPDATE, normalized);
391
1061
  set({ lastModelsUpdate: normalized });
392
1062
  },
393
- setCachedTokens: (value) => {
394
- set((state) => {
395
- const updates = typeof value === "function" ? value(state.cachedTokens) : value;
396
- const normalized = updates.map((entry) => ({
397
- ...entry,
398
- baseUrl: normalizeBaseUrl(entry.baseUrl),
399
- balance: typeof entry.balance === "number" ? entry.balance : getCashuTokenBalance(entry.token),
400
- lastUsed: entry.lastUsed ?? null
401
- }));
402
- void driver.setItem(SDK_STORAGE_KEYS.LOCAL_CASHU_TOKENS, normalized);
403
- return { cachedTokens: normalized };
404
- });
405
- },
406
1063
  setApiKeys: (value) => {
407
1064
  set((state) => {
408
1065
  const updates = typeof value === "function" ? value(state.apiKeys) : value;
409
1066
  const normalized = updates.map((entry) => ({
410
1067
  ...entry,
411
- baseUrl: normalizeBaseUrl(entry.baseUrl),
1068
+ baseUrl: normalizeBaseUrl5(entry.baseUrl),
412
1069
  balance: entry.balance ?? 0,
413
1070
  lastUsed: entry.lastUsed ?? null
414
1071
  }));
@@ -420,7 +1077,7 @@ var createEmptyStore = (driver) => vanilla.createStore((set, get) => ({
420
1077
  set((state) => {
421
1078
  const updates = typeof value === "function" ? value(state.childKeys) : value;
422
1079
  const normalized = updates.map((entry) => ({
423
- parentBaseUrl: normalizeBaseUrl(entry.parentBaseUrl),
1080
+ parentBaseUrl: normalizeBaseUrl5(entry.parentBaseUrl),
424
1081
  childKey: entry.childKey,
425
1082
  balance: entry.balance ?? 0,
426
1083
  balanceLimit: entry.balanceLimit,
@@ -431,6 +1088,30 @@ var createEmptyStore = (driver) => vanilla.createStore((set, get) => ({
431
1088
  return { childKeys: normalized };
432
1089
  });
433
1090
  },
1091
+ setXcashuTokens: (value) => {
1092
+ const normalized = {};
1093
+ for (const [baseUrl, tokens] of Object.entries(value)) {
1094
+ normalized[normalizeBaseUrl5(baseUrl)] = tokens.map((entry) => ({
1095
+ ...entry,
1096
+ baseUrl: normalizeBaseUrl5(entry.baseUrl),
1097
+ createdAt: entry.createdAt ?? Date.now(),
1098
+ tryCount: entry.tryCount ?? 0
1099
+ }));
1100
+ }
1101
+ void driver.setItem(SDK_STORAGE_KEYS.XCASHU_TOKENS, normalized);
1102
+ set({ xcashuTokens: normalized });
1103
+ },
1104
+ updateXcashuTokenTryCount: (token, tryCount) => {
1105
+ const currentTokens = get().xcashuTokens;
1106
+ const updatedTokens = {};
1107
+ for (const [baseUrl, tokens] of Object.entries(currentTokens)) {
1108
+ updatedTokens[baseUrl] = tokens.map(
1109
+ (entry) => entry.token === token ? { ...entry, tryCount } : entry
1110
+ );
1111
+ }
1112
+ void driver.setItem(SDK_STORAGE_KEYS.XCASHU_TOKENS, updatedTokens);
1113
+ set({ xcashuTokens: updatedTokens });
1114
+ },
434
1115
  setRoutstr21Models: (value) => {
435
1116
  void driver.setItem(SDK_STORAGE_KEYS.ROUTSTR21_MODELS, value);
436
1117
  set({ routstr21Models: value });
@@ -449,10 +1130,6 @@ var createEmptyStore = (driver) => vanilla.createStore((set, get) => ({
449
1130
  void driver.setItem(SDK_STORAGE_KEYS.CACHED_RECEIVE_TOKENS, normalized);
450
1131
  set({ cachedReceiveTokens: normalized });
451
1132
  },
452
- setUsageTracking: (value) => {
453
- void driver.setItem(SDK_STORAGE_KEYS.USAGE_TRACKING, value);
454
- set({ usageTracking: value });
455
- },
456
1133
  setClientIds: (value) => {
457
1134
  set((state) => {
458
1135
  const updates = typeof value === "function" ? value(state.clientIds) : value;
@@ -476,13 +1153,12 @@ var hydrateStoreFromDriver = async (store, driver) => {
476
1153
  rawMints,
477
1154
  rawInfo,
478
1155
  rawLastModelsUpdate,
479
- rawCachedTokens,
480
1156
  rawApiKeys,
481
1157
  rawChildKeys,
1158
+ rawXcashuTokens,
482
1159
  rawRoutstr21Models,
483
1160
  rawLastRoutstr21ModelsUpdate,
484
1161
  rawCachedReceiveTokens,
485
- rawUsageTracking,
486
1162
  rawClientIds
487
1163
  ] = await Promise.all([
488
1164
  driver.getItem(
@@ -505,66 +1181,70 @@ var hydrateStoreFromDriver = async (store, driver) => {
505
1181
  SDK_STORAGE_KEYS.LAST_MODELS_UPDATE,
506
1182
  {}
507
1183
  ),
508
- driver.getItem(SDK_STORAGE_KEYS.LOCAL_CASHU_TOKENS, []),
509
1184
  driver.getItem(SDK_STORAGE_KEYS.API_KEYS, []),
510
1185
  driver.getItem(SDK_STORAGE_KEYS.CHILD_KEYS, []),
1186
+ driver.getItem(SDK_STORAGE_KEYS.XCASHU_TOKENS, {}),
511
1187
  driver.getItem(SDK_STORAGE_KEYS.ROUTSTR21_MODELS, []),
512
1188
  driver.getItem(
513
1189
  SDK_STORAGE_KEYS.LAST_ROUTSTR21_MODELS_UPDATE,
514
1190
  null
515
1191
  ),
516
1192
  driver.getItem(SDK_STORAGE_KEYS.CACHED_RECEIVE_TOKENS, []),
517
- driver.getItem(SDK_STORAGE_KEYS.USAGE_TRACKING, []),
518
1193
  driver.getItem(SDK_STORAGE_KEYS.CLIENT_IDS, [])
519
1194
  ]);
520
1195
  const modelsFromAllProviders = Object.fromEntries(
521
1196
  Object.entries(rawModels).map(([baseUrl, models]) => [
522
- normalizeBaseUrl(baseUrl),
1197
+ normalizeBaseUrl5(baseUrl),
523
1198
  models
524
1199
  ])
525
1200
  );
526
- const baseUrlsList = rawBaseUrls.map((url) => normalizeBaseUrl(url));
1201
+ const baseUrlsList = rawBaseUrls.map((url) => normalizeBaseUrl5(url));
527
1202
  const disabledProviders = rawDisabledProviders.map(
528
- (url) => normalizeBaseUrl(url)
1203
+ (url) => normalizeBaseUrl5(url)
529
1204
  );
530
1205
  const mintsFromAllProviders = Object.fromEntries(
531
1206
  Object.entries(rawMints).map(([baseUrl, mints]) => [
532
- normalizeBaseUrl(baseUrl),
1207
+ normalizeBaseUrl5(baseUrl),
533
1208
  mints.map((mint) => mint.endsWith("/") ? mint.slice(0, -1) : mint)
534
1209
  ])
535
1210
  );
536
1211
  const infoFromAllProviders = Object.fromEntries(
537
1212
  Object.entries(rawInfo).map(([baseUrl, info]) => [
538
- normalizeBaseUrl(baseUrl),
1213
+ normalizeBaseUrl5(baseUrl),
539
1214
  info
540
1215
  ])
541
1216
  );
542
1217
  const lastModelsUpdate = Object.fromEntries(
543
1218
  Object.entries(rawLastModelsUpdate).map(([baseUrl, timestamp]) => [
544
- normalizeBaseUrl(baseUrl),
1219
+ normalizeBaseUrl5(baseUrl),
545
1220
  timestamp
546
1221
  ])
547
1222
  );
548
- const cachedTokens = rawCachedTokens.map((entry) => ({
549
- ...entry,
550
- baseUrl: normalizeBaseUrl(entry.baseUrl),
551
- balance: typeof entry.balance === "number" ? entry.balance : getCashuTokenBalance(entry.token),
552
- lastUsed: entry.lastUsed ?? null
553
- }));
554
1223
  const apiKeys = rawApiKeys.map((entry) => ({
555
1224
  ...entry,
556
- baseUrl: normalizeBaseUrl(entry.baseUrl),
1225
+ baseUrl: normalizeBaseUrl5(entry.baseUrl),
557
1226
  balance: entry.balance ?? 0,
558
1227
  lastUsed: entry.lastUsed ?? null
559
1228
  }));
560
1229
  const childKeys = rawChildKeys.map((entry) => ({
561
- parentBaseUrl: normalizeBaseUrl(entry.parentBaseUrl),
1230
+ parentBaseUrl: normalizeBaseUrl5(entry.parentBaseUrl),
562
1231
  childKey: entry.childKey,
563
1232
  balance: entry.balance ?? 0,
564
1233
  balanceLimit: entry.balanceLimit,
565
1234
  validityDate: entry.validityDate,
566
1235
  createdAt: entry.createdAt ?? Date.now()
567
1236
  }));
1237
+ const xcashuTokens = Object.fromEntries(
1238
+ Object.entries(rawXcashuTokens).map(([baseUrl, tokens]) => [
1239
+ normalizeBaseUrl5(baseUrl),
1240
+ tokens.map((entry) => ({
1241
+ baseUrl: normalizeBaseUrl5(entry.baseUrl),
1242
+ token: entry.token,
1243
+ createdAt: entry.createdAt ?? Date.now(),
1244
+ tryCount: entry.tryCount ?? 0
1245
+ }))
1246
+ ])
1247
+ );
568
1248
  const routstr21Models = rawRoutstr21Models;
569
1249
  const lastRoutstr21ModelsUpdate = rawLastRoutstr21ModelsUpdate;
570
1250
  const cachedReceiveTokens = rawCachedReceiveTokens?.map((entry) => ({
@@ -573,7 +1253,6 @@ var hydrateStoreFromDriver = async (store, driver) => {
573
1253
  unit: entry.unit || "sat",
574
1254
  createdAt: entry.createdAt ?? Date.now()
575
1255
  }));
576
- const usageTracking = rawUsageTracking;
577
1256
  const clientIds = rawClientIds.map((entry) => ({
578
1257
  ...entry,
579
1258
  createdAt: entry.createdAt ?? Date.now(),
@@ -588,13 +1267,12 @@ var hydrateStoreFromDriver = async (store, driver) => {
588
1267
  mintsFromAllProviders,
589
1268
  infoFromAllProviders,
590
1269
  lastModelsUpdate,
591
- cachedTokens,
592
1270
  apiKeys,
593
1271
  childKeys,
1272
+ xcashuTokens,
594
1273
  routstr21Models,
595
1274
  lastRoutstr21ModelsUpdate,
596
1275
  cachedReceiveTokens,
597
- usageTracking,
598
1276
  clientIds
599
1277
  });
600
1278
  };
@@ -615,12 +1293,12 @@ var createDiscoveryAdapterFromStore = (store) => ({
615
1293
  getCachedProviderInfo: () => store.getState().infoFromAllProviders,
616
1294
  setCachedProviderInfo: (info) => store.getState().setInfoFromAllProviders(info),
617
1295
  getProviderLastUpdate: (baseUrl) => {
618
- const normalized = normalizeBaseUrl(baseUrl);
1296
+ const normalized = normalizeBaseUrl5(baseUrl);
619
1297
  const timestamps = store.getState().lastModelsUpdate;
620
1298
  return timestamps[normalized] || null;
621
1299
  },
622
1300
  setProviderLastUpdate: (baseUrl, timestamp) => {
623
- const normalized = normalizeBaseUrl(baseUrl);
1301
+ const normalized = normalizeBaseUrl5(baseUrl);
624
1302
  const timestamps = { ...store.getState().lastModelsUpdate };
625
1303
  timestamps[normalized] = timestamp;
626
1304
  store.getState().setLastModelsUpdate(timestamps);
@@ -638,59 +1316,6 @@ var createDiscoveryAdapterFromStore = (store) => ({
638
1316
  setRoutstr21ModelsLastUpdate: (timestamp) => store.getState().setRoutstr21ModelsLastUpdate(timestamp)
639
1317
  });
640
1318
  var createStorageAdapterFromStore = (store) => ({
641
- getToken: (baseUrl) => {
642
- const normalized = normalizeBaseUrl(baseUrl);
643
- const entry = store.getState().cachedTokens.find((token) => token.baseUrl === normalized);
644
- if (!entry) return null;
645
- const next = store.getState().cachedTokens.map(
646
- (token) => token.baseUrl === normalized ? { ...token, lastUsed: Date.now() } : token
647
- );
648
- store.getState().setCachedTokens(next);
649
- return entry.token;
650
- },
651
- setToken: (baseUrl, token) => {
652
- const normalized = normalizeBaseUrl(baseUrl);
653
- const tokens = store.getState().cachedTokens;
654
- const balance = getCashuTokenBalance(token);
655
- const existingIndex = tokens.findIndex(
656
- (entry) => entry.baseUrl === normalized
657
- );
658
- if (existingIndex !== -1) {
659
- throw new Error(`Token already exists for baseUrl: ${normalized}`);
660
- }
661
- const next = [...tokens];
662
- next.push({
663
- baseUrl: normalized,
664
- token,
665
- balance,
666
- lastUsed: Date.now()
667
- });
668
- store.getState().setCachedTokens(next);
669
- },
670
- removeToken: (baseUrl) => {
671
- const normalized = normalizeBaseUrl(baseUrl);
672
- const next = store.getState().cachedTokens.filter((entry) => entry.baseUrl !== normalized);
673
- store.getState().setCachedTokens(next);
674
- },
675
- updateTokenBalance: (baseUrl, balance) => {
676
- const normalized = normalizeBaseUrl(baseUrl);
677
- const tokens = store.getState().cachedTokens;
678
- const next = tokens.map(
679
- (entry) => entry.baseUrl === normalized ? { ...entry, balance } : entry
680
- );
681
- store.getState().setCachedTokens(next);
682
- },
683
- getCachedTokenDistribution: () => {
684
- const cachedTokens = store.getState().cachedTokens;
685
- const distributionMap = {};
686
- for (const entry of cachedTokens) {
687
- const sum = entry.balance || 0;
688
- if (sum > 0) {
689
- distributionMap[entry.baseUrl] = (distributionMap[entry.baseUrl] || 0) + sum;
690
- }
691
- }
692
- return Object.entries(distributionMap).map(([baseUrl, amt]) => ({ baseUrl, amount: amt })).sort((a, b) => b.amount - a.amount);
693
- },
694
1319
  getApiKeyDistribution: () => {
695
1320
  const apiKeys = store.getState().apiKeys;
696
1321
  const distributionMap = {};
@@ -703,28 +1328,24 @@ var createStorageAdapterFromStore = (store) => ({
703
1328
  return Object.entries(distributionMap).map(([baseUrl, amt]) => ({ baseUrl, amount: amt })).sort((a, b) => b.amount - a.amount);
704
1329
  },
705
1330
  saveProviderInfo: (baseUrl, info) => {
706
- const normalized = normalizeBaseUrl(baseUrl);
1331
+ const normalized = normalizeBaseUrl5(baseUrl);
707
1332
  const next = { ...store.getState().infoFromAllProviders };
708
1333
  next[normalized] = info;
709
1334
  store.getState().setInfoFromAllProviders(next);
710
1335
  },
711
1336
  getProviderInfo: (baseUrl) => {
712
- const normalized = normalizeBaseUrl(baseUrl);
1337
+ const normalized = normalizeBaseUrl5(baseUrl);
713
1338
  return store.getState().infoFromAllProviders[normalized] || null;
714
1339
  },
715
1340
  // ========== API Keys (for apikeys mode) ==========
716
1341
  getApiKey: (baseUrl) => {
717
- const normalized = normalizeBaseUrl(baseUrl);
1342
+ const normalized = normalizeBaseUrl5(baseUrl);
718
1343
  const entry = store.getState().apiKeys.find((key) => key.baseUrl === normalized);
719
1344
  if (!entry) return null;
720
- const next = store.getState().apiKeys.map(
721
- (key) => key.baseUrl === normalized ? { ...key, lastUsed: Date.now() } : key
722
- );
723
- store.getState().setApiKeys(next);
724
1345
  return entry;
725
1346
  },
726
1347
  setApiKey: (baseUrl, key) => {
727
- const normalized = normalizeBaseUrl(baseUrl);
1348
+ const normalized = normalizeBaseUrl5(baseUrl);
728
1349
  const keys = store.getState().apiKeys;
729
1350
  const existingIndex = keys.findIndex(
730
1351
  (entry) => entry.baseUrl === normalized
@@ -742,15 +1363,15 @@ var createStorageAdapterFromStore = (store) => ({
742
1363
  store.getState().setApiKeys(next);
743
1364
  },
744
1365
  updateApiKeyBalance: (baseUrl, balance) => {
745
- const normalized = normalizeBaseUrl(baseUrl);
1366
+ const normalized = normalizeBaseUrl5(baseUrl);
746
1367
  const keys = store.getState().apiKeys;
747
1368
  const next = keys.map(
748
- (entry) => entry.baseUrl === normalized ? { ...entry, balance } : entry
1369
+ (entry) => entry.baseUrl === normalized ? { ...entry, balance, lastUsed: Date.now() } : entry
749
1370
  );
750
1371
  store.getState().setApiKeys(next);
751
1372
  },
752
1373
  removeApiKey: (baseUrl) => {
753
- const normalized = normalizeBaseUrl(baseUrl);
1374
+ const normalized = normalizeBaseUrl5(baseUrl);
754
1375
  const next = store.getState().apiKeys.filter((entry) => entry.baseUrl !== normalized);
755
1376
  store.getState().setApiKeys(next);
756
1377
  },
@@ -764,7 +1385,7 @@ var createStorageAdapterFromStore = (store) => ({
764
1385
  },
765
1386
  // ========== Child Keys ==========
766
1387
  getChildKey: (parentBaseUrl) => {
767
- const normalized = normalizeBaseUrl(parentBaseUrl);
1388
+ const normalized = normalizeBaseUrl5(parentBaseUrl);
768
1389
  const entry = store.getState().childKeys.find((key) => key.parentBaseUrl === normalized);
769
1390
  if (!entry) return null;
770
1391
  return {
@@ -777,7 +1398,7 @@ var createStorageAdapterFromStore = (store) => ({
777
1398
  };
778
1399
  },
779
1400
  setChildKey: (parentBaseUrl, childKey, balance, validityDate, balanceLimit) => {
780
- const normalized = normalizeBaseUrl(parentBaseUrl);
1401
+ const normalized = normalizeBaseUrl5(parentBaseUrl);
781
1402
  const keys = store.getState().childKeys;
782
1403
  const existingIndex = keys.findIndex(
783
1404
  (entry) => entry.parentBaseUrl === normalized
@@ -808,7 +1429,7 @@ var createStorageAdapterFromStore = (store) => ({
808
1429
  }
809
1430
  },
810
1431
  updateChildKeyBalance: (parentBaseUrl, balance) => {
811
- const normalized = normalizeBaseUrl(parentBaseUrl);
1432
+ const normalized = normalizeBaseUrl5(parentBaseUrl);
812
1433
  const keys = store.getState().childKeys;
813
1434
  const next = keys.map(
814
1435
  (entry) => entry.parentBaseUrl === normalized ? { ...entry, balance } : entry
@@ -816,7 +1437,7 @@ var createStorageAdapterFromStore = (store) => ({
816
1437
  store.getState().setChildKeys(next);
817
1438
  },
818
1439
  removeChildKey: (parentBaseUrl) => {
819
- const normalized = normalizeBaseUrl(parentBaseUrl);
1440
+ const normalized = normalizeBaseUrl5(parentBaseUrl);
820
1441
  const next = store.getState().childKeys.filter((entry) => entry.parentBaseUrl !== normalized);
821
1442
  store.getState().setChildKeys(next);
822
1443
  },
@@ -835,20 +1456,60 @@ var createStorageAdapterFromStore = (store) => ({
835
1456
  },
836
1457
  setCachedReceiveTokens: (tokens) => {
837
1458
  store.getState().setCachedReceiveTokens(tokens);
1459
+ },
1460
+ // ========== XCashu Tokens (multiple tokens per baseUrl) ==========
1461
+ getXcashuTokens: () => {
1462
+ return store.getState().xcashuTokens;
1463
+ },
1464
+ getXcashuTokensForBaseUrl: (baseUrl) => {
1465
+ const normalized = normalizeBaseUrl5(baseUrl);
1466
+ return store.getState().xcashuTokens[normalized] || [];
1467
+ },
1468
+ addXcashuToken: (baseUrl, token) => {
1469
+ const normalized = normalizeBaseUrl5(baseUrl);
1470
+ const tokens = store.getState().xcashuTokens;
1471
+ const existing = tokens[normalized] || [];
1472
+ const next = { ...tokens };
1473
+ next[normalized] = [
1474
+ ...existing,
1475
+ { baseUrl: normalized, token, createdAt: Date.now(), tryCount: 0 }
1476
+ ];
1477
+ store.getState().setXcashuTokens(next);
1478
+ },
1479
+ removeXcashuToken: (baseUrl, token) => {
1480
+ const normalized = normalizeBaseUrl5(baseUrl);
1481
+ const tokens = store.getState().xcashuTokens;
1482
+ const existing = tokens[normalized] || [];
1483
+ const next = { ...tokens };
1484
+ next[normalized] = existing.filter((entry) => entry.token !== token);
1485
+ if (next[normalized].length === 0) {
1486
+ delete next[normalized];
1487
+ }
1488
+ store.getState().setXcashuTokens(next);
1489
+ },
1490
+ clearXcashuTokensForBaseUrl: (baseUrl) => {
1491
+ const normalized = normalizeBaseUrl5(baseUrl);
1492
+ const tokens = store.getState().xcashuTokens;
1493
+ const next = { ...tokens };
1494
+ delete next[normalized];
1495
+ store.getState().setXcashuTokens(next);
1496
+ },
1497
+ updateXcashuTokenTryCount: (token, tryCount) => {
1498
+ store.getState().updateXcashuTokenTryCount(token, tryCount);
838
1499
  }
839
1500
  });
840
1501
  var createProviderRegistryFromStore = (store) => ({
841
1502
  getModelsForProvider: (baseUrl) => {
842
- const normalized = normalizeBaseUrl(baseUrl);
1503
+ const normalized = normalizeBaseUrl5(baseUrl);
843
1504
  return store.getState().modelsFromAllProviders[normalized] || [];
844
1505
  },
845
1506
  getDisabledProviders: () => store.getState().disabledProviders,
846
1507
  getProviderMints: (baseUrl) => {
847
- const normalized = normalizeBaseUrl(baseUrl);
1508
+ const normalized = normalizeBaseUrl5(baseUrl);
848
1509
  return store.getState().mintsFromAllProviders[normalized] || [];
849
1510
  },
850
1511
  getProviderInfo: async (baseUrl) => {
851
- const normalized = normalizeBaseUrl(baseUrl);
1512
+ const normalized = normalizeBaseUrl5(baseUrl);
852
1513
  const cached = store.getState().infoFromAllProviders[normalized];
853
1514
  if (cached) return cached;
854
1515
  try {
@@ -870,7 +1531,7 @@ var createProviderRegistryFromStore = (store) => ({
870
1531
  });
871
1532
 
872
1533
  // storage/index.ts
873
- var isBrowser2 = () => {
1534
+ var isBrowser3 = () => {
874
1535
  try {
875
1536
  return typeof window !== "undefined" && typeof window.localStorage !== "undefined";
876
1537
  } catch {
@@ -885,16 +1546,16 @@ var isNode = () => {
885
1546
  }
886
1547
  };
887
1548
  var defaultDriver = null;
888
- var isBun2 = () => {
1549
+ var isBun3 = () => {
889
1550
  return typeof process.versions.bun !== "undefined";
890
1551
  };
891
1552
  var getDefaultSdkDriver = () => {
892
1553
  if (defaultDriver) return defaultDriver;
893
- if (isBrowser2()) {
1554
+ if (isBrowser3()) {
894
1555
  defaultDriver = localStorageDriver;
895
1556
  return defaultDriver;
896
1557
  }
897
- if (isBun2()) {
1558
+ if (isBun3()) {
898
1559
  defaultDriver = createMemoryDriver();
899
1560
  return defaultDriver;
900
1561
  }
@@ -906,29 +1567,62 @@ var getDefaultSdkDriver = () => {
906
1567
  return defaultDriver;
907
1568
  };
908
1569
  var defaultStore = null;
1570
+ var defaultUsageTrackingDriver = null;
909
1571
  var getDefaultSdkStore = () => {
910
1572
  if (!defaultStore) {
911
1573
  defaultStore = createSdkStore({ driver: getDefaultSdkDriver() });
912
1574
  }
913
1575
  return defaultStore.hydrate.then(() => defaultStore.store);
914
1576
  };
1577
+ var getDefaultUsageTrackingDriver = () => {
1578
+ if (defaultUsageTrackingDriver) return defaultUsageTrackingDriver;
1579
+ const storageDriver = getDefaultSdkDriver();
1580
+ if (isBrowser3()) {
1581
+ defaultUsageTrackingDriver = createIndexedDBUsageTrackingDriver({
1582
+ legacyStorageDriver: storageDriver
1583
+ });
1584
+ return defaultUsageTrackingDriver;
1585
+ }
1586
+ if (isBun3()) {
1587
+ defaultUsageTrackingDriver = createBunSqliteUsageTrackingDriver();
1588
+ return defaultUsageTrackingDriver;
1589
+ }
1590
+ if (isNode()) {
1591
+ defaultUsageTrackingDriver = createSqliteUsageTrackingDriver({
1592
+ legacyStorageDriver: storageDriver
1593
+ });
1594
+ return defaultUsageTrackingDriver;
1595
+ }
1596
+ defaultUsageTrackingDriver = createMemoryUsageTrackingDriver();
1597
+ return defaultUsageTrackingDriver;
1598
+ };
1599
+ var setDefaultUsageTrackingDriver = (driver) => {
1600
+ defaultUsageTrackingDriver = driver;
1601
+ };
915
1602
  var getDefaultDiscoveryAdapter = async () => createDiscoveryAdapterFromStore(await getDefaultSdkStore());
916
1603
  var getDefaultStorageAdapter = async () => createStorageAdapterFromStore(await getDefaultSdkStore());
917
1604
  var getDefaultProviderRegistry = async () => createProviderRegistryFromStore(await getDefaultSdkStore());
918
1605
 
919
1606
  exports.SDK_STORAGE_KEYS = SDK_STORAGE_KEYS;
1607
+ exports.createBunSqliteDriver = createBunSqliteDriver;
1608
+ exports.createBunSqliteUsageTrackingDriver = createBunSqliteUsageTrackingDriver;
920
1609
  exports.createDiscoveryAdapterFromStore = createDiscoveryAdapterFromStore;
921
1610
  exports.createIndexedDBDriver = createIndexedDBDriver;
1611
+ exports.createIndexedDBUsageTrackingDriver = createIndexedDBUsageTrackingDriver;
922
1612
  exports.createMemoryDriver = createMemoryDriver;
1613
+ exports.createMemoryUsageTrackingDriver = createMemoryUsageTrackingDriver;
923
1614
  exports.createProviderRegistryFromStore = createProviderRegistryFromStore;
924
1615
  exports.createSdkStore = createSdkStore;
925
1616
  exports.createSqliteDriver = createSqliteDriver;
1617
+ exports.createSqliteUsageTrackingDriver = createSqliteUsageTrackingDriver;
926
1618
  exports.createStorageAdapterFromStore = createStorageAdapterFromStore;
927
1619
  exports.getDefaultDiscoveryAdapter = getDefaultDiscoveryAdapter;
928
1620
  exports.getDefaultProviderRegistry = getDefaultProviderRegistry;
929
1621
  exports.getDefaultSdkDriver = getDefaultSdkDriver;
930
1622
  exports.getDefaultSdkStore = getDefaultSdkStore;
931
1623
  exports.getDefaultStorageAdapter = getDefaultStorageAdapter;
1624
+ exports.getDefaultUsageTrackingDriver = getDefaultUsageTrackingDriver;
932
1625
  exports.localStorageDriver = localStorageDriver;
1626
+ exports.setDefaultUsageTrackingDriver = setDefaultUsageTrackingDriver;
933
1627
  //# sourceMappingURL=index.js.map
934
1628
  //# sourceMappingURL=index.js.map