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