@routstr/sdk 0.1.1 → 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.
package/dist/index.js CHANGED
@@ -151,6 +151,7 @@ var ModelManager = class _ModelManager {
151
151
  const filtered = this.filterBaseUrlsForTor(nostrProviders, torMode);
152
152
  this.adapter.setBaseUrlsList(filtered);
153
153
  this.adapter.setBaseUrlsLastUpdate(Date.now());
154
+ await this.fetchRoutstr21Models();
154
155
  return filtered;
155
156
  }
156
157
  } catch (e) {
@@ -282,6 +283,7 @@ var ModelManager = class _ModelManager {
282
283
  if (list.length > 0) {
283
284
  this.adapter.setBaseUrlsList(list);
284
285
  this.adapter.setBaseUrlsLastUpdate(Date.now());
286
+ await this.fetchRoutstr21Models();
285
287
  }
286
288
  return list;
287
289
  } catch (e) {
@@ -448,6 +450,57 @@ var ModelManager = class _ModelManager {
448
450
  }
449
451
  return url.endsWith("/") ? url : `${url}/`;
450
452
  }
453
+ /**
454
+ * Fetch routstr21 models from Nostr network (kind 38423)
455
+ * @returns Array of model IDs or empty array if not found
456
+ */
457
+ async fetchRoutstr21Models() {
458
+ const DEFAULT_RELAYS = [
459
+ "wss://relay.primal.net",
460
+ "wss://nos.lol",
461
+ "wss://relay.routstr.com"
462
+ ];
463
+ const pool = new applesauceRelay.RelayPool();
464
+ const localEventStore = new applesauceCore.EventStore();
465
+ const timeoutMs = 5e3;
466
+ await new Promise((resolve) => {
467
+ pool.req(DEFAULT_RELAYS, {
468
+ kinds: [38423],
469
+ "#d": ["routstr-21-models"],
470
+ limit: 1,
471
+ authors: ["4ad6fa2d16e2a9b576c863b4cf7404a70d4dc320c0c447d10ad6ff58993eacc8"]
472
+ }).pipe(
473
+ applesauceRelay.onlyEvents(),
474
+ rxjs.tap((event2) => {
475
+ localEventStore.add(event2);
476
+ })
477
+ ).subscribe({
478
+ complete: () => {
479
+ resolve();
480
+ }
481
+ });
482
+ setTimeout(() => {
483
+ resolve();
484
+ }, timeoutMs);
485
+ });
486
+ const timeline = localEventStore.getTimeline({ kinds: [38423] });
487
+ if (timeline.length === 0) {
488
+ return [];
489
+ }
490
+ const event = timeline[0];
491
+ try {
492
+ const content = JSON.parse(event.content);
493
+ const models = Array.isArray(content?.models) ? content.models : [];
494
+ this.adapter.setRoutstr21Models(models);
495
+ return models;
496
+ } catch {
497
+ console.warn(
498
+ "[Routstr21Models] Failed to parse Nostr event content:",
499
+ event.id
500
+ );
501
+ return [];
502
+ }
503
+ }
451
504
  };
452
505
 
453
506
  // discovery/MintDiscovery.ts
@@ -677,6 +730,26 @@ var CashuSpender = class {
677
730
  this.balanceManager = balanceManager;
678
731
  }
679
732
  _isBusy = false;
