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