@routstr/sdk 0.1.0 → 0.1.2

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