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/README.md CHANGED
@@ -1,164 +1,700 @@
1
- # @spaps/sdk
1
+ # Sweet Potato SDK
2
2
 
3
- > Sweet Potato Authentication & Payment Service SDK
3
+ [![npm version](https://badge.fury.io/js/spaps-sdk.svg)](https://www.npmjs.com/package/spaps-sdk)
4
+ [![TypeScript](https://img.shields.io/badge/TypeScript-4.5%2B-blue)](https://www.typescriptlang.org/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
6
 
5
- Zero-config client for SPAPS authentication and payments. Works automatically with local development mode.
7
+ A comprehensive TypeScript SDK for integrating with the Sweet Potato Authentication and Payment Service (SPAPS). This SDK provides complete functionality for user authentication, Stripe payment processing, subscription management, and more.
8
+
9
+ **[πŸ“š Full API Documentation](../API_INTEGRATION_GUIDE.md) | [πŸ› οΈ Stripe Admin Guide](../STRIPE_ADMIN_GUIDE.md)**
10
+
11
+ ## Features
12
+
13
+ ### Authentication
14
+ - πŸ” **Multi-wallet Authentication**: Support for Solana, Ethereum, Bitcoin, and Base wallets
15
+ - πŸ”‘ **Traditional Authentication**: Email/password and magic link authentication
16
+ - πŸ”„ **Token Management**: Automatic token refresh and secure storage utilities
17
+ - 🧰 **Wallet Utilities**: Address validation, chain detection
18
+
19
+ ### Payments & Subscriptions
20
+ - πŸ’³ **Stripe Checkout Sessions**: One-time payments and subscriptions
21
+ - πŸ“¦ **Product Management**: List, create, update products and prices
22
+ - πŸ”„ **Subscription Management**: Create, update, cancel subscriptions
23
+ - πŸͺ **Customer Portal**: Self-service billing management
24
+ - 🎣 **Webhook Handling**: Secure event processing
25
+
26
+ ### Developer Experience
27
+ - 🎯 **TypeScript First**: Full TypeScript support with comprehensive type definitions
28
+ - πŸ›‘οΈ **Error Handling**: Robust error handling with custom error types
29
+ - πŸ” **Retry Logic**: Built-in retry mechanism with exponential backoff
30
+ - βš›οΈ **React Integration**: Ready-to-use hooks and components
31
+ - πŸ“š **Extensive Examples**: Real-world usage patterns
32
+ - πŸ§ͺ **Well Tested**: Comprehensive test suite with high coverage
6
33
 
7
34
  ## Installation
8
35
 
9
36
  ```bash
10
- npm install @spaps/sdk
37
+ npm install spaps-sdk
11
38
  # or
12
- yarn add @spaps/sdk
39
+ yarn add spaps-sdk
40
+ # or
41
+ pnpm add spaps-sdk
13
42
  ```
14
43
 
44
+ > **πŸ“ Important:** SPAPS runs on port **3456**. This is standardized across all tools.
45
+
46
+ ### Requirements
47
+
48
+ - Node.js 14+ or modern browser
49
+ - TypeScript 4.5+ (optional, for TypeScript projects)
50
+
15
51
  ## Quick Start
16
52
 
17
- ```javascript
18
- import { SPAPSClient } from '@spaps/sdk';
19
- // or
20
- const { SPAPSClient } = require('@spaps/sdk');
53
+ ### Basic Setup
21
54
 
22
- // Auto-detects local mode - no API key needed for localhost!
23
- const spaps = new SPAPSClient({
24
- apiUrl: 'http://localhost:3300' // Optional, auto-detected
25
- });
55
+ ```typescript
56
+ import { SweetPotatoSDK, TokenManager } from 'spaps-sdk';
26
57
 
27
- // Login
28
- const { data } = await spaps.login('user@example.com', 'password');
29
- console.log('User:', data.user);
58
+ // Initialize the SDK
59
+ const sdk = new SweetPotatoSDK({
60
+ apiUrl: 'http://localhost:3456', // Always port 3456 for local dev
61
+ // apiUrl: 'https://api.sweetpotato.dev', // Production (not available yet)
62
+ apiKey: process.env.SPAPS_API_KEY || 'test_key_local_dev_only',
63
+ timeout: 30000, // Optional: 30 second timeout
64
+ retries: 3 // Optional: 3 retry attempts
65
+ });
30
66
 
31
- // Check authentication
32
- if (spaps.isAuthenticated()) {
33
- const user = await spaps.getUser();
34
- console.log('Current user:', user.data);
35
- }
67
+ // Auto-restore authentication state (browser only)
68
+ await TokenManager.autoRefreshToken(sdk);
36
69
  ```
37
70
 
38
- ## Features
71
+ ## Authentication Examples
72
+
73
+ ### Wallet Authentication (Complete Flow)
74
+
75
+ ```typescript
76
+ // Complete implementation with proper signature handling
77
+ const walletAddress = '0x742d35CC6354C7Cb24b5d2C2C7f9Ff5Ef8B4d5f6';
78
+
79
+ const authResponse = await sdk.auth.authenticateWallet(
80
+ walletAddress,
81
+ async (message) => {
82
+ // The SDK provides the message to sign
83
+ // You must return the signed message
84
+
85
+ // Browser (MetaMask):
86
+ if (typeof window !== 'undefined' && window.ethereum) {
87
+ return await window.ethereum.request({
88
+ method: 'personal_sign',
89
+ params: [message, walletAddress]
90
+ });
91
+ }
92
+
93
+ // Node.js (ethers.js):
94
+ // const { Wallet } = require('ethers');
95
+ // const wallet = new Wallet(privateKey);
96
+ // return await wallet.signMessage(message);
97
+ },
98
+ 'ethereum', // Chain type: 'ethereum', 'solana', 'bitcoin', 'base'
99
+ 'username123' // Optional: username for new users
100
+ );
101
+
102
+ // Store tokens for future use
103
+ TokenManager.storeTokens(authResponse);
104
+ console.log('User:', authResponse.user);
105
+ ```
39
106
 
40
- ### πŸš€ Zero Configuration
41
- - **Auto-detects local mode** - No API key needed for localhost
42
- - **Auto-refreshes tokens** - Handles expired tokens automatically
43
- - **TypeScript support** - Full type definitions included
107
+ ### Email/Password Authentication
44
108
 
45
- ### πŸ” Authentication Methods
46
- ```javascript
47
- // Email/Password
48
- await spaps.login(email, password);
49
- await spaps.register(email, password);
109
+ ```typescript
110
+ const authResponse = await sdk.auth.signInWithPassword({
111
+ email: 'user@example.com',
112
+ password: 'securePassword123!'
113
+ });
50
114
 
51
- // Wallet Authentication
52
- await spaps.walletSignIn(walletAddress, signature, message, 'solana');
115
+ TokenManager.storeTokens(authResponse);
116
+ ```
53
117
 
54
- // Token Management
55
- await spaps.refresh();
56
- await spaps.logout();
118
+ ### Magic Link Authentication
57
119
 
58
- // Get User
59
- const user = await spaps.getUser();
120
+ ```typescript
121
+ await sdk.auth.requestMagicLink({
122
+ email: 'user@example.com',
123
+ redirect_url: 'https://myapp.com/auth/callback'
124
+ });
125
+ // User will receive email with authentication link
60
126
  ```
61
127
 
62
- ### πŸ’³ Stripe Integration
63
- ```javascript
64
- // Create checkout session
65
- const session = await spaps.createCheckoutSession(priceId, successUrl);
66
- window.location.href = session.data.url;
128
+ ## Payment Examples
129
+
130
+ ### One-Time Payment
67
131
 
68
- // Manage subscription
69
- const subscription = await spaps.getSubscription();
70
- await spaps.cancelSubscription();
132
+ ```typescript
133
+ // Using existing price
134
+ const checkoutSession = await sdk.payments.createPaymentCheckout({
135
+ price_id: 'price_1234567890',
136
+ success_url: 'https://myapp.com/success',
137
+ cancel_url: 'https://myapp.com/cancel',
138
+ metadata: {
139
+ order_id: 'order_123',
140
+ user_type: 'premium'
141
+ }
142
+ });
143
+
144
+ // Redirect to Stripe Checkout
145
+ window.location.href = checkoutSession.url!;
71
146
  ```
72
147
 
73
- ### πŸ“Š Usage Tracking
74
- ```javascript
75
- // Check balance
76
- const balance = await spaps.getUsageBalance();
77
- console.log(`Credits: ${balance.data.balance}`);
148
+ ### Dynamic Pricing
149
+
150
+ ```typescript
151
+ // Create payment with custom price
152
+ const checkoutSession = await sdk.payments.createPaymentCheckout({
153
+ product_name: 'Premium Feature Access',
154
+ amount: 2999, // $29.99 in cents
155
+ currency: 'usd',
156
+ quantity: 1,
157
+ success_url: 'https://myapp.com/success',
158
+ cancel_url: 'https://myapp.com/cancel'
159
+ });
160
+ ```
78
161
 
79
- // Record usage
80
- await spaps.recordUsage('api-call', 1);
162
+ ### Subscription Creation
163
+
164
+ ```typescript
165
+ const subscriptionCheckout = await sdk.payments.createSubscriptionCheckout({
166
+ price_id: 'price_monthly_subscription',
167
+ success_url: 'https://myapp.com/subscription-success',
168
+ cancel_url: 'https://myapp.com/subscription-cancel',
169
+ trial_period_days: 14,
170
+ metadata: {
171
+ subscription_type: 'pro',
172
+ source: 'website'
173
+ }
174
+ });
81
175
  ```
82
176
 
83
- ## Configuration
177
+ ### Product Management
84
178
 
85
- ### Production Mode
86
- ```javascript
87
- const spaps = new SPAPSClient({
88
- apiUrl: 'https://api.sweetpotato.com',
89
- apiKey: 'spaps_your_api_key_here',
90
- timeout: 10000 // Optional timeout in ms
179
+ ```typescript
180
+ // List all products
181
+ const products = await sdk.payments.listProducts({
182
+ category: 'subscription',
183
+ active: true,
184
+ limit: 20
185
+ });
186
+
187
+ // Get specific product with prices
188
+ const product = await sdk.payments.getProduct('prod_123');
189
+
190
+ // Create new product (admin only)
191
+ const newProduct = await sdk.payments.createProduct({
192
+ name: 'New Premium Plan',
193
+ description: 'Enhanced features for power users',
194
+ category: 'subscription',
195
+ metadata: {
196
+ tier: 'premium',
197
+ features: 'advanced-analytics,priority-support'
198
+ }
91
199
  });
92
200
  ```
93
201
 
94
- ### Local Development Mode (Auto-detected)
95
- ```javascript
96
- const spaps = new SPAPSClient();
97
- // Automatically uses http://localhost:3300 with no API key
202
+ ### Subscription Management
203
+
204
+ ```typescript
205
+ // List user subscriptions
206
+ const subscriptions = await sdk.payments.listSubscriptions({
207
+ status: 'active'
208
+ });
209
+
210
+ // Update subscription
211
+ await sdk.payments.updateSubscription('sub_123', {
212
+ price_id: 'price_new_plan',
213
+ metadata: { upgrade_reason: 'user_requested' }
214
+ });
215
+
216
+ // Cancel subscription at period end
217
+ await sdk.payments.updateSubscription('sub_123', {
218
+ cancel_at_period_end: true
219
+ });
220
+
221
+ // Create customer portal session
222
+ const portalSession = await sdk.payments.createCustomerPortalSession({
223
+ return_url: 'https://myapp.com/account'
224
+ });
225
+ window.location.href = portalSession.url;
98
226
  ```
99
227
 
100
- ### Environment Variables
101
- ```bash
102
- # .env
103
- SPAPS_API_URL=https://api.sweetpotato.com
104
- SPAPS_API_KEY=spaps_your_api_key_here
228
+ ## Token Management
229
+
230
+ ### Automatic Token Refresh
231
+
232
+ ```typescript
233
+ // Set up automatic token refresh
234
+ async function setupAutoRefresh() {
235
+ const refreshSuccess = await TokenManager.autoRefreshToken(sdk);
236
+
237
+ if (refreshSuccess) {
238
+ console.log('Authentication restored from stored tokens');
239
+ } else {
240
+ console.log('No valid tokens found, user needs to authenticate');
241
+ }
242
+ }
105
243
 
106
- # Next.js
107
- NEXT_PUBLIC_SPAPS_API_URL=https://api.sweetpotato.com
244
+ // Manual token refresh
245
+ async function refreshTokens() {
246
+ try {
247
+ const refreshToken = TokenManager.getRefreshToken();
248
+ if (refreshToken) {
249
+ const newTokens = await sdk.auth.refreshToken(refreshToken);
250
+ TokenManager.storeTokens(newTokens);
251
+ }
252
+ } catch (error) {
253
+ console.error('Token refresh failed:', error);
254
+ // Redirect to login
255
+ }
256
+ }
108
257
  ```
109
258
 
110
- ## Helper Methods
259
+ ### Logout
111
260
 
112
- ```javascript
113
- // Check if authenticated
114
- spaps.isAuthenticated() // boolean
261
+ ```typescript
262
+ async function logout() {
263
+ try {
264
+ await sdk.auth.logout();
265
+ TokenManager.clearTokens();
266
+ console.log('Successfully logged out');
267
+ } catch (error) {
268
+ console.error('Logout failed:', error);
269
+ }
270
+ }
271
+ ```
115
272
 
116
- // Get current access token
117
- spaps.getAccessToken() // string | undefined
273
+ ## User Management
118
274
 
119
- // Set access token manually
120
- spaps.setAccessToken(token)
275
+ ### Get Current User
121
276
 
122
- // Check if in local mode
123
- spaps.isLocalMode() // boolean
277
+ ```typescript
278
+ async function getCurrentUser() {
279
+ try {
280
+ const user = await sdk.auth.getCurrentUser();
281
+ console.log('Current user:', user);
282
+ return user;
283
+ } catch (error) {
284
+ console.error('Failed to get user:', error);
285
+ // User might not be authenticated
286
+ }
287
+ }
288
+ ```
289
+
290
+ ### Check Authentication Status
124
291
 
125
- // Health check
126
- await spaps.health()
292
+ ```typescript
293
+ function checkAuthStatus() {
294
+ if (sdk.auth.isAuthenticated()) {
295
+ console.log('User is authenticated');
296
+ } else {
297
+ console.log('User needs to log in');
298
+ }
299
+ }
127
300
  ```
128
301
 
129
- ## Import Styles
302
+ ## Utility Functions
303
+
304
+ ### Wallet Address Validation
130
305
 
131
- All these work:
132
- ```javascript
133
- // ES6 Import
134
- import { SPAPSClient } from '@spaps/sdk';
135
- import SPAPSClient from '@spaps/sdk';
306
+ ```typescript
307
+ import { WalletUtils } from '@sweet-potato/auth-sdk';
136
308
 
137
- // CommonJS
138
- const { SPAPSClient } = require('@spaps/sdk');
139
- const SPAPSClient = require('@spaps/sdk');
309
+ // Detect chain type
310
+ const chainType = WalletUtils.detectChainType('0x742d35Cc6634C0532925a3b8D6Ac6d8F49c3589F');
311
+ console.log(chainType); // 'ethereum'
140
312
 
141
- // Alternative names
142
- import { SPAPS } from '@spaps/sdk';
143
- import { SweetPotatoSDK } from '@spaps/sdk';
313
+ // Validate address format
314
+ const isValid = WalletUtils.isValidAddress('0x742d35Cc6634C0532925a3b8D6Ac6d8F49c3589F', 'ethereum');
315
+ console.log(isValid); // true
316
+
317
+ // Auto-detect and validate
318
+ const isValidAuto = WalletUtils.isValidAddress('0x742d35Cc6634C0532925a3b8D6Ac6d8F49c3589F');
319
+ console.log(isValidAuto); // true
320
+ ```
321
+
322
+ ### Token Utilities
323
+
324
+ ```typescript
325
+ // Check if token is expired
326
+ const token = TokenManager.getAccessToken();
327
+ if (token && TokenManager.isTokenExpired(token)) {
328
+ console.log('Token is expired, refreshing...');
329
+ await refreshTokens();
330
+ }
144
331
  ```
145
332
 
146
333
  ## Error Handling
147
334
 
148
- ```javascript
335
+ ```typescript
336
+ import { SweetPotatoAPIError } from '@sweet-potato/auth-sdk';
337
+
149
338
  try {
150
- await spaps.login(email, password);
339
+ await sdk.auth.signInWithPassword({
340
+ email: 'invalid@example.com',
341
+ password: 'wrongpassword'
342
+ });
151
343
  } catch (error) {
152
- if (error.response?.status === 401) {
153
- console.error('Invalid credentials');
154
- } else if (error.response?.status === 429) {
155
- console.error('Rate limited');
344
+ if (error instanceof SweetPotatoAPIError) {
345
+ console.error('API Error:', {
346
+ message: error.message,
347
+ code: error.code,
348
+ status: error.status,
349
+ details: error.details
350
+ });
351
+
352
+ // Handle specific error codes
353
+ switch (error.code) {
354
+ case 'INVALID_CREDENTIALS':
355
+ console.log('Please check your email and password');
356
+ break;
357
+ case 'RATE_LIMITED':
358
+ console.log('Too many attempts, please wait');
359
+ break;
360
+ default:
361
+ console.log('An unexpected error occurred');
362
+ }
363
+ }
364
+ }
365
+ ```
366
+
367
+ ## Advanced Usage
368
+
369
+ ### Custom Requests
370
+
371
+ ```typescript
372
+ // Make custom authenticated requests
373
+ async function makeCustomRequest() {
374
+ try {
375
+ const response = await sdk.request(
376
+ 'GET',
377
+ '/api/custom-endpoint',
378
+ null,
379
+ true // requires authentication
380
+ );
381
+
382
+ console.log('Custom response:', response.data);
383
+ } catch (error) {
384
+ console.error('Custom request failed:', error);
385
+ }
386
+ }
387
+ ```
388
+
389
+ ### Health Check
390
+
391
+ ```typescript
392
+ async function checkAPIHealth() {
393
+ const isHealthy = await sdk.healthCheck();
394
+ if (isHealthy) {
395
+ console.log('API is healthy');
156
396
  } else {
157
- console.error('Error:', error.message);
397
+ console.log('API is down or unreachable');
158
398
  }
159
399
  }
160
400
  ```
161
401
 
402
+ ## React Integration Example
403
+
404
+ ```typescript
405
+ import React, { useEffect, useState } from 'react';
406
+ import { createSweetPotatoSDK, TokenManager, User } from '@sweet-potato/auth-sdk';
407
+
408
+ const sdk = createSweetPotatoSDK({
409
+ apiUrl: process.env.REACT_APP_API_URL!,
410
+ apiKey: process.env.REACT_APP_API_KEY!
411
+ });
412
+
413
+ export function useAuth() {
414
+ const [user, setUser] = useState<User | null>(null);
415
+ const [loading, setLoading] = useState(true);
416
+
417
+ useEffect(() => {
418
+ async function restoreAuth() {
419
+ try {
420
+ const restored = await TokenManager.autoRefreshToken(sdk);
421
+ if (restored) {
422
+ const currentUser = await sdk.auth.getCurrentUser();
423
+ setUser(currentUser);
424
+ }
425
+ } catch (error) {
426
+ console.error('Failed to restore authentication:', error);
427
+ } finally {
428
+ setLoading(false);
429
+ }
430
+ }
431
+
432
+ restoreAuth();
433
+ }, []);
434
+
435
+ const login = async (email: string, password: string) => {
436
+ const result = await sdk.auth.signInWithPassword({ email, password });
437
+ TokenManager.storeTokens(result);
438
+ setUser(result.user);
439
+ return result;
440
+ };
441
+
442
+ const logout = async () => {
443
+ await sdk.auth.logout();
444
+ TokenManager.clearTokens();
445
+ setUser(null);
446
+ };
447
+
448
+ return {
449
+ user,
450
+ loading,
451
+ login,
452
+ logout,
453
+ isAuthenticated: !!user
454
+ };
455
+ }
456
+ ```
457
+
458
+ ## Configuration Options
459
+
460
+ ```typescript
461
+ interface SweetPotatoConfig {
462
+ apiUrl: string; // Required: Your API base URL
463
+ apiKey: string; // Required: Your application API key
464
+ timeout?: number; // Optional: Request timeout in ms (default: 30000)
465
+ retries?: number; // Optional: Number of retries (default: 3)
466
+ }
467
+ ```
468
+
469
+ ## TypeScript Types
470
+
471
+ The SDK exports comprehensive TypeScript types for all API responses and request payloads:
472
+
473
+ ```typescript
474
+ import type {
475
+ User,
476
+ UserWallet,
477
+ AuthResponse,
478
+ NonceResponse,
479
+ WalletSignInRequest,
480
+ TraditionalLoginRequest,
481
+ ApiResponse,
482
+ SweetPotatoAPIError
483
+ } from '@sweet-potato/auth-sdk';
484
+ ```
485
+
486
+ ## Browser Compatibility
487
+
488
+ The SDK supports all modern browsers with ES2018+ support. For older browsers, you may need to include polyfills for:
489
+
490
+ - `fetch` API
491
+ - `Promise`
492
+ - `async/await`
493
+
494
+ ## Error Codes
495
+
496
+ Common error codes you might encounter:
497
+
498
+ - `INVALID_CREDENTIALS`: Invalid email/password or wallet signature
499
+ - `MISSING_REQUIRED_FIELDS`: Required fields are missing from request
500
+ - `INVALID_SIGNATURE`: Wallet signature verification failed
501
+ - `RATE_LIMITED`: Too many requests, rate limit exceeded
502
+ - `UNAUTHORIZED`: Invalid or expired tokens
503
+ - `INVALID_APPLICATION`: Invalid API key or application configuration
504
+ - `INTERNAL_SERVER_ERROR`: Server-side error occurred
505
+
506
+ ## API Reference
507
+
508
+ ### SDK Classes
509
+
510
+ #### `SweetPotatoSDK`
511
+ Main SDK class that provides access to all services.
512
+
513
+ #### `AuthService`
514
+ - `authenticateWallet()` - Complete wallet authentication flow
515
+ - `signInWithPassword()` - Email/password login
516
+ - `signUp()` - Create new account
517
+ - `requestMagicLink()` - Send magic link email
518
+ - `verifyMagicLink()` - Verify magic link token
519
+ - `refreshToken()` - Refresh access token
520
+ - `logout()` - Sign out and invalidate tokens
521
+ - `getCurrentUser()` - Get authenticated user
522
+ - `isAuthenticated()` - Check auth status
523
+
524
+ #### `PaymentsService`
525
+ - `createCheckoutSession()` - Create Stripe checkout
526
+ - `createPaymentCheckout()` - Simplified one-time payment
527
+ - `createSubscriptionCheckout()` - Simplified subscription
528
+ - `listProducts()` - Get available products
529
+ - `getProduct()` - Get product details
530
+ - `createProduct()` - Create product (admin)
531
+ - `updateProduct()` - Update product (admin)
532
+ - `syncProducts()` - Sync from Stripe (admin)
533
+ - `listSubscriptions()` - User's subscriptions
534
+ - `updateSubscription()` - Modify subscription
535
+ - `cancelSubscription()` - Cancel subscription
536
+ - `createCustomerPortalSession()` - Billing portal
537
+
538
+ #### `TokenManager`
539
+ Static utility class for browser token management.
540
+ - `storeTokens()` - Save tokens to localStorage
541
+ - `getAccessToken()` - Retrieve access token
542
+ - `getRefreshToken()` - Retrieve refresh token
543
+ - `clearTokens()` - Remove all tokens
544
+ - `isTokenExpired()` - Check token expiration
545
+ - `autoRefreshToken()` - Auto-refresh if needed
546
+
547
+ #### `WalletUtils`
548
+ Static utility class for wallet operations.
549
+ - `detectChainType()` - Identify blockchain from address
550
+ - `isValidAddress()` - Validate wallet address format
551
+
552
+ ## What's NOT in the SDK
553
+
554
+ > **⚠️ Important:** These features require direct API calls with admin authentication.
555
+
556
+ ### Whitelist Management
557
+ ❌ **Not available:** `sdk.whitelist.check()`, `sdk.admin.addToWhitelist()`
558
+
559
+ Whitelist operations require admin JWT authentication and must be done via direct API calls:
560
+
561
+ ```typescript
562
+ // Authenticate as admin first
563
+ const adminAuth = await sdk.auth.signInWithPassword({
564
+ email: 'admin@example.com',
565
+ password: 'admin_password'
566
+ });
567
+
568
+ // Use JWT for admin API calls
569
+ const response = await fetch(`${apiUrl}/api/v1/whitelist`, {
570
+ method: 'POST',
571
+ headers: {
572
+ 'Authorization': `Bearer ${adminAuth.access_token}`,
573
+ 'X-API-Key': apiKey,
574
+ 'Content-Type': 'application/json'
575
+ },
576
+ body: JSON.stringify({
577
+ email: 'vip@example.com',
578
+ tier: 'premium',
579
+ bypass_payment: true
580
+ })
581
+ });
582
+ ```
583
+
584
+ ### Admin Operations
585
+ ❌ **Not available:** `sdk.admin.*` methods
586
+
587
+ Admin operations require JWT authentication:
588
+ - Application management (create/rotate API keys)
589
+ - User management (admin dashboard)
590
+ - Direct database operations
591
+ - Product sync from Stripe
592
+
593
+ All admin operations follow this pattern:
594
+ 1. Authenticate as admin user via `sdk.auth.signInWithPassword()`
595
+ 2. Use the JWT token for direct API calls
596
+ 3. Include both JWT and API key in headers
597
+
598
+ See [Stripe Admin Guide](../STRIPE_ADMIN_GUIDE.md) for product management instructions.
599
+
600
+ ## Local Development Mode
601
+
602
+ When using `npx spaps local`:
603
+ - βœ… Auto-authentication enabled (no signup needed)
604
+ - βœ… Test users pre-created: 'user', 'admin', 'premium'
605
+ - βœ… CORS enabled for all origins
606
+ - βœ… No real API keys required
607
+ - βœ… Mock Stripe integration ready
608
+ - βœ… Runs on port **3456** by default
609
+
610
+ ```bash
611
+ # Start local server
612
+ npx spaps local
613
+
614
+ # Your app can now connect to:
615
+ http://localhost:3456
616
+ ```
617
+
618
+ ## Production Notes
619
+
620
+ ⚠️ **Production API is not yet available.** Currently, only local development mode is supported.
621
+
622
+ Future production URL: `https://api.sweetpotato.dev` (coming soon)
623
+
624
+ ## Troubleshooting
625
+
626
+ ### Common Issues
627
+
628
+ **Wrong Port**
629
+ ```typescript
630
+ // ❌ Wrong
631
+ apiUrl: 'http://localhost:3000'
632
+ apiUrl: 'http://localhost:3300'
633
+
634
+ // βœ… Correct - always use 3456
635
+ apiUrl: 'http://localhost:3456'
636
+ ```
637
+
638
+ **CORS Errors**
639
+ ```typescript
640
+ // In local mode, CORS is enabled for all origins
641
+ // In production, ensure your domain is whitelisted
642
+ ```
643
+
644
+ **Token Expired**
645
+ ```typescript
646
+ // Use TokenManager for automatic refresh
647
+ await TokenManager.autoRefreshToken(sdk);
648
+ ```
649
+
650
+ **Rate Limiting**
651
+ ```typescript
652
+ // SDK automatically retries with exponential backoff
653
+ // Configure retries in SDK initialization
654
+ const sdk = new SweetPotatoSDK({
655
+ apiUrl: '...',
656
+ apiKey: '...',
657
+ retries: 5 // Increase retry count
658
+ });
659
+ ```
660
+
661
+ ## Migration Guide
662
+
663
+ ### From v0.x to v1.0
664
+
665
+ ```typescript
666
+ // Old (v0.x)
667
+ const sdk = new SweetPotatoSDK(apiUrl, apiKey);
668
+
669
+ // New (v1.0)
670
+ const sdk = new SweetPotatoSDK({
671
+ apiUrl,
672
+ apiKey,
673
+ timeout: 30000,
674
+ retries: 3
675
+ });
676
+ ```
677
+
678
+ ## Contributing
679
+
680
+ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
681
+
682
+ ## Security
683
+
684
+ - **Never expose API keys in client-side code**
685
+ - **Use environment variables for sensitive data**
686
+ - **Enable HTTPS in production**
687
+ - **Implement proper CORS policies**
688
+
689
+ Report security vulnerabilities to security@sweetpotato.dev
690
+
691
+ ## Support
692
+
693
+ - πŸ“– [Full Documentation](../API_INTEGRATION_GUIDE.md)
694
+ - πŸ’¬ Discord: [discord.gg/sweetpotato](https://discord.gg/sweetpotato)
695
+ - πŸ“§ Email: support@sweetpotato.dev
696
+ - πŸ› Issues: [GitHub Issues](https://github.com/sweet-potato/sdk/issues)
697
+
162
698
  ## License
163
699
 
164
- MIT
700
+ MIT Β© Sweet Potato Team