@routstr/sdk 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,809 @@
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
+
11
+ // storage/drivers/localStorage.ts
12
+ var canUseLocalStorage = () => {
13
+ return typeof window !== "undefined" && typeof window.localStorage !== "undefined";
14
+ };
15
+ var isQuotaExceeded = (error) => {
16
+ const e = error;
17
+ return !!e && (e?.name === "QuotaExceededError" || e?.code === 22 || e?.code === 1014);
18
+ };
19
+ var NON_CRITICAL_KEYS = /* @__PURE__ */ new Set(["modelsFromAllProviders"]);
20
+ var localStorageDriver = {
21
+ async getItem(key, defaultValue) {
22
+ if (!canUseLocalStorage()) return defaultValue;
23
+ try {
24
+ const item = window.localStorage.getItem(key);
25
+ if (item === null) return defaultValue;
26
+ try {
27
+ return JSON.parse(item);
28
+ } catch (parseError) {
29
+ if (typeof defaultValue === "string") {
30
+ return item;
31
+ }
32
+ throw parseError;
33
+ }
34
+ } catch (error) {
35
+ console.error(`Error retrieving item with key "${key}":`, error);
36
+ if (canUseLocalStorage()) {
37
+ try {
38
+ window.localStorage.removeItem(key);
39
+ } catch (removeError) {
40
+ console.error(
41
+ `Error removing corrupted item with key "${key}":`,
42
+ removeError
43
+ );
44
+ }
45
+ }
46
+ return defaultValue;
47
+ }
48
+ },
49
+ async setItem(key, value) {
50
+ if (!canUseLocalStorage()) return;
51
+ try {
52
+ window.localStorage.setItem(key, JSON.stringify(value));
53
+ } catch (error) {
54
+ if (isQuotaExceeded(error)) {
55
+ if (NON_CRITICAL_KEYS.has(key)) {
56
+ console.warn(
57
+ `Storage quota exceeded; skipping non-critical key "${key}".`
58
+ );
59
+ return;
60
+ }
61
+ try {
62
+ window.localStorage.removeItem("modelsFromAllProviders");
63
+ } catch {
64
+ }
65
+ try {
66
+ window.localStorage.setItem(key, JSON.stringify(value));
67
+ return;
68
+ } catch (retryError) {
69
+ console.warn(
70
+ `Storage quota exceeded; unable to persist key "${key}" after cleanup attempt.`,
71
+ retryError
72
+ );
73
+ return;
74
+ }
75
+ }
76
+ console.error(`Error storing item with key "${key}":`, error);
77
+ }
78
+ },
79
+ async removeItem(key) {
80
+ if (!canUseLocalStorage()) return;
81
+ try {
82
+ window.localStorage.removeItem(key);
83
+ } catch (error) {
84
+ console.error(`Error removing item with key "${key}":`, error);
85
+ }
86
+ }
87
+ };
88
+
89
+ // storage/drivers/memory.ts
90
+ var createMemoryDriver = (seed) => {
91
+ const store = /* @__PURE__ */ new Map();
92
+ if (seed) {
93
+ for (const [key, value] of Object.entries(seed)) {
94
+ store.set(key, value);
95
+ }
96
+ }
97
+ return {
98
+ async getItem(key, defaultValue) {
99
+ const item = store.get(key);
100
+ if (item === void 0) return defaultValue;
101
+ try {
102
+ return JSON.parse(item);
103
+ } catch (parseError) {
104
+ if (typeof defaultValue === "string") {
105
+ return item;
106
+ }
107
+ throw parseError;
108
+ }
109
+ },
110
+ async setItem(key, value) {
111
+ store.set(key, JSON.stringify(value));
112
+ },
113
+ async removeItem(key) {
114
+ store.delete(key);
115
+ }
116
+ };
117
+ };
118
+
119
+ // storage/drivers/sqlite.ts
120
+ var isBun = () => {
121
+ return typeof process.versions.bun !== "undefined";
122
+ };
123
+ var createDatabase = (dbPath) => {
124
+ if (isBun()) {
125
+ throw new Error(
126
+ "SQLite driver not supported in Bun. Use createMemoryDriver() instead."
127
+ );
128
+ }
129
+ let Database = null;
130
+ try {
131
+ Database = __require("better-sqlite3");
132
+ } catch (error) {
133
+ throw new Error(
134
+ `better-sqlite3 is required for sqlite storage. Install it to use sqlite storage. (${error})`
135
+ );
136
+ }
137
+ return new Database(dbPath);
138
+ };
139
+ var createSqliteDriver = (options = {}) => {
140
+ const dbPath = options.dbPath || "routstr.sqlite";
141
+ 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 (?, ?)
149
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value`
150
+ );
151
+ const deleteStmt = db.prepare(`DELETE FROM ${tableName} WHERE key = ?`);
152
+ return {
153
+ async getItem(key, defaultValue) {
154
+ try {
155
+ const row = selectStmt.get(key);
156
+ if (!row || typeof row.value !== "string") return defaultValue;
157
+ try {
158
+ return JSON.parse(row.value);
159
+ } catch (parseError) {
160
+ if (typeof defaultValue === "string") {
161
+ return row.value;
162
+ }
163
+ throw parseError;
164
+ }
165
+ } catch (error) {
166
+ console.error(`SQLite getItem failed for key "${key}":`, error);
167
+ return defaultValue;
168
+ }
169
+ },
170
+ async setItem(key, value) {
171
+ try {
172
+ upsertStmt.run(key, JSON.stringify(value));
173
+ } catch (error) {
174
+ console.error(`SQLite setItem failed for key "${key}":`, error);
175
+ }
176
+ },
177
+ async removeItem(key) {
178
+ try {
179
+ deleteStmt.run(key);
180
+ } catch (error) {
181
+ console.error(`SQLite removeItem failed for key "${key}":`, error);
182
+ }
183
+ }
184
+ };
185
+ };
186
+
187
+ // storage/drivers/indexedDB.ts
188
+ var openDatabase = (dbName, storeName) => {
189
+ return new Promise((resolve, reject) => {
190
+ const request = indexedDB.open(dbName, 1);
191
+ request.onupgradeneeded = () => {
192
+ const db = request.result;
193
+ if (!db.objectStoreNames.contains(storeName)) {
194
+ db.createObjectStore(storeName);
195
+ }
196
+ };
197
+ request.onsuccess = () => resolve(request.result);
198
+ request.onerror = () => reject(request.error);
199
+ });
200
+ };
201
+ var createIndexedDBDriver = (options = {}) => {
202
+ const dbName = options.dbName || "routstr-sdk";
203
+ const storeName = options.storeName || "sdk_storage";
204
+ let dbPromise = null;
205
+ const getDb = () => {
206
+ if (!dbPromise) {
207
+ dbPromise = openDatabase(dbName, storeName);
208
+ }
209
+ return dbPromise;
210
+ };
211
+ return {
212
+ async getItem(key, defaultValue) {
213
+ try {
214
+ const db = await getDb();
215
+ return new Promise((resolve, reject) => {
216
+ const tx = db.transaction(storeName, "readonly");
217
+ const store = tx.objectStore(storeName);
218
+ const request = store.get(key);
219
+ request.onsuccess = () => {
220
+ const raw = request.result;
221
+ if (raw === void 0) {
222
+ resolve(defaultValue);
223
+ return;
224
+ }
225
+ if (typeof raw === "string") {
226
+ try {
227
+ resolve(JSON.parse(raw));
228
+ } catch {
229
+ if (typeof defaultValue === "string") {
230
+ resolve(raw);
231
+ } else {
232
+ resolve(defaultValue);
233
+ }
234
+ }
235
+ } else {
236
+ resolve(raw);
237
+ }
238
+ };
239
+ request.onerror = () => reject(request.error);
240
+ });
241
+ } catch (error) {
242
+ console.error(`IndexedDB getItem failed for key "${key}":`, error);
243
+ return defaultValue;
244
+ }
245
+ },
246
+ async setItem(key, value) {
247
+ try {
248
+ const db = await getDb();
249
+ return new Promise((resolve, reject) => {
250
+ const tx = db.transaction(storeName, "readwrite");
251
+ const store = tx.objectStore(storeName);
252
+ store.put(JSON.stringify(value), key);
253
+ tx.oncomplete = () => resolve();
254
+ tx.onerror = () => reject(tx.error);
255
+ });
256
+ } catch (error) {
257
+ console.error(`IndexedDB setItem failed for key "${key}":`, error);
258
+ }
259
+ },
260
+ async removeItem(key) {
261
+ try {
262
+ const db = await getDb();
263
+ return new Promise((resolve, reject) => {
264
+ const tx = db.transaction(storeName, "readwrite");
265
+ const store = tx.objectStore(storeName);
266
+ store.delete(key);
267
+ tx.oncomplete = () => resolve();
268
+ tx.onerror = () => reject(tx.error);
269
+ });
270
+ } catch (error) {
271
+ console.error(`IndexedDB removeItem failed for key "${key}":`, error);
272
+ }
273
+ }
274
+ };
275
+ };
276
+
277
+ // storage/keys.ts
278
+ var SDK_STORAGE_KEYS = {
279
+ MODELS_FROM_ALL_PROVIDERS: "modelsFromAllProviders",
280
+ LAST_USED_MODEL: "lastUsedModel",
281
+ BASE_URLS_LIST: "base_urls_list",
282
+ DISABLED_PROVIDERS: "disabled_providers",
283
+ MINTS_FROM_ALL_PROVIDERS: "mints_from_all_providers",
284
+ INFO_FROM_ALL_PROVIDERS: "info_from_all_providers",
285
+ LAST_MODELS_UPDATE: "lastModelsUpdate",
286
+ LAST_BASE_URLS_UPDATE: "lastBaseUrlsUpdate",
287
+ LOCAL_CASHU_TOKENS: "local_cashu_tokens",
288
+ API_KEYS: "api_keys",
289
+ CHILD_KEYS: "child_keys"
290
+ };
291
+
292
+ // storage/store.ts
293
+ var normalizeBaseUrl = (baseUrl) => baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
294
+ var getTokenBalance = (token) => {
295
+ try {
296
+ const decoded = getDecodedToken(token);
297
+ const unitDivisor = decoded.unit === "msat" ? 1e3 : 1;
298
+ let sum = 0;
299
+ for (const proof of decoded.proofs) {
300
+ sum += proof.amount / unitDivisor;
301
+ }
302
+ return sum;
303
+ } catch {
304
+ return 0;
305
+ }
306
+ };
307
+ var createSdkStore = async ({
308
+ driver
309
+ }) => {
310
+ const [
311
+ rawModels,
312
+ lastUsedModel,
313
+ rawBaseUrls,
314
+ lastBaseUrlsUpdate,
315
+ rawDisabledProviders,
316
+ rawMints,
317
+ rawInfo,
318
+ rawLastModelsUpdate,
319
+ rawCachedTokens,
320
+ rawApiKeys,
321
+ rawChildKeys
322
+ ] = await Promise.all([
323
+ driver.getItem(
324
+ SDK_STORAGE_KEYS.MODELS_FROM_ALL_PROVIDERS,
325
+ {}
326
+ ),
327
+ driver.getItem(SDK_STORAGE_KEYS.LAST_USED_MODEL, null),
328
+ driver.getItem(SDK_STORAGE_KEYS.BASE_URLS_LIST, []),
329
+ driver.getItem(SDK_STORAGE_KEYS.LAST_BASE_URLS_UPDATE, null),
330
+ driver.getItem(SDK_STORAGE_KEYS.DISABLED_PROVIDERS, []),
331
+ driver.getItem(
332
+ SDK_STORAGE_KEYS.MINTS_FROM_ALL_PROVIDERS,
333
+ {}
334
+ ),
335
+ driver.getItem(
336
+ SDK_STORAGE_KEYS.INFO_FROM_ALL_PROVIDERS,
337
+ {}
338
+ ),
339
+ driver.getItem(
340
+ SDK_STORAGE_KEYS.LAST_MODELS_UPDATE,
341
+ {}
342
+ ),
343
+ driver.getItem(SDK_STORAGE_KEYS.LOCAL_CASHU_TOKENS, []),
344
+ driver.getItem(SDK_STORAGE_KEYS.API_KEYS, []),
345
+ driver.getItem(SDK_STORAGE_KEYS.CHILD_KEYS, [])
346
+ ]);
347
+ const modelsFromAllProviders = Object.fromEntries(
348
+ Object.entries(rawModels).map(([baseUrl, models]) => [
349
+ normalizeBaseUrl(baseUrl),
350
+ models
351
+ ])
352
+ );
353
+ const baseUrlsList = rawBaseUrls.map((url) => normalizeBaseUrl(url));
354
+ const disabledProviders = rawDisabledProviders.map(
355
+ (url) => normalizeBaseUrl(url)
356
+ );
357
+ const mintsFromAllProviders = Object.fromEntries(
358
+ Object.entries(rawMints).map(([baseUrl, mints]) => [
359
+ normalizeBaseUrl(baseUrl),
360
+ mints.map((mint) => mint.endsWith("/") ? mint.slice(0, -1) : mint)
361
+ ])
362
+ );
363
+ const infoFromAllProviders = Object.fromEntries(
364
+ Object.entries(rawInfo).map(([baseUrl, info]) => [
365
+ normalizeBaseUrl(baseUrl),
366
+ info
367
+ ])
368
+ );
369
+ const lastModelsUpdate = Object.fromEntries(
370
+ Object.entries(rawLastModelsUpdate).map(([baseUrl, timestamp]) => [
371
+ normalizeBaseUrl(baseUrl),
372
+ timestamp
373
+ ])
374
+ );
375
+ const cachedTokens = rawCachedTokens.map((entry) => ({
376
+ ...entry,
377
+ baseUrl: normalizeBaseUrl(entry.baseUrl),
378
+ balance: typeof entry.balance === "number" ? entry.balance : getTokenBalance(entry.token),
379
+ lastUsed: entry.lastUsed ?? null
380
+ }));
381
+ const apiKeys = rawApiKeys.map((entry) => ({
382
+ ...entry,
383
+ baseUrl: normalizeBaseUrl(entry.baseUrl),
384
+ balance: entry.balance ?? 0,
385
+ lastUsed: entry.lastUsed ?? null
386
+ }));
387
+ const childKeys = rawChildKeys.map((entry) => ({
388
+ parentBaseUrl: normalizeBaseUrl(entry.parentBaseUrl),
389
+ childKey: entry.childKey,
390
+ balance: entry.balance ?? 0,
391
+ balanceLimit: entry.balanceLimit,
392
+ validityDate: entry.validityDate,
393
+ createdAt: entry.createdAt ?? Date.now()
394
+ }));
395
+ return createStore((set, get) => ({
396
+ modelsFromAllProviders,
397
+ lastUsedModel,
398
+ baseUrlsList,
399
+ lastBaseUrlsUpdate,
400
+ disabledProviders,
401
+ mintsFromAllProviders,
402
+ infoFromAllProviders,
403
+ lastModelsUpdate,
404
+ cachedTokens,
405
+ apiKeys,
406
+ childKeys,
407
+ setModelsFromAllProviders: (value) => {
408
+ const normalized = {};
409
+ for (const [baseUrl, models] of Object.entries(value)) {
410
+ normalized[normalizeBaseUrl(baseUrl)] = models;
411
+ }
412
+ void driver.setItem(
413
+ SDK_STORAGE_KEYS.MODELS_FROM_ALL_PROVIDERS,
414
+ normalized
415
+ );
416
+ set({ modelsFromAllProviders: normalized });
417
+ },
418
+ setLastUsedModel: (value) => {
419
+ void driver.setItem(SDK_STORAGE_KEYS.LAST_USED_MODEL, value);
420
+ set({ lastUsedModel: value });
421
+ },
422
+ setBaseUrlsList: (value) => {
423
+ const normalized = value.map((url) => normalizeBaseUrl(url));
424
+ void driver.setItem(SDK_STORAGE_KEYS.BASE_URLS_LIST, normalized);
425
+ set({ baseUrlsList: normalized });
426
+ },
427
+ setBaseUrlsLastUpdate: (value) => {
428
+ void driver.setItem(SDK_STORAGE_KEYS.LAST_BASE_URLS_UPDATE, value);
429
+ set({ lastBaseUrlsUpdate: value });
430
+ },
431
+ setDisabledProviders: (value) => {
432
+ const normalized = value.map((url) => normalizeBaseUrl(url));
433
+ void driver.setItem(SDK_STORAGE_KEYS.DISABLED_PROVIDERS, normalized);
434
+ set({ disabledProviders: normalized });
435
+ },
436
+ setMintsFromAllProviders: (value) => {
437
+ const normalized = {};
438
+ for (const [baseUrl, mints] of Object.entries(value)) {
439
+ normalized[normalizeBaseUrl(baseUrl)] = mints.map(
440
+ (mint) => mint.endsWith("/") ? mint.slice(0, -1) : mint
441
+ );
442
+ }
443
+ void driver.setItem(
444
+ SDK_STORAGE_KEYS.MINTS_FROM_ALL_PROVIDERS,
445
+ normalized
446
+ );
447
+ set({ mintsFromAllProviders: normalized });
448
+ },
449
+ setInfoFromAllProviders: (value) => {
450
+ const normalized = {};
451
+ for (const [baseUrl, info] of Object.entries(value)) {
452
+ normalized[normalizeBaseUrl(baseUrl)] = info;
453
+ }
454
+ void driver.setItem(SDK_STORAGE_KEYS.INFO_FROM_ALL_PROVIDERS, normalized);
455
+ set({ infoFromAllProviders: normalized });
456
+ },
457
+ setLastModelsUpdate: (value) => {
458
+ const normalized = {};
459
+ for (const [baseUrl, timestamp] of Object.entries(value)) {
460
+ normalized[normalizeBaseUrl(baseUrl)] = timestamp;
461
+ }
462
+ void driver.setItem(SDK_STORAGE_KEYS.LAST_MODELS_UPDATE, normalized);
463
+ set({ lastModelsUpdate: normalized });
464
+ },
465
+ setCachedTokens: (value) => {
466
+ set((state) => {
467
+ const updates = typeof value === "function" ? value(state.cachedTokens) : value;
468
+ const normalized = updates.map((entry) => ({
469
+ ...entry,
470
+ baseUrl: normalizeBaseUrl(entry.baseUrl),
471
+ balance: typeof entry.balance === "number" ? entry.balance : getTokenBalance(entry.token),
472
+ lastUsed: entry.lastUsed ?? null
473
+ }));
474
+ void driver.setItem(SDK_STORAGE_KEYS.LOCAL_CASHU_TOKENS, normalized);
475
+ return { cachedTokens: normalized };
476
+ });
477
+ },
478
+ setApiKeys: (value) => {
479
+ set((state) => {
480
+ const updates = typeof value === "function" ? value(state.apiKeys) : value;
481
+ const normalized = updates.map((entry) => ({
482
+ ...entry,
483
+ baseUrl: normalizeBaseUrl(entry.baseUrl),
484
+ balance: entry.balance ?? 0,
485
+ lastUsed: entry.lastUsed ?? null
486
+ }));
487
+ void driver.setItem(SDK_STORAGE_KEYS.API_KEYS, normalized);
488
+ return { apiKeys: normalized };
489
+ });
490
+ },
491
+ setChildKeys: (value) => {
492
+ set((state) => {
493
+ const updates = typeof value === "function" ? value(state.childKeys) : value;
494
+ const normalized = updates.map((entry) => ({
495
+ parentBaseUrl: normalizeBaseUrl(entry.parentBaseUrl),
496
+ childKey: entry.childKey,
497
+ balance: entry.balance ?? 0,
498
+ balanceLimit: entry.balanceLimit,
499
+ validityDate: entry.validityDate,
500
+ createdAt: entry.createdAt ?? Date.now()
501
+ }));
502
+ void driver.setItem(SDK_STORAGE_KEYS.CHILD_KEYS, normalized);
503
+ return { childKeys: normalized };
504
+ });
505
+ }
506
+ }));
507
+ };
508
+ var createDiscoveryAdapterFromStore = (store) => ({
509
+ getCachedModels: () => store.getState().modelsFromAllProviders,
510
+ setCachedModels: (models) => store.getState().setModelsFromAllProviders(models),
511
+ getCachedMints: () => store.getState().mintsFromAllProviders,
512
+ setCachedMints: (mints) => store.getState().setMintsFromAllProviders(mints),
513
+ getCachedProviderInfo: () => store.getState().infoFromAllProviders,
514
+ setCachedProviderInfo: (info) => store.getState().setInfoFromAllProviders(info),
515
+ getProviderLastUpdate: (baseUrl) => {
516
+ const normalized = normalizeBaseUrl(baseUrl);
517
+ const timestamps = store.getState().lastModelsUpdate;
518
+ return timestamps[normalized] || null;
519
+ },
520
+ setProviderLastUpdate: (baseUrl, timestamp) => {
521
+ const normalized = normalizeBaseUrl(baseUrl);
522
+ const timestamps = { ...store.getState().lastModelsUpdate };
523
+ timestamps[normalized] = timestamp;
524
+ store.getState().setLastModelsUpdate(timestamps);
525
+ },
526
+ getLastUsedModel: () => store.getState().lastUsedModel,
527
+ setLastUsedModel: (modelId) => store.getState().setLastUsedModel(modelId),
528
+ getDisabledProviders: () => store.getState().disabledProviders,
529
+ getBaseUrlsList: () => store.getState().baseUrlsList,
530
+ setBaseUrlsList: (urls) => store.getState().setBaseUrlsList(urls),
531
+ getBaseUrlsLastUpdate: () => store.getState().lastBaseUrlsUpdate,
532
+ setBaseUrlsLastUpdate: (timestamp) => store.getState().setBaseUrlsLastUpdate(timestamp)
533
+ });
534
+ var createStorageAdapterFromStore = (store) => ({
535
+ getToken: (baseUrl) => {
536
+ const normalized = normalizeBaseUrl(baseUrl);
537
+ const entry = store.getState().cachedTokens.find((token) => token.baseUrl === normalized);
538
+ if (!entry) return null;
539
+ const next = store.getState().cachedTokens.map(
540
+ (token) => token.baseUrl === normalized ? { ...token, lastUsed: Date.now() } : token
541
+ );
542
+ store.getState().setCachedTokens(next);
543
+ return entry.token;
544
+ },
545
+ setToken: (baseUrl, token) => {
546
+ const normalized = normalizeBaseUrl(baseUrl);
547
+ const tokens = store.getState().cachedTokens;
548
+ const balance = getTokenBalance(token);
549
+ const existingIndex = tokens.findIndex(
550
+ (entry) => entry.baseUrl === normalized
551
+ );
552
+ if (existingIndex !== -1) {
553
+ throw new Error(`Token already exists for baseUrl: ${normalized}`);
554
+ }
555
+ const next = [...tokens];
556
+ next.push({
557
+ baseUrl: normalized,
558
+ token,
559
+ balance,
560
+ lastUsed: Date.now()
561
+ });
562
+ store.getState().setCachedTokens(next);
563
+ },
564
+ removeToken: (baseUrl) => {
565
+ const normalized = normalizeBaseUrl(baseUrl);
566
+ const next = store.getState().cachedTokens.filter((entry) => entry.baseUrl !== normalized);
567
+ store.getState().setCachedTokens(next);
568
+ },
569
+ updateTokenBalance: (baseUrl, balance) => {
570
+ const normalized = normalizeBaseUrl(baseUrl);
571
+ const tokens = store.getState().cachedTokens;
572
+ const next = tokens.map(
573
+ (entry) => entry.baseUrl === normalized ? { ...entry, balance } : entry
574
+ );
575
+ store.getState().setCachedTokens(next);
576
+ },
577
+ getCachedTokenDistribution: () => {
578
+ const cachedTokens = store.getState().cachedTokens;
579
+ const distributionMap = {};
580
+ for (const entry of cachedTokens) {
581
+ const sum = entry.balance || 0;
582
+ if (sum > 0) {
583
+ distributionMap[entry.baseUrl] = (distributionMap[entry.baseUrl] || 0) + sum;
584
+ }
585
+ }
586
+ return Object.entries(distributionMap).map(([baseUrl, amt]) => ({ baseUrl, amount: amt })).sort((a, b) => b.amount - a.amount);
587
+ },
588
+ getApiKeyDistribution: () => {
589
+ const apiKeys = store.getState().apiKeys;
590
+ const distributionMap = {};
591
+ for (const entry of apiKeys) {
592
+ const sum = entry.balance || 0;
593
+ if (sum > 0) {
594
+ distributionMap[entry.baseUrl] = (distributionMap[entry.baseUrl] || 0) + sum;
595
+ }
596
+ }
597
+ return Object.entries(distributionMap).map(([baseUrl, amt]) => ({ baseUrl, amount: amt })).sort((a, b) => b.amount - a.amount);
598
+ },
599
+ saveProviderInfo: (baseUrl, info) => {
600
+ const normalized = normalizeBaseUrl(baseUrl);
601
+ const next = { ...store.getState().infoFromAllProviders };
602
+ next[normalized] = info;
603
+ store.getState().setInfoFromAllProviders(next);
604
+ },
605
+ getProviderInfo: (baseUrl) => {
606
+ const normalized = normalizeBaseUrl(baseUrl);
607
+ return store.getState().infoFromAllProviders[normalized] || null;
608
+ },
609
+ // ========== API Keys (for apikeys mode) ==========
610
+ getApiKey: (baseUrl) => {
611
+ const normalized = normalizeBaseUrl(baseUrl);
612
+ const entry = store.getState().apiKeys.find((key) => key.baseUrl === normalized);
613
+ if (!entry) return null;
614
+ const next = store.getState().apiKeys.map(
615
+ (key) => key.baseUrl === normalized ? { ...key, lastUsed: Date.now() } : key
616
+ );
617
+ store.getState().setApiKeys(next);
618
+ return entry;
619
+ },
620
+ setApiKey: (baseUrl, key) => {
621
+ const normalized = normalizeBaseUrl(baseUrl);
622
+ const keys = store.getState().apiKeys;
623
+ const existingIndex = keys.findIndex(
624
+ (entry) => entry.baseUrl === normalized
625
+ );
626
+ if (existingIndex !== -1) {
627
+ throw new Error(`ApiKey already exists for baseUrl: ${normalized}`);
628
+ }
629
+ const next = [...keys];
630
+ next.push({
631
+ baseUrl: normalized,
632
+ key,
633
+ balance: 0,
634
+ lastUsed: Date.now()
635
+ });
636
+ store.getState().setApiKeys(next);
637
+ },
638
+ updateApiKeyBalance: (baseUrl, balance) => {
639
+ const normalized = normalizeBaseUrl(baseUrl);
640
+ const keys = store.getState().apiKeys;
641
+ const next = keys.map(
642
+ (entry) => entry.baseUrl === normalized ? { ...entry, balance } : entry
643
+ );
644
+ store.getState().setApiKeys(next);
645
+ },
646
+ removeApiKey: (baseUrl) => {
647
+ const normalized = normalizeBaseUrl(baseUrl);
648
+ const next = store.getState().apiKeys.filter((entry) => entry.baseUrl !== normalized);
649
+ store.getState().setApiKeys(next);
650
+ },
651
+ getAllApiKeys: () => {
652
+ return store.getState().apiKeys.map((entry) => ({
653
+ baseUrl: entry.baseUrl,
654
+ key: entry.key,
655
+ balance: entry.balance,
656
+ lastUsed: entry.lastUsed
657
+ }));
658
+ },
659
+ // ========== Child Keys ==========
660
+ getChildKey: (parentBaseUrl) => {
661
+ const normalized = normalizeBaseUrl(parentBaseUrl);
662
+ const entry = store.getState().childKeys.find((key) => key.parentBaseUrl === normalized);
663
+ if (!entry) return null;
664
+ return {
665
+ parentBaseUrl: entry.parentBaseUrl,
666
+ childKey: entry.childKey,
667
+ balance: entry.balance,
668
+ balanceLimit: entry.balanceLimit,
669
+ validityDate: entry.validityDate,
670
+ createdAt: entry.createdAt
671
+ };
672
+ },
673
+ setChildKey: (parentBaseUrl, childKey, balance, validityDate, balanceLimit) => {
674
+ const normalized = normalizeBaseUrl(parentBaseUrl);
675
+ const keys = store.getState().childKeys;
676
+ const existingIndex = keys.findIndex(
677
+ (entry) => entry.parentBaseUrl === normalized
678
+ );
679
+ if (existingIndex !== -1) {
680
+ const next = keys.map(
681
+ (entry) => entry.parentBaseUrl === normalized ? {
682
+ ...entry,
683
+ childKey,
684
+ balance: balance ?? 0,
685
+ validityDate,
686
+ balanceLimit,
687
+ createdAt: Date.now()
688
+ } : entry
689
+ );
690
+ store.getState().setChildKeys(next);
691
+ } else {
692
+ const next = [...keys];
693
+ next.push({
694
+ parentBaseUrl: normalized,
695
+ childKey,
696
+ balance: balance ?? 0,
697
+ validityDate,
698
+ balanceLimit,
699
+ createdAt: Date.now()
700
+ });
701
+ store.getState().setChildKeys(next);
702
+ }
703
+ },
704
+ updateChildKeyBalance: (parentBaseUrl, balance) => {
705
+ const normalized = normalizeBaseUrl(parentBaseUrl);
706
+ const keys = store.getState().childKeys;
707
+ const next = keys.map(
708
+ (entry) => entry.parentBaseUrl === normalized ? { ...entry, balance } : entry
709
+ );
710
+ store.getState().setChildKeys(next);
711
+ },
712
+ removeChildKey: (parentBaseUrl) => {
713
+ const normalized = normalizeBaseUrl(parentBaseUrl);
714
+ const next = store.getState().childKeys.filter((entry) => entry.parentBaseUrl !== normalized);
715
+ store.getState().setChildKeys(next);
716
+ },
717
+ getAllChildKeys: () => {
718
+ return store.getState().childKeys.map((entry) => ({
719
+ parentBaseUrl: entry.parentBaseUrl,
720
+ childKey: entry.childKey,
721
+ balance: entry.balance,
722
+ balanceLimit: entry.balanceLimit,
723
+ validityDate: entry.validityDate,
724
+ createdAt: entry.createdAt
725
+ }));
726
+ }
727
+ });
728
+ var createProviderRegistryFromStore = (store) => ({
729
+ getModelsForProvider: (baseUrl) => {
730
+ const normalized = normalizeBaseUrl(baseUrl);
731
+ return store.getState().modelsFromAllProviders[normalized] || [];
732
+ },
733
+ getDisabledProviders: () => store.getState().disabledProviders,
734
+ getProviderMints: (baseUrl) => {
735
+ const normalized = normalizeBaseUrl(baseUrl);
736
+ return store.getState().mintsFromAllProviders[normalized] || [];
737
+ },
738
+ getProviderInfo: async (baseUrl) => {
739
+ const normalized = normalizeBaseUrl(baseUrl);
740
+ const cached = store.getState().infoFromAllProviders[normalized];
741
+ if (cached) return cached;
742
+ try {
743
+ const response = await fetch(`${normalized}v1/info`);
744
+ if (!response.ok) {
745
+ throw new Error(`Failed ${response.status}`);
746
+ }
747
+ const info = await response.json();
748
+ const next = { ...store.getState().infoFromAllProviders };
749
+ next[normalized] = info;
750
+ store.getState().setInfoFromAllProviders(next);
751
+ return info;
752
+ } catch (error) {
753
+ console.warn(`Failed to fetch provider info from ${normalized}:`, error);
754
+ return null;
755
+ }
756
+ },
757
+ getAllProvidersModels: () => store.getState().modelsFromAllProviders
758
+ });
759
+
760
+ // storage/index.ts
761
+ var isBrowser = () => {
762
+ try {
763
+ return typeof window !== "undefined" && typeof window.localStorage !== "undefined";
764
+ } catch {
765
+ return false;
766
+ }
767
+ };
768
+ var isNode = () => {
769
+ try {
770
+ return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
771
+ } catch {
772
+ return false;
773
+ }
774
+ };
775
+ var defaultDriver = null;
776
+ var isBun2 = () => {
777
+ return typeof process.versions.bun !== "undefined";
778
+ };
779
+ var getDefaultSdkDriver = () => {
780
+ if (defaultDriver) return defaultDriver;
781
+ if (isBrowser()) {
782
+ defaultDriver = localStorageDriver;
783
+ return defaultDriver;
784
+ }
785
+ if (isBun2()) {
786
+ defaultDriver = createMemoryDriver();
787
+ return defaultDriver;
788
+ }
789
+ if (isNode()) {
790
+ defaultDriver = createSqliteDriver();
791
+ return defaultDriver;
792
+ }
793
+ defaultDriver = createMemoryDriver();
794
+ return defaultDriver;
795
+ };
796
+ var defaultStorePromise = null;
797
+ var getDefaultSdkStore = () => {
798
+ if (!defaultStorePromise) {
799
+ defaultStorePromise = createSdkStore({ driver: getDefaultSdkDriver() });
800
+ }
801
+ return defaultStorePromise;
802
+ };
803
+ var getDefaultDiscoveryAdapter = async () => createDiscoveryAdapterFromStore(await getDefaultSdkStore());
804
+ var getDefaultStorageAdapter = async () => createStorageAdapterFromStore(await getDefaultSdkStore());
805
+ var getDefaultProviderRegistry = async () => createProviderRegistryFromStore(await getDefaultSdkStore());
806
+
807
+ export { SDK_STORAGE_KEYS, createDiscoveryAdapterFromStore, createIndexedDBDriver, createMemoryDriver, createProviderRegistryFromStore, createSdkStore, createSqliteDriver, createStorageAdapterFromStore, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultSdkDriver, getDefaultSdkStore, getDefaultStorageAdapter, localStorageDriver };
808
+ //# sourceMappingURL=index.mjs.map
809
+ //# sourceMappingURL=index.mjs.map