spaps-sdk 1.0.1 → 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 +82 -22
- package/admin-utils.ts +12 -12
- package/dist/index.js +4 -0
- package/dist/index.mjs +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Sweet Potato SDK
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/spaps-sdk)
|
|
4
4
|
[](https://www.typescriptlang.org/)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
|
|
@@ -34,13 +34,15 @@ A comprehensive TypeScript SDK for integrating with the Sweet Potato Authenticat
|
|
|
34
34
|
## Installation
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
npm install
|
|
37
|
+
npm install spaps-sdk
|
|
38
38
|
# or
|
|
39
|
-
yarn add
|
|
40
|
-
# or
|
|
41
|
-
pnpm add
|
|
39
|
+
yarn add spaps-sdk
|
|
40
|
+
# or
|
|
41
|
+
pnpm add spaps-sdk
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
+
> **📍 Important:** SPAPS runs on port **3456**. This is standardized across all tools.
|
|
45
|
+
|
|
44
46
|
### Requirements
|
|
45
47
|
|
|
46
48
|
- Node.js 14+ or modern browser
|
|
@@ -51,13 +53,13 @@ pnpm add @sweet-potato/sdk
|
|
|
51
53
|
### Basic Setup
|
|
52
54
|
|
|
53
55
|
```typescript
|
|
54
|
-
import { SweetPotatoSDK, TokenManager } from '
|
|
56
|
+
import { SweetPotatoSDK, TokenManager } from 'spaps-sdk';
|
|
55
57
|
|
|
56
58
|
// Initialize the SDK
|
|
57
59
|
const sdk = new SweetPotatoSDK({
|
|
58
|
-
apiUrl: 'http://localhost:3456', //
|
|
59
|
-
// apiUrl: 'https://api.sweetpotato.dev', // Production
|
|
60
|
-
apiKey: '
|
|
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',
|
|
61
63
|
timeout: 30000, // Optional: 30 second timeout
|
|
62
64
|
retries: 3 // Optional: 3 retry attempts
|
|
63
65
|
});
|
|
@@ -71,18 +73,29 @@ await TokenManager.autoRefreshToken(sdk);
|
|
|
71
73
|
### Wallet Authentication (Complete Flow)
|
|
72
74
|
|
|
73
75
|
```typescript
|
|
74
|
-
//
|
|
76
|
+
// Complete implementation with proper signature handling
|
|
77
|
+
const walletAddress = '0x742d35CC6354C7Cb24b5d2C2C7f9Ff5Ef8B4d5f6';
|
|
78
|
+
|
|
75
79
|
const authResponse = await sdk.auth.authenticateWallet(
|
|
76
|
-
|
|
80
|
+
walletAddress,
|
|
77
81
|
async (message) => {
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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);
|
|
84
97
|
},
|
|
85
|
-
'ethereum', //
|
|
98
|
+
'ethereum', // Chain type: 'ethereum', 'solana', 'bitcoin', 'base'
|
|
86
99
|
'username123' // Optional: username for new users
|
|
87
100
|
);
|
|
88
101
|
|
|
@@ -538,7 +551,11 @@ Static utility class for wallet operations.
|
|
|
538
551
|
|
|
539
552
|
## What's NOT in the SDK
|
|
540
553
|
|
|
541
|
-
|
|
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
|
+
|
|
542
559
|
Whitelist operations require admin JWT authentication and must be done via direct API calls:
|
|
543
560
|
|
|
544
561
|
```typescript
|
|
@@ -565,20 +582,63 @@ const response = await fetch(`${apiUrl}/api/v1/whitelist`, {
|
|
|
565
582
|
```
|
|
566
583
|
|
|
567
584
|
### Admin Operations
|
|
585
|
+
❌ **Not available:** `sdk.admin.*` methods
|
|
586
|
+
|
|
587
|
+
Admin operations require JWT authentication:
|
|
568
588
|
- Application management (create/rotate API keys)
|
|
569
|
-
- User management (admin dashboard)
|
|
589
|
+
- User management (admin dashboard)
|
|
570
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
|
|
571
597
|
|
|
572
598
|
See [Stripe Admin Guide](../STRIPE_ADMIN_GUIDE.md) for product management instructions.
|
|
573
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
|
+
|
|
574
624
|
## Troubleshooting
|
|
575
625
|
|
|
576
626
|
### Common Issues
|
|
577
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
|
+
|
|
578
638
|
**CORS Errors**
|
|
579
639
|
```typescript
|
|
580
|
-
//
|
|
581
|
-
//
|
|
640
|
+
// In local mode, CORS is enabled for all origins
|
|
641
|
+
// In production, ensure your domain is whitelisted
|
|
582
642
|
```
|
|
583
643
|
|
|
584
644
|
**Token Expired**
|
package/admin-utils.ts
CHANGED
|
@@ -25,7 +25,7 @@ export interface WhitelistClient {
|
|
|
25
25
|
* Requires admin JWT token from authentication
|
|
26
26
|
*/
|
|
27
27
|
export class WhitelistManager {
|
|
28
|
-
private headers:
|
|
28
|
+
private headers: Record<string, string>;
|
|
29
29
|
|
|
30
30
|
constructor(private config: WhitelistClient) {
|
|
31
31
|
this.headers = {
|
|
@@ -44,7 +44,7 @@ export class WhitelistManager {
|
|
|
44
44
|
{ headers: { 'X-API-Key': this.config.apiKey } }
|
|
45
45
|
);
|
|
46
46
|
|
|
47
|
-
const result = await response.json();
|
|
47
|
+
const result = await response.json() as any;
|
|
48
48
|
return result.data?.entry || null;
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -71,11 +71,11 @@ export class WhitelistManager {
|
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
if (!response.ok) {
|
|
74
|
-
const error = await response.json();
|
|
74
|
+
const error = await response.json() as any;
|
|
75
75
|
throw new Error(error.error?.message || 'Failed to add to whitelist');
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
const result = await response.json();
|
|
78
|
+
const result = await response.json() as any;
|
|
79
79
|
return result.data.entry;
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -99,7 +99,7 @@ export class WhitelistManager {
|
|
|
99
99
|
body: JSON.stringify({ emails })
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
-
const result = await response.json();
|
|
102
|
+
const result = await response.json() as any;
|
|
103
103
|
return result.data;
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -124,7 +124,7 @@ export class WhitelistManager {
|
|
|
124
124
|
{ headers: this.headers }
|
|
125
125
|
);
|
|
126
126
|
|
|
127
|
-
const result = await response.json();
|
|
127
|
+
const result = await response.json() as any;
|
|
128
128
|
return result.data;
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -149,11 +149,11 @@ export class WhitelistManager {
|
|
|
149
149
|
);
|
|
150
150
|
|
|
151
151
|
if (!response.ok) {
|
|
152
|
-
const error = await response.json();
|
|
152
|
+
const error = await response.json() as any;
|
|
153
153
|
throw new Error(error.error?.message || 'Failed to update whitelist');
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
const result = await response.json();
|
|
156
|
+
const result = await response.json() as any;
|
|
157
157
|
return result.data.entry;
|
|
158
158
|
}
|
|
159
159
|
|
|
@@ -170,7 +170,7 @@ export class WhitelistManager {
|
|
|
170
170
|
);
|
|
171
171
|
|
|
172
172
|
if (!response.ok) {
|
|
173
|
-
const error = await response.json();
|
|
173
|
+
const error = await response.json() as any;
|
|
174
174
|
throw new Error(error.error?.message || 'Failed to remove from whitelist');
|
|
175
175
|
}
|
|
176
176
|
}
|
|
@@ -188,7 +188,7 @@ export class WhitelistManager {
|
|
|
188
188
|
{ headers: this.headers }
|
|
189
189
|
);
|
|
190
190
|
|
|
191
|
-
const result = await response.json();
|
|
191
|
+
const result = await response.json() as any;
|
|
192
192
|
return result.data.stats;
|
|
193
193
|
}
|
|
194
194
|
|
|
@@ -205,11 +205,11 @@ export class WhitelistManager {
|
|
|
205
205
|
);
|
|
206
206
|
|
|
207
207
|
if (!response.ok) {
|
|
208
|
-
const error = await response.json();
|
|
208
|
+
const error = await response.json() as any;
|
|
209
209
|
throw new Error(error.error?.message || 'Failed to clear whitelist');
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
const result = await response.json();
|
|
212
|
+
const result = await response.json() as any;
|
|
213
213
|
const match = result.data.message.match(/Cleared (\d+) entries/);
|
|
214
214
|
return match ? parseInt(match[1]) : 0;
|
|
215
215
|
}
|
package/dist/index.js
CHANGED
|
@@ -279,6 +279,10 @@ var AuthService = class {
|
|
|
279
279
|
async signInWithPassword(request) {
|
|
280
280
|
var _a;
|
|
281
281
|
const response = await this.httpClient.post("/api/auth/login", request);
|
|
282
|
+
if (response.access_token && response.refresh_token && response.user) {
|
|
283
|
+
this.httpClient.setAccessToken(response.access_token);
|
|
284
|
+
return response;
|
|
285
|
+
}
|
|
282
286
|
if (!response.success || !response.data) {
|
|
283
287
|
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Login failed");
|
|
284
288
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -245,6 +245,10 @@ var AuthService = class {
|
|
|
245
245
|
async signInWithPassword(request) {
|
|
246
246
|
var _a;
|
|
247
247
|
const response = await this.httpClient.post("/api/auth/login", request);
|
|
248
|
+
if (response.access_token && response.refresh_token && response.user) {
|
|
249
|
+
this.httpClient.setAccessToken(response.access_token);
|
|
250
|
+
return response;
|
|
251
|
+
}
|
|
248
252
|
if (!response.success || !response.data) {
|
|
249
253
|
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Login failed");
|
|
250
254
|
}
|