spaps-sdk 1.0.2 โ 1.1.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/README.md +213 -602
- package/dist/index.d.mts +302 -0
- package/dist/index.d.ts +302 -0
- package/dist/index.js +382 -854
- package/dist/index.mjs +379 -840
- package/package.json +52 -33
- package/.env.example +0 -23
- package/admin-utils.ts +0 -243
package/README.md
CHANGED
|
@@ -1,700 +1,311 @@
|
|
|
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 spaps-sdk
|
|
38
|
-
# or
|
|
39
|
-
yarn add spaps-sdk
|
|
40
|
-
# or
|
|
41
|
-
pnpm add spaps-sdk
|
|
42
|
-
```
|
|
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
|
-
|
|
51
|
-
## Quick Start
|
|
52
|
-
|
|
53
|
-
### Basic Setup
|
|
54
|
-
|
|
55
|
-
```typescript
|
|
56
|
-
import { SweetPotatoSDK, TokenManager } from 'spaps-sdk';
|
|
57
|
-
|
|
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
|
-
});
|
|
66
|
-
|
|
67
|
-
// Auto-restore authentication state (browser only)
|
|
68
|
-
await TokenManager.autoRefreshToken(sdk);
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Authentication Examples
|
|
72
|
-
|
|
73
|
-
### Wallet Authentication (Complete Flow)
|
|
9
|
+
Built-in admin API methods for Stripe product management:
|
|
74
10
|
|
|
75
11
|
```typescript
|
|
76
|
-
|
|
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
|
-
```
|
|
12
|
+
import { SPAPSClient } from 'spaps-sdk';
|
|
106
13
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const authResponse = await sdk.auth.signInWithPassword({
|
|
111
|
-
email: 'user@example.com',
|
|
112
|
-
password: 'securePassword123!'
|
|
14
|
+
const spaps = new SPAPSClient({
|
|
15
|
+
apiKey: 'your-api-key',
|
|
16
|
+
apiUrl: 'https://api.sweetpotato.dev'
|
|
113
17
|
});
|
|
114
18
|
|
|
115
|
-
|
|
116
|
-
|
|
19
|
+
// Authenticate as admin
|
|
20
|
+
await spaps.signIn('admin@example.com', 'password');
|
|
117
21
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
redirect_url: 'https://myapp.com/auth/callback'
|
|
22
|
+
// Admin API methods
|
|
23
|
+
await spaps.admin.createProduct({
|
|
24
|
+
name: 'Premium Plan',
|
|
25
|
+
category: 'subscription',
|
|
26
|
+
description: 'Advanced features'
|
|
124
27
|
});
|
|
125
|
-
// User will receive email with authentication link
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Payment Examples
|
|
129
28
|
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
}
|
|
29
|
+
await spaps.admin.updateProduct('prod_123', {
|
|
30
|
+
name: 'Premium Plan Pro'
|
|
142
31
|
});
|
|
143
32
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
|
33
|
+
await spaps.admin.createPrice({
|
|
34
|
+
product_id: 'prod_123',
|
|
35
|
+
unit_amount: 2999,
|
|
155
36
|
currency: 'usd',
|
|
156
|
-
|
|
157
|
-
success_url: 'https://myapp.com/success',
|
|
158
|
-
cancel_url: 'https://myapp.com/cancel'
|
|
37
|
+
interval: 'month'
|
|
159
38
|
});
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Subscription Creation
|
|
163
39
|
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
});
|
|
40
|
+
// Super admin operations
|
|
41
|
+
await spaps.admin.syncProducts();
|
|
175
42
|
```
|
|
176
43
|
|
|
177
|
-
|
|
178
|
-
|
|
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
|
-
}
|
|
199
|
-
});
|
|
200
|
-
```
|
|
44
|
+
## ๐ Permission Utilities
|
|
201
45
|
|
|
202
|
-
|
|
46
|
+
Built-in permission checking and role-based access control:
|
|
203
47
|
|
|
204
48
|
```typescript
|
|
205
|
-
|
|
206
|
-
const subscriptions = await sdk.payments.listSubscriptions({
|
|
207
|
-
status: 'active'
|
|
208
|
-
});
|
|
49
|
+
import { isAdminAccount, canAccessAdmin, getUserRole } from 'spaps-sdk';
|
|
209
50
|
|
|
210
|
-
//
|
|
211
|
-
|
|
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
|
-
});
|
|
51
|
+
// Check admin status
|
|
52
|
+
const isAdmin = isAdminAccount('buildooor@gmail.com'); // true
|
|
220
53
|
|
|
221
|
-
//
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
window.location.href = portalSession.url;
|
|
226
|
-
```
|
|
227
|
-
|
|
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
|
-
}
|
|
54
|
+
// Check admin access with detailed result
|
|
55
|
+
const adminCheck = canAccessAdmin(user);
|
|
56
|
+
if (adminCheck.allowed) {
|
|
57
|
+
// Show admin UI
|
|
242
58
|
}
|
|
243
59
|
|
|
244
|
-
//
|
|
245
|
-
|
|
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
|
-
}
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
### Logout
|
|
60
|
+
// Get user role
|
|
61
|
+
const role = getUserRole('user@example.com'); // 'user' | 'admin' | 'guest'
|
|
260
62
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
await sdk.auth.logout();
|
|
265
|
-
TokenManager.clearTokens();
|
|
266
|
-
console.log('Successfully logged out');
|
|
267
|
-
} catch (error) {
|
|
268
|
-
console.error('Logout failed:', error);
|
|
269
|
-
}
|
|
63
|
+
// Check if authenticated user is admin
|
|
64
|
+
if (spaps.isAdmin(currentUser)) {
|
|
65
|
+
// Show admin features
|
|
270
66
|
}
|
|
271
67
|
```
|
|
272
68
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
### Get Current User
|
|
69
|
+
See [PERMISSIONS.md](./PERMISSIONS.md) for React examples and complete documentation.
|
|
276
70
|
|
|
277
|
-
|
|
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
|
|
71
|
+
## Installation
|
|
291
72
|
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
}
|
|
73
|
+
```bash
|
|
74
|
+
npm install spaps-sdk
|
|
75
|
+
# or
|
|
76
|
+
yarn add spaps-sdk
|
|
77
|
+
# or
|
|
78
|
+
pnpm add spaps-sdk
|
|
300
79
|
```
|
|
301
80
|
|
|
302
|
-
|
|
81
|
+
### Compatibility
|
|
303
82
|
|
|
304
|
-
|
|
83
|
+
- โ
**Node.js**: Fully supported (v14+) with automatic fetch polyfill
|
|
84
|
+
- โ
**Browser**: Works in all modern browsers
|
|
85
|
+
- โ
**TypeScript**: Full type definitions included
|
|
86
|
+
- โ
**Next.js**: Server and client components supported
|
|
87
|
+
- โ
**React Native**: Compatible with proper setup
|
|
305
88
|
|
|
306
|
-
|
|
307
|
-
import { WalletUtils } from '@sweet-potato/auth-sdk';
|
|
89
|
+
The SDK automatically includes a `cross-fetch` polyfill for Node.js environments that don't have native fetch support.
|
|
308
90
|
|
|
309
|
-
|
|
310
|
-
const chainType = WalletUtils.detectChainType('0x742d35Cc6634C0532925a3b8D6Ac6d8F49c3589F');
|
|
311
|
-
console.log(chainType); // 'ethereum'
|
|
91
|
+
## Quick Start
|
|
312
92
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
93
|
+
```javascript
|
|
94
|
+
import { SPAPSClient } from 'spaps-sdk';
|
|
95
|
+
// or
|
|
96
|
+
const { SPAPSClient } = require('spaps-sdk');
|
|
316
97
|
|
|
317
|
-
// Auto-
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
|
|
98
|
+
// Auto-detects local mode - no API key needed for localhost!
|
|
99
|
+
const spaps = new SPAPSClient({
|
|
100
|
+
apiUrl: 'http://localhost:3300' // Optional, auto-detected
|
|
101
|
+
});
|
|
321
102
|
|
|
322
|
-
|
|
103
|
+
// Login
|
|
104
|
+
const { data } = await spaps.login('user@example.com', 'password');
|
|
105
|
+
console.log('User:', data.user);
|
|
323
106
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
console.log('Token is expired, refreshing...');
|
|
329
|
-
await refreshTokens();
|
|
107
|
+
// Check authentication
|
|
108
|
+
if (spaps.isAuthenticated()) {
|
|
109
|
+
const user = await spaps.getUser();
|
|
110
|
+
console.log('Current user:', user.data);
|
|
330
111
|
}
|
|
331
112
|
```
|
|
332
113
|
|
|
333
|
-
##
|
|
114
|
+
## Features
|
|
334
115
|
|
|
335
|
-
|
|
336
|
-
|
|
116
|
+
### ๐ Zero Configuration
|
|
117
|
+
- **Auto-detects local mode** - No API key needed for localhost
|
|
118
|
+
- **Auto-refreshes tokens** - Handles expired tokens automatically
|
|
119
|
+
- **TypeScript support** - Full type definitions included
|
|
337
120
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
} catch (error) {
|
|
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
|
-
```
|
|
121
|
+
### ๐ Authentication Methods
|
|
122
|
+
```javascript
|
|
123
|
+
// Email/Password
|
|
124
|
+
await spaps.login(email, password);
|
|
125
|
+
await spaps.register(email, password);
|
|
366
126
|
|
|
367
|
-
|
|
127
|
+
// Wallet Authentication
|
|
128
|
+
await spaps.walletSignIn(walletAddress, signature, message, 'solana');
|
|
368
129
|
|
|
369
|
-
|
|
130
|
+
// Token Management
|
|
131
|
+
await spaps.refresh();
|
|
132
|
+
await spaps.logout();
|
|
370
133
|
|
|
371
|
-
|
|
372
|
-
|
|
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
|
-
}
|
|
134
|
+
// Get User
|
|
135
|
+
const user = await spaps.getUser();
|
|
387
136
|
```
|
|
388
137
|
|
|
389
|
-
###
|
|
138
|
+
### ๐ณ Stripe Integration
|
|
139
|
+
```javascript
|
|
140
|
+
// Create checkout session
|
|
141
|
+
const session = await spaps.createCheckoutSession(priceId, successUrl);
|
|
142
|
+
window.location.href = session.data.url;
|
|
390
143
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
if (isHealthy) {
|
|
395
|
-
console.log('API is healthy');
|
|
396
|
-
} else {
|
|
397
|
-
console.log('API is down or unreachable');
|
|
398
|
-
}
|
|
399
|
-
}
|
|
144
|
+
// Manage subscription
|
|
145
|
+
const subscription = await spaps.getSubscription();
|
|
146
|
+
await spaps.cancelSubscription();
|
|
400
147
|
```
|
|
401
148
|
|
|
402
|
-
|
|
149
|
+
### ๐ Usage Tracking
|
|
150
|
+
```javascript
|
|
151
|
+
// Check balance
|
|
152
|
+
const balance = await spaps.getUsageBalance();
|
|
153
|
+
console.log(`Credits: ${balance.data.balance}`);
|
|
403
154
|
|
|
404
|
-
|
|
405
|
-
|
|
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
|
-
}
|
|
155
|
+
// Record usage
|
|
156
|
+
await spaps.recordUsage('api-call', 1);
|
|
456
157
|
```
|
|
457
158
|
|
|
458
|
-
## Configuration
|
|
159
|
+
## Configuration
|
|
459
160
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
}
|
|
161
|
+
### Production Mode
|
|
162
|
+
```javascript
|
|
163
|
+
const spaps = new SPAPSClient({
|
|
164
|
+
apiUrl: 'https://api.sweetpotato.dev',
|
|
165
|
+
apiKey: 'spaps_your_api_key_here',
|
|
166
|
+
timeout: 10000 // Optional timeout in ms
|
|
167
|
+
});
|
|
467
168
|
```
|
|
468
169
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
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';
|
|
170
|
+
### Local Development Mode (Auto-detected)
|
|
171
|
+
```javascript
|
|
172
|
+
const spaps = new SPAPSClient();
|
|
173
|
+
// Automatically uses http://localhost:3300 with no API key
|
|
484
174
|
```
|
|
485
175
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
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
|
-
});
|
|
176
|
+
### Environment Variables
|
|
177
|
+
```bash
|
|
178
|
+
# .env
|
|
179
|
+
SPAPS_API_URL=https://api.sweetpotato.dev
|
|
180
|
+
SPAPS_API_KEY=spaps_your_api_key_here
|
|
567
181
|
|
|
568
|
-
|
|
569
|
-
|
|
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
|
-
});
|
|
182
|
+
# Next.js
|
|
183
|
+
NEXT_PUBLIC_SPAPS_API_URL=https://api.sweetpotato.dev
|
|
582
184
|
```
|
|
583
185
|
|
|
584
|
-
|
|
585
|
-
โ **Not available:** `sdk.admin.*` methods
|
|
186
|
+
## Helper Methods
|
|
586
187
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
- Direct database operations
|
|
591
|
-
- Product sync from Stripe
|
|
188
|
+
```javascript
|
|
189
|
+
// Check if authenticated
|
|
190
|
+
spaps.isAuthenticated() // boolean
|
|
592
191
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
2. Use the JWT token for direct API calls
|
|
596
|
-
3. Include both JWT and API key in headers
|
|
192
|
+
// Get current access token
|
|
193
|
+
spaps.getAccessToken() // string | undefined
|
|
597
194
|
|
|
598
|
-
|
|
195
|
+
// Set access token manually
|
|
196
|
+
spaps.setAccessToken(token)
|
|
599
197
|
|
|
600
|
-
|
|
198
|
+
// Check if in local mode
|
|
199
|
+
spaps.isLocalMode() // boolean
|
|
601
200
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
- โ
CORS enabled for all origins
|
|
606
|
-
- โ
No real API keys required
|
|
607
|
-
- โ
Mock Stripe integration ready
|
|
608
|
-
- โ
Runs on port **3456** by default
|
|
201
|
+
// Health check
|
|
202
|
+
await spaps.health()
|
|
203
|
+
```
|
|
609
204
|
|
|
610
|
-
|
|
611
|
-
# Start local server
|
|
612
|
-
npx spaps local
|
|
205
|
+
## Import Styles
|
|
613
206
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
207
|
+
All these work:
|
|
208
|
+
```javascript
|
|
209
|
+
// ES6 Import
|
|
210
|
+
import { SPAPSClient } from 'spaps-sdk';
|
|
211
|
+
import SPAPSClient from 'spaps-sdk';
|
|
617
212
|
|
|
618
|
-
|
|
213
|
+
// CommonJS
|
|
214
|
+
const { SPAPSClient } = require('spaps-sdk');
|
|
215
|
+
const SPAPSClient = require('spaps-sdk');
|
|
619
216
|
|
|
620
|
-
|
|
217
|
+
// Alternative names
|
|
218
|
+
import { SPAPS } from 'spaps-sdk';
|
|
219
|
+
import { SweetPotatoSDK } from 'spaps-sdk';
|
|
220
|
+
```
|
|
621
221
|
|
|
622
|
-
|
|
222
|
+
## Admin API Methods
|
|
623
223
|
|
|
624
|
-
|
|
224
|
+
The SDK includes comprehensive admin methods for Stripe product management:
|
|
625
225
|
|
|
626
|
-
###
|
|
226
|
+
### Product Management
|
|
627
227
|
|
|
628
|
-
**Wrong Port**
|
|
629
228
|
```typescript
|
|
630
|
-
//
|
|
631
|
-
|
|
632
|
-
|
|
229
|
+
// Create product (Admin required)
|
|
230
|
+
const product = await spaps.admin.createProduct({
|
|
231
|
+
name: 'Premium Plan',
|
|
232
|
+
category: 'subscription',
|
|
233
|
+
description: 'Advanced features for power users',
|
|
234
|
+
images: ['https://example.com/product-image.jpg'],
|
|
235
|
+
metadata: { feature_set: 'premium' },
|
|
236
|
+
active: true
|
|
237
|
+
});
|
|
633
238
|
|
|
634
|
-
//
|
|
635
|
-
|
|
636
|
-
|
|
239
|
+
// Update product (Admin required)
|
|
240
|
+
const updatedProduct = await spaps.admin.updateProduct('prod_123', {
|
|
241
|
+
name: 'Premium Plan Pro',
|
|
242
|
+
description: 'Updated features'
|
|
243
|
+
});
|
|
637
244
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
// In local mode, CORS is enabled for all origins
|
|
641
|
-
// In production, ensure your domain is whitelisted
|
|
642
|
-
```
|
|
245
|
+
// Archive product (Admin required)
|
|
246
|
+
await spaps.admin.deleteProduct('prod_123');
|
|
643
247
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
248
|
+
// Get products (includes admin metadata if user is admin)
|
|
249
|
+
const { data } = await spaps.admin.getProducts();
|
|
250
|
+
if (data.adminMetadata) {
|
|
251
|
+
console.log('Total revenue:', data.adminMetadata.total_revenue);
|
|
252
|
+
}
|
|
648
253
|
```
|
|
649
254
|
|
|
650
|
-
|
|
255
|
+
### Price Management
|
|
256
|
+
|
|
651
257
|
```typescript
|
|
652
|
-
//
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
258
|
+
// Create price (Admin required)
|
|
259
|
+
const price = await spaps.admin.createPrice({
|
|
260
|
+
product_id: 'prod_123',
|
|
261
|
+
unit_amount: 2999, // $29.99
|
|
262
|
+
currency: 'usd',
|
|
263
|
+
interval: 'month',
|
|
264
|
+
interval_count: 1,
|
|
265
|
+
nickname: 'Monthly Premium'
|
|
658
266
|
});
|
|
659
267
|
```
|
|
660
268
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
### From v0.x to v1.0
|
|
269
|
+
### Super Admin Operations
|
|
664
270
|
|
|
665
271
|
```typescript
|
|
666
|
-
//
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
// New (v1.0)
|
|
670
|
-
const sdk = new SweetPotatoSDK({
|
|
671
|
-
apiUrl,
|
|
672
|
-
apiKey,
|
|
673
|
-
timeout: 30000,
|
|
674
|
-
retries: 3
|
|
675
|
-
});
|
|
272
|
+
// Sync all products from Stripe (Super Admin required)
|
|
273
|
+
const syncResult = await spaps.admin.syncProducts();
|
|
274
|
+
console.log(`Synced ${syncResult.data.synced_count} products`);
|
|
676
275
|
```
|
|
677
276
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
681
|
-
|
|
682
|
-
## Security
|
|
277
|
+
### Permission Checking
|
|
683
278
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
279
|
+
```typescript
|
|
280
|
+
// Check if current user can access admin features
|
|
281
|
+
const user = await spaps.getCurrentUser();
|
|
282
|
+
if (spaps.isAdmin(user)) {
|
|
283
|
+
// Show admin UI components
|
|
284
|
+
console.log('User has admin privileges');
|
|
285
|
+
} else {
|
|
286
|
+
// Show regular user UI
|
|
287
|
+
console.log('Regular user');
|
|
288
|
+
}
|
|
289
|
+
```
|
|
690
290
|
|
|
691
|
-
##
|
|
291
|
+
## Error Handling
|
|
692
292
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
293
|
+
```javascript
|
|
294
|
+
try {
|
|
295
|
+
await spaps.admin.createProduct(productData);
|
|
296
|
+
} catch (error) {
|
|
297
|
+
if (error.response?.status === 401) {
|
|
298
|
+
console.error('Authentication required');
|
|
299
|
+
} else if (error.response?.status === 403) {
|
|
300
|
+
console.error('Admin privileges required');
|
|
301
|
+
} else if (error.response?.status === 429) {
|
|
302
|
+
console.error('Rate limited');
|
|
303
|
+
} else {
|
|
304
|
+
console.error('Error:', error.message);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
```
|
|
697
308
|
|
|
698
309
|
## License
|
|
699
310
|
|
|
700
|
-
MIT
|
|
311
|
+
MIT
|