spaps-sdk 0.1.0 → 1.0.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/.env.example +23 -0
- package/README.md +639 -103
- package/admin-utils.ts +243 -0
- package/dist/index.js +890 -134
- package/dist/index.mjs +880 -121
- package/package.json +34 -40
- package/dist/index.d.mts +0 -82
- package/dist/index.d.ts +0 -82
package/dist/index.mjs
CHANGED
|
@@ -1,154 +1,913 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
// types.ts
|
|
2
|
+
var SweetPotatoAPIError = class extends Error {
|
|
3
|
+
constructor(message, code, status, details) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "SweetPotatoAPIError";
|
|
6
|
+
if (code !== void 0) this.code = code;
|
|
7
|
+
if (status !== void 0) this.status = status;
|
|
8
|
+
if (details !== void 0) this.details = details;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// client.ts
|
|
13
|
+
function detectLocalEnvironment() {
|
|
14
|
+
var _a;
|
|
15
|
+
if (typeof process !== "undefined" && process.env) {
|
|
16
|
+
if (process.env.NODE_ENV === "development" || process.env.SPAPS_LOCAL_MODE === "true") {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (typeof globalThis !== "undefined" && ((_a = globalThis.window) == null ? void 0 : _a.location)) {
|
|
21
|
+
const hostname = globalThis.window.location.hostname;
|
|
22
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname.endsWith(".local");
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
var HttpClient = class {
|
|
27
|
+
constructor(config) {
|
|
28
|
+
var _a, _b;
|
|
29
|
+
const localMode = (_b = config.localMode) != null ? _b : ((_a = config.apiUrl) == null ? void 0 : _a.includes("localhost")) || detectLocalEnvironment();
|
|
30
|
+
this.config = {
|
|
31
|
+
timeout: 3e4,
|
|
32
|
+
retries: 3,
|
|
33
|
+
...config,
|
|
34
|
+
localMode
|
|
35
|
+
};
|
|
36
|
+
this.isLocalMode = this.config.localMode || false;
|
|
37
|
+
this.accessToken = void 0;
|
|
38
|
+
if (this.isLocalMode && typeof console !== "undefined") {
|
|
39
|
+
console.log("[SPAPS SDK] Running in local development mode - authentication will be automatic");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Set the access token for authenticated requests
|
|
44
|
+
*/
|
|
45
|
+
setAccessToken(token) {
|
|
46
|
+
this.accessToken = token;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Clear the access token
|
|
50
|
+
*/
|
|
51
|
+
clearAccessToken() {
|
|
52
|
+
this.accessToken = void 0;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Make an HTTP request with automatic retries and error handling
|
|
56
|
+
*/
|
|
57
|
+
async request(options) {
|
|
58
|
+
var _a, _b, _c, _d;
|
|
59
|
+
const { method, url, data, headers = {}, requiresAuth = false } = options;
|
|
60
|
+
const fullUrl = url.startsWith("http") ? url : `${this.config.apiUrl.replace(/\/$/, "")}${url}`;
|
|
61
|
+
const requestHeaders = {
|
|
62
|
+
"Content-Type": "application/json",
|
|
63
|
+
...headers
|
|
64
|
+
};
|
|
65
|
+
if (this.config.apiKey) {
|
|
66
|
+
requestHeaders["x-api-key"] = this.config.apiKey;
|
|
67
|
+
} else if (this.isLocalMode) {
|
|
68
|
+
requestHeaders["x-local-mode"] = "true";
|
|
20
69
|
} else {
|
|
21
|
-
|
|
22
|
-
console.warn("\u26A0\uFE0F SPAPS: No API key provided. Some features may not work.");
|
|
23
|
-
}
|
|
24
|
-
this.apiKey = config.apiKey || process.env.SPAPS_API_KEY;
|
|
25
|
-
this.client = axios.create({
|
|
26
|
-
baseURL: apiUrl,
|
|
27
|
-
timeout: config.timeout || 1e4,
|
|
28
|
-
headers: {
|
|
29
|
-
"Content-Type": "application/json",
|
|
30
|
-
...this.apiKey && { "X-API-Key": this.apiKey }
|
|
31
|
-
}
|
|
32
|
-
});
|
|
70
|
+
console.warn("[SPAPS SDK] No API key provided and not in local mode");
|
|
33
71
|
}
|
|
34
|
-
this.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
72
|
+
if (requiresAuth && this.accessToken) {
|
|
73
|
+
requestHeaders["Authorization"] = `Bearer ${this.accessToken}`;
|
|
74
|
+
}
|
|
75
|
+
let lastError = null;
|
|
76
|
+
for (let attempt = 1; attempt <= this.config.retries; attempt++) {
|
|
77
|
+
try {
|
|
78
|
+
const controller = new AbortController();
|
|
79
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
80
|
+
const requestInit = {
|
|
81
|
+
method,
|
|
82
|
+
headers: requestHeaders,
|
|
83
|
+
signal: controller.signal
|
|
84
|
+
};
|
|
85
|
+
if (data && (method === "POST" || method === "PUT" || method === "PATCH")) {
|
|
86
|
+
requestInit.body = JSON.stringify(data);
|
|
87
|
+
}
|
|
88
|
+
const response = await fetch(fullUrl, requestInit);
|
|
89
|
+
clearTimeout(timeoutId);
|
|
90
|
+
if (!response) {
|
|
91
|
+
throw new Error("No response received");
|
|
92
|
+
}
|
|
93
|
+
let responseData;
|
|
94
|
+
const contentType = (_a = response.headers) == null ? void 0 : _a.get("content-type");
|
|
95
|
+
if (contentType && contentType.includes("application/json")) {
|
|
96
|
+
responseData = await response.json();
|
|
97
|
+
} else {
|
|
98
|
+
throw new SweetPotatoAPIError(
|
|
99
|
+
"Invalid response format: expected JSON",
|
|
100
|
+
"INVALID_RESPONSE_FORMAT",
|
|
101
|
+
response.status
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
if (!(response == null ? void 0 : response.ok)) {
|
|
105
|
+
throw new SweetPotatoAPIError(
|
|
106
|
+
((_b = responseData.error) == null ? void 0 : _b.message) || `HTTP ${response == null ? void 0 : response.status}: ${response == null ? void 0 : response.statusText}`,
|
|
107
|
+
((_c = responseData.error) == null ? void 0 : _c.code) || "HTTP_ERROR",
|
|
108
|
+
response == null ? void 0 : response.status,
|
|
109
|
+
(_d = responseData.error) == null ? void 0 : _d.details
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return responseData;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
lastError = error;
|
|
115
|
+
if (error instanceof SweetPotatoAPIError) {
|
|
116
|
+
if (error.status && error.status >= 400 && error.status < 500) {
|
|
117
|
+
throw error;
|
|
55
118
|
}
|
|
56
119
|
}
|
|
57
|
-
|
|
120
|
+
if (attempt === this.config.retries) {
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
const delayMs = Math.min(1e3 * Math.pow(2, attempt - 1), 1e4);
|
|
124
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
58
125
|
}
|
|
126
|
+
}
|
|
127
|
+
if (lastError instanceof SweetPotatoAPIError) {
|
|
128
|
+
throw lastError;
|
|
129
|
+
}
|
|
130
|
+
throw new SweetPotatoAPIError(
|
|
131
|
+
(lastError == null ? void 0 : lastError.message) || "Request failed after all retries",
|
|
132
|
+
"REQUEST_FAILED",
|
|
133
|
+
void 0,
|
|
134
|
+
{ originalError: lastError }
|
|
59
135
|
);
|
|
60
136
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
137
|
+
/**
|
|
138
|
+
* Convenience method for GET requests
|
|
139
|
+
*/
|
|
140
|
+
async get(url, requiresAuth = false) {
|
|
141
|
+
return this.request({
|
|
142
|
+
method: "GET",
|
|
143
|
+
url,
|
|
144
|
+
requiresAuth
|
|
66
145
|
});
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
async
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Convenience method for POST requests
|
|
149
|
+
*/
|
|
150
|
+
async post(url, data, requiresAuth = false) {
|
|
151
|
+
return this.request({
|
|
152
|
+
method: "POST",
|
|
153
|
+
url,
|
|
154
|
+
data,
|
|
155
|
+
requiresAuth
|
|
75
156
|
});
|
|
76
|
-
this.accessToken = response.data.access_token;
|
|
77
|
-
this.refreshToken = response.data.refresh_token;
|
|
78
|
-
return response;
|
|
79
157
|
}
|
|
80
|
-
|
|
81
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Convenience method for PUT requests
|
|
160
|
+
*/
|
|
161
|
+
async put(url, data, requiresAuth = false) {
|
|
162
|
+
return this.request({
|
|
163
|
+
method: "PUT",
|
|
164
|
+
url,
|
|
165
|
+
data,
|
|
166
|
+
requiresAuth
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Convenience method for DELETE requests
|
|
171
|
+
*/
|
|
172
|
+
async delete(url, requiresAuth = false) {
|
|
173
|
+
return this.request({
|
|
174
|
+
method: "DELETE",
|
|
175
|
+
url,
|
|
176
|
+
requiresAuth
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// auth.ts
|
|
182
|
+
var AuthService = class {
|
|
183
|
+
constructor(httpClient) {
|
|
184
|
+
this.httpClient = httpClient;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get a nonce for wallet signature
|
|
188
|
+
* @param walletAddress - The wallet address to generate a nonce for
|
|
189
|
+
* @returns Promise<NonceResponse>
|
|
190
|
+
*/
|
|
191
|
+
async getNonce(walletAddress) {
|
|
192
|
+
var _a;
|
|
193
|
+
const response = await this.httpClient.post("/api/auth/nonce", {
|
|
194
|
+
wallet_address: walletAddress
|
|
195
|
+
});
|
|
196
|
+
if (!response.success || !response.data) {
|
|
197
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to generate nonce");
|
|
198
|
+
}
|
|
199
|
+
return response.data;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Sign in with wallet signature
|
|
203
|
+
* @param request - Wallet sign-in request data
|
|
204
|
+
* @returns Promise<AuthResponse>
|
|
205
|
+
*/
|
|
206
|
+
async signInWithWallet(request) {
|
|
207
|
+
var _a;
|
|
208
|
+
const response = await this.httpClient.post("/api/auth/wallet-sign-in", request);
|
|
209
|
+
if (!response.success || !response.data) {
|
|
210
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Wallet sign-in failed");
|
|
211
|
+
}
|
|
212
|
+
this.httpClient.setAccessToken(response.data.access_token);
|
|
213
|
+
return response.data;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Complete wallet authentication flow
|
|
217
|
+
* This is a convenience method that combines getNonce and signInWithWallet
|
|
218
|
+
* @param walletAddress - The wallet address
|
|
219
|
+
* @param signatureFunction - Function that signs the auth message
|
|
220
|
+
* @param chainType - Optional chain type (will be auto-detected if not provided)
|
|
221
|
+
* @param username - Optional username for new users
|
|
222
|
+
* @returns Promise<AuthResponse>
|
|
223
|
+
*/
|
|
224
|
+
async authenticateWallet(walletAddress, signatureFunction, chainType, username) {
|
|
225
|
+
const nonceData = await this.getNonce(walletAddress);
|
|
226
|
+
const signature = await signatureFunction(nonceData.message);
|
|
227
|
+
const request = {
|
|
82
228
|
wallet_address: walletAddress,
|
|
83
229
|
signature,
|
|
84
|
-
message
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
230
|
+
message: nonceData.message
|
|
231
|
+
};
|
|
232
|
+
if (chainType) {
|
|
233
|
+
request.chain_type = chainType;
|
|
234
|
+
}
|
|
235
|
+
if (username) {
|
|
236
|
+
request.username = username;
|
|
237
|
+
}
|
|
238
|
+
return this.signInWithWallet(request);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Sign in with email and password
|
|
242
|
+
* @param request - Traditional login request data
|
|
243
|
+
* @returns Promise<AuthResponse>
|
|
244
|
+
*/
|
|
245
|
+
async signInWithPassword(request) {
|
|
246
|
+
var _a;
|
|
247
|
+
const response = await this.httpClient.post("/api/auth/login", request);
|
|
248
|
+
if (response.access_token && response.refresh_token && response.user) {
|
|
249
|
+
this.httpClient.setAccessToken(response.access_token);
|
|
250
|
+
return response;
|
|
251
|
+
}
|
|
252
|
+
if (!response.success || !response.data) {
|
|
253
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Login failed");
|
|
254
|
+
}
|
|
255
|
+
this.httpClient.setAccessToken(response.data.access_token);
|
|
256
|
+
return response.data;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Request a magic link for email authentication
|
|
260
|
+
* @param request - Magic link request data
|
|
261
|
+
* @returns Promise<void>
|
|
262
|
+
*/
|
|
263
|
+
async requestMagicLink(request) {
|
|
264
|
+
var _a;
|
|
265
|
+
const response = await this.httpClient.post("/api/auth/magic-link", request);
|
|
266
|
+
if (!response.success) {
|
|
267
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to send magic link");
|
|
268
|
+
}
|
|
90
269
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
270
|
+
/**
|
|
271
|
+
* Refresh access token using refresh token
|
|
272
|
+
* @param refreshToken - The refresh token
|
|
273
|
+
* @returns Promise<TokenPair>
|
|
274
|
+
*/
|
|
275
|
+
async refreshToken(refreshToken) {
|
|
276
|
+
var _a;
|
|
277
|
+
const response = await this.httpClient.post("/api/auth/refresh", {
|
|
278
|
+
refresh_token: refreshToken
|
|
94
279
|
});
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
280
|
+
if (!response.success || !response.data) {
|
|
281
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Token refresh failed");
|
|
282
|
+
}
|
|
283
|
+
this.httpClient.setAccessToken(response.data.access_token);
|
|
284
|
+
return response.data;
|
|
98
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Log out and invalidate tokens
|
|
288
|
+
* @returns Promise<void>
|
|
289
|
+
*/
|
|
99
290
|
async logout() {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
291
|
+
var _a;
|
|
292
|
+
try {
|
|
293
|
+
const response = await this.httpClient.post("/api/auth/logout", {}, true);
|
|
294
|
+
if (!response.success) {
|
|
295
|
+
console.warn("Logout API call failed:", ((_a = response.error) == null ? void 0 : _a.message) || "Unknown error");
|
|
296
|
+
}
|
|
297
|
+
} catch (error) {
|
|
298
|
+
console.warn("Logout API call failed:", error);
|
|
299
|
+
} finally {
|
|
300
|
+
this.httpClient.clearAccessToken();
|
|
301
|
+
}
|
|
103
302
|
}
|
|
104
|
-
|
|
105
|
-
|
|
303
|
+
/**
|
|
304
|
+
* Get current user profile
|
|
305
|
+
* @returns Promise<User>
|
|
306
|
+
*/
|
|
307
|
+
async getCurrentUser() {
|
|
308
|
+
var _a;
|
|
309
|
+
const response = await this.httpClient.get("/api/auth/user", true);
|
|
310
|
+
if (!response.success || !response.data) {
|
|
311
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to get user profile");
|
|
312
|
+
}
|
|
313
|
+
return response.data.user;
|
|
106
314
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
});
|
|
315
|
+
/**
|
|
316
|
+
* Check if user is currently authenticated
|
|
317
|
+
* @returns boolean
|
|
318
|
+
*/
|
|
319
|
+
isAuthenticated() {
|
|
320
|
+
return this.httpClient["accessToken"] !== void 0;
|
|
114
321
|
}
|
|
115
|
-
|
|
116
|
-
|
|
322
|
+
/**
|
|
323
|
+
* Clear authentication state (useful for client-side logout)
|
|
324
|
+
*/
|
|
325
|
+
clearAuth() {
|
|
326
|
+
this.httpClient.clearAccessToken();
|
|
117
327
|
}
|
|
118
|
-
|
|
119
|
-
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// payments.ts
|
|
331
|
+
var PaymentsService = class {
|
|
332
|
+
constructor(httpClient) {
|
|
333
|
+
this.httpClient = httpClient;
|
|
120
334
|
}
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
335
|
+
// Checkout Sessions
|
|
336
|
+
/**
|
|
337
|
+
* Create a new Stripe checkout session
|
|
338
|
+
* @param request - Checkout session creation parameters
|
|
339
|
+
* @returns Promise<CheckoutSession>
|
|
340
|
+
*/
|
|
341
|
+
async createCheckoutSession(request) {
|
|
342
|
+
var _a;
|
|
343
|
+
const response = await this.httpClient.post(
|
|
344
|
+
"/api/stripe/checkout-sessions",
|
|
345
|
+
request,
|
|
346
|
+
true
|
|
347
|
+
);
|
|
348
|
+
if (!response.success || !response.data) {
|
|
349
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to create checkout session");
|
|
350
|
+
}
|
|
351
|
+
return response.data;
|
|
124
352
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
353
|
+
/**
|
|
354
|
+
* Retrieve a checkout session by ID
|
|
355
|
+
* @param sessionId - The checkout session ID
|
|
356
|
+
* @returns Promise<CheckoutSession>
|
|
357
|
+
*/
|
|
358
|
+
async getCheckoutSession(sessionId) {
|
|
359
|
+
var _a;
|
|
360
|
+
const response = await this.httpClient.get(
|
|
361
|
+
`/api/stripe/checkout-sessions/${sessionId}`,
|
|
362
|
+
true
|
|
363
|
+
);
|
|
364
|
+
if (!response.success || !response.data) {
|
|
365
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to retrieve checkout session");
|
|
366
|
+
}
|
|
367
|
+
return response.data;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Expire a checkout session
|
|
371
|
+
* @param sessionId - The checkout session ID to expire
|
|
372
|
+
* @returns Promise<{id: string, status: string, expired: boolean}>
|
|
373
|
+
*/
|
|
374
|
+
async expireCheckoutSession(sessionId) {
|
|
375
|
+
var _a;
|
|
376
|
+
const response = await this.httpClient.post(
|
|
377
|
+
`/api/stripe/checkout-sessions/${sessionId}/expire`,
|
|
378
|
+
{},
|
|
379
|
+
true
|
|
380
|
+
);
|
|
381
|
+
if (!response.success || !response.data) {
|
|
382
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to expire checkout session");
|
|
383
|
+
}
|
|
384
|
+
return response.data;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* List checkout sessions for the current user
|
|
388
|
+
* @param options - List options (limit, pagination)
|
|
389
|
+
* @returns Promise<CheckoutSessionListResponse>
|
|
390
|
+
*/
|
|
391
|
+
async listCheckoutSessions(options = {}) {
|
|
392
|
+
var _a;
|
|
393
|
+
const params = new URLSearchParams();
|
|
394
|
+
if (options.limit) params.append("limit", options.limit.toString());
|
|
395
|
+
if (options.starting_after) params.append("starting_after", options.starting_after);
|
|
396
|
+
const url = `/api/stripe/checkout-sessions${params.toString() ? `?${params.toString()}` : ""}`;
|
|
397
|
+
const response = await this.httpClient.get(url, true);
|
|
398
|
+
if (!response.success || !response.data) {
|
|
399
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to list checkout sessions");
|
|
400
|
+
}
|
|
401
|
+
return response.data;
|
|
402
|
+
}
|
|
403
|
+
// Products
|
|
404
|
+
/**
|
|
405
|
+
* List available products
|
|
406
|
+
* @param request - Product list filters
|
|
407
|
+
* @returns Promise<ProductsListResponse>
|
|
408
|
+
*/
|
|
409
|
+
async listProducts(request = {}) {
|
|
410
|
+
var _a;
|
|
411
|
+
const params = new URLSearchParams();
|
|
412
|
+
if (request.category) params.append("category", request.category);
|
|
413
|
+
if (request.active !== void 0) params.append("active", request.active.toString());
|
|
414
|
+
if (request.limit) params.append("limit", request.limit.toString());
|
|
415
|
+
if (request.starting_after) params.append("starting_after", request.starting_after);
|
|
416
|
+
const url = `/api/stripe/products${params.toString() ? `?${params.toString()}` : ""}`;
|
|
417
|
+
const response = await this.httpClient.get(url, true);
|
|
418
|
+
if (!response.success || !response.data) {
|
|
419
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to list products");
|
|
420
|
+
}
|
|
421
|
+
return response.data;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Get a specific product by ID
|
|
425
|
+
* @param productId - The product ID
|
|
426
|
+
* @param includePrices - Whether to include associated prices (default: true)
|
|
427
|
+
* @returns Promise<StripeProduct>
|
|
428
|
+
*/
|
|
429
|
+
async getProduct(productId, includePrices = true) {
|
|
430
|
+
var _a;
|
|
431
|
+
const params = new URLSearchParams();
|
|
432
|
+
if (!includePrices) params.append("include_prices", "false");
|
|
433
|
+
const url = `/api/stripe/products/${productId}${params.toString() ? `?${params.toString()}` : ""}`;
|
|
434
|
+
const response = await this.httpClient.get(url, true);
|
|
435
|
+
if (!response.success || !response.data) {
|
|
436
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to retrieve product");
|
|
437
|
+
}
|
|
438
|
+
return response.data;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Create a new product (Admin only)
|
|
442
|
+
* @param request - Product creation parameters
|
|
443
|
+
* @returns Promise<StripeProduct>
|
|
444
|
+
*/
|
|
445
|
+
async createProduct(request) {
|
|
446
|
+
var _a;
|
|
447
|
+
const response = await this.httpClient.post(
|
|
448
|
+
"/api/stripe/products",
|
|
449
|
+
request,
|
|
450
|
+
true
|
|
451
|
+
);
|
|
452
|
+
if (!response.success || !response.data) {
|
|
453
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to create product");
|
|
454
|
+
}
|
|
455
|
+
return response.data;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Update an existing product (Admin only)
|
|
459
|
+
* @param productId - The product ID to update
|
|
460
|
+
* @param request - Product update parameters
|
|
461
|
+
* @returns Promise<StripeProduct>
|
|
462
|
+
*/
|
|
463
|
+
async updateProduct(productId, request) {
|
|
464
|
+
var _a;
|
|
465
|
+
const response = await this.httpClient.put(
|
|
466
|
+
`/api/stripe/products/${productId}`,
|
|
467
|
+
request,
|
|
468
|
+
true
|
|
469
|
+
);
|
|
470
|
+
if (!response.success || !response.data) {
|
|
471
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to update product");
|
|
472
|
+
}
|
|
473
|
+
return response.data;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Archive a product (Admin only)
|
|
477
|
+
* @param productId - The product ID to archive
|
|
478
|
+
* @returns Promise<{id: string, archived: boolean, active: boolean}>
|
|
479
|
+
*/
|
|
480
|
+
async archiveProduct(productId) {
|
|
481
|
+
var _a;
|
|
482
|
+
const response = await this.httpClient.delete(
|
|
483
|
+
`/api/stripe/products/${productId}`,
|
|
484
|
+
true
|
|
485
|
+
);
|
|
486
|
+
if (!response.success || !response.data) {
|
|
487
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to archive product");
|
|
488
|
+
}
|
|
489
|
+
return response.data;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Sync products from Stripe (Admin only)
|
|
493
|
+
* @returns Promise<{synced_count: number, message: string}>
|
|
494
|
+
*/
|
|
495
|
+
async syncProducts() {
|
|
496
|
+
var _a;
|
|
497
|
+
const response = await this.httpClient.post(
|
|
498
|
+
"/api/stripe/products/sync",
|
|
499
|
+
{},
|
|
500
|
+
true
|
|
501
|
+
);
|
|
502
|
+
if (!response.success || !response.data) {
|
|
503
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to sync products");
|
|
504
|
+
}
|
|
505
|
+
return response.data;
|
|
506
|
+
}
|
|
507
|
+
// Prices
|
|
508
|
+
/**
|
|
509
|
+
* Create a new price for a product (Admin only)
|
|
510
|
+
* @param request - Price creation parameters
|
|
511
|
+
* @returns Promise<StripePrice>
|
|
512
|
+
*/
|
|
513
|
+
async createPrice(request) {
|
|
514
|
+
var _a;
|
|
515
|
+
const response = await this.httpClient.post(
|
|
516
|
+
"/api/stripe/prices",
|
|
517
|
+
request,
|
|
518
|
+
true
|
|
519
|
+
);
|
|
520
|
+
if (!response.success || !response.data) {
|
|
521
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to create price");
|
|
522
|
+
}
|
|
523
|
+
return response.data;
|
|
524
|
+
}
|
|
525
|
+
// Subscriptions
|
|
526
|
+
/**
|
|
527
|
+
* Create a new subscription
|
|
528
|
+
* @param request - Subscription creation parameters
|
|
529
|
+
* @returns Promise<Subscription>
|
|
530
|
+
*/
|
|
531
|
+
async createSubscription(request) {
|
|
532
|
+
var _a;
|
|
533
|
+
const response = await this.httpClient.post(
|
|
534
|
+
"/api/stripe/subscriptions",
|
|
535
|
+
request,
|
|
536
|
+
true
|
|
537
|
+
);
|
|
538
|
+
if (!response.success || !response.data) {
|
|
539
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to create subscription");
|
|
540
|
+
}
|
|
541
|
+
return response.data;
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Get a subscription by ID
|
|
545
|
+
* @param subscriptionId - The subscription ID
|
|
546
|
+
* @returns Promise<Subscription>
|
|
547
|
+
*/
|
|
548
|
+
async getSubscription(subscriptionId) {
|
|
549
|
+
var _a;
|
|
550
|
+
const response = await this.httpClient.get(
|
|
551
|
+
`/api/stripe/subscriptions/${subscriptionId}`,
|
|
552
|
+
true
|
|
553
|
+
);
|
|
554
|
+
if (!response.success || !response.data) {
|
|
555
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to retrieve subscription");
|
|
556
|
+
}
|
|
557
|
+
return response.data;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* List subscriptions for the current user
|
|
561
|
+
* @param options - List options
|
|
562
|
+
* @returns Promise<{subscriptions: Subscription[], has_more: boolean}>
|
|
563
|
+
*/
|
|
564
|
+
async listSubscriptions(options = {}) {
|
|
565
|
+
var _a;
|
|
566
|
+
const params = new URLSearchParams();
|
|
567
|
+
if (options.limit) params.append("limit", options.limit.toString());
|
|
568
|
+
if (options.starting_after) params.append("starting_after", options.starting_after);
|
|
569
|
+
if (options.status) params.append("status", options.status);
|
|
570
|
+
const url = `/api/stripe/subscriptions${params.toString() ? `?${params.toString()}` : ""}`;
|
|
571
|
+
const response = await this.httpClient.get(url, true);
|
|
572
|
+
if (!response.success || !response.data) {
|
|
573
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to list subscriptions");
|
|
574
|
+
}
|
|
575
|
+
return response.data;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Cancel a subscription
|
|
579
|
+
* @param subscriptionId - The subscription ID to cancel
|
|
580
|
+
* @returns Promise<Subscription>
|
|
581
|
+
*/
|
|
582
|
+
async cancelSubscription(subscriptionId) {
|
|
583
|
+
var _a;
|
|
584
|
+
const response = await this.httpClient.post(
|
|
585
|
+
`/api/stripe/subscriptions/${subscriptionId}/cancel`,
|
|
586
|
+
{},
|
|
587
|
+
true
|
|
588
|
+
);
|
|
589
|
+
if (!response.success || !response.data) {
|
|
590
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to cancel subscription");
|
|
591
|
+
}
|
|
592
|
+
return response.data;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Update a subscription
|
|
596
|
+
* @param subscriptionId - The subscription ID to update
|
|
597
|
+
* @param request - Update parameters
|
|
598
|
+
* @returns Promise<Subscription>
|
|
599
|
+
*/
|
|
600
|
+
async updateSubscription(subscriptionId, request) {
|
|
601
|
+
var _a;
|
|
602
|
+
const response = await this.httpClient.put(
|
|
603
|
+
`/api/stripe/subscriptions/${subscriptionId}`,
|
|
604
|
+
request,
|
|
605
|
+
true
|
|
606
|
+
);
|
|
607
|
+
if (!response.success || !response.data) {
|
|
608
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to update subscription");
|
|
609
|
+
}
|
|
610
|
+
return response.data;
|
|
611
|
+
}
|
|
612
|
+
// Customer Portal
|
|
613
|
+
/**
|
|
614
|
+
* Create a customer portal session
|
|
615
|
+
* @param request - Portal session parameters
|
|
616
|
+
* @returns Promise<CustomerPortalSession>
|
|
617
|
+
*/
|
|
618
|
+
async createCustomerPortalSession(request) {
|
|
619
|
+
var _a;
|
|
620
|
+
const response = await this.httpClient.post(
|
|
621
|
+
"/api/stripe/customer-portal",
|
|
622
|
+
request,
|
|
623
|
+
true
|
|
624
|
+
);
|
|
625
|
+
if (!response.success || !response.data) {
|
|
626
|
+
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to create customer portal session");
|
|
627
|
+
}
|
|
628
|
+
return response.data;
|
|
130
629
|
}
|
|
131
630
|
// Utility Methods
|
|
132
|
-
|
|
133
|
-
|
|
631
|
+
/**
|
|
632
|
+
* Create a one-time payment checkout session
|
|
633
|
+
* Convenience method for simple one-time payments
|
|
634
|
+
* @param params - Payment parameters
|
|
635
|
+
* @returns Promise<CheckoutSession>
|
|
636
|
+
*/
|
|
637
|
+
async createPaymentCheckout(params) {
|
|
638
|
+
const lineItems = [];
|
|
639
|
+
if (params.price_id) {
|
|
640
|
+
lineItems.push({
|
|
641
|
+
price_id: params.price_id,
|
|
642
|
+
quantity: params.quantity || 1
|
|
643
|
+
});
|
|
644
|
+
} else if (params.product_name && params.amount && params.currency) {
|
|
645
|
+
lineItems.push({
|
|
646
|
+
quantity: params.quantity || 1,
|
|
647
|
+
price_data: {
|
|
648
|
+
currency: params.currency,
|
|
649
|
+
unit_amount: params.amount,
|
|
650
|
+
product_data: {
|
|
651
|
+
name: params.product_name
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
} else {
|
|
656
|
+
throw new Error("Either price_id or (product_name, amount, currency) must be provided");
|
|
657
|
+
}
|
|
658
|
+
return this.createCheckoutSession({
|
|
659
|
+
mode: "payment",
|
|
660
|
+
line_items: lineItems,
|
|
661
|
+
success_url: params.success_url,
|
|
662
|
+
cancel_url: params.cancel_url,
|
|
663
|
+
...params.metadata && { metadata: params.metadata }
|
|
664
|
+
});
|
|
134
665
|
}
|
|
135
|
-
|
|
136
|
-
|
|
666
|
+
/**
|
|
667
|
+
* Create a subscription checkout session
|
|
668
|
+
* Convenience method for subscription creation
|
|
669
|
+
* @param params - Subscription parameters
|
|
670
|
+
* @returns Promise<CheckoutSession>
|
|
671
|
+
*/
|
|
672
|
+
async createSubscriptionCheckout(params) {
|
|
673
|
+
return this.createCheckoutSession({
|
|
674
|
+
mode: "subscription",
|
|
675
|
+
line_items: [{
|
|
676
|
+
price_id: params.price_id,
|
|
677
|
+
quantity: 1
|
|
678
|
+
}],
|
|
679
|
+
success_url: params.success_url,
|
|
680
|
+
cancel_url: params.cancel_url,
|
|
681
|
+
subscription_data: {
|
|
682
|
+
...params.trial_period_days !== void 0 && { trial_period_days: params.trial_period_days },
|
|
683
|
+
...params.metadata && { metadata: params.metadata }
|
|
684
|
+
}
|
|
685
|
+
});
|
|
137
686
|
}
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
// index.ts
|
|
690
|
+
var SweetPotatoSDK = class {
|
|
691
|
+
constructor(config) {
|
|
692
|
+
if (!config.apiUrl) {
|
|
693
|
+
throw new Error("apiUrl is required");
|
|
694
|
+
}
|
|
695
|
+
this.httpClient = new HttpClient(config);
|
|
696
|
+
this.auth = new AuthService(this.httpClient);
|
|
697
|
+
this.payments = new PaymentsService(this.httpClient);
|
|
698
|
+
this.isLocalMode = this.httpClient["isLocalMode"] || false;
|
|
699
|
+
if (this.isLocalMode) {
|
|
700
|
+
console.log("[SPAPS SDK] Initialized in local development mode");
|
|
701
|
+
console.log("[SPAPS SDK] API URL:", config.apiUrl);
|
|
702
|
+
console.log("[SPAPS SDK] Authentication will be automatic");
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Set access token for authenticated requests
|
|
707
|
+
* @param token - Access token
|
|
708
|
+
*/
|
|
138
709
|
setAccessToken(token) {
|
|
139
|
-
this.
|
|
710
|
+
this.httpClient.setAccessToken(token);
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Clear access token
|
|
714
|
+
*/
|
|
715
|
+
clearAccessToken() {
|
|
716
|
+
this.httpClient.clearAccessToken();
|
|
140
717
|
}
|
|
141
|
-
|
|
142
|
-
|
|
718
|
+
/**
|
|
719
|
+
* Get SDK configuration
|
|
720
|
+
*/
|
|
721
|
+
getConfig() {
|
|
722
|
+
return {
|
|
723
|
+
apiUrl: this.httpClient["config"].apiUrl,
|
|
724
|
+
timeout: this.httpClient["config"].timeout,
|
|
725
|
+
retries: this.httpClient["config"].retries
|
|
726
|
+
};
|
|
143
727
|
}
|
|
144
|
-
|
|
145
|
-
|
|
728
|
+
/**
|
|
729
|
+
* Health check endpoint
|
|
730
|
+
* @returns Promise<boolean>
|
|
731
|
+
*/
|
|
732
|
+
async healthCheck() {
|
|
733
|
+
try {
|
|
734
|
+
const response = await this.httpClient.get("/api/health");
|
|
735
|
+
return response.success;
|
|
736
|
+
} catch (e) {
|
|
737
|
+
return false;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Make a custom authenticated request
|
|
742
|
+
* This allows advanced users to make direct API calls not covered by the SDK
|
|
743
|
+
*/
|
|
744
|
+
async request(method, url, data, requiresAuth = false) {
|
|
745
|
+
return this.httpClient.request({
|
|
746
|
+
method,
|
|
747
|
+
url,
|
|
748
|
+
data,
|
|
749
|
+
requiresAuth
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
function createSweetPotatoSDK(config) {
|
|
754
|
+
return new SweetPotatoSDK(config);
|
|
755
|
+
}
|
|
756
|
+
var _TokenManager = class _TokenManager {
|
|
757
|
+
/**
|
|
758
|
+
* Get localStorage instance (browser or test environment)
|
|
759
|
+
*/
|
|
760
|
+
static getStorage() {
|
|
761
|
+
var _a, _b;
|
|
762
|
+
if (typeof globalThis !== "undefined" && globalThis.localStorage) {
|
|
763
|
+
return globalThis.localStorage;
|
|
764
|
+
}
|
|
765
|
+
if (typeof globalThis !== "undefined" && ((_a = globalThis.window) == null ? void 0 : _a.localStorage)) {
|
|
766
|
+
return globalThis.window.localStorage;
|
|
767
|
+
}
|
|
768
|
+
if (typeof global !== "undefined" && ((_b = global.window) == null ? void 0 : _b.localStorage)) {
|
|
769
|
+
return global.window.localStorage;
|
|
770
|
+
}
|
|
771
|
+
return null;
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Store tokens in localStorage (browser only)
|
|
775
|
+
*/
|
|
776
|
+
static storeTokens(tokens) {
|
|
777
|
+
const localStorage = _TokenManager.getStorage();
|
|
778
|
+
if (localStorage) {
|
|
779
|
+
localStorage.setItem(_TokenManager.ACCESS_TOKEN_KEY, tokens.access_token);
|
|
780
|
+
localStorage.setItem(_TokenManager.REFRESH_TOKEN_KEY, tokens.refresh_token);
|
|
781
|
+
localStorage.setItem(_TokenManager.USER_KEY, JSON.stringify(tokens.user));
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Get stored access token (browser only)
|
|
786
|
+
*/
|
|
787
|
+
static getAccessToken() {
|
|
788
|
+
const localStorage = _TokenManager.getStorage();
|
|
789
|
+
return localStorage ? localStorage.getItem(_TokenManager.ACCESS_TOKEN_KEY) : null;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Get stored refresh token (browser only)
|
|
793
|
+
*/
|
|
794
|
+
static getRefreshToken() {
|
|
795
|
+
const localStorage = _TokenManager.getStorage();
|
|
796
|
+
return localStorage ? localStorage.getItem(_TokenManager.REFRESH_TOKEN_KEY) : null;
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Get stored user data (browser only)
|
|
800
|
+
*/
|
|
801
|
+
static getStoredUser() {
|
|
802
|
+
const localStorage = _TokenManager.getStorage();
|
|
803
|
+
if (localStorage) {
|
|
804
|
+
const userData = localStorage.getItem(_TokenManager.USER_KEY);
|
|
805
|
+
return userData ? JSON.parse(userData) : null;
|
|
806
|
+
}
|
|
807
|
+
return null;
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Clear all stored tokens and user data (browser only)
|
|
811
|
+
*/
|
|
812
|
+
static clearTokens() {
|
|
813
|
+
const localStorage = _TokenManager.getStorage();
|
|
814
|
+
if (localStorage) {
|
|
815
|
+
localStorage.removeItem(_TokenManager.ACCESS_TOKEN_KEY);
|
|
816
|
+
localStorage.removeItem(_TokenManager.REFRESH_TOKEN_KEY);
|
|
817
|
+
localStorage.removeItem(_TokenManager.USER_KEY);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Check if access token is expired (basic check, doesn't verify signature)
|
|
822
|
+
*/
|
|
823
|
+
static isTokenExpired(token) {
|
|
824
|
+
try {
|
|
825
|
+
const parts = token.split(".");
|
|
826
|
+
if (parts.length !== 3 || !parts[1]) return true;
|
|
827
|
+
const payload = JSON.parse(atob(parts[1]));
|
|
828
|
+
const currentTime = Math.floor(Date.now() / 1e3);
|
|
829
|
+
return payload.exp < currentTime;
|
|
830
|
+
} catch (e) {
|
|
831
|
+
return true;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Auto-refresh token if needed
|
|
836
|
+
*/
|
|
837
|
+
static async autoRefreshToken(sdk) {
|
|
838
|
+
const accessToken = _TokenManager.getAccessToken();
|
|
839
|
+
const refreshToken = _TokenManager.getRefreshToken();
|
|
840
|
+
if (!accessToken || !refreshToken) {
|
|
841
|
+
return false;
|
|
842
|
+
}
|
|
843
|
+
if (!_TokenManager.isTokenExpired(accessToken)) {
|
|
844
|
+
sdk.setAccessToken(accessToken);
|
|
845
|
+
return true;
|
|
846
|
+
}
|
|
847
|
+
try {
|
|
848
|
+
const newTokens = await sdk.auth.refreshToken(refreshToken);
|
|
849
|
+
_TokenManager.storeTokens(newTokens);
|
|
850
|
+
return true;
|
|
851
|
+
} catch (e) {
|
|
852
|
+
_TokenManager.clearTokens();
|
|
853
|
+
return false;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
_TokenManager.ACCESS_TOKEN_KEY = "sweet_potato_access_token";
|
|
858
|
+
_TokenManager.REFRESH_TOKEN_KEY = "sweet_potato_refresh_token";
|
|
859
|
+
_TokenManager.USER_KEY = "sweet_potato_user";
|
|
860
|
+
var TokenManager = _TokenManager;
|
|
861
|
+
var WalletUtils = class _WalletUtils {
|
|
862
|
+
/**
|
|
863
|
+
* Detect chain type from wallet address
|
|
864
|
+
*/
|
|
865
|
+
static detectChainType(address) {
|
|
866
|
+
if (/^0x[a-fA-F0-9]{40}$/.test(address)) {
|
|
867
|
+
return "ethereum";
|
|
868
|
+
}
|
|
869
|
+
if (/^bc1[a-z0-9]{39,59}$/.test(address)) {
|
|
870
|
+
return "bitcoin";
|
|
871
|
+
}
|
|
872
|
+
if (/^[1-9A-HJ-NP-Za-km-z]{32}$/.test(address) || /^[1-9A-HJ-NP-Za-km-z]{44}$/.test(address)) {
|
|
873
|
+
return "solana";
|
|
874
|
+
}
|
|
875
|
+
if (/^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(address) && address.length >= 26 && address.length <= 35) {
|
|
876
|
+
return "bitcoin";
|
|
877
|
+
}
|
|
878
|
+
if (/^[1-9A-HJ-NP-Za-km-z]{35,44}$/.test(address)) {
|
|
879
|
+
return "solana";
|
|
880
|
+
}
|
|
881
|
+
return null;
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Validate wallet address format
|
|
885
|
+
*/
|
|
886
|
+
static isValidAddress(address, chainType) {
|
|
887
|
+
if (!chainType) {
|
|
888
|
+
chainType = _WalletUtils.detectChainType(address) || "ethereum";
|
|
889
|
+
}
|
|
890
|
+
switch (chainType) {
|
|
891
|
+
case "solana":
|
|
892
|
+
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address);
|
|
893
|
+
case "ethereum":
|
|
894
|
+
case "base":
|
|
895
|
+
return /^0x[a-fA-F0-9]{40}$/.test(address);
|
|
896
|
+
case "bitcoin":
|
|
897
|
+
return /^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(address) || /^bc1[a-z0-9]{39,59}$/.test(address);
|
|
898
|
+
default:
|
|
899
|
+
return false;
|
|
900
|
+
}
|
|
146
901
|
}
|
|
147
902
|
};
|
|
148
|
-
var index_default = SPAPSClient;
|
|
149
903
|
export {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
904
|
+
AuthService,
|
|
905
|
+
HttpClient,
|
|
906
|
+
PaymentsService,
|
|
907
|
+
SweetPotatoAPIError,
|
|
908
|
+
SweetPotatoSDK,
|
|
909
|
+
TokenManager,
|
|
910
|
+
WalletUtils,
|
|
911
|
+
createSweetPotatoSDK,
|
|
912
|
+
SweetPotatoSDK as default
|
|
154
913
|
};
|