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