@routstr/sdk 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.d.mts +16 -2
- package/dist/client/index.d.ts +16 -2
- package/dist/client/index.js +276 -37
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +276 -37
- package/dist/client/index.mjs.map +1 -1
- package/dist/discovery/index.js +1 -1
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +1 -1
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/index.d.mts +9 -5
- package/dist/index.d.ts +9 -5
- package/dist/index.js +281 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +281 -41
- package/dist/index.mjs.map +1 -1
- package/dist/storage/index.d.mts +5 -2
- package/dist/storage/index.d.ts +5 -2
- package/dist/storage/index.js +95 -4
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/index.mjs +95 -4
- package/dist/storage/index.mjs.map +1 -1
- package/dist/{store-C5lnyX8k.d.mts → store-DGeLPv9E.d.mts} +21 -0
- package/dist/{store-BJlwiDX5.d.ts → store-h7m23ffq.d.ts} +21 -0
- package/dist/wallet/index.d.mts +10 -4
- package/dist/wallet/index.d.ts +10 -4
- package/dist/wallet/index.js +45 -24
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +45 -24
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -466,7 +466,7 @@ var ModelManager = class _ModelManager {
|
|
|
466
466
|
}
|
|
467
467
|
}
|
|
468
468
|
const DEFAULT_RELAYS = [
|
|
469
|
-
"wss://relay.
|
|
469
|
+
"wss://relay.damus.io",
|
|
470
470
|
"wss://nos.lol",
|
|
471
471
|
"wss://relay.routstr.com"
|
|
472
472
|
];
|
|
@@ -1081,8 +1081,9 @@ var CashuSpender = class {
|
|
|
1081
1081
|
return null;
|
|
1082
1082
|
}
|
|
1083
1083
|
/**
|
|
1084
|
-
* Refund all xcashu tokens from storage
|
|
1085
|
-
*
|
|
1084
|
+
* Refund all xcashu tokens from storage by calling the provider's refund endpoint.
|
|
1085
|
+
* The xcashu token acts as an API key to claim the refund, and the response contains
|
|
1086
|
+
* the actual refunded Cashu token which is then received into the wallet.
|
|
1086
1087
|
* @param mintUrl - The mint URL for receiving tokens
|
|
1087
1088
|
* @param excludeBaseUrls - Base URLs to exclude from refund (optional)
|
|
1088
1089
|
* @returns Results for each xcashu token refund attempt
|
|
@@ -1095,7 +1096,20 @@ var CashuSpender = class {
|
|
|
1095
1096
|
if (excludedUrls.has(baseUrl)) continue;
|
|
1096
1097
|
for (const xcashuToken of tokens) {
|
|
1097
1098
|
try {
|
|
1098
|
-
|
|
1099
|
+
if (!this.balanceManager) {
|
|
1100
|
+
throw new Error("BalanceManager not available for xcashu refund");
|
|
1101
|
+
}
|
|
1102
|
+
const fetchResult = await this.balanceManager.fetchRefundToken(
|
|
1103
|
+
baseUrl,
|
|
1104
|
+
xcashuToken.token,
|
|
1105
|
+
true
|
|
1106
|
+
);
|
|
1107
|
+
if (!fetchResult.success || !fetchResult.token) {
|
|
1108
|
+
throw new Error(
|
|
1109
|
+
fetchResult.error || "Failed to fetch refund token from provider"
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
const receiveResult = await this.receiveToken(fetchResult.token);
|
|
1099
1113
|
if (receiveResult.success) {
|
|
1100
1114
|
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
1101
1115
|
results.push({
|
|
@@ -1110,7 +1124,10 @@ var CashuSpender = class {
|
|
|
1110
1124
|
} else {
|
|
1111
1125
|
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
1112
1126
|
const newTryCount = currentTryCount + 1;
|
|
1113
|
-
this.storageAdapter.updateXcashuTokenTryCount(
|
|
1127
|
+
this.storageAdapter.updateXcashuTokenTryCount(
|
|
1128
|
+
xcashuToken.token,
|
|
1129
|
+
newTryCount
|
|
1130
|
+
);
|
|
1114
1131
|
results.push({
|
|
1115
1132
|
baseUrl,
|
|
1116
1133
|
token: xcashuToken.token,
|
|
@@ -1119,13 +1136,16 @@ var CashuSpender = class {
|
|
|
1119
1136
|
});
|
|
1120
1137
|
this._log(
|
|
1121
1138
|
"DEBUG",
|
|
1122
|
-
`[CashuSpender] refundXcashuTokens: Failed to refund
|
|
1139
|
+
`[CashuSpender] refundXcashuTokens: Failed to receive refund token for ${baseUrl}, incremented tryCount to ${newTryCount}`
|
|
1123
1140
|
);
|
|
1124
1141
|
}
|
|
1125
1142
|
} catch (error) {
|
|
1126
1143
|
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
1127
1144
|
const newTryCount = currentTryCount + 1;
|
|
1128
|
-
this.storageAdapter.updateXcashuTokenTryCount(
|
|
1145
|
+
this.storageAdapter.updateXcashuTokenTryCount(
|
|
1146
|
+
xcashuToken.token,
|
|
1147
|
+
newTryCount
|
|
1148
|
+
);
|
|
1129
1149
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1130
1150
|
results.push({
|
|
1131
1151
|
baseUrl,
|
|
@@ -1162,7 +1182,10 @@ var CashuSpender = class {
|
|
|
1162
1182
|
if (refundResult.success) {
|
|
1163
1183
|
this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);
|
|
1164
1184
|
} else {
|
|
1165
|
-
this.storageAdapter.updateApiKeyBalance(
|
|
1185
|
+
this.storageAdapter.updateApiKeyBalance(
|
|
1186
|
+
apiKeyEntry.baseUrl,
|
|
1187
|
+
apiKeyEntry.amount
|
|
1188
|
+
);
|
|
1166
1189
|
}
|
|
1167
1190
|
results.push({
|
|
1168
1191
|
baseUrl: apiKeyEntry.baseUrl,
|
|
@@ -1300,7 +1323,7 @@ var BalanceManager = class {
|
|
|
1300
1323
|
}
|
|
1301
1324
|
let fetchResult;
|
|
1302
1325
|
try {
|
|
1303
|
-
fetchResult = await this.
|
|
1326
|
+
fetchResult = await this.fetchRefundToken(baseUrl, apiKey);
|
|
1304
1327
|
if (!fetchResult.success) {
|
|
1305
1328
|
return {
|
|
1306
1329
|
success: false,
|
|
@@ -1336,9 +1359,9 @@ var BalanceManager = class {
|
|
|
1336
1359
|
}
|
|
1337
1360
|
}
|
|
1338
1361
|
/**
|
|
1339
|
-
* Fetch refund token from provider API using API key authentication
|
|
1362
|
+
* Fetch refund token from provider API using API key (or xcashu token) authentication
|
|
1340
1363
|
*/
|
|
1341
|
-
async
|
|
1364
|
+
async fetchRefundToken(baseUrl, apiKeyOrToken, xCashu = false) {
|
|
1342
1365
|
if (!baseUrl) {
|
|
1343
1366
|
return {
|
|
1344
1367
|
success: false,
|
|
@@ -1352,12 +1375,17 @@ var BalanceManager = class {
|
|
|
1352
1375
|
controller.abort();
|
|
1353
1376
|
}, 6e4);
|
|
1354
1377
|
try {
|
|
1378
|
+
const headers = {
|
|
1379
|
+
"Content-Type": "application/json"
|
|
1380
|
+
};
|
|
1381
|
+
if (xCashu) {
|
|
1382
|
+
headers["X-Cashu"] = apiKeyOrToken;
|
|
1383
|
+
} else {
|
|
1384
|
+
headers["Authorization"] = `Bearer ${apiKeyOrToken}`;
|
|
1385
|
+
}
|
|
1355
1386
|
const response = await fetch(url, {
|
|
1356
1387
|
method: "POST",
|
|
1357
|
-
headers
|
|
1358
|
-
Authorization: `Bearer ${apiKey}`,
|
|
1359
|
-
"Content-Type": "application/json"
|
|
1360
|
-
},
|
|
1388
|
+
headers,
|
|
1361
1389
|
signal: controller.signal
|
|
1362
1390
|
});
|
|
1363
1391
|
clearTimeout(timeoutId);
|
|
@@ -1378,10 +1406,7 @@ var BalanceManager = class {
|
|
|
1378
1406
|
};
|
|
1379
1407
|
} catch (error) {
|
|
1380
1408
|
clearTimeout(timeoutId);
|
|
1381
|
-
console.error(
|
|
1382
|
-
"[BalanceManager._fetchRefundTokenWithApiKey] Fetch error",
|
|
1383
|
-
error
|
|
1384
|
-
);
|
|
1409
|
+
console.error("[BalanceManager.fetchRefundToken] Fetch error", error);
|
|
1385
1410
|
if (error instanceof Error) {
|
|
1386
1411
|
if (error.name === "AbortError") {
|
|
1387
1412
|
return {
|
|
@@ -1428,11 +1453,7 @@ var BalanceManager = class {
|
|
|
1428
1453
|
};
|
|
1429
1454
|
}
|
|
1430
1455
|
cashuToken = tokenResult.token;
|
|
1431
|
-
const topUpResult = await this._postTopUp(
|
|
1432
|
-
baseUrl,
|
|
1433
|
-
apiKey,
|
|
1434
|
-
cashuToken
|
|
1435
|
-
);
|
|
1456
|
+
const topUpResult = await this._postTopUp(baseUrl, apiKey, cashuToken);
|
|
1436
1457
|
requestId = topUpResult.requestId;
|
|
1437
1458
|
console.log(topUpResult);
|
|
1438
1459
|
if (!topUpResult.success) {
|
|
@@ -1798,7 +1819,7 @@ var BalanceManager = class {
|
|
|
1798
1819
|
console.log(response.status);
|
|
1799
1820
|
const data = await response.json();
|
|
1800
1821
|
console.log("FAILED ", data);
|
|
1801
|
-
const isInvalidApiKey = response.status === 401 && data?.code === "invalid_api_key" && data?.message?.includes("proofs already spent");
|
|
1822
|
+
const isInvalidApiKey = response.status === 401 && data?.detail?.error?.code === "invalid_api_key" && data?.detail?.error?.message?.includes("proofs already spent");
|
|
1802
1823
|
return {
|
|
1803
1824
|
amount: -1,
|
|
1804
1825
|
reserved: data.reserved ?? 0,
|
|
@@ -2296,8 +2317,13 @@ function isInsecureHttpUrl(url) {
|
|
|
2296
2317
|
return url.startsWith("http://");
|
|
2297
2318
|
}
|
|
2298
2319
|
var ProviderManager = class _ProviderManager {
|
|
2299
|
-
constructor(providerRegistry) {
|
|
2320
|
+
constructor(providerRegistry, store) {
|
|
2300
2321
|
this.providerRegistry = providerRegistry;
|
|
2322
|
+
this.instanceId = `pm_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2323
|
+
if (store) {
|
|
2324
|
+
this.store = store;
|
|
2325
|
+
this.hydrateFromStore();
|
|
2326
|
+
}
|
|
2301
2327
|
}
|
|
2302
2328
|
failedProviders = /* @__PURE__ */ new Set();
|
|
2303
2329
|
/** Track when each provider last failed (provider URL -> timestamp) */
|
|
@@ -2306,14 +2332,57 @@ var ProviderManager = class _ProviderManager {
|
|
|
2306
2332
|
providersOnCoolDown = [];
|
|
2307
2333
|
/** Cooldown duration in milliseconds (5 minutes) */
|
|
2308
2334
|
static COOLDOWN_DURATION_MS = 5 * 60 * 1e3;
|
|
2335
|
+
/** Optional persistent store for failure tracking */
|
|
2336
|
+
store = null;
|
|
2337
|
+
/** Instance ID for debugging */
|
|
2338
|
+
instanceId;
|
|
2339
|
+
/**
|
|
2340
|
+
* Hydrate in-memory state from persistent store
|
|
2341
|
+
*/
|
|
2342
|
+
hydrateFromStore() {
|
|
2343
|
+
if (!this.store) return;
|
|
2344
|
+
const state = this.store.getState();
|
|
2345
|
+
this.failedProviders = new Set(state.failedProviders);
|
|
2346
|
+
this.lastFailed = new Map(Object.entries(state.lastFailed));
|
|
2347
|
+
const now = Date.now();
|
|
2348
|
+
this.providersOnCoolDown = state.providersOnCooldown.filter(
|
|
2349
|
+
(entry) => now - entry.timestamp < _ProviderManager.COOLDOWN_DURATION_MS
|
|
2350
|
+
).map((entry) => [entry.baseUrl, entry.timestamp]);
|
|
2351
|
+
console.log(`[ProviderManager:${this.instanceId}] Hydrated from store:`);
|
|
2352
|
+
console.log(` failedProviders: ${this.failedProviders.size}`);
|
|
2353
|
+
console.log(` lastFailed: ${this.lastFailed.size}`);
|
|
2354
|
+
console.log(` providersOnCooldown: ${this.providersOnCoolDown.length}`);
|
|
2355
|
+
}
|
|
2356
|
+
/**
|
|
2357
|
+
* Get instance ID for debugging
|
|
2358
|
+
*/
|
|
2359
|
+
getInstanceId() {
|
|
2360
|
+
return this.instanceId;
|
|
2361
|
+
}
|
|
2309
2362
|
/**
|
|
2310
2363
|
* Clean up expired cooldown entries
|
|
2311
2364
|
*/
|
|
2312
2365
|
cleanupExpiredCooldowns() {
|
|
2313
2366
|
const now = Date.now();
|
|
2367
|
+
const before = this.providersOnCoolDown.length;
|
|
2314
2368
|
this.providersOnCoolDown = this.providersOnCoolDown.filter(
|
|
2315
|
-
([, timestamp]) =>
|
|
2369
|
+
([url, timestamp]) => {
|
|
2370
|
+
const age = now - timestamp;
|
|
2371
|
+
const isExpired = age >= _ProviderManager.COOLDOWN_DURATION_MS;
|
|
2372
|
+
if (isExpired) {
|
|
2373
|
+
console.log(
|
|
2374
|
+
`[cleanupExpiredCooldowns:${this.instanceId}] Removing expired cooldown for ${url} (age: ${age}ms, cooldown: ${_ProviderManager.COOLDOWN_DURATION_MS}ms)`
|
|
2375
|
+
);
|
|
2376
|
+
}
|
|
2377
|
+
return !isExpired;
|
|
2378
|
+
}
|
|
2316
2379
|
);
|
|
2380
|
+
const after = this.providersOnCoolDown.length;
|
|
2381
|
+
if (before !== after) {
|
|
2382
|
+
console.log(
|
|
2383
|
+
`[cleanupExpiredCooldowns:${this.instanceId}] Cleaned up ${before - after} expired cooldown(s), ${after} remaining`
|
|
2384
|
+
);
|
|
2385
|
+
}
|
|
2317
2386
|
}
|
|
2318
2387
|
/**
|
|
2319
2388
|
* Get the cooldown duration in milliseconds
|
|
@@ -2326,7 +2395,8 @@ var ProviderManager = class _ProviderManager {
|
|
|
2326
2395
|
*/
|
|
2327
2396
|
isOnCooldown(baseUrl) {
|
|
2328
2397
|
this.cleanupExpiredCooldowns();
|
|
2329
|
-
|
|
2398
|
+
const result = this.providersOnCoolDown.some(([url]) => url === baseUrl);
|
|
2399
|
+
return result;
|
|
2330
2400
|
}
|
|
2331
2401
|
/**
|
|
2332
2402
|
* Get all providers currently on cooldown
|
|
@@ -2340,6 +2410,9 @@ var ProviderManager = class _ProviderManager {
|
|
|
2340
2410
|
*/
|
|
2341
2411
|
resetFailedProviders() {
|
|
2342
2412
|
this.failedProviders.clear();
|
|
2413
|
+
if (this.store) {
|
|
2414
|
+
this.store.getState().setFailedProviders([]);
|
|
2415
|
+
}
|
|
2343
2416
|
}
|
|
2344
2417
|
/**
|
|
2345
2418
|
* Get the last failed timestamp for a provider
|
|
@@ -2360,13 +2433,62 @@ var ProviderManager = class _ProviderManager {
|
|
|
2360
2433
|
markFailed(baseUrl) {
|
|
2361
2434
|
const now = Date.now();
|
|
2362
2435
|
const lastFailure = this.lastFailed.get(baseUrl);
|
|
2436
|
+
console.log(`[markFailed:${this.instanceId}] baseUrl: ${baseUrl}`);
|
|
2437
|
+
console.log(
|
|
2438
|
+
`[markFailed:${this.instanceId}] lastFailure from map: ${lastFailure}`
|
|
2439
|
+
);
|
|
2440
|
+
console.log(
|
|
2441
|
+
`[markFailed:${this.instanceId}] current timestamp (now): ${now}`
|
|
2442
|
+
);
|
|
2443
|
+
console.log(
|
|
2444
|
+
`[markFailed:${this.instanceId}] COOLDOWN_DURATION_MS: ${_ProviderManager.COOLDOWN_DURATION_MS}`
|
|
2445
|
+
);
|
|
2446
|
+
if (lastFailure !== void 0) {
|
|
2447
|
+
const timeSinceLastFailure = now - lastFailure;
|
|
2448
|
+
console.log(
|
|
2449
|
+
`[markFailed:${this.instanceId}] timeSinceLastFailure: ${timeSinceLastFailure}ms`
|
|
2450
|
+
);
|
|
2451
|
+
console.log(
|
|
2452
|
+
`[markFailed:${this.instanceId}] isWithinCooldownWindow: ${timeSinceLastFailure < _ProviderManager.COOLDOWN_DURATION_MS}`
|
|
2453
|
+
);
|
|
2454
|
+
}
|
|
2363
2455
|
this.lastFailed.set(baseUrl, now);
|
|
2364
2456
|
this.failedProviders.add(baseUrl);
|
|
2457
|
+
if (this.store) {
|
|
2458
|
+
this.store.getState().setLastFailedTimestamp(baseUrl, now);
|
|
2459
|
+
this.store.getState().addFailedProvider(baseUrl);
|
|
2460
|
+
}
|
|
2461
|
+
console.log(
|
|
2462
|
+
`[markFailed:${this.instanceId}] Updated lastFailed map for ${baseUrl} to ${now}`
|
|
2463
|
+
);
|
|
2464
|
+
console.log(
|
|
2465
|
+
`[markFailed:${this.instanceId}] failedProviders set size: ${this.failedProviders.size}`
|
|
2466
|
+
);
|
|
2365
2467
|
if (lastFailure !== void 0 && now - lastFailure < _ProviderManager.COOLDOWN_DURATION_MS) {
|
|
2468
|
+
console.log(
|
|
2469
|
+
`[markFailed:${this.instanceId}] Second failure detected within cooldown window for ${baseUrl}`
|
|
2470
|
+
);
|
|
2366
2471
|
if (!this.isOnCooldown(baseUrl)) {
|
|
2367
2472
|
this.providersOnCoolDown.push([baseUrl, now]);
|
|
2473
|
+
if (this.store) {
|
|
2474
|
+
this.store.getState().addProviderOnCooldown(baseUrl, now);
|
|
2475
|
+
}
|
|
2368
2476
|
console.log(
|
|
2369
|
-
`Provider ${baseUrl} added to cooldown after second failure within 5 minutes`
|
|
2477
|
+
`[markFailed:${this.instanceId}] Provider ${baseUrl} added to cooldown after second failure within 5 minutes`
|
|
2478
|
+
);
|
|
2479
|
+
} else {
|
|
2480
|
+
console.log(
|
|
2481
|
+
`[markFailed:${this.instanceId}] Provider ${baseUrl} is already on cooldown`
|
|
2482
|
+
);
|
|
2483
|
+
}
|
|
2484
|
+
} else {
|
|
2485
|
+
if (lastFailure === void 0) {
|
|
2486
|
+
console.log(
|
|
2487
|
+
`[markFailed:${this.instanceId}] First failure for ${baseUrl} - not adding to cooldown yet`
|
|
2488
|
+
);
|
|
2489
|
+
} else {
|
|
2490
|
+
console.log(
|
|
2491
|
+
`[markFailed:${this.instanceId}] Failure outside cooldown window for ${baseUrl} (timeSinceLastFailure: ${now - lastFailure}ms)`
|
|
2370
2492
|
);
|
|
2371
2493
|
}
|
|
2372
2494
|
}
|
|
@@ -2378,18 +2500,27 @@ var ProviderManager = class _ProviderManager {
|
|
|
2378
2500
|
this.providersOnCoolDown = this.providersOnCoolDown.filter(
|
|
2379
2501
|
([url]) => url !== baseUrl
|
|
2380
2502
|
);
|
|
2503
|
+
if (this.store) {
|
|
2504
|
+
this.store.getState().removeProviderFromCooldown(baseUrl);
|
|
2505
|
+
}
|
|
2381
2506
|
}
|
|
2382
2507
|
/**
|
|
2383
2508
|
* Clear all cooldown tracking
|
|
2384
2509
|
*/
|
|
2385
2510
|
clearCooldowns() {
|
|
2386
2511
|
this.providersOnCoolDown = [];
|
|
2512
|
+
if (this.store) {
|
|
2513
|
+
this.store.getState().clearProvidersOnCooldown();
|
|
2514
|
+
}
|
|
2387
2515
|
}
|
|
2388
2516
|
/**
|
|
2389
2517
|
* Clear all failure tracking (lastFailed timestamps)
|
|
2390
2518
|
*/
|
|
2391
2519
|
clearFailureHistory() {
|
|
2392
2520
|
this.lastFailed.clear();
|
|
2521
|
+
if (this.store) {
|
|
2522
|
+
this.store.getState().setLastFailed({});
|
|
2523
|
+
}
|
|
2393
2524
|
}
|
|
2394
2525
|
/**
|
|
2395
2526
|
* Check if a provider has failed
|
|
@@ -2958,7 +3089,10 @@ var SDK_STORAGE_KEYS = {
|
|
|
2958
3089
|
LAST_ROUTSTR21_MODELS_UPDATE: "lastRoutstr21ModelsUpdate",
|
|
2959
3090
|
CACHED_RECEIVE_TOKENS: "cached_receive_tokens",
|
|
2960
3091
|
USAGE_TRACKING: "usage_tracking",
|
|
2961
|
-
CLIENT_IDS: "client_ids"
|
|
3092
|
+
CLIENT_IDS: "client_ids",
|
|
3093
|
+
FAILED_PROVIDERS: "failed_providers",
|
|
3094
|
+
LAST_FAILED: "last_failed",
|
|
3095
|
+
PROVIDERS_ON_COOLDOWN: "providers_on_cooldown"
|
|
2962
3096
|
};
|
|
2963
3097
|
|
|
2964
3098
|
// storage/usageTracking/indexedDB.ts
|
|
@@ -3605,6 +3739,9 @@ var createEmptyStore = (driver) => createStore((set, get) => ({
|
|
|
3605
3739
|
lastRoutstr21ModelsUpdate: null,
|
|
3606
3740
|
cachedReceiveTokens: [],
|
|
3607
3741
|
clientIds: [],
|
|
3742
|
+
failedProviders: [],
|
|
3743
|
+
lastFailed: {},
|
|
3744
|
+
providersOnCooldown: [],
|
|
3608
3745
|
setModelsFromAllProviders: (value) => {
|
|
3609
3746
|
const normalized = {};
|
|
3610
3747
|
for (const [baseUrl, models] of Object.entries(value)) {
|
|
@@ -3744,6 +3881,71 @@ var createEmptyStore = (driver) => createStore((set, get) => ({
|
|
|
3744
3881
|
void driver.setItem(SDK_STORAGE_KEYS.CLIENT_IDS, normalized);
|
|
3745
3882
|
return { clientIds: normalized };
|
|
3746
3883
|
});
|
|
3884
|
+
},
|
|
3885
|
+
// ========== Failure Tracking ==========
|
|
3886
|
+
setFailedProviders: (value) => {
|
|
3887
|
+
const normalized = value.map((url) => normalizeBaseUrl5(url));
|
|
3888
|
+
void driver.setItem(SDK_STORAGE_KEYS.FAILED_PROVIDERS, normalized);
|
|
3889
|
+
set({ failedProviders: normalized });
|
|
3890
|
+
},
|
|
3891
|
+
addFailedProvider: (baseUrl) => {
|
|
3892
|
+
const normalized = normalizeBaseUrl5(baseUrl);
|
|
3893
|
+
const current = get().failedProviders;
|
|
3894
|
+
if (!current.includes(normalized)) {
|
|
3895
|
+
const updated = [...current, normalized];
|
|
3896
|
+
void driver.setItem(SDK_STORAGE_KEYS.FAILED_PROVIDERS, updated);
|
|
3897
|
+
set({ failedProviders: updated });
|
|
3898
|
+
}
|
|
3899
|
+
},
|
|
3900
|
+
removeFailedProvider: (baseUrl) => {
|
|
3901
|
+
const normalized = normalizeBaseUrl5(baseUrl);
|
|
3902
|
+
const current = get().failedProviders;
|
|
3903
|
+
const updated = current.filter((url) => url !== normalized);
|
|
3904
|
+
void driver.setItem(SDK_STORAGE_KEYS.FAILED_PROVIDERS, updated);
|
|
3905
|
+
set({ failedProviders: updated });
|
|
3906
|
+
},
|
|
3907
|
+
setLastFailed: (value) => {
|
|
3908
|
+
const normalized = {};
|
|
3909
|
+
for (const [baseUrl, timestamp] of Object.entries(value)) {
|
|
3910
|
+
normalized[normalizeBaseUrl5(baseUrl)] = timestamp;
|
|
3911
|
+
}
|
|
3912
|
+
void driver.setItem(SDK_STORAGE_KEYS.LAST_FAILED, normalized);
|
|
3913
|
+
set({ lastFailed: normalized });
|
|
3914
|
+
},
|
|
3915
|
+
setLastFailedTimestamp: (baseUrl, timestamp) => {
|
|
3916
|
+
const normalized = normalizeBaseUrl5(baseUrl);
|
|
3917
|
+
const current = get().lastFailed;
|
|
3918
|
+
const updated = { ...current, [normalized]: timestamp };
|
|
3919
|
+
void driver.setItem(SDK_STORAGE_KEYS.LAST_FAILED, updated);
|
|
3920
|
+
set({ lastFailed: updated });
|
|
3921
|
+
},
|
|
3922
|
+
setProvidersOnCooldown: (value) => {
|
|
3923
|
+
const normalized = value.map((entry) => ({
|
|
3924
|
+
baseUrl: normalizeBaseUrl5(entry.baseUrl),
|
|
3925
|
+
timestamp: entry.timestamp
|
|
3926
|
+
}));
|
|
3927
|
+
void driver.setItem(SDK_STORAGE_KEYS.PROVIDERS_ON_COOLDOWN, normalized);
|
|
3928
|
+
set({ providersOnCooldown: normalized });
|
|
3929
|
+
},
|
|
3930
|
+
addProviderOnCooldown: (baseUrl, timestamp) => {
|
|
3931
|
+
const normalized = normalizeBaseUrl5(baseUrl);
|
|
3932
|
+
const current = get().providersOnCooldown;
|
|
3933
|
+
if (!current.some((entry) => entry.baseUrl === normalized)) {
|
|
3934
|
+
const updated = [...current, { baseUrl: normalized, timestamp }];
|
|
3935
|
+
void driver.setItem(SDK_STORAGE_KEYS.PROVIDERS_ON_COOLDOWN, updated);
|
|
3936
|
+
set({ providersOnCooldown: updated });
|
|
3937
|
+
}
|
|
3938
|
+
},
|
|
3939
|
+
removeProviderFromCooldown: (baseUrl) => {
|
|
3940
|
+
const normalized = normalizeBaseUrl5(baseUrl);
|
|
3941
|
+
const current = get().providersOnCooldown;
|
|
3942
|
+
const updated = current.filter((entry) => entry.baseUrl !== normalized);
|
|
3943
|
+
void driver.setItem(SDK_STORAGE_KEYS.PROVIDERS_ON_COOLDOWN, updated);
|
|
3944
|
+
set({ providersOnCooldown: updated });
|
|
3945
|
+
},
|
|
3946
|
+
clearProvidersOnCooldown: () => {
|
|
3947
|
+
void driver.setItem(SDK_STORAGE_KEYS.PROVIDERS_ON_COOLDOWN, []);
|
|
3948
|
+
set({ providersOnCooldown: [] });
|
|
3747
3949
|
}
|
|
3748
3950
|
}));
|
|
3749
3951
|
var hydrateStoreFromDriver = async (store, driver) => {
|
|
@@ -3762,7 +3964,10 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
3762
3964
|
rawRoutstr21Models,
|
|
3763
3965
|
rawLastRoutstr21ModelsUpdate,
|
|
3764
3966
|
rawCachedReceiveTokens,
|
|
3765
|
-
rawClientIds
|
|
3967
|
+
rawClientIds,
|
|
3968
|
+
rawFailedProviders,
|
|
3969
|
+
rawLastFailed,
|
|
3970
|
+
rawProvidersOnCooldown
|
|
3766
3971
|
] = await Promise.all([
|
|
3767
3972
|
driver.getItem(
|
|
3768
3973
|
SDK_STORAGE_KEYS.MODELS_FROM_ALL_PROVIDERS,
|
|
@@ -3793,7 +3998,10 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
3793
3998
|
null
|
|
3794
3999
|
),
|
|
3795
4000
|
driver.getItem(SDK_STORAGE_KEYS.CACHED_RECEIVE_TOKENS, []),
|
|
3796
|
-
driver.getItem(SDK_STORAGE_KEYS.CLIENT_IDS, [])
|
|
4001
|
+
driver.getItem(SDK_STORAGE_KEYS.CLIENT_IDS, []),
|
|
4002
|
+
driver.getItem(SDK_STORAGE_KEYS.FAILED_PROVIDERS, []),
|
|
4003
|
+
driver.getItem(SDK_STORAGE_KEYS.LAST_FAILED, {}),
|
|
4004
|
+
driver.getItem(SDK_STORAGE_KEYS.PROVIDERS_ON_COOLDOWN, [])
|
|
3797
4005
|
]);
|
|
3798
4006
|
const modelsFromAllProviders = Object.fromEntries(
|
|
3799
4007
|
Object.entries(rawModels).map(([baseUrl, models]) => [
|
|
@@ -3861,6 +4069,17 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
3861
4069
|
createdAt: entry.createdAt ?? Date.now(),
|
|
3862
4070
|
lastUsed: entry.lastUsed ?? null
|
|
3863
4071
|
}));
|
|
4072
|
+
const failedProviders = rawFailedProviders.map((url) => normalizeBaseUrl5(url));
|
|
4073
|
+
const lastFailed = Object.fromEntries(
|
|
4074
|
+
Object.entries(rawLastFailed).map(([baseUrl, timestamp]) => [
|
|
4075
|
+
normalizeBaseUrl5(baseUrl),
|
|
4076
|
+
timestamp
|
|
4077
|
+
])
|
|
4078
|
+
);
|
|
4079
|
+
const providersOnCooldown = rawProvidersOnCooldown.map((entry) => ({
|
|
4080
|
+
baseUrl: normalizeBaseUrl5(entry.baseUrl),
|
|
4081
|
+
timestamp: entry.timestamp
|
|
4082
|
+
}));
|
|
3864
4083
|
store.setState({
|
|
3865
4084
|
modelsFromAllProviders,
|
|
3866
4085
|
lastUsedModel,
|
|
@@ -3876,7 +4095,10 @@ var hydrateStoreFromDriver = async (store, driver) => {
|
|
|
3876
4095
|
routstr21Models,
|
|
3877
4096
|
lastRoutstr21ModelsUpdate,
|
|
3878
4097
|
cachedReceiveTokens,
|
|
3879
|
-
clientIds
|
|
4098
|
+
clientIds,
|
|
4099
|
+
failedProviders,
|
|
4100
|
+
lastFailed,
|
|
4101
|
+
providersOnCooldown
|
|
3880
4102
|
});
|
|
3881
4103
|
};
|
|
3882
4104
|
var createSdkStore = ({
|
|
@@ -4292,11 +4514,11 @@ var RoutstrClient = class {
|
|
|
4292
4514
|
this.balanceManager
|
|
4293
4515
|
);
|
|
4294
4516
|
this.streamProcessor = new StreamProcessor();
|
|
4295
|
-
this.providerManager = new ProviderManager(providerRegistry);
|
|
4296
4517
|
this.alertLevel = alertLevel;
|
|
4297
4518
|
this.mode = mode;
|
|
4298
4519
|
this.usageTrackingDriver = options.usageTrackingDriver;
|
|
4299
4520
|
this.sdkStore = options.sdkStore;
|
|
4521
|
+
this.providerManager = options.providerManager ?? new ProviderManager(providerRegistry, this.sdkStore);
|
|
4300
4522
|
}
|
|
4301
4523
|
cashuSpender;
|
|
4302
4524
|
balanceManager;
|
|
@@ -4826,6 +5048,10 @@ var RoutstrClient = class {
|
|
|
4826
5048
|
const currentBalance = currentBalanceInfo.unit === "msat" ? currentBalanceInfo.amount / 1e3 : currentBalanceInfo.amount;
|
|
4827
5049
|
const shortfall = Math.max(0, params.requiredSats - currentBalance);
|
|
4828
5050
|
topupAmount = shortfall > 0 ? shortfall : params.requiredSats;
|
|
5051
|
+
this._log(
|
|
5052
|
+
"DEBUG",
|
|
5053
|
+
`The shortfall is: ${shortfall}. requiredSats: ${params.requiredSats}. Current Balance: ${currentBalance} `
|
|
5054
|
+
);
|
|
4829
5055
|
} catch (e) {
|
|
4830
5056
|
this._log(
|
|
4831
5057
|
"WARN",
|
|
@@ -4955,6 +5181,20 @@ var RoutstrClient = class {
|
|
|
4955
5181
|
tryNextProvider = true;
|
|
4956
5182
|
}
|
|
4957
5183
|
}
|
|
5184
|
+
if (status === 401 && this.mode === "apikeys") {
|
|
5185
|
+
this._log(
|
|
5186
|
+
"DEBUG",
|
|
5187
|
+
`[RoutstrClient] _handleErrorResponse: Checking balance for ${baseUrl}, key preview=${token}`
|
|
5188
|
+
);
|
|
5189
|
+
const latestBalanceInfo = await this.balanceManager.getTokenBalance(
|
|
5190
|
+
token,
|
|
5191
|
+
baseUrl
|
|
5192
|
+
);
|
|
5193
|
+
if (latestBalanceInfo.isInvalidApiKey) {
|
|
5194
|
+
this.storageAdapter.removeApiKey(baseUrl);
|
|
5195
|
+
tryNextProvider = true;
|
|
5196
|
+
}
|
|
5197
|
+
}
|
|
4958
5198
|
if ((status === 401 || status === 403 || status === 413 || status === 400 || status === 500 || status === 502 || status === 503 || status === 504 || status === 521) && !tryNextProvider) {
|
|
4959
5199
|
this._log(
|
|
4960
5200
|
"DEBUG",
|
|
@@ -4965,13 +5205,13 @@ var RoutstrClient = class {
|
|
|
4965
5205
|
"DEBUG",
|
|
4966
5206
|
`[RoutstrClient] _handleErrorResponse: Attempting API key refund for ${baseUrl}, key preview=${token}`
|
|
4967
5207
|
);
|
|
4968
|
-
const
|
|
5208
|
+
const latestBalanceInfo = await this.balanceManager.getTokenBalance(
|
|
4969
5209
|
token,
|
|
4970
5210
|
baseUrl
|
|
4971
5211
|
);
|
|
4972
5212
|
this._log(
|
|
4973
5213
|
"DEBUG",
|
|
4974
|
-
`[RoutstrClient] _handleErrorResponse: Initial API key balance: ${
|
|
5214
|
+
`[RoutstrClient] _handleErrorResponse: Initial API key balance: ${latestBalanceInfo.amount}`
|
|
4975
5215
|
);
|
|
4976
5216
|
const refundResult = await this.balanceManager.refundApiKey({
|
|
4977
5217
|
mintUrl,
|
|
@@ -4983,7 +5223,7 @@ var RoutstrClient = class {
|
|
|
4983
5223
|
"DEBUG",
|
|
4984
5224
|
`[RoutstrClient] _handleErrorResponse: API key refund result: success=${refundResult.success}, message=${refundResult.message}`
|
|
4985
5225
|
);
|
|
4986
|
-
if (!refundResult.success &&
|
|
5226
|
+
if (!refundResult.success && latestBalanceInfo.amount > 0) {
|
|
4987
5227
|
throw new ProviderError(
|
|
4988
5228
|
baseUrl,
|
|
4989
5229
|
status,
|
|
@@ -5123,7 +5363,6 @@ var RoutstrClient = class {
|
|
|
5123
5363
|
try {
|
|
5124
5364
|
const xcashuResults = await this.cashuSpender.refundXcashuTokens(mintUrl);
|
|
5125
5365
|
this._log("DEBUG", "Refund xcashu tokens results:", xcashuResults);
|
|
5126
|
-
const results = await this.cashuSpender.refundProviders(mintUrl);
|
|
5127
5366
|
} catch (error) {
|
|
5128
5367
|
this._log("ERROR", "Failed to refund providers:", error);
|
|
5129
5368
|
}
|
|
@@ -5464,7 +5703,8 @@ async function resolveRouteRequestContext(options) {
|
|
|
5464
5703
|
debugLevel,
|
|
5465
5704
|
mode = "apikeys",
|
|
5466
5705
|
usageTrackingDriver,
|
|
5467
|
-
sdkStore
|
|
5706
|
+
sdkStore,
|
|
5707
|
+
providerManager: providedProviderManager
|
|
5468
5708
|
} = options;
|
|
5469
5709
|
let modelManager;
|
|
5470
5710
|
let providers;
|
|
@@ -5484,7 +5724,7 @@ async function resolveRouteRequestContext(options) {
|
|
|
5484
5724
|
}
|
|
5485
5725
|
await modelManager.fetchModels(providers, forceRefresh);
|
|
5486
5726
|
}
|
|
5487
|
-
const providerManager = new ProviderManager(providerRegistry);
|
|
5727
|
+
const providerManager = providedProviderManager ?? new ProviderManager(providerRegistry, sdkStore);
|
|
5488
5728
|
let baseUrl;
|
|
5489
5729
|
let selectedModel;
|
|
5490
5730
|
if (forcedProvider) {
|
|
@@ -5529,7 +5769,7 @@ async function resolveRouteRequestContext(options) {
|
|
|
5529
5769
|
providerRegistry,
|
|
5530
5770
|
"min",
|
|
5531
5771
|
mode,
|
|
5532
|
-
{ usageTrackingDriver, sdkStore }
|
|
5772
|
+
{ usageTrackingDriver, sdkStore, providerManager }
|
|
5533
5773
|
);
|
|
5534
5774
|
if (debugLevel) {
|
|
5535
5775
|
client.setDebugLevel(debugLevel);
|