spaps-sdk 1.0.1 โ 1.1.0
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 +204 -545
- package/dist/index.d.mts +302 -0
- package/dist/index.d.ts +302 -0
- package/dist/index.js +379 -850
- package/dist/index.mjs +370 -836
- package/package.json +40 -34
- package/.env.example +0 -23
- package/admin-utils.ts +0 -243
package/README.md
CHANGED
|
@@ -1,640 +1,299 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @spaps/sdk
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://www.typescriptlang.org/)
|
|
5
|
-
[](https://opensource.org/licenses/MIT)
|
|
3
|
+
> Sweet Potato Authentication & Payment Service SDK
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
Zero-config client for SPAPS authentication, payments, and permission checking. Works automatically with local development mode.
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
## ๐ New in v1.1.0: Admin API Methods!
|
|
10
8
|
|
|
11
|
-
|
|
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
|
|
33
|
-
|
|
34
|
-
## Installation
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
npm install @sweet-potato/sdk
|
|
38
|
-
# or
|
|
39
|
-
yarn add @sweet-potato/sdk
|
|
40
|
-
# or
|
|
41
|
-
pnpm add @sweet-potato/sdk
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### Requirements
|
|
45
|
-
|
|
46
|
-
- Node.js 14+ or modern browser
|
|
47
|
-
- TypeScript 4.5+ (optional, for TypeScript projects)
|
|
48
|
-
|
|
49
|
-
## Quick Start
|
|
50
|
-
|
|
51
|
-
### Basic Setup
|
|
9
|
+
Built-in admin API methods for Stripe product management:
|
|
52
10
|
|
|
53
11
|
```typescript
|
|
54
|
-
import {
|
|
12
|
+
import { SPAPSClient } from 'spaps-sdk';
|
|
55
13
|
|
|
56
|
-
|
|
57
|
-
const sdk = new SweetPotatoSDK({
|
|
58
|
-
apiUrl: 'http://localhost:3456', // Development
|
|
59
|
-
// apiUrl: 'https://api.sweetpotato.dev', // Production
|
|
14
|
+
const spaps = new SPAPSClient({
|
|
60
15
|
apiKey: 'your-api-key',
|
|
61
|
-
|
|
62
|
-
retries: 3 // Optional: 3 retry attempts
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// Auto-restore authentication state (browser only)
|
|
66
|
-
await TokenManager.autoRefreshToken(sdk);
|
|
67
|
-
```
|
|
68
|
-
|
|
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
|
-
```
|
|
93
|
-
|
|
94
|
-
### Email/Password Authentication
|
|
95
|
-
|
|
96
|
-
```typescript
|
|
97
|
-
const authResponse = await sdk.auth.signInWithPassword({
|
|
98
|
-
email: 'user@example.com',
|
|
99
|
-
password: 'securePassword123!'
|
|
16
|
+
apiUrl: 'https://api.sweetpotato.dev'
|
|
100
17
|
});
|
|
101
18
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
### Magic Link Authentication
|
|
19
|
+
// Authenticate as admin
|
|
20
|
+
await spaps.signIn('admin@example.com', 'password');
|
|
106
21
|
|
|
107
|
-
|
|
108
|
-
await
|
|
109
|
-
|
|
110
|
-
|
|
22
|
+
// Admin API methods
|
|
23
|
+
await spaps.admin.createProduct({
|
|
24
|
+
name: 'Premium Plan',
|
|
25
|
+
category: 'subscription',
|
|
26
|
+
description: 'Advanced features'
|
|
111
27
|
});
|
|
112
|
-
// User will receive email with authentication link
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
## Payment Examples
|
|
116
|
-
|
|
117
|
-
### One-Time Payment
|
|
118
28
|
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
}
|
|
29
|
+
await spaps.admin.updateProduct('prod_123', {
|
|
30
|
+
name: 'Premium Plan Pro'
|
|
129
31
|
});
|
|
130
32
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
|
33
|
+
await spaps.admin.createPrice({
|
|
34
|
+
product_id: 'prod_123',
|
|
35
|
+
unit_amount: 2999,
|
|
142
36
|
currency: 'usd',
|
|
143
|
-
|
|
144
|
-
success_url: 'https://myapp.com/success',
|
|
145
|
-
cancel_url: 'https://myapp.com/cancel'
|
|
37
|
+
interval: 'month'
|
|
146
38
|
});
|
|
147
|
-
```
|
|
148
39
|
|
|
149
|
-
|
|
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
|
-
});
|
|
40
|
+
// Super admin operations
|
|
41
|
+
await spaps.admin.syncProducts();
|
|
162
42
|
```
|
|
163
43
|
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
}
|
|
186
|
-
});
|
|
187
|
-
```
|
|
44
|
+
## ๐ Permission Utilities
|
|
188
45
|
|
|
189
|
-
|
|
46
|
+
Built-in permission checking and role-based access control:
|
|
190
47
|
|
|
191
48
|
```typescript
|
|
192
|
-
|
|
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;
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
## Token Management
|
|
49
|
+
import { isAdminAccount, canAccessAdmin, getUserRole } from 'spaps-sdk';
|
|
216
50
|
|
|
217
|
-
|
|
51
|
+
// Check admin status
|
|
52
|
+
const isAdmin = isAdminAccount('buildooor@gmail.com'); // true
|
|
218
53
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
-
}
|
|
54
|
+
// Check admin access with detailed result
|
|
55
|
+
const adminCheck = canAccessAdmin(user);
|
|
56
|
+
if (adminCheck.allowed) {
|
|
57
|
+
// Show admin UI
|
|
229
58
|
}
|
|
230
59
|
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
TokenManager.storeTokens(newTokens);
|
|
238
|
-
}
|
|
239
|
-
} catch (error) {
|
|
240
|
-
console.error('Token refresh failed:', error);
|
|
241
|
-
// Redirect to login
|
|
242
|
-
}
|
|
60
|
+
// Get user role
|
|
61
|
+
const role = getUserRole('user@example.com'); // 'user' | 'admin' | 'guest'
|
|
62
|
+
|
|
63
|
+
// Check if authenticated user is admin
|
|
64
|
+
if (spaps.isAdmin(currentUser)) {
|
|
65
|
+
// Show admin features
|
|
243
66
|
}
|
|
244
67
|
```
|
|
245
68
|
|
|
246
|
-
|
|
69
|
+
See [PERMISSIONS.md](./PERMISSIONS.md) for React examples and complete documentation.
|
|
247
70
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
} catch (error) {
|
|
255
|
-
console.error('Logout failed:', error);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
71
|
+
## Installation
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npm install @spaps/sdk
|
|
75
|
+
# or
|
|
76
|
+
yarn add @spaps/sdk
|
|
258
77
|
```
|
|
259
78
|
|
|
260
|
-
##
|
|
79
|
+
## Quick Start
|
|
261
80
|
|
|
262
|
-
|
|
81
|
+
```javascript
|
|
82
|
+
import { SPAPSClient } from '@spaps/sdk';
|
|
83
|
+
// or
|
|
84
|
+
const { SPAPSClient } = require('@spaps/sdk');
|
|
263
85
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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
|
-
```
|
|
86
|
+
// Auto-detects local mode - no API key needed for localhost!
|
|
87
|
+
const spaps = new SPAPSClient({
|
|
88
|
+
apiUrl: 'http://localhost:3300' // Optional, auto-detected
|
|
89
|
+
});
|
|
276
90
|
|
|
277
|
-
|
|
91
|
+
// Login
|
|
92
|
+
const { data } = await spaps.login('user@example.com', 'password');
|
|
93
|
+
console.log('User:', data.user);
|
|
278
94
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
} else {
|
|
284
|
-
console.log('User needs to log in');
|
|
285
|
-
}
|
|
95
|
+
// Check authentication
|
|
96
|
+
if (spaps.isAuthenticated()) {
|
|
97
|
+
const user = await spaps.getUser();
|
|
98
|
+
console.log('Current user:', user.data);
|
|
286
99
|
}
|
|
287
100
|
```
|
|
288
101
|
|
|
289
|
-
##
|
|
102
|
+
## Features
|
|
290
103
|
|
|
291
|
-
###
|
|
104
|
+
### ๐ Zero Configuration
|
|
105
|
+
- **Auto-detects local mode** - No API key needed for localhost
|
|
106
|
+
- **Auto-refreshes tokens** - Handles expired tokens automatically
|
|
107
|
+
- **TypeScript support** - Full type definitions included
|
|
292
108
|
|
|
293
|
-
|
|
294
|
-
|
|
109
|
+
### ๐ Authentication Methods
|
|
110
|
+
```javascript
|
|
111
|
+
// Email/Password
|
|
112
|
+
await spaps.login(email, password);
|
|
113
|
+
await spaps.register(email, password);
|
|
295
114
|
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
console.log(chainType); // 'ethereum'
|
|
115
|
+
// Wallet Authentication
|
|
116
|
+
await spaps.walletSignIn(walletAddress, signature, message, 'solana');
|
|
299
117
|
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
|
|
118
|
+
// Token Management
|
|
119
|
+
await spaps.refresh();
|
|
120
|
+
await spaps.logout();
|
|
303
121
|
|
|
304
|
-
//
|
|
305
|
-
const
|
|
306
|
-
console.log(isValidAuto); // true
|
|
122
|
+
// Get User
|
|
123
|
+
const user = await spaps.getUser();
|
|
307
124
|
```
|
|
308
125
|
|
|
309
|
-
###
|
|
126
|
+
### ๐ณ Stripe Integration
|
|
127
|
+
```javascript
|
|
128
|
+
// Create checkout session
|
|
129
|
+
const session = await spaps.createCheckoutSession(priceId, successUrl);
|
|
130
|
+
window.location.href = session.data.url;
|
|
310
131
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (token && TokenManager.isTokenExpired(token)) {
|
|
315
|
-
console.log('Token is expired, refreshing...');
|
|
316
|
-
await refreshTokens();
|
|
317
|
-
}
|
|
132
|
+
// Manage subscription
|
|
133
|
+
const subscription = await spaps.getSubscription();
|
|
134
|
+
await spaps.cancelSubscription();
|
|
318
135
|
```
|
|
319
136
|
|
|
320
|
-
|
|
137
|
+
### ๐ Usage Tracking
|
|
138
|
+
```javascript
|
|
139
|
+
// Check balance
|
|
140
|
+
const balance = await spaps.getUsageBalance();
|
|
141
|
+
console.log(`Credits: ${balance.data.balance}`);
|
|
321
142
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
try {
|
|
326
|
-
await sdk.auth.signInWithPassword({
|
|
327
|
-
email: 'invalid@example.com',
|
|
328
|
-
password: 'wrongpassword'
|
|
329
|
-
});
|
|
330
|
-
} catch (error) {
|
|
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
|
-
}
|
|
143
|
+
// Record usage
|
|
144
|
+
await spaps.recordUsage('api-call', 1);
|
|
352
145
|
```
|
|
353
146
|
|
|
354
|
-
##
|
|
147
|
+
## Configuration
|
|
355
148
|
|
|
356
|
-
###
|
|
149
|
+
### Production Mode
|
|
150
|
+
```javascript
|
|
151
|
+
const spaps = new SPAPSClient({
|
|
152
|
+
apiUrl: 'https://api.sweetpotato.com',
|
|
153
|
+
apiKey: 'spaps_your_api_key_here',
|
|
154
|
+
timeout: 10000 // Optional timeout in ms
|
|
155
|
+
});
|
|
156
|
+
```
|
|
357
157
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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
|
-
}
|
|
158
|
+
### Local Development Mode (Auto-detected)
|
|
159
|
+
```javascript
|
|
160
|
+
const spaps = new SPAPSClient();
|
|
161
|
+
// Automatically uses http://localhost:3300 with no API key
|
|
374
162
|
```
|
|
375
163
|
|
|
376
|
-
###
|
|
164
|
+
### Environment Variables
|
|
165
|
+
```bash
|
|
166
|
+
# .env
|
|
167
|
+
SPAPS_API_URL=https://api.sweetpotato.com
|
|
168
|
+
SPAPS_API_KEY=spaps_your_api_key_here
|
|
377
169
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const isHealthy = await sdk.healthCheck();
|
|
381
|
-
if (isHealthy) {
|
|
382
|
-
console.log('API is healthy');
|
|
383
|
-
} else {
|
|
384
|
-
console.log('API is down or unreachable');
|
|
385
|
-
}
|
|
386
|
-
}
|
|
170
|
+
# Next.js
|
|
171
|
+
NEXT_PUBLIC_SPAPS_API_URL=https://api.sweetpotato.com
|
|
387
172
|
```
|
|
388
173
|
|
|
389
|
-
##
|
|
174
|
+
## Helper Methods
|
|
390
175
|
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
|
|
176
|
+
```javascript
|
|
177
|
+
// Check if authenticated
|
|
178
|
+
spaps.isAuthenticated() // boolean
|
|
394
179
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
apiKey: process.env.REACT_APP_API_KEY!
|
|
398
|
-
});
|
|
180
|
+
// Get current access token
|
|
181
|
+
spaps.getAccessToken() // string | undefined
|
|
399
182
|
|
|
400
|
-
|
|
401
|
-
|
|
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
|
-
```
|
|
183
|
+
// Set access token manually
|
|
184
|
+
spaps.setAccessToken(token)
|
|
444
185
|
|
|
445
|
-
|
|
186
|
+
// Check if in local mode
|
|
187
|
+
spaps.isLocalMode() // boolean
|
|
446
188
|
|
|
447
|
-
|
|
448
|
-
|
|
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
|
-
}
|
|
189
|
+
// Health check
|
|
190
|
+
await spaps.health()
|
|
454
191
|
```
|
|
455
192
|
|
|
456
|
-
##
|
|
193
|
+
## Import Styles
|
|
457
194
|
|
|
458
|
-
|
|
195
|
+
All these work:
|
|
196
|
+
```javascript
|
|
197
|
+
// ES6 Import
|
|
198
|
+
import { SPAPSClient } from '@spaps/sdk';
|
|
199
|
+
import SPAPSClient from '@spaps/sdk';
|
|
459
200
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
TraditionalLoginRequest,
|
|
468
|
-
ApiResponse,
|
|
469
|
-
SweetPotatoAPIError
|
|
470
|
-
} from '@sweet-potato/auth-sdk';
|
|
201
|
+
// CommonJS
|
|
202
|
+
const { SPAPSClient } = require('@spaps/sdk');
|
|
203
|
+
const SPAPSClient = require('@spaps/sdk');
|
|
204
|
+
|
|
205
|
+
// Alternative names
|
|
206
|
+
import { SPAPS } from '@spaps/sdk';
|
|
207
|
+
import { SweetPotatoSDK } from '@spaps/sdk';
|
|
471
208
|
```
|
|
472
209
|
|
|
473
|
-
##
|
|
474
|
-
|
|
475
|
-
The SDK
|
|
476
|
-
|
|
477
|
-
|
|
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:
|
|
210
|
+
## Admin API Methods
|
|
211
|
+
|
|
212
|
+
The SDK includes comprehensive admin methods for Stripe product management:
|
|
213
|
+
|
|
214
|
+
### Product Management
|
|
543
215
|
|
|
544
216
|
```typescript
|
|
545
|
-
//
|
|
546
|
-
const
|
|
547
|
-
|
|
548
|
-
|
|
217
|
+
// Create product (Admin required)
|
|
218
|
+
const product = await spaps.admin.createProduct({
|
|
219
|
+
name: 'Premium Plan',
|
|
220
|
+
category: 'subscription',
|
|
221
|
+
description: 'Advanced features for power users',
|
|
222
|
+
images: ['https://example.com/product-image.jpg'],
|
|
223
|
+
metadata: { feature_set: 'premium' },
|
|
224
|
+
active: true
|
|
549
225
|
});
|
|
550
226
|
|
|
551
|
-
//
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
|
|
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
|
-
})
|
|
227
|
+
// Update product (Admin required)
|
|
228
|
+
const updatedProduct = await spaps.admin.updateProduct('prod_123', {
|
|
229
|
+
name: 'Premium Plan Pro',
|
|
230
|
+
description: 'Updated features'
|
|
564
231
|
});
|
|
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
232
|
|
|
574
|
-
|
|
233
|
+
// Archive product (Admin required)
|
|
234
|
+
await spaps.admin.deleteProduct('prod_123');
|
|
575
235
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
// Contact support to add your domain
|
|
236
|
+
// Get products (includes admin metadata if user is admin)
|
|
237
|
+
const { data } = await spaps.admin.getProducts();
|
|
238
|
+
if (data.adminMetadata) {
|
|
239
|
+
console.log('Total revenue:', data.adminMetadata.total_revenue);
|
|
240
|
+
}
|
|
582
241
|
```
|
|
583
242
|
|
|
584
|
-
|
|
585
|
-
```typescript
|
|
586
|
-
// Use TokenManager for automatic refresh
|
|
587
|
-
await TokenManager.autoRefreshToken(sdk);
|
|
588
|
-
```
|
|
243
|
+
### Price Management
|
|
589
244
|
|
|
590
|
-
**Rate Limiting**
|
|
591
245
|
```typescript
|
|
592
|
-
//
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
246
|
+
// Create price (Admin required)
|
|
247
|
+
const price = await spaps.admin.createPrice({
|
|
248
|
+
product_id: 'prod_123',
|
|
249
|
+
unit_amount: 2999, // $29.99
|
|
250
|
+
currency: 'usd',
|
|
251
|
+
interval: 'month',
|
|
252
|
+
interval_count: 1,
|
|
253
|
+
nickname: 'Monthly Premium'
|
|
598
254
|
});
|
|
599
255
|
```
|
|
600
256
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
### From v0.x to v1.0
|
|
257
|
+
### Super Admin Operations
|
|
604
258
|
|
|
605
259
|
```typescript
|
|
606
|
-
//
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
// New (v1.0)
|
|
610
|
-
const sdk = new SweetPotatoSDK({
|
|
611
|
-
apiUrl,
|
|
612
|
-
apiKey,
|
|
613
|
-
timeout: 30000,
|
|
614
|
-
retries: 3
|
|
615
|
-
});
|
|
260
|
+
// Sync all products from Stripe (Super Admin required)
|
|
261
|
+
const syncResult = await spaps.admin.syncProducts();
|
|
262
|
+
console.log(`Synced ${syncResult.data.synced_count} products`);
|
|
616
263
|
```
|
|
617
264
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
265
|
+
### Permission Checking
|
|
621
266
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
267
|
+
```typescript
|
|
268
|
+
// Check if current user can access admin features
|
|
269
|
+
const user = await spaps.getCurrentUser();
|
|
270
|
+
if (spaps.isAdmin(user)) {
|
|
271
|
+
// Show admin UI components
|
|
272
|
+
console.log('User has admin privileges');
|
|
273
|
+
} else {
|
|
274
|
+
// Show regular user UI
|
|
275
|
+
console.log('Regular user');
|
|
276
|
+
}
|
|
277
|
+
```
|
|
630
278
|
|
|
631
|
-
##
|
|
279
|
+
## Error Handling
|
|
632
280
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
281
|
+
```javascript
|
|
282
|
+
try {
|
|
283
|
+
await spaps.admin.createProduct(productData);
|
|
284
|
+
} catch (error) {
|
|
285
|
+
if (error.response?.status === 401) {
|
|
286
|
+
console.error('Authentication required');
|
|
287
|
+
} else if (error.response?.status === 403) {
|
|
288
|
+
console.error('Admin privileges required');
|
|
289
|
+
} else if (error.response?.status === 429) {
|
|
290
|
+
console.error('Rate limited');
|
|
291
|
+
} else {
|
|
292
|
+
console.error('Error:', error.message);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
637
296
|
|
|
638
297
|
## License
|
|
639
298
|
|
|
640
|
-
MIT
|
|
299
|
+
MIT
|