@routstr/sdk 0.2.6 → 0.2.8
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 +342 -87
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +342 -87
- 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 +347 -91
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +347 -91
- 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 +11 -4
- package/dist/wallet/index.d.ts +11 -4
- package/dist/wallet/index.js +83 -41
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +83 -41
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -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>;
|
package/dist/wallet/index.d.mts
CHANGED
|
@@ -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
|
-
|
|
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
|
*/
|
|
@@ -167,6 +172,7 @@ declare class CashuSpender {
|
|
|
167
172
|
unit: "sat" | "msat";
|
|
168
173
|
message?: string;
|
|
169
174
|
}>;
|
|
175
|
+
private _decodeTokenAmount;
|
|
170
176
|
private _getBalanceState;
|
|
171
177
|
private _logTransaction;
|
|
172
178
|
/**
|
|
@@ -194,8 +200,9 @@ declare class CashuSpender {
|
|
|
194
200
|
*/
|
|
195
201
|
private _tryReuseToken;
|
|
196
202
|
/**
|
|
197
|
-
* Refund all xcashu tokens from storage
|
|
198
|
-
*
|
|
203
|
+
* Refund all xcashu tokens from storage by calling the provider's refund endpoint.
|
|
204
|
+
* The xcashu token acts as an API key to claim the refund, and the response contains
|
|
205
|
+
* the actual refunded Cashu token which is then received into the wallet.
|
|
199
206
|
* @param mintUrl - The mint URL for receiving tokens
|
|
200
207
|
* @param excludeBaseUrls - Base URLs to exclude from refund (optional)
|
|
201
208
|
* @returns Results for each xcashu token refund attempt
|
package/dist/wallet/index.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
*/
|
|
@@ -167,6 +172,7 @@ declare class CashuSpender {
|
|
|
167
172
|
unit: "sat" | "msat";
|
|
168
173
|
message?: string;
|
|
169
174
|
}>;
|
|
175
|
+
private _decodeTokenAmount;
|
|
170
176
|
private _getBalanceState;
|
|
171
177
|
private _logTransaction;
|
|
172
178
|
/**
|
|
@@ -194,8 +200,9 @@ declare class CashuSpender {
|
|
|
194
200
|
*/
|
|
195
201
|
private _tryReuseToken;
|
|
196
202
|
/**
|
|
197
|
-
* Refund all xcashu tokens from storage
|
|
198
|
-
*
|
|
203
|
+
* Refund all xcashu tokens from storage by calling the provider's refund endpoint.
|
|
204
|
+
* The xcashu token acts as an API key to claim the refund, and the response contains
|
|
205
|
+
* the actual refunded Cashu token which is then received into the wallet.
|
|
199
206
|
* @param mintUrl - The mint URL for receiving tokens
|
|
200
207
|
* @param excludeBaseUrls - Base URLs to exclude from refund (optional)
|
|
201
208
|
* @returns Results for each xcashu token refund attempt
|
package/dist/wallet/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var cashuTs = require('@cashu/cashu-ts');
|
|
4
|
+
|
|
3
5
|
// core/errors.ts
|
|
4
6
|
var InsufficientBalanceError = class extends Error {
|
|
5
7
|
constructor(required, available, maxMintBalance = 0, maxMintUrl = "", customMessage) {
|
|
@@ -77,8 +79,6 @@ function selectMintWithBalance(balances, units, amount, excludeMints = []) {
|
|
|
77
79
|
}
|
|
78
80
|
return { selectedMintUrl: null, selectedMintBalance: 0 };
|
|
79
81
|
}
|
|
80
|
-
|
|
81
|
-
// wallet/CashuSpender.ts
|
|
82
82
|
var CashuSpender = class {
|
|
83
83
|
constructor(walletAdapter, storageAdapter, _providerRegistry, balanceManager) {
|
|
84
84
|
this.walletAdapter = walletAdapter;
|
|
@@ -89,23 +89,43 @@ var CashuSpender = class {
|
|
|
89
89
|
_isBusy = false;
|
|
90
90
|
debugLevel = "WARN";
|
|
91
91
|
async receiveToken(token) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
92
|
+
try {
|
|
93
|
+
const result = await this.walletAdapter.receiveToken(token);
|
|
94
|
+
return result;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
97
|
+
if (errorMessage.includes("Failed to fetch mint")) {
|
|
98
|
+
const cachedTokens = this.storageAdapter.getCachedReceiveTokens();
|
|
99
|
+
const existingIndex = cachedTokens.findIndex((t) => t.token === token);
|
|
100
|
+
if (existingIndex === -1) {
|
|
101
|
+
const { amount: amount2, unit: unit2 } = this._decodeTokenAmount(token);
|
|
102
|
+
this.storageAdapter.setCachedReceiveTokens([
|
|
103
|
+
...cachedTokens,
|
|
104
|
+
{
|
|
105
|
+
token,
|
|
106
|
+
amount: amount2,
|
|
107
|
+
unit: unit2,
|
|
108
|
+
createdAt: Date.now()
|
|
109
|
+
}
|
|
110
|
+
]);
|
|
111
|
+
}
|
|
106
112
|
}
|
|
113
|
+
const { amount, unit } = this._decodeTokenAmount(token);
|
|
114
|
+
return { success: false, amount, unit, message: errorMessage };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
_decodeTokenAmount(token) {
|
|
118
|
+
try {
|
|
119
|
+
const decoded = cashuTs.getDecodedToken(token);
|
|
120
|
+
const amount = decoded.proofs.reduce(
|
|
121
|
+
(acc, proof) => acc + proof.amount,
|
|
122
|
+
0
|
|
123
|
+
);
|
|
124
|
+
const unit = decoded.unit || "sat";
|
|
125
|
+
return { amount, unit };
|
|
126
|
+
} catch {
|
|
127
|
+
return { amount: 0, unit: "sat" };
|
|
107
128
|
}
|
|
108
|
-
return result;
|
|
109
129
|
}
|
|
110
130
|
async _getBalanceState() {
|
|
111
131
|
if (this.balanceManager) {
|
|
@@ -425,8 +445,9 @@ var CashuSpender = class {
|
|
|
425
445
|
return null;
|
|
426
446
|
}
|
|
427
447
|
/**
|
|
428
|
-
* Refund all xcashu tokens from storage
|
|
429
|
-
*
|
|
448
|
+
* Refund all xcashu tokens from storage by calling the provider's refund endpoint.
|
|
449
|
+
* The xcashu token acts as an API key to claim the refund, and the response contains
|
|
450
|
+
* the actual refunded Cashu token which is then received into the wallet.
|
|
430
451
|
* @param mintUrl - The mint URL for receiving tokens
|
|
431
452
|
* @param excludeBaseUrls - Base URLs to exclude from refund (optional)
|
|
432
453
|
* @returns Results for each xcashu token refund attempt
|
|
@@ -439,7 +460,20 @@ var CashuSpender = class {
|
|
|
439
460
|
if (excludedUrls.has(baseUrl)) continue;
|
|
440
461
|
for (const xcashuToken of tokens) {
|
|
441
462
|
try {
|
|
442
|
-
|
|
463
|
+
if (!this.balanceManager) {
|
|
464
|
+
throw new Error("BalanceManager not available for xcashu refund");
|
|
465
|
+
}
|
|
466
|
+
const fetchResult = await this.balanceManager.fetchRefundToken(
|
|
467
|
+
baseUrl,
|
|
468
|
+
xcashuToken.token,
|
|
469
|
+
true
|
|
470
|
+
);
|
|
471
|
+
if (!fetchResult.success || !fetchResult.token) {
|
|
472
|
+
throw new Error(
|
|
473
|
+
fetchResult.error || "Failed to fetch refund token from provider"
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
const receiveResult = await this.receiveToken(fetchResult.token);
|
|
443
477
|
if (receiveResult.success) {
|
|
444
478
|
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
445
479
|
results.push({
|
|
@@ -454,7 +488,10 @@ var CashuSpender = class {
|
|
|
454
488
|
} else {
|
|
455
489
|
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
456
490
|
const newTryCount = currentTryCount + 1;
|
|
457
|
-
this.storageAdapter.updateXcashuTokenTryCount(
|
|
491
|
+
this.storageAdapter.updateXcashuTokenTryCount(
|
|
492
|
+
xcashuToken.token,
|
|
493
|
+
newTryCount
|
|
494
|
+
);
|
|
458
495
|
results.push({
|
|
459
496
|
baseUrl,
|
|
460
497
|
token: xcashuToken.token,
|
|
@@ -463,13 +500,16 @@ var CashuSpender = class {
|
|
|
463
500
|
});
|
|
464
501
|
this._log(
|
|
465
502
|
"DEBUG",
|
|
466
|
-
`[CashuSpender] refundXcashuTokens: Failed to refund
|
|
503
|
+
`[CashuSpender] refundXcashuTokens: Failed to receive refund token for ${baseUrl}, incremented tryCount to ${newTryCount}: ${receiveResult.message}`
|
|
467
504
|
);
|
|
468
505
|
}
|
|
469
506
|
} catch (error) {
|
|
470
507
|
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
471
508
|
const newTryCount = currentTryCount + 1;
|
|
472
|
-
this.storageAdapter.updateXcashuTokenTryCount(
|
|
509
|
+
this.storageAdapter.updateXcashuTokenTryCount(
|
|
510
|
+
xcashuToken.token,
|
|
511
|
+
newTryCount
|
|
512
|
+
);
|
|
473
513
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
474
514
|
results.push({
|
|
475
515
|
baseUrl,
|
|
@@ -506,7 +546,10 @@ var CashuSpender = class {
|
|
|
506
546
|
if (refundResult.success) {
|
|
507
547
|
this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);
|
|
508
548
|
} else {
|
|
509
|
-
this.storageAdapter.updateApiKeyBalance(
|
|
549
|
+
this.storageAdapter.updateApiKeyBalance(
|
|
550
|
+
apiKeyEntry.baseUrl,
|
|
551
|
+
apiKeyEntry.amount
|
|
552
|
+
);
|
|
510
553
|
}
|
|
511
554
|
results.push({
|
|
512
555
|
baseUrl: apiKeyEntry.baseUrl,
|
|
@@ -644,7 +687,7 @@ var BalanceManager = class {
|
|
|
644
687
|
}
|
|
645
688
|
let fetchResult;
|
|
646
689
|
try {
|
|
647
|
-
fetchResult = await this.
|
|
690
|
+
fetchResult = await this.fetchRefundToken(baseUrl, apiKey);
|
|
648
691
|
if (!fetchResult.success) {
|
|
649
692
|
return {
|
|
650
693
|
success: false,
|
|
@@ -672,6 +715,7 @@ var BalanceManager = class {
|
|
|
672
715
|
return {
|
|
673
716
|
success: receiveResult.success,
|
|
674
717
|
refundedAmount: totalAmountMsat,
|
|
718
|
+
message: receiveResult.message,
|
|
675
719
|
requestId: fetchResult.requestId
|
|
676
720
|
};
|
|
677
721
|
} catch (error) {
|
|
@@ -680,9 +724,9 @@ var BalanceManager = class {
|
|
|
680
724
|
}
|
|
681
725
|
}
|
|
682
726
|
/**
|
|
683
|
-
* Fetch refund token from provider API using API key authentication
|
|
727
|
+
* Fetch refund token from provider API using API key (or xcashu token) authentication
|
|
684
728
|
*/
|
|
685
|
-
async
|
|
729
|
+
async fetchRefundToken(baseUrl, apiKeyOrToken, xCashu = false) {
|
|
686
730
|
if (!baseUrl) {
|
|
687
731
|
return {
|
|
688
732
|
success: false,
|
|
@@ -696,12 +740,17 @@ var BalanceManager = class {
|
|
|
696
740
|
controller.abort();
|
|
697
741
|
}, 6e4);
|
|
698
742
|
try {
|
|
743
|
+
const headers = {
|
|
744
|
+
"Content-Type": "application/json"
|
|
745
|
+
};
|
|
746
|
+
if (xCashu) {
|
|
747
|
+
headers["X-Cashu"] = apiKeyOrToken;
|
|
748
|
+
} else {
|
|
749
|
+
headers["Authorization"] = `Bearer ${apiKeyOrToken}`;
|
|
750
|
+
}
|
|
699
751
|
const response = await fetch(url, {
|
|
700
752
|
method: "POST",
|
|
701
|
-
headers
|
|
702
|
-
Authorization: `Bearer ${apiKey}`,
|
|
703
|
-
"Content-Type": "application/json"
|
|
704
|
-
},
|
|
753
|
+
headers,
|
|
705
754
|
signal: controller.signal
|
|
706
755
|
});
|
|
707
756
|
clearTimeout(timeoutId);
|
|
@@ -722,10 +771,7 @@ var BalanceManager = class {
|
|
|
722
771
|
};
|
|
723
772
|
} catch (error) {
|
|
724
773
|
clearTimeout(timeoutId);
|
|
725
|
-
console.error(
|
|
726
|
-
"[BalanceManager._fetchRefundTokenWithApiKey] Fetch error",
|
|
727
|
-
error
|
|
728
|
-
);
|
|
774
|
+
console.error("[BalanceManager.fetchRefundToken] Fetch error", error);
|
|
729
775
|
if (error instanceof Error) {
|
|
730
776
|
if (error.name === "AbortError") {
|
|
731
777
|
return {
|
|
@@ -772,11 +818,7 @@ var BalanceManager = class {
|
|
|
772
818
|
};
|
|
773
819
|
}
|
|
774
820
|
cashuToken = tokenResult.token;
|
|
775
|
-
const topUpResult = await this._postTopUp(
|
|
776
|
-
baseUrl,
|
|
777
|
-
apiKey,
|
|
778
|
-
cashuToken
|
|
779
|
-
);
|
|
821
|
+
const topUpResult = await this._postTopUp(baseUrl, apiKey, cashuToken);
|
|
780
822
|
requestId = topUpResult.requestId;
|
|
781
823
|
console.log(topUpResult);
|
|
782
824
|
if (!topUpResult.success) {
|
|
@@ -1142,7 +1184,7 @@ var BalanceManager = class {
|
|
|
1142
1184
|
console.log(response.status);
|
|
1143
1185
|
const data = await response.json();
|
|
1144
1186
|
console.log("FAILED ", data);
|
|
1145
|
-
const isInvalidApiKey = response.status === 401 && data?.code === "invalid_api_key" && data?.message?.includes("proofs already spent");
|
|
1187
|
+
const isInvalidApiKey = response.status === 401 && data?.detail?.error?.code === "invalid_api_key" && data?.detail?.error?.message?.includes("proofs already spent");
|
|
1146
1188
|
return {
|
|
1147
1189
|
amount: -1,
|
|
1148
1190
|
reserved: data.reserved ?? 0,
|