@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.
@@ -87,6 +87,15 @@ interface SdkStorageState {
87
87
  createdAt: number;
88
88
  lastUsed?: number | null;
89
89
  }>;
90
+ /** Set of failed provider URLs */
91
+ failedProviders: string[];
92
+ /** Map of provider URL -> timestamp of last failure */
93
+ lastFailed: Record<string, number>;
94
+ /** Providers currently on cooldown: [baseUrl, timestamp][] */
95
+ providersOnCooldown: Array<{
96
+ baseUrl: string;
97
+ timestamp: number;
98
+ }>;
90
99
  }
91
100
 
92
101
  interface SdkStoreOptions {
@@ -137,6 +146,18 @@ interface SdkStorageStore extends SdkStorageState {
137
146
  createdAt?: number;
138
147
  lastUsed?: number | null;
139
148
  }> | ((current: SdkStorageStore["clientIds"]) => SdkStorageStore["clientIds"])) => void;
149
+ setFailedProviders: (value: string[]) => void;
150
+ addFailedProvider: (baseUrl: string) => void;
151
+ removeFailedProvider: (baseUrl: string) => void;
152
+ setLastFailed: (value: Record<string, number>) => void;
153
+ setLastFailedTimestamp: (baseUrl: string, timestamp: number) => void;
154
+ setProvidersOnCooldown: (value: Array<{
155
+ baseUrl: string;
156
+ timestamp: number;
157
+ }>) => void;
158
+ addProviderOnCooldown: (baseUrl: string, timestamp: number) => void;
159
+ removeProviderFromCooldown: (baseUrl: string) => void;
160
+ clearProvidersOnCooldown: () => void;
140
161
  }
141
162
  /** Store type returned after async initialization */
142
163
  type SdkStore = StoreApi<SdkStorageStore>;
@@ -87,6 +87,15 @@ interface SdkStorageState {
87
87
  createdAt: number;
88
88
  lastUsed?: number | null;
89
89
  }>;
90
+ /** Set of failed provider URLs */
91
+ failedProviders: string[];
92
+ /** Map of provider URL -> timestamp of last failure */
93
+ lastFailed: Record<string, number>;
94
+ /** Providers currently on cooldown: [baseUrl, timestamp][] */
95
+ providersOnCooldown: Array<{
96
+ baseUrl: string;
97
+ timestamp: number;
98
+ }>;
90
99
  }
91
100
 
92
101
  interface SdkStoreOptions {
@@ -137,6 +146,18 @@ interface SdkStorageStore extends SdkStorageState {
137
146
  createdAt?: number;
138
147
  lastUsed?: number | null;
139
148
  }> | ((current: SdkStorageStore["clientIds"]) => SdkStorageStore["clientIds"])) => void;
149
+ setFailedProviders: (value: string[]) => void;
150
+ addFailedProvider: (baseUrl: string) => void;
151
+ removeFailedProvider: (baseUrl: string) => void;
152
+ setLastFailed: (value: Record<string, number>) => void;
153
+ setLastFailedTimestamp: (baseUrl: string, timestamp: number) => void;
154
+ setProvidersOnCooldown: (value: Array<{
155
+ baseUrl: string;
156
+ timestamp: number;
157
+ }>) => void;
158
+ addProviderOnCooldown: (baseUrl: string, timestamp: number) => void;
159
+ removeProviderFromCooldown: (baseUrl: string) => void;
160
+ clearProvidersOnCooldown: () => void;
140
161
  }
141
162
  /** Store type returned after async initialization */
142
163
  type SdkStore = StoreApi<SdkStorageStore>;