733
+ debugLevel = "WARN";
734
+ async receiveToken(token) {
735
+ const result = await this.walletAdapter.receiveToken(token);
736
+ if (!result.success && result.message?.includes("Failed to fetch mint")) {
737
+ const cachedTokens = this.storageAdapter.getCachedReceiveTokens();
738
+ const existingIndex = cachedTokens.findIndex((t) => t.token === token);
739
+ if (existingIndex === -1) {
740
+ this.storageAdapter.setCachedReceiveTokens([
741
+ ...cachedTokens,
742
+ {
743
+ token,
744
+ amount: result.amount,
745
+ unit: result.unit,
746
+ createdAt: Date.now()
747
+ }
748
+ ]);
749
+ }
750
+ }
751
+ return result;
752
+ }
680
753
  async _getBalanceState() {
681
754
  const mintBalances = await this.walletAdapter.getBalances();
682
755
  const units = this.walletAdapter.getMintUnits();
@@ -719,6 +792,32 @@ var CashuSpender = class {
719
792
  get isBusy() {
720
793
  return this._isBusy;
721
794
  }
795
+ getDebugLevel() {
796
+ return this.debugLevel;
797
+ }
798
+ setDebugLevel(level) {
799
+ this.debugLevel = level;
800
+ }
801
+ _log(level, ...args) {
802
+ const levelPriority = {
803
+ DEBUG: 0,
804
+ WARN: 1,
805
+ ERROR: 2
806
+ };
807
+ if (levelPriority[level] >= levelPriority[this.debugLevel]) {
808
+ switch (level) {
809
+ case "DEBUG":
810
+ console.log(...args);
811
+ break;
812
+ case "WARN":
813
+ console.warn(...args);
814
+ break;
815
+ case "ERROR":
816
+ console.error(...args);
817
+ break;
818
+ }
819
+ }
820
+ }
722
821
  /**
723
822
  * Spend Cashu tokens with automatic mint selection and retry logic
724
823
  * Throws errors on failure instead of returning failed SpendResult
@@ -785,12 +884,16 @@ var CashuSpender = class {
785
884
  excludeMints,
786
885
  retryCount
787
886
  } = options;
788
- console.log(
887
+ this._log(
888
+ "DEBUG",
789
889
  `[CashuSpender] _spendInternal: amount=${amount}, mintUrl=${mintUrl}, baseUrl=${baseUrl}, reuseToken=${reuseToken}`
790
890
  );
791
891
  let adjustedAmount = Math.ceil(amount);
792
892
  if (!adjustedAmount || isNaN(adjustedAmount)) {
793
- console.error(`[CashuSpender] _spendInternal: Invalid amount: ${amount}`);
893
+ this._log(
894
+ "ERROR",
895
+ `[CashuSpender] _spendInternal: Invalid amount: ${amount}`
896
+ );
794
897
  return {
795
898
  token: null,
796
899
  status: "failed",
@@ -799,7 +902,8 @@ var CashuSpender = class {
799
902
  };
800
903
  }
801
904
  if (reuseToken && baseUrl) {
802
- console.log(
905
+ this._log(
906
+ "DEBUG",
803
907
  `[CashuSpender] _spendInternal: Attempting to reuse token for ${baseUrl}`
804
908
  );
805
909
  const existingResult = await this._tryReuseToken(
@@ -808,12 +912,14 @@ var CashuSpender = class {
808
912
  mintUrl
809
913
  );
810
914
  if (existingResult) {
811
- console.log(
915
+ this._log(
916
+ "DEBUG",
812
917
  `[CashuSpender] _spendInternal: Successfully reused token, balance: ${existingResult.balance}`
813
918
  );
814
919
  return existingResult;
815
920
  }
816
- console.log(
921
+ this._log(
922
+ "DEBUG",
817
923
  `[CashuSpender] _spendInternal: Could not reuse token, will create new token`
818
924
  );
819
925
  }
@@ -831,12 +937,14 @@ var CashuSpender = class {
831
937
  (sum, item) => sum + item.amount,
832
938
  0
833
939
  );
834
- console.log(
940
+ this._log(
941
+ "DEBUG",
835
942
  `[CashuSpender] _spendInternal: totalBalance=${totalBalance}, totalPending=${totalPending}, adjustedAmount=${adjustedAmount}`
836
943
  );
837
944
  const totalAvailableBalance = totalBalance + totalPending;
838
945
  if (totalAvailableBalance < adjustedAmount) {
839
- console.error(
946
+ this._log(
947
+ "ERROR",
840
948
  `[CashuSpender] _spendInternal: Insufficient balance, have=${totalAvailableBalance}, need=${adjustedAmount}`
841
949
  );
842
950
  return this._createInsufficientBalanceError(
@@ -904,7 +1012,8 @@ var CashuSpender = class {
904
1012
  baseUrl,
905
1013
  status: "success"
906
1014
  });
907
- console.log(
1015
+ this._log(
1016
+ "DEBUG",
908
1017
  `[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`
909
1018
  );
910
1019
  return {
@@ -922,7 +1031,7 @@ var CashuSpender = class {
922
1031
  if (!storedToken) return null;
923
1032
  const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
924
1033
  const balanceForBaseUrl = pendingDistribution.find((b) => b.baseUrl === baseUrl)?.amount || 0;
925
- console.log("RESUINGDSR GSODGNSD", balanceForBaseUrl, amount);
1034
+ this._log("DEBUG", "RESUINGDSR GSODGNSD", balanceForBaseUrl, amount);
926
1035
  if (balanceForBaseUrl > amount) {
927
1036
  const units = this.walletAdapter.getMintUnits();
928
1037
  const unit = units[mintUrl] || "sat";
@@ -940,7 +1049,7 @@ var CashuSpender = class {
940
1049
  baseUrl,
941
1050
  amount: topUpAmount
942
1051
  });
943
- console.log("TOPUP ", topUpResult);
1052
+ this._log("DEBUG", "TOPUP ", topUpResult);
944
1053
  if (topUpResult.success && topUpResult.toppedUpAmount) {
945
1054
  const newBalance = balanceForBaseUrl + topUpResult.toppedUpAmount;
946
1055
  const units = this.walletAdapter.getMintUnits();
@@ -962,7 +1071,7 @@ var CashuSpender = class {
962
1071
  baseUrl,
963
1072
  storedToken
964
1073
  );
965
- console.log(providerBalance);
1074
+ this._log("DEBUG", providerBalance);
966
1075
  if (providerBalance <= 0) {
967
1076
  this.storageAdapter.removeToken(baseUrl);
968
1077
  }
@@ -981,7 +1090,7 @@ var CashuSpender = class {
981
1090
  const refundResults = await Promise.allSettled(
982
1091
  toRefund.map(async (pending) => {
983
1092
  const token = this.storageAdapter.getToken(pending.baseUrl);
984
- console.log(token, this.balanceManager);
1093
+ this._log("DEBUG", token, this.balanceManager);
985
1094
  if (!token || !this.balanceManager) {
986
1095
  return { baseUrl: pending.baseUrl, success: false };
987
1096
  }
@@ -997,7 +1106,7 @@ var CashuSpender = class {
997
1106
  baseUrl: pending.baseUrl,
998
1107
  token
999
1108
  });
1000
- console.log(result);
1109
+ this._log("DEBUG", result);
1001
1110
  if (result.success) {
1002
1111
  this.storageAdapter.removeToken(pending.baseUrl);
1003
1112
  }
@@ -1095,11 +1204,22 @@ var CashuSpender = class {
1095
1204
 
1096
1205
  // wallet/BalanceManager.ts
1097
1206
  var BalanceManager = class {
1098
- constructor(walletAdapter, storageAdapter, providerRegistry) {
1207
+ constructor(walletAdapter, storageAdapter, providerRegistry, cashuSpender) {
1099
1208
  this.walletAdapter = walletAdapter;
1100
1209
  this.storageAdapter = storageAdapter;
1101
1210
  this.providerRegistry = providerRegistry;
1211
+ if (cashuSpender) {
1212
+ this.cashuSpender = cashuSpender;
1213
+ } else {
1214
+ this.cashuSpender = new CashuSpender(
1215
+ walletAdapter,
1216
+ storageAdapter,
1217
+ providerRegistry,
1218
+ this
1219
+ );
1220
+ }
1102
1221
  }
1222
+ cashuSpender;
1103
1223
  /**
1104
1224
  * Unified refund - handles both NIP-60 and legacy wallet refunds
1105
1225
  */
@@ -1134,7 +1254,7 @@ var BalanceManager = class {
1134
1254
  this.storageAdapter.removeToken(baseUrl);
1135
1255
  return { success: true, message: "No balance to refund" };
1136
1256
  }
1137
- const receiveResult = await this.walletAdapter.receiveToken(
1257
+ const receiveResult = await this.cashuSpender.receiveToken(
1138
1258
  fetchResult.token
1139
1259
  );
1140
1260
  const totalAmountMsat = receiveResult.unit === "msat" ? receiveResult.amount : receiveResult.amount * 1e3;
@@ -1179,7 +1299,7 @@ var BalanceManager = class {
1179
1299
  if (fetchResult.error === "No balance to refund") {
1180
1300
  return { success: false, message: "No balance to refund" };
1181
1301
  }
1182
- const receiveResult = await this.walletAdapter.receiveToken(
1302
+ const receiveResult = await this.cashuSpender.receiveToken(
1183
1303
  fetchResult.token
1184
1304
  );
1185
1305
  const totalAmountMsat = receiveResult.unit === "msat" ? receiveResult.amount : receiveResult.amount * 1e3;
@@ -1620,7 +1740,7 @@ var BalanceManager = class {
1620
1740
  */
1621
1741
  async _recoverFailedTopUp(cashuToken) {
1622
1742
  try {
1623
- await this.walletAdapter.receiveToken(cashuToken);
1743
+ await this.cashuSpender.receiveToken(cashuToken);
1624
1744
  } catch (error) {
1625
1745
  console.error(
1626
1746
  "[BalanceManager._recoverFailedTopUp] Failed to recover token",
@@ -2347,12 +2467,39 @@ var RoutstrClient = class {
2347
2467
  providerManager;
2348
2468
  alertLevel;
2349
2469
  mode;
2470
+ debugLevel = "WARN";
2350
2471
  /**
2351
2472
  * Get the current client mode
2352
2473
  */
2353
2474
  getMode() {
2354
2475
  return this.mode;
2355
2476
  }
2477
+ getDebugLevel() {
2478
+ return this.debugLevel;
2479
+ }
2480
+ setDebugLevel(level) {
2481
+ this.debugLevel = level;
2482
+ }
2483
+ _log(level, ...args) {
2484
+ const levelPriority = {
2485
+ DEBUG: 0,
2486
+ WARN: 1,
2487
+ ERROR: 2
2488
+ };
2489
+ if (levelPriority[level] >= levelPriority[this.debugLevel]) {
2490
+ switch (level) {
2491
+ case "DEBUG":
2492
+ console.log(...args);
2493
+ break;
2494
+ case "WARN":
2495
+ console.warn(...args);
2496
+ break;
2497
+ case "ERROR":
2498
+ console.error(...args);
2499
+ break;
2500
+ }
2501
+ }
2502
+ }
2356
2503
  /**
2357
2504
  * Get the CashuSpender instance
2358
2505
  */
@@ -2416,7 +2563,7 @@ var RoutstrClient = class {
2416
2563
  amount: requiredSats,
2417
2564
  baseUrl
2418
2565
  });
2419
- console.log(token, baseUrl);
2566
+ this._log("DEBUG", token, baseUrl);
2420
2567
  let requestBody = body;
2421
2568
  if (body && typeof body === "object") {
2422
2569
  const bodyObj = body;
@@ -2440,8 +2587,9 @@ var RoutstrClient = class {
2440
2587
  });
2441
2588
  const tokenBalanceInSats = tokenBalanceUnit === "msat" ? tokenBalance / 1e3 : tokenBalance;
2442
2589
  const baseUrlUsed = response.baseUrl || baseUrl;
2590
+ const tokenUsed = response.token || token;
2443
2591
  await this._handlePostResponseBalanceUpdate({
2444
- token,
2592
+ token: tokenUsed,
2445
2593
  baseUrl: baseUrlUsed,
2446
2594
  initialTokenBalance: tokenBalanceInSats,
2447
2595
  response
@@ -2577,14 +2725,15 @@ var RoutstrClient = class {
2577
2725
  const { path, method, body, baseUrl, token, headers } = params;
2578
2726
  try {
2579
2727
  const url = `${baseUrl.replace(/\/$/, "")}${path}`;
2580
- if (this.mode === "xcashu") console.log("HEADERS,", headers);
2728
+ if (this.mode === "xcashu") this._log("DEBUG", "HEADERS,", headers);
2581
2729
  const response = await fetch(url, {
2582
2730
  method,
2583
2731
  headers,
2584
2732
  body: body === void 0 || method === "GET" ? void 0 : JSON.stringify(body)
2585
2733
  });
2586
- if (this.mode === "xcashu") console.log("response,", response);
2734
+ if (this.mode === "xcashu") this._log("DEBUG", "response,", response);
2587
2735
  response.baseUrl = baseUrl;
2736
+ response.token = token;
2588
2737
  if (!response.ok) {
2589
2738
  const requestId = response.headers.get("x-routstr-request-id") || void 0;
2590
2739
  return await this._handleErrorResponse(
@@ -2614,38 +2763,44 @@ var RoutstrClient = class {
2614
2763
  async _handleErrorResponse(params, token, status, requestId, xCashuRefundToken) {
2615
2764
  const { path, method, body, selectedModel, baseUrl, mintUrl } = params;
2616
2765
  let tryNextProvider = false;
2617
- console.log(
2766
+ this._log(
2767
+ "DEBUG",
2618
2768
  `[RoutstrClient] _handleErrorResponse: status=${status}, baseUrl=${baseUrl}, mode=${this.mode}, token preview=${token}, requestId=${requestId}`
2619
2769
  );
2620
- console.log(
2770
+ this._log(
2771
+ "DEBUG",
2621
2772
  `[RoutstrClient] _handleErrorResponse: Attempting to receive/restore token for ${baseUrl}`
2622
2773
  );
2623
2774
  if (params.token.startsWith("cashu")) {
2624
- const tryReceiveTokenResult = await this.walletAdapter.receiveToken(
2775
+ const tryReceiveTokenResult = await this.cashuSpender.receiveToken(
2625
2776
  params.token
2626
2777
  );
2627
2778
  if (tryReceiveTokenResult.success) {
2628
- console.log(
2779
+ this._log(
2780
+ "DEBUG",
2629
2781
  `[RoutstrClient] _handleErrorResponse: Token restored successfully, amount=${tryReceiveTokenResult.amount}`
2630
2782
  );
2631
2783
  tryNextProvider = true;
2632
2784
  if (this.mode === "lazyrefund")
2633
2785
  this.storageAdapter.removeToken(baseUrl);
2634
2786
  } else {
2635
- console.log(
2636
- `[RoutstrClient] _handleErrorResponse: Token restore failed or not needed`
2787
+ this._log(
2788
+ "DEBUG",
2789
+ `[RoutstrClient] _handleErrorResponse: Failed to receive token. `
2637
2790
  );
2638
2791
  }
2639
2792
  }
2640
2793
  if (this.mode === "xcashu") {
2641
2794
  if (xCashuRefundToken) {
2642
- console.log(
2795
+ this._log(
2796
+ "DEBUG",
2643
2797
  `[RoutstrClient] _handleErrorResponse: Attempting to receive xcashu refund token, preview=${xCashuRefundToken.substring(0, 20)}...`
2644
2798
  );
2645
2799
  try {
2646
- const receiveResult = await this.walletAdapter.receiveToken(xCashuRefundToken);
2800
+ const receiveResult = await this.cashuSpender.receiveToken(xCashuRefundToken);
2647
2801
  if (receiveResult.success) {
2648
- console.log(
2802
+ this._log(
2803
+ "DEBUG",
2649
2804
  `[RoutstrClient] _handleErrorResponse: xcashu refund received, amount=${receiveResult.amount}`
2650
2805
  );
2651
2806
  tryNextProvider = true;
@@ -2657,7 +2812,7 @@ var RoutstrClient = class {
2657
2812
  requestId
2658
2813
  );
2659
2814
  } catch (error) {
2660
- console.error("[xcashu] Failed to receive refund token:", error);
2815
+ this._log("ERROR", "[xcashu] Failed to receive refund token:", error);
2661
2816
  throw new ProviderError(
2662
2817
  baseUrl,
2663
2818
  status,
@@ -2682,7 +2837,8 @@ var RoutstrClient = class {
2682
2837
  amount: params.requiredSats * TOPUP_MARGIN,
2683
2838
  token: params.token
2684
2839
  });
2685
- console.log(
2840
+ this._log(
2841
+ "DEBUG",
2686
2842
  `[RoutstrClient] _handleErrorResponse: Topup result for ${baseUrl}: success=${topupResult.success}, message=${topupResult.message}`
2687
2843
  );
2688
2844
  if (!topupResult.success) {
@@ -2692,18 +2848,21 @@ var RoutstrClient = class {
2692
2848
  const haveMatch = message.match(/have (\d+)/);
2693
2849
  const required = needMatch ? parseInt(needMatch[1], 10) : params.requiredSats;
2694
2850
  const available = haveMatch ? parseInt(haveMatch[1], 10) : 0;
2695
- console.log(
2851
+ this._log(
2852
+ "DEBUG",
2696
2853
  `[RoutstrClient] _handleErrorResponse: Insufficient balance, need=${required}, have=${available}`
2697
2854
  );
2698
2855
  throw new InsufficientBalanceError(required, available);
2699
2856
  } else {
2700
- console.log(
2857
+ this._log(
2858
+ "DEBUG",
2701
2859
  `[RoutstrClient] _handleErrorResponse: Topup failed with non-insufficient-balance error, will try next provider`
2702
2860
  );
2703
2861
  tryNextProvider = true;
2704
2862
  }
2705
2863
  } else {
2706
- console.log(
2864
+ this._log(
2865
+ "DEBUG",
2707
2866
  `[RoutstrClient] _handleErrorResponse: Topup successful, will retry with new token`
2708
2867
  );
2709
2868
  }
@@ -2714,8 +2873,9 @@ var RoutstrClient = class {
2714
2873
  headers: this._withAuthHeader(params.baseHeaders, params.token)
2715
2874
  });
2716
2875
  }
2717
- if ((status === 401 || status === 403 || status === 413 || status === 400 || status === 500 || status === 502 || status === 503 || status === 521) && !tryNextProvider) {
2718
- console.log(
2876
+ if ((status === 401 || status === 403 || status === 413 || status === 400 || status === 500 || status === 502 || status === 503 || status === 504 || status === 521) && !tryNextProvider) {
2877
+ this._log(
2878
+ "DEBUG",
2719
2879
  `[RoutstrClient] _handleErrorResponse: Status ${status} (auth/server error), attempting refund for ${baseUrl}, mode=${this.mode}`
2720
2880
  );
2721
2881
  if (this.mode === "lazyrefund") {
@@ -2725,7 +2885,8 @@ var RoutstrClient = class {
2725
2885
  baseUrl,
2726
2886
  token: params.token
2727
2887
  });
2728
- console.log(
2888
+ this._log(
2889
+ "DEBUG",
2729
2890
  `[RoutstrClient] _handleErrorResponse: Lazyrefund result: success=${refundResult.success}`
2730
2891
  );
2731
2892
  if (refundResult.success) this.storageAdapter.removeToken(baseUrl);
@@ -2745,14 +2906,16 @@ var RoutstrClient = class {
2745
2906
  );
2746
2907
  }
2747
2908
  } else if (this.mode === "apikeys") {
2748
- console.log(
2909
+ this._log(
2910
+ "DEBUG",
2749
2911
  `[RoutstrClient] _handleErrorResponse: Attempting API key refund for ${baseUrl}, key preview=${token}`
2750
2912
  );
2751
2913
  const initialBalance = await this.balanceManager.getTokenBalance(
2752
2914
  token,
2753
2915
  baseUrl
2754
2916
  );
2755
- console.log(
2917
+ this._log(
2918
+ "DEBUG",
2756
2919
  `[RoutstrClient] _handleErrorResponse: Initial API key balance: ${initialBalance.amount}`
2757
2920
  );
2758
2921
  const refundResult = await this.balanceManager.refundApiKey({
@@ -2760,7 +2923,8 @@ var RoutstrClient = class {
2760
2923
  baseUrl,
2761
2924
  apiKey: token
2762
2925
  });
2763
- console.log(
2926
+ this._log(
2927
+ "DEBUG",
2764
2928
  `[RoutstrClient] _handleErrorResponse: API key refund result: success=${refundResult.success}, message=${refundResult.message}`
2765
2929
  );
2766
2930
  if (!refundResult.success && initialBalance.amount > 0) {
@@ -2775,7 +2939,8 @@ var RoutstrClient = class {
2775
2939
  }
2776
2940
  }
2777
2941
  this.providerManager.markFailed(baseUrl);
2778
- console.log(
2942
+ this._log(
2943
+ "DEBUG",
2779
2944
  `[RoutstrClient] _handleErrorResponse: Marked provider ${baseUrl} as failed`
2780
2945
  );
2781
2946
  if (!selectedModel) {
@@ -2790,7 +2955,8 @@ var RoutstrClient = class {
2790
2955
  baseUrl
2791
2956
  );
2792
2957
  if (nextProvider) {
2793
- console.log(
2958
+ this._log(
2959
+ "DEBUG",
2794
2960
  `[RoutstrClient] _handleErrorResponse: Failing over to next provider: ${nextProvider}, model: ${selectedModel.id}`
2795
2961
  );
2796
2962
  const newModel = await this.providerManager.getModelForProvider(
@@ -2805,7 +2971,8 @@ var RoutstrClient = class {
2805
2971
  messagesForPricing,
2806
2972
  params.maxTokens
2807
2973
  );
2808
- console.log(
2974
+ this._log(
2975
+ "DEBUG",
2809
2976
  `[RoutstrClient] _handleErrorResponse: Creating new token for failover provider ${nextProvider}, required sats: ${newRequiredSats}`
2810
2977
  );
2811
2978
  const spendResult = await this._spendToken({
@@ -2837,10 +3004,10 @@ var RoutstrClient = class {
2837
3004
  const refundToken = response.headers.get("x-cashu") ?? void 0;
2838
3005
  if (refundToken) {
2839
3006
  try {
2840
- const receiveResult = await this.walletAdapter.receiveToken(refundToken);
3007
+ const receiveResult = await this.cashuSpender.receiveToken(refundToken);
2841
3008
  satsSpent = initialTokenBalance - receiveResult.amount * (receiveResult.unit == "sat" ? 1 : 1e3);
2842
3009
  } catch (error) {
2843
- console.error("[xcashu] Failed to receive refund token:", error);
3010
+ this._log("ERROR", "[xcashu] Failed to receive refund token:", error);
2844
3011
  }
2845
3012
  }
2846
3013
  } else if (this.mode === "lazyrefund") {
@@ -2857,7 +3024,8 @@ var RoutstrClient = class {
2857
3024
  token,
2858
3025
  baseUrl
2859
3026
  );
2860
- console.log(
3027
+ this._log(
3028
+ "DEBUG",
2861
3029
  "LATEST Balance",
2862
3030
  latestBalanceInfo.amount,
2863
3031
  latestBalanceInfo.reserved,
@@ -2869,7 +3037,7 @@ var RoutstrClient = class {
2869
3037
  this.storageAdapter.updateApiKeyBalance(baseUrl, latestTokenBalance);
2870
3038
  satsSpent = initialTokenBalance - latestTokenBalance;
2871
3039
  } catch (e) {
2872
- console.warn("Could not get updated API key balance:", e);
3040
+ this._log("WARN", "Could not get updated API key balance:", e);
2873
3041
  satsSpent = fallbackSatsSpent ?? initialTokenBalance;
2874
3042
  }
2875
3043
  }
@@ -2980,11 +3148,12 @@ var RoutstrClient = class {
2980
3148
  * Handle errors and notify callbacks
2981
3149
  */
2982
3150
  _handleError(error, callbacks) {
2983
- console.error("[RoutstrClient] _handleError: Error occurred", error);
3151
+ this._log("ERROR", "[RoutstrClient] _handleError: Error occurred", error);
2984
3152
  if (error instanceof Error) {
2985
3153
  const isStreamError = error.message.includes("Error in input stream") || error.message.includes("Load failed");
2986
3154
  const modifiedErrorMsg = isStreamError ? "AI stream was cut off, turn on Keep Active or please try again" : error.message;
2987
- console.error(
3155
+ this._log(
3156
+ "ERROR",
2988
3157
  `[RoutstrClient] _handleError: Error type=${error.constructor.name}, message=${modifiedErrorMsg}, isStreamError=${isStreamError}`
2989
3158
  );
2990
3159
  callbacks.onMessageAppend({
@@ -3013,13 +3182,15 @@ var RoutstrClient = class {
3013
3182
  */
3014
3183
  async _spendToken(params) {
3015
3184
  const { mintUrl, amount, baseUrl } = params;
3016
- console.log(
3185
+ this._log(
3186
+ "DEBUG",
3017
3187
  `[RoutstrClient] _spendToken: mode=${this.mode}, amount=${amount}, baseUrl=${baseUrl}, mintUrl=${mintUrl}`
3018
3188
  );
3019
3189
  if (this.mode === "apikeys") {
3020
3190
  let parentApiKey = this.storageAdapter.getApiKey(baseUrl);
3021
3191
  if (!parentApiKey) {
3022
- console.log(
3192
+ this._log(
3193
+ "DEBUG",
3023
3194
  `[RoutstrClient] _spendToken: No existing API key for ${baseUrl}, creating new one via Cashu`
3024
3195
  );
3025
3196
  const spendResult2 = await this.cashuSpender.spend({
@@ -3029,7 +3200,8 @@ var RoutstrClient = class {
3029
3200
  reuseToken: false
3030
3201
  });
3031
3202
  if (!spendResult2.token) {
3032
- console.error(
3203
+ this._log(
3204
+ "ERROR",
3033
3205
  `[RoutstrClient] _spendToken: Failed to create Cashu token for API key creation, error:`,
3034
3206
  spendResult2.error
3035
3207
  );
@@ -3037,30 +3209,35 @@ var RoutstrClient = class {
3037
3209
  `[RoutstrClient] _spendToken: Failed to create Cashu token for API key creation, error: ${spendResult2.error}`
3038
3210
  );
3039
3211
  } else {
3040
- console.log(
3212
+ this._log(
3213
+ "DEBUG",
3041
3214
  `[RoutstrClient] _spendToken: Cashu token created, token preview: ${spendResult2.token}`
3042
3215
  );
3043
3216
  }
3044
- console.log(
3217
+ this._log(
3218
+ "DEBUG",
3045
3219
  `[RoutstrClient] _spendToken: Created API key for ${baseUrl}, key preview: ${spendResult2.token}, balance: ${spendResult2.balance}`
3046
3220
  );
3047
3221
  try {
3048
3222
  this.storageAdapter.setApiKey(baseUrl, spendResult2.token);
3049
3223
  } catch (error) {
3050
3224
  if (error instanceof Error && error.message.includes("ApiKey already exists")) {
3051
- const tryReceiveTokenResult = await this.walletAdapter.receiveToken(
3225
+ const tryReceiveTokenResult = await this.cashuSpender.receiveToken(
3052
3226
  spendResult2.token
3053
3227
  );
3054
3228
  if (tryReceiveTokenResult.success) {
3055
- console.log(
3229
+ this._log(
3230
+ "DEBUG",
3056
3231
  `[RoutstrClient] _handleErrorResponse: Token restored successfully, amount=${tryReceiveTokenResult.amount}`
3057
3232
  );
3058
3233
  } else {
3059
- console.log(
3234
+ this._log(
3235
+ "DEBUG",
3060
3236
  `[RoutstrClient] _handleErrorResponse: Token restore failed or not needed`
3061
3237
  );
3062
3238
  }
3063
- console.log(
3239
+ this._log(
3240
+ "DEBUG",
3064
3241
  `[RoutstrClient] _spendToken: API key already exists for ${baseUrl}, using existing key`
3065
3242
  );
3066
3243
  } else {
@@ -3069,7 +3246,8 @@ var RoutstrClient = class {
3069
3246
  }
3070
3247
  parentApiKey = this.storageAdapter.getApiKey(baseUrl);
3071
3248
  } else {
3072
- console.log(
3249
+ this._log(
3250
+ "DEBUG",
3073
3251
  `[RoutstrClient] _spendToken: Using existing API key for ${baseUrl}, key preview: ${parentApiKey.key}`
3074
3252
  );
3075
3253
  }
@@ -3091,10 +3269,11 @@ var RoutstrClient = class {
3091
3269
  tokenBalance = balanceInfo.amount;
3092
3270
  tokenBalanceUnit = balanceInfo.unit;
3093
3271
  } catch (e) {
3094
- console.warn("Could not get initial API key balance:", e);
3272
+ this._log("WARN", "Could not get initial API key balance:", e);
3095
3273
  }
3096
3274
  }
3097
- console.log(
3275
+ this._log(
3276
+ "DEBUG",
3098
3277
  `[RoutstrClient] _spendToken: Returning token with balance=${tokenBalance} ${tokenBalanceUnit}`
3099
3278
  );
3100
3279
  return {
@@ -3103,7 +3282,8 @@ var RoutstrClient = class {
3103
3282
  tokenBalanceUnit
3104
3283
  };
3105
3284
  }
3106
- console.log(
3285
+ this._log(
3286
+ "DEBUG",
3107
3287
  `[RoutstrClient] _spendToken: Calling CashuSpender.spend for amount=${amount}, mintUrl=${mintUrl}, mode=${this.mode}`
3108
3288
  );
3109
3289
  const spendResult = await this.cashuSpender.spend({
@@ -3113,12 +3293,14 @@ var RoutstrClient = class {
3113
3293
  reuseToken: this.mode === "lazyrefund"
3114
3294
  });
3115
3295
  if (!spendResult.token) {
3116
- console.error(
3296
+ this._log(
3297
+ "ERROR",
3117
3298
  `[RoutstrClient] _spendToken: CashuSpender.spend failed, error:`,
3118
3299
  spendResult.error
3119
3300
  );
3120
3301
  } else {
3121
- console.log(
3302
+ this._log(
3303
+ "DEBUG",
3122
3304
  `[RoutstrClient] _spendToken: Cashu token created, token preview: ${spendResult.token}, balance: ${spendResult.balance} ${spendResult.unit ?? "sat"}`
3123
3305
  );
3124
3306
  }
@@ -3430,7 +3612,9 @@ var SDK_STORAGE_KEYS = {
3430
3612
  LAST_BASE_URLS_UPDATE: "lastBaseUrlsUpdate",
3431
3613
  LOCAL_CASHU_TOKENS: "local_cashu_tokens",
3432
3614
  API_KEYS: "api_keys",
3433
- CHILD_KEYS: "child_keys"
3615
+ CHILD_KEYS: "child_keys",
3616
+ ROUTSTR21_MODELS: "routstr21Models",
3617
+ CACHED_RECEIVE_TOKENS: "cached_receive_tokens"
3434
3618
  };
3435
3619
 
3436
3620
  // storage/store.ts
@@ -3462,7 +3646,9 @@ var createSdkStore = async ({
3462
3646
  rawLastModelsUpdate,
3463
3647
  rawCachedTokens,
3464
3648
  rawApiKeys,
3465
- rawChildKeys
3649
+ rawChildKeys,
3650
+ rawRoutstr21Models,
3651
+ rawCachedReceiveTokens
3466
3652
  ] = await Promise.all([
3467
3653
  driver.getItem(
3468
3654
  SDK_STORAGE_KEYS.MODELS_FROM_ALL_PROVIDERS,
@@ -3486,7 +3672,9 @@ var createSdkStore = async ({
3486
3672
  ),
3487
3673
  driver.getItem(SDK_STORAGE_KEYS.LOCAL_CASHU_TOKENS, []),
3488
3674
  driver.getItem(SDK_STORAGE_KEYS.API_KEYS, []),
3489
- driver.getItem(SDK_STORAGE_KEYS.CHILD_KEYS, [])
3675
+ driver.getItem(SDK_STORAGE_KEYS.CHILD_KEYS, []),
3676
+ driver.getItem(SDK_STORAGE_KEYS.ROUTSTR21_MODELS, []),
3677
+ driver.getItem(SDK_STORAGE_KEYS.CACHED_RECEIVE_TOKENS, [])
3490
3678
  ]);
3491
3679
  const modelsFromAllProviders = Object.fromEntries(
3492
3680
  Object.entries(rawModels).map(([baseUrl, models]) => [
@@ -3536,6 +3724,13 @@ var createSdkStore = async ({
3536
3724
  validityDate: entry.validityDate,
3537
3725
  createdAt: entry.createdAt ?? Date.now()
3538
3726
  }));
3727
+ const routstr21Models = rawRoutstr21Models;
3728
+ const cachedReceiveTokens = rawCachedReceiveTokens.map((entry) => ({
3729
+ token: entry.token,
3730
+ amount: entry.amount,
3731
+ unit: entry.unit || "sat",
3732
+ createdAt: entry.createdAt ?? Date.now()
3733
+ }));
3539
3734
  return vanilla.createStore((set, get) => ({
3540
3735
  modelsFromAllProviders,
3541
3736
  lastUsedModel,
@@ -3548,6 +3743,8 @@ var createSdkStore = async ({
3548
3743
  cachedTokens,
3549
3744
  apiKeys,
3550
3745
  childKeys,
3746
+ routstr21Models,
3747
+ cachedReceiveTokens,
3551
3748
  setModelsFromAllProviders: (value) => {
3552
3749
  const normalized = {};
3553
3750
  for (const [baseUrl, models] of Object.entries(value)) {
@@ -3646,6 +3843,20 @@ var createSdkStore = async ({
3646
3843
  void driver.setItem(SDK_STORAGE_KEYS.CHILD_KEYS, normalized);
3647
3844
  return { childKeys: normalized };
3648
3845
  });
3846
+ },
3847
+ setRoutstr21Models: (value) => {
3848
+ void driver.setItem(SDK_STORAGE_KEYS.ROUTSTR21_MODELS, value);
3849
+ set({ routstr21Models: value });
3850
+ },
3851
+ setCachedReceiveTokens: (value) => {
3852
+ const normalized = value.map((entry) => ({
3853
+ token: entry.token,
3854
+ amount: entry.amount,
3855
+ unit: entry.unit || "sat",
3856
+ createdAt: entry.createdAt ?? Date.now()
3857
+ }));
3858
+ void driver.setItem(SDK_STORAGE_KEYS.CACHED_RECEIVE_TOKENS, normalized);
3859
+ set({ cachedReceiveTokens: normalized });
3649
3860
  }
3650
3861
  }));
3651
3862
  };
@@ -3673,7 +3884,9 @@ var createDiscoveryAdapterFromStore = (store) => ({
3673
3884
  getBaseUrlsList: () => store.getState().baseUrlsList,
3674
3885
  setBaseUrlsList: (urls) => store.getState().setBaseUrlsList(urls),
3675
3886
  getBaseUrlsLastUpdate: () => store.getState().lastBaseUrlsUpdate,
3676
- setBaseUrlsLastUpdate: (timestamp) => store.getState().setBaseUrlsLastUpdate(timestamp)
3887
+ setBaseUrlsLastUpdate: (timestamp) => store.getState().setBaseUrlsLastUpdate(timestamp),
3888
+ getRoutstr21Models: () => store.getState().routstr21Models,
3889
+ setRoutstr21Models: (models) => store.getState().setRoutstr21Models(models)
3677
3890
  });
3678
3891
  var createStorageAdapterFromStore = (store) => ({
3679
3892
  getToken: (baseUrl) => {
@@ -3867,6 +4080,12 @@ var createStorageAdapterFromStore = (store) => ({
3867
4080
  validityDate: entry.validityDate,
3868
4081
  createdAt: entry.createdAt
3869
4082
  }));
4083
+ },
4084
+ getCachedReceiveTokens: () => {
4085
+ return store.getState().cachedReceiveTokens;
4086
+ },
4087
+ setCachedReceiveTokens: (tokens) => {
4088
+ store.getState().setCachedReceiveTokens(tokens);
3870
4089
  }
3871
4090
  });
3872
4091
  var createProviderRegistryFromStore = (store) => ({