@routstr/sdk 0.1.6 → 0.1.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/index.mjs CHANGED
@@ -1820,6 +1820,14 @@ var BalanceManager = class {
1820
1820
  console.log(response.status);
1821
1821
  const data = await response.json();
1822
1822
  console.log("FAILED ", data);
1823
+ const isInvalidApiKey = response.status === 401 && data?.code === "invalid_api_key" && data?.message?.includes("proofs already spent");
1824
+ return {
1825
+ amount: -1,
1826
+ reserved: data.reserved ?? 0,
1827
+ unit: "msat",
1828
+ apiKey: data.api_key,
1829
+ isInvalidApiKey
1830
+ };
1823
1831
  }
1824
1832
  } catch (error) {
1825
1833
  console.error("ERRORR IN RESTPONSE", error);
@@ -2768,7 +2776,8 @@ var RoutstrClient = class {
2768
2776
  response.status,
2769
2777
  requestId,
2770
2778
  this.mode === "xcashu" ? response.headers.get("x-cashu") ?? void 0 : void 0,
2771
- bodyText
2779
+ bodyText,
2780
+ params.retryCount ?? 0
2772
2781
  );
2773
2782
  }
2774
2783
  return response;
@@ -2777,8 +2786,12 @@ var RoutstrClient = class {
2777
2786
  return await this._handleErrorResponse(
2778
2787
  params,
2779
2788
  token,
2780
- -1
2789
+ -1,
2781
2790
  // just for Network Error to skip all statuses
2791
+ void 0,
2792
+ void 0,
2793
+ void 0,
2794
+ params.retryCount ?? 0
2782
2795
  );
2783
2796
  }
2784
2797
  throw error;