@@ -78,9 +78,14 @@ declare class BalanceManager {
78
78
  */
79
79
  refundApiKey(options: RefundApiKeyOptions): Promise<RefundResult>;
80
80
  /**
81
- * Fetch refund token from provider API using API key authentication
81
+ * Fetch refund token from provider API using API key (or xcashu token) authentication
82
82
  */
83
- private _fetchRefundTokenWithApiKey;
83
+ fetchRefundToken(baseUrl: string, apiKeyOrToken: string, xCashu?: boolean): Promise<{
84
+ success: boolean;
85
+ token?: string;
86
+ requestId?: string;
87
+ error?: string;
88
+ }>;
84
89
  /**
85
90
  * Top up API key balance with a cashu token
86
91
  */
@@ -194,8 +199,9 @@ declare class CashuSpender {
194
199
  */
195
200
  private _tryReuseToken;
196
201
  /**
197
- * Refund all xcashu tokens from storage and increment tryCounts on failure.
198
- * Reuses receiveToken from BalanceManager/CashuSpender for receiving refunds.
202
+ * Refund all xcashu tokens from storage by calling the provider's refund endpoint.
203
+ * The xcashu token acts as an API key to claim the refund, and the response contains
204
+ * the actual refunded Cashu token which is then received into the wallet.
199
205
  * @param mintUrl - The mint URL for receiving tokens
200
206
  * @param excludeBaseUrls - Base URLs to exclude from refund (optional)
201
207
  * @returns Results for each xcashu token refund attempt
@@ -78,9 +78,14 @@ declare class BalanceManager {
78
78
  */
79
79
  refundApiKey(options: RefundApiKeyOptions): Promise<RefundResult>;
80
80
  /**
81
- * Fetch refund token from provider API using API key authentication
81
+ * Fetch refund token from provider API using API key (or xcashu token) authentication
82
82
  */
83
- private _fetchRefundTokenWithApiKey;
83
+ fetchRefundToken(baseUrl: string, apiKeyOrToken: string, xCashu?: boolean): Promise<{
84
+ success: boolean;
85
+ token?: string;
86
+ requestId?: string;
87
+ error?: string;
88
+ }>;
84
89
  /**
85
90
  * Top up API key balance with a cashu token
86
91
  */
@@ -194,8 +199,9 @@ declare class CashuSpender {
194
199
  */
195
200
  private _tryReuseToken;
196
201
  /**
197
- * Refund all xcashu tokens from storage and increment tryCounts on failure.
198
- * Reuses receiveToken from BalanceManager/CashuSpender for receiving refunds.
202
+ * Refund all xcashu tokens from storage by calling the provider's refund endpoint.
203
+ * The xcashu token acts as an API key to claim the refund, and the response contains
204
+ * the actual refunded Cashu token which is then received into the wallet.
199
205
  * @param mintUrl - The mint URL for receiving tokens
200
206
  * @param excludeBaseUrls - Base URLs to exclude from refund (optional)
201
207
  * @returns Results for each xcashu token refund attempt
@@ -425,8 +425,9 @@ var CashuSpender = class {
425
425
  return null;
426
426
  }
427
427
  /**
428
- * Refund all xcashu tokens from storage and increment tryCounts on failure.
429
- * Reuses receiveToken from BalanceManager/CashuSpender for receiving refunds.
428
+ * Refund all xcashu tokens from storage by calling the provider's refund endpoint.
429
+ * The xcashu token acts as an API key to claim the refund, and the response contains
430
+ * the actual refunded Cashu token which is then received into the wallet.
430
431
  * @param mintUrl - The mint URL for receiving tokens
431
432
  * @param excludeBaseUrls - Base URLs to exclude from refund (optional)
432
433
  * @returns Results for each xcashu token refund attempt
@@ -439,7 +440,20 @@ var CashuSpender = class {
439
440
  if (excludedUrls.has(baseUrl)) continue;
440
441
  for (const xcashuToken of tokens) {
441
442
  try {
442
- const receiveResult = await this.receiveToken(xcashuToken.token);
443
+ if (!this.balanceManager) {
444
+ throw new Error("BalanceManager not available for xcashu refund");
445
+ }
446
+ const fetchResult = await this.balanceManager.fetchRefundToken(
447
+ baseUrl,
448
+ xcashuToken.token,
449
+ true
450
+ );
451
+ if (!fetchResult.success || !fetchResult.token) {
452
+ throw new Error(
453
+ fetchResult.error || "Failed to fetch refund token from provider"
454
+ );
455
+ }
456
+ const receiveResult = await this.receiveToken(fetchResult.token);
443
457
  if (receiveResult.success) {
444
458
  this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
445
459
  results.push({
@@ -454,7 +468,10 @@ var CashuSpender = class {
454
468
  } else {
455
469
  const currentTryCount = xcashuToken.tryCount ?? 0;
456
470
  const newTryCount = currentTryCount + 1;
457
- this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
471
+ this.storageAdapter.updateXcashuTokenTryCount(
472
+ xcashuToken.token,
473
+ newTryCount
474
+ );
458
475
  results.push({
459
476
  baseUrl,
460
477
  token: xcashuToken.token,
@@ -463,13 +480,16 @@ var CashuSpender = class {
463
480
  });
464
481
  this._log(
465
482
  "DEBUG",
466
- `[CashuSpender] refundXcashuTokens: Failed to refund xcashu token for ${baseUrl}, incremented tryCount to ${newTryCount}`
483
+ `[CashuSpender] refundXcashuTokens: Failed to receive refund token for ${baseUrl}, incremented tryCount to ${newTryCount}`
467
484
  );
468
485
  }
469
486
  } catch (error) {
470
487
  const currentTryCount = xcashuToken.tryCount ?? 0;
471
488
  const newTryCount = currentTryCount + 1;
472
- this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
489
+ this.storageAdapter.updateXcashuTokenTryCount(
490
+ xcashuToken.token,
491
+ newTryCount
492
+ );
473
493
  const errorMessage = error instanceof Error ? error.message : String(error);
474
494
  results.push({
475
495
  baseUrl,
@@ -506,7 +526,10 @@ var CashuSpender = class {
506
526
  if (refundResult.success) {
507
527
  this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);
508
528
  } else {
509
- this.storageAdapter.updateApiKeyBalance(apiKeyEntry.baseUrl, apiKeyEntry.amount);
529
+ this.storageAdapter.updateApiKeyBalance(
530
+ apiKeyEntry.baseUrl,
531
+ apiKeyEntry.amount
532
+ );
510
533
  }
511
534
  results.push({
512
535
  baseUrl: apiKeyEntry.baseUrl,
@@ -644,7 +667,7 @@ var BalanceManager = class {
644
667
  }
645
668
  let fetchResult;
646
669
  try {
647
- fetchResult = await this._fetchRefundTokenWithApiKey(baseUrl, apiKey);
670
+ fetchResult = await this.fetchRefundToken(baseUrl, apiKey);
648
671
  if (!fetchResult.success) {
649
672
  return {
650
673
  success: false,
@@ -680,9 +703,9 @@ var BalanceManager = class {
680
703
  }
681
704
  }
682
705
  /**
683
- * Fetch refund token from provider API using API key authentication
706
+ * Fetch refund token from provider API using API key (or xcashu token) authentication
684
707
  */
685
- async _fetchRefundTokenWithApiKey(baseUrl, apiKey) {
708
+ async fetchRefundToken(baseUrl, apiKeyOrToken, xCashu = false) {
686
709
  if (!baseUrl) {
687
710
  return {
688
711
  success: false,
@@ -696,12 +719,17 @@ var BalanceManager = class {
696
719
  controller.abort();
697
720
  }, 6e4);
698
721
  try {
722
+ const headers = {
723
+ "Content-Type": "application/json"
724
+ };
725
+ if (xCashu) {
726
+ headers["X-Cashu"] = apiKeyOrToken;
727
+ } else {
728
+ headers["Authorization"] = `Bearer ${apiKeyOrToken}`;
729
+ }
699
730
  const response = await fetch(url, {
700
731
  method: "POST",
701
- headers: {
702
- Authorization: `Bearer ${apiKey}`,
703
- "Content-Type": "application/json"
704
- },
732
+ headers,
705
733
  signal: controller.signal
706
734
  });
707
735
  clearTimeout(timeoutId);
@@ -722,10 +750,7 @@ var BalanceManager = class {
722
750
  };
723
751
  } catch (error) {
724
752
  clearTimeout(timeoutId);
725
- console.error(
726
- "[BalanceManager._fetchRefundTokenWithApiKey] Fetch error",
727
- error
728
- );
753
+ console.error("[BalanceManager.fetchRefundToken] Fetch error", error);
729
754
  if (error instanceof Error) {
730
755
  if (error.name === "AbortError") {
731
756
  return {
@@ -772,11 +797,7 @@ var BalanceManager = class {
772
797
  };
773
798
  }
774
799
  cashuToken = tokenResult.token;
775
- const topUpResult = await this._postTopUp(
776
- baseUrl,
777
- apiKey,
778
- cashuToken
779
- );
800
+ const topUpResult = await this._postTopUp(baseUrl, apiKey, cashuToken);
780
801
  requestId = topUpResult.requestId;
781
802
  console.log(topUpResult);
782
803
  if (!topUpResult.success) {
@@ -1142,7 +1163,7 @@ var BalanceManager = class {
1142
1163
  console.log(response.status);
1143
1164
  const data = await response.json();
1144
1165
  console.log("FAILED ", data);
1145
- const isInvalidApiKey = response.status === 401 && data?.code === "invalid_api_key" && data?.message?.includes("proofs already spent");
1166
+ const isInvalidApiKey = response.status === 401 && data?.detail?.error?.code === "invalid_api_key" && data?.detail?.error?.message?.includes("proofs already spent");
1146
1167
  return {
1147
1168
  amount: -1,
1148
1169
  reserved: data.reserved ?? 0,