@@ -2787,7 +2800,8 @@ var RoutstrClient = class {
2787
2800
  /**
2788
2801
  * Handle error responses with failover
2789
2802
  */
2790
- async _handleErrorResponse(params, token, status, requestId, xCashuRefundToken, responseBody) {
2803
+ async _handleErrorResponse(params, token, status, requestId, xCashuRefundToken, responseBody, retryCount = 0) {
2804
+ const MAX_RETRIES_PER_PROVIDER = 2;
2791
2805
  const { path, method, body, selectedModel, baseUrl, mintUrl } = params;
2792
2806
  let tryNextProvider = false;
2793
2807
  this._log(
@@ -2893,12 +2907,26 @@ var RoutstrClient = class {
2893
2907
  `[RoutstrClient] _handleErrorResponse: Topup successful, will retry with new token`
2894
2908
  );
2895
2909
  }
2896
- if (!tryNextProvider)
2897
- return this._makeRequest({
2898
- ...params,
2899
- token: params.token,
2900
- headers: this._withAuthHeader(params.baseHeaders, params.token)
2901
- });
2910
+ if (!tryNextProvider) {
2911
+ if (retryCount < MAX_RETRIES_PER_PROVIDER) {
2912
+ this._log(
2913
+ "DEBUG",
2914
+ `[RoutstrClient] _handleErrorResponse: Retrying 402 (attempt ${retryCount + 1}/${MAX_RETRIES_PER_PROVIDER})`
2915
+ );
2916
+ return this._makeRequest({
2917
+ ...params,
2918
+ token: params.token,
2919
+ headers: this._withAuthHeader(params.baseHeaders, params.token),
2920
+ retryCount: retryCount + 1
2921
+ });
2922
+ } else {
2923
+ this._log(
2924
+ "DEBUG",
2925
+ `[RoutstrClient] _handleErrorResponse: 402 retry limit reached (${retryCount}/${MAX_RETRIES_PER_PROVIDER}), failing over to next provider`
2926
+ );
2927
+ tryNextProvider = true;
2928
+ }
2929
+ }
2902
2930
  }
2903
2931
  const isInsufficientBalance413 = status === 413 && responseBody?.includes("Insufficient balance");
2904
2932
  if (isInsufficientBalance413 && !tryNextProvider && this.mode === "apikeys") {
@@ -2908,19 +2936,28 @@ var RoutstrClient = class {
2908
2936
  params.token,
2909
2937
  baseUrl
2910
2938
  );
2911
- const latestTokenBalance = latestBalanceInfo.unit === "msat" ? latestBalanceInfo.amount / 1e3 : latestBalanceInfo.amount;
2912
- if (latestBalanceInfo.apiKey) {
2913
- const storedApiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
2914
- if (storedApiKeyEntry?.key !== latestBalanceInfo.apiKey) {
2915
- if (storedApiKeyEntry) {
2916
- this.storageAdapter.removeApiKey(baseUrl);
2939
+ if (latestBalanceInfo.isInvalidApiKey) {
2940
+ this._log(
2941
+ "DEBUG",
2942
+ `[RoutstrClient] _handleErrorResponse: Invalid API key (proofs already spent), removing for ${baseUrl}`
2943
+ );
2944
+ this.storageAdapter.removeApiKey(baseUrl);
2945
+ tryNextProvider = true;
2946
+ } else {
2947
+ const latestTokenBalance = latestBalanceInfo.unit === "msat" ? latestBalanceInfo.amount / 1e3 : latestBalanceInfo.amount;
2948
+ if (latestBalanceInfo.apiKey) {
2949
+ const storedApiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
2950
+ if (storedApiKeyEntry?.key !== latestBalanceInfo.apiKey) {
2951
+ if (storedApiKeyEntry) {
2952
+ this.storageAdapter.removeApiKey(baseUrl);
2953
+ }
2954
+ this.storageAdapter.setApiKey(baseUrl, latestBalanceInfo.apiKey);
2917
2955
  }
2918
- this.storageAdapter.setApiKey(baseUrl, latestBalanceInfo.apiKey);
2956
+ retryToken = latestBalanceInfo.apiKey;
2957
+ }
2958
+ if (latestTokenBalance >= 0) {
2959
+ this.storageAdapter.updateApiKeyBalance(baseUrl, latestTokenBalance);
2919
2960
  }
2920
- retryToken = latestBalanceInfo.apiKey;
2921
- }
2922
- if (latestTokenBalance >= 0) {
2923
- this.storageAdapter.updateApiKeyBalance(baseUrl, latestTokenBalance);
2924
2961
  }
2925
2962
  } catch (error) {
2926
2963
  this._log(
@@ -2929,11 +2966,24 @@ var RoutstrClient = class {
2929
2966
  error
2930
2967
  );
2931
2968
  }
2932
- return this._makeRequest({
2933
- ...params,
2934
- token: retryToken,
2935
- headers: this._withAuthHeader(params.baseHeaders, retryToken)
2936
- });
2969
+ if (retryCount < MAX_RETRIES_PER_PROVIDER) {
2970
+ this._log(
2971
+ "DEBUG",
2972
+ `[RoutstrClient] _handleErrorResponse: Retrying 413 (attempt ${retryCount + 1}/${MAX_RETRIES_PER_PROVIDER})`
2973
+ );
2974
+ return this._makeRequest({
2975
+ ...params,
2976
+ token: retryToken,
2977
+ headers: this._withAuthHeader(params.baseHeaders, retryToken),
2978
+ retryCount: retryCount + 1
2979
+ });
2980
+ } else {
2981
+ this._log(
2982
+ "DEBUG",
2983
+ `[RoutstrClient] _handleErrorResponse: 413 retry limit reached (${retryCount}/${MAX_RETRIES_PER_PROVIDER}), failing over to next provider`
2984
+ );
2985
+ tryNextProvider = true;
2986
+ }
2937
2987
  }
2938
2988
  if ((status === 401 || status === 403 || status === 413 || status === 400 || status === 500 || status === 502 || status === 503 || status === 504 || status === 521) && !tryNextProvider) {
2939
2989
  this._log(
@@ -3049,7 +3099,8 @@ var RoutstrClient = class {
3049
3099
  selectedModel: newModel,
3050
3100
  token: spendResult.token,
3051
3101
  requiredSats: newRequiredSats,
3052
- headers: this._withAuthHeader(params.baseHeaders, spendResult.token)
3102
+ headers: this._withAuthHeader(params.baseHeaders, spendResult.token),
3103
+ retryCount: 0
3053
3104
  });
3054
3105
  }
3055
3106
  throw new FailoverError(baseUrl, Array.from(this.providerManager));
@@ -3684,7 +3735,7 @@ var SDK_STORAGE_KEYS = {
3684
3735
 
3685
3736
  // storage/store.ts
3686
3737
  var normalizeBaseUrl = (baseUrl) => baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
3687
- var getTokenBalance = (token) => {
3738
+ var getCashuTokenBalance = (token) => {
3688
3739
  try {
3689
3740
  const decoded = getDecodedToken(token);
3690
3741
  const unitDivisor = decoded.unit === "msat" ? 1e3 : 1;
@@ -3777,7 +3828,7 @@ var createSdkStore = async ({
3777
3828
  const cachedTokens = rawCachedTokens.map((entry) => ({
3778
3829
  ...entry,
3779
3830
  baseUrl: normalizeBaseUrl(entry.baseUrl),
3780
- balance: typeof entry.balance === "number" ? entry.balance : getTokenBalance(entry.token),
3831
+ balance: typeof entry.balance === "number" ? entry.balance : getCashuTokenBalance(entry.token),
3781
3832
  lastUsed: entry.lastUsed ?? null
3782
3833
  }));
3783
3834
  const apiKeys = rawApiKeys.map((entry) => ({
@@ -3881,7 +3932,7 @@ var createSdkStore = async ({
3881
3932
  const normalized = updates.map((entry) => ({
3882
3933
  ...entry,
3883
3934
  baseUrl: normalizeBaseUrl(entry.baseUrl),
3884
- balance: typeof entry.balance === "number" ? entry.balance : getTokenBalance(entry.token),
3935
+ balance: typeof entry.balance === "number" ? entry.balance : getCashuTokenBalance(entry.token),
3885
3936
  lastUsed: entry.lastUsed ?? null
3886
3937
  }));
3887
3938
  void driver.setItem(SDK_STORAGE_KEYS.LOCAL_CASHU_TOKENS, normalized);
@@ -3980,7 +4031,7 @@ var createStorageAdapterFromStore = (store) => ({
3980
4031
  setToken: (baseUrl, token) => {
3981
4032
  const normalized = normalizeBaseUrl(baseUrl);
3982
4033
  const tokens = store.getState().cachedTokens;
3983
- const balance = getTokenBalance(token);
4034
+ const balance = getCashuTokenBalance(token);
3984
4035
  const existingIndex = tokens.findIndex(
3985
4036
  (entry) => entry.baseUrl === normalized
3986
4037
  );