swiftshopr-payments 1.0.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/LICENSE +21 -0
- package/README.md +339 -0
- package/package.json +54 -0
- package/src/branding.js +127 -0
- package/src/client.js +111 -0
- package/src/config.js +273 -0
- package/src/dashboard.js +265 -0
- package/src/index.js +79 -0
- package/src/payments.js +319 -0
- package/src/refunds.js +209 -0
- package/src/types/index.d.ts +460 -0
- package/src/utils/http.js +217 -0
- package/src/webhooks.js +163 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 SwiftShopr
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# swiftshopr-payments
|
|
2
|
+
|
|
3
|
+
Official Node.js SDK for SwiftShopr Payments API. Accept USDC payments with zero chargebacks, instant settlement, and lower fees than card networks.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Zero Dependencies** - Uses native `fetch` (Node.js 18+)
|
|
8
|
+
- **TypeScript Support** - Full type definitions included
|
|
9
|
+
- **Automatic Retries** - Exponential backoff for failed requests
|
|
10
|
+
- **Idempotency** - Safe retries for payment operations
|
|
11
|
+
- **Webhook Verification** - HMAC signature validation
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install swiftshopr-payments
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
const { SwiftShoprClient } = require('swiftshopr-payments');
|
|
23
|
+
|
|
24
|
+
const client = new SwiftShoprClient({
|
|
25
|
+
apiKey: 'sk_live_your_api_key',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Create an onramp session (Add Funds)
|
|
29
|
+
const session = await client.payments.createSession({
|
|
30
|
+
amount: 25.00,
|
|
31
|
+
orderId: 'ORDER-123',
|
|
32
|
+
storeId: 'STORE001',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
console.log('Redirect user to:', session.onrampUrl);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Payment Flows
|
|
39
|
+
|
|
40
|
+
### Two-Button Pattern
|
|
41
|
+
|
|
42
|
+
SwiftShopr supports two payment methods:
|
|
43
|
+
|
|
44
|
+
| Button | Method | When to Use | Fees |
|
|
45
|
+
|--------|--------|-------------|------|
|
|
46
|
+
| **Add Funds** | `createSession()` | User has no USDC | ~$0.30 |
|
|
47
|
+
| **Purchase** | `createTransfer()` | User has USDC balance | $0 |
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
// Check user's USDC balance first
|
|
51
|
+
const balance = await getUserBalance(); // Your wallet SDK
|
|
52
|
+
|
|
53
|
+
if (balance >= purchaseAmount) {
|
|
54
|
+
// Direct transfer - no fees!
|
|
55
|
+
const transfer = await client.payments.createTransfer({
|
|
56
|
+
amount: 25.00,
|
|
57
|
+
userWalletAddress: '0xUserWallet...',
|
|
58
|
+
storeId: 'STORE001',
|
|
59
|
+
});
|
|
60
|
+
} else {
|
|
61
|
+
// Onramp - small fee for ACH conversion
|
|
62
|
+
const session = await client.payments.createSession({
|
|
63
|
+
amount: 25.00,
|
|
64
|
+
storeId: 'STORE001',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## API Reference
|
|
70
|
+
|
|
71
|
+
### Payments
|
|
72
|
+
|
|
73
|
+
#### Create Onramp Session
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
const session = await client.payments.createSession({
|
|
77
|
+
amount: 25.00, // Required: Amount in USD
|
|
78
|
+
orderId: 'ORDER-123', // Optional: Your order reference
|
|
79
|
+
storeId: 'STORE001', // Optional: Store ID (resolves wallet)
|
|
80
|
+
destinationAddress: '0x...', // Optional: Explicit wallet address
|
|
81
|
+
paymentMethod: 'ACH_BANK_ACCOUNT', // Optional: ACH_BANK_ACCOUNT, CARD
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Response
|
|
85
|
+
{
|
|
86
|
+
intentId: 'uuid',
|
|
87
|
+
sessionId: 'sess_xxx',
|
|
88
|
+
orderId: 'ORDER-123',
|
|
89
|
+
onrampUrl: 'https://pay.coinbase.com/...',
|
|
90
|
+
expiresAt: '2024-12-23T10:30:00Z',
|
|
91
|
+
branding: { ... }
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### Create Direct Transfer
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
const transfer = await client.payments.createTransfer({
|
|
99
|
+
amount: 25.00,
|
|
100
|
+
userWalletAddress: '0xUserWallet...',
|
|
101
|
+
storeId: 'STORE001',
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Response includes transfer instructions
|
|
105
|
+
{
|
|
106
|
+
intentId: 'uuid',
|
|
107
|
+
transfer: {
|
|
108
|
+
to: '0xRetailerWallet...',
|
|
109
|
+
amount: '25.00',
|
|
110
|
+
asset: 'USDC',
|
|
111
|
+
network: 'base',
|
|
112
|
+
chainId: 8453,
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Get Payment Status
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
// By intent ID
|
|
121
|
+
const status = await client.payments.getStatus('intent-uuid');
|
|
122
|
+
|
|
123
|
+
// By your order ID
|
|
124
|
+
const status = await client.payments.getStatusByOrderId('ORDER-123');
|
|
125
|
+
|
|
126
|
+
// Poll until complete
|
|
127
|
+
const finalStatus = await client.payments.waitForCompletion('intent-uuid', {
|
|
128
|
+
timeout: 300000, // 5 minutes
|
|
129
|
+
interval: 2000, // Check every 2 seconds
|
|
130
|
+
onStatusChange: (status) => console.log('Status:', status.status),
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Refunds
|
|
135
|
+
|
|
136
|
+
#### Request a Refund
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
const refund = await client.refunds.create({
|
|
140
|
+
intentId: 'original-payment-intent-uuid',
|
|
141
|
+
amount: 25.00, // Optional: Defaults to full refund
|
|
142
|
+
reason: 'Customer request',
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Response includes transfer instructions
|
|
146
|
+
{
|
|
147
|
+
id: 'refund-uuid',
|
|
148
|
+
status: 'requested',
|
|
149
|
+
instructions: {
|
|
150
|
+
message: 'Send USDC to complete the refund...',
|
|
151
|
+
transfer: {
|
|
152
|
+
to: '0xUserWallet...',
|
|
153
|
+
amount: '25.00',
|
|
154
|
+
asset: 'USDC',
|
|
155
|
+
},
|
|
156
|
+
fromWallet: '0xYourStoreWallet...',
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### Check Refund Status
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
const refund = await client.refunds.get('refund-uuid');
|
|
165
|
+
|
|
166
|
+
// List all refunds for a payment
|
|
167
|
+
const refunds = await client.refunds.listForPayment('intent-uuid');
|
|
168
|
+
|
|
169
|
+
// Wait for completion
|
|
170
|
+
const completedRefund = await client.refunds.waitForCompletion('refund-uuid');
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Dashboard
|
|
174
|
+
|
|
175
|
+
```javascript
|
|
176
|
+
// Summary metrics
|
|
177
|
+
const summary = await client.dashboard.getSummary();
|
|
178
|
+
|
|
179
|
+
// Transaction list with filters
|
|
180
|
+
const { transactions, pagination } = await client.dashboard.getTransactions({
|
|
181
|
+
status: 'completed',
|
|
182
|
+
storeId: 'STORE001',
|
|
183
|
+
startDate: '2024-01-01',
|
|
184
|
+
endDate: '2024-12-31',
|
|
185
|
+
limit: 50,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Store breakdown
|
|
189
|
+
const stores = await client.dashboard.getStores();
|
|
190
|
+
|
|
191
|
+
// Daily data for charts
|
|
192
|
+
const daily = await client.dashboard.getDaily({ days: 30 });
|
|
193
|
+
|
|
194
|
+
// Export CSV
|
|
195
|
+
const csv = await client.dashboard.export({
|
|
196
|
+
startDate: '2024-01-01',
|
|
197
|
+
endDate: '2024-12-31',
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Branding
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
// Get branding for white-label UI
|
|
205
|
+
const branding = await client.branding.get('STORE001');
|
|
206
|
+
|
|
207
|
+
// Generate CSS variables
|
|
208
|
+
const css = client.branding.toCssVariables(branding);
|
|
209
|
+
// --swiftshopr-primary: #E31837;
|
|
210
|
+
// --swiftshopr-background: #FFFFFF;
|
|
211
|
+
|
|
212
|
+
// Get CDP/OnchainKit theme tokens
|
|
213
|
+
const cdpTheme = client.branding.toCdpTheme(branding);
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Webhooks
|
|
217
|
+
|
|
218
|
+
### Verify Webhook Signatures
|
|
219
|
+
|
|
220
|
+
```javascript
|
|
221
|
+
const { SwiftShoprClient, webhookMiddleware } = require('swiftshopr-payments');
|
|
222
|
+
|
|
223
|
+
// Option 1: Express middleware
|
|
224
|
+
app.post('/webhooks/swiftshopr',
|
|
225
|
+
express.raw({ type: 'application/json' }),
|
|
226
|
+
webhookMiddleware('whsec_your_secret'),
|
|
227
|
+
(req, res) => {
|
|
228
|
+
const event = req.webhookEvent;
|
|
229
|
+
|
|
230
|
+
switch (event.type) {
|
|
231
|
+
case 'payment.completed':
|
|
232
|
+
console.log('Payment completed:', event.data.orderId);
|
|
233
|
+
break;
|
|
234
|
+
case 'refund.completed':
|
|
235
|
+
console.log('Refund completed:', event.data.refundId);
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
res.json({ received: true });
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
// Option 2: Manual verification
|
|
244
|
+
const client = new SwiftShoprClient({
|
|
245
|
+
apiKey: 'sk_live_...',
|
|
246
|
+
webhookSecret: 'whsec_your_secret',
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const event = client.webhooks.constructEvent(
|
|
250
|
+
req.body, // Raw body
|
|
251
|
+
req.headers // { 'x-webhook-signature': '...', 'x-webhook-timestamp': '...' }
|
|
252
|
+
);
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Webhook Events
|
|
256
|
+
|
|
257
|
+
| Event | Description |
|
|
258
|
+
|-------|-------------|
|
|
259
|
+
| `payment.completed` | Payment confirmed on-chain |
|
|
260
|
+
| `payment.failed` | Payment failed |
|
|
261
|
+
| `payment.expired` | Payment intent expired |
|
|
262
|
+
| `refund.requested` | Refund initiated |
|
|
263
|
+
| `refund.completed` | Refund confirmed on-chain |
|
|
264
|
+
| `refund.failed` | Refund failed |
|
|
265
|
+
|
|
266
|
+
## Error Handling
|
|
267
|
+
|
|
268
|
+
```javascript
|
|
269
|
+
const { SwiftShoprError, HttpError, TimeoutError } = require('swiftshopr-payments');
|
|
270
|
+
|
|
271
|
+
try {
|
|
272
|
+
await client.payments.createSession({ amount: 25.00 });
|
|
273
|
+
} catch (error) {
|
|
274
|
+
if (error instanceof SwiftShoprError) {
|
|
275
|
+
// Validation or business logic error
|
|
276
|
+
console.log('Code:', error.code);
|
|
277
|
+
console.log('Message:', error.message);
|
|
278
|
+
console.log('Details:', error.details);
|
|
279
|
+
} else if (error instanceof HttpError) {
|
|
280
|
+
// HTTP error from API
|
|
281
|
+
console.log('Status:', error.statusCode);
|
|
282
|
+
console.log('Response:', error.response);
|
|
283
|
+
} else if (error instanceof TimeoutError) {
|
|
284
|
+
// Request timed out
|
|
285
|
+
console.log('Timeout after:', error.timeout, 'ms');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Configuration
|
|
291
|
+
|
|
292
|
+
```javascript
|
|
293
|
+
const client = new SwiftShoprClient({
|
|
294
|
+
apiKey: 'sk_live_...', // Required
|
|
295
|
+
webhookSecret: 'whsec_...', // Optional: For webhook verification
|
|
296
|
+
baseUrl: 'https://...', // Optional: Custom API URL
|
|
297
|
+
timeout: 30000, // Optional: Request timeout (ms)
|
|
298
|
+
retries: 3, // Optional: Retry attempts
|
|
299
|
+
|
|
300
|
+
// Hooks for logging/monitoring
|
|
301
|
+
onRequest: ({ method, url }) => {
|
|
302
|
+
console.log(`[API] ${method} ${url}`);
|
|
303
|
+
},
|
|
304
|
+
onResponse: ({ status, data }) => {
|
|
305
|
+
console.log(`[API] Response: ${status}`);
|
|
306
|
+
},
|
|
307
|
+
onError: (error) => {
|
|
308
|
+
console.error('[API] Error:', error.message);
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## TypeScript
|
|
314
|
+
|
|
315
|
+
Full TypeScript support with type definitions:
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
import { SwiftShoprClient, PaymentStatus, RefundResult } from 'swiftshopr-payments';
|
|
319
|
+
|
|
320
|
+
const client = new SwiftShoprClient({ apiKey: 'sk_live_...' });
|
|
321
|
+
|
|
322
|
+
const status: PaymentStatus = await client.payments.getStatus('uuid');
|
|
323
|
+
const refund: RefundResult = await client.refunds.create({ intentId: 'uuid' });
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Requirements
|
|
327
|
+
|
|
328
|
+
- Node.js 18+ (uses native `fetch`)
|
|
329
|
+
- SwiftShopr API key
|
|
330
|
+
|
|
331
|
+
## Support
|
|
332
|
+
|
|
333
|
+
- Documentation: https://docs.swiftshopr.com
|
|
334
|
+
- Issues: https://github.com/swiftshopr/payments-sdk/issues
|
|
335
|
+
- Email: sdk@swiftshopr.com
|
|
336
|
+
|
|
337
|
+
## License
|
|
338
|
+
|
|
339
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "swiftshopr-payments",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official Node.js SDK for SwiftShopr Payments - Accept USDC payments with zero chargebacks",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "src/types/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./src/index.js",
|
|
10
|
+
"import": "./src/index.js",
|
|
11
|
+
"types": "./src/types/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"src/**/*",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"test": "jest --passWithNoTests",
|
|
21
|
+
"lint": "echo 'Linting skipped - no eslint config'",
|
|
22
|
+
"prepublishOnly": "npm test"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/swiftshopr/payments-sdk.git"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"swiftshopr",
|
|
30
|
+
"payments",
|
|
31
|
+
"usdc",
|
|
32
|
+
"crypto",
|
|
33
|
+
"stablecoin",
|
|
34
|
+
"point-of-sale",
|
|
35
|
+
"pos",
|
|
36
|
+
"retail",
|
|
37
|
+
"sdk",
|
|
38
|
+
"api",
|
|
39
|
+
"base",
|
|
40
|
+
"coinbase",
|
|
41
|
+
"web3"
|
|
42
|
+
],
|
|
43
|
+
"author": "SwiftShopr <sdk@swiftshopr.com>",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/swiftshopr/payments-sdk/issues"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://docs.swiftshopr.com/sdk",
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18.0.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {},
|
|
53
|
+
"dependencies": {}
|
|
54
|
+
}
|
package/src/branding.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branding API Module
|
|
3
|
+
* Fetch retailer branding for white-label UI
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { SwiftShoprError } = require('./utils/http');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Create Branding API instance
|
|
10
|
+
*/
|
|
11
|
+
function createBrandingAPI(http) {
|
|
12
|
+
return {
|
|
13
|
+
/**
|
|
14
|
+
* Get branding for a store
|
|
15
|
+
*
|
|
16
|
+
* @param {string} storeId - Store ID
|
|
17
|
+
* @returns {Promise<Object>} Branding configuration
|
|
18
|
+
*/
|
|
19
|
+
async get(storeId) {
|
|
20
|
+
if (!storeId) {
|
|
21
|
+
throw new SwiftShoprError('VALIDATION_ERROR', 'storeId is required');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const response = await http.get(
|
|
25
|
+
`/api/v1/sdk/onramp/branding/${encodeURIComponent(storeId)}`,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
storeId: response.store_id,
|
|
30
|
+
branding: {
|
|
31
|
+
name: response.branding?.name || null,
|
|
32
|
+
logoUrl: response.branding?.logo_url || null,
|
|
33
|
+
theme: {
|
|
34
|
+
primaryColor: response.branding?.theme?.primary_color || '#000000',
|
|
35
|
+
secondaryColor:
|
|
36
|
+
response.branding?.theme?.secondary_color || '#FFFFFF',
|
|
37
|
+
backgroundColor:
|
|
38
|
+
response.branding?.theme?.background_color || '#FFFFFF',
|
|
39
|
+
textColor: response.branding?.theme?.text_color || '#333333',
|
|
40
|
+
accentColor: response.branding?.theme?.accent_color || '#007AFF',
|
|
41
|
+
mode: response.branding?.theme?.mode || 'light',
|
|
42
|
+
fontFamily: response.branding?.theme?.font_family || null,
|
|
43
|
+
},
|
|
44
|
+
// CDP/OnchainKit compatible theme tokens
|
|
45
|
+
cdpTheme: response.branding?.cdp_theme || null,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Generate CSS variables from branding
|
|
52
|
+
*
|
|
53
|
+
* @param {Object} branding - Branding object from get()
|
|
54
|
+
* @returns {string} CSS custom properties
|
|
55
|
+
*/
|
|
56
|
+
toCssVariables(branding) {
|
|
57
|
+
if (!branding?.branding?.theme) {
|
|
58
|
+
return '';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { theme } = branding.branding;
|
|
62
|
+
const vars = [
|
|
63
|
+
`--swiftshopr-primary: ${theme.primaryColor};`,
|
|
64
|
+
`--swiftshopr-secondary: ${theme.secondaryColor};`,
|
|
65
|
+
`--swiftshopr-background: ${theme.backgroundColor};`,
|
|
66
|
+
`--swiftshopr-text: ${theme.textColor};`,
|
|
67
|
+
`--swiftshopr-accent: ${theme.accentColor};`,
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
if (theme.fontFamily) {
|
|
71
|
+
vars.push(`--swiftshopr-font: ${theme.fontFamily};`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return vars.join('\n');
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Generate style object for React inline styles
|
|
79
|
+
*
|
|
80
|
+
* @param {Object} branding - Branding object from get()
|
|
81
|
+
* @returns {Object} Style object
|
|
82
|
+
*/
|
|
83
|
+
toStyleObject(branding) {
|
|
84
|
+
if (!branding?.branding?.theme) {
|
|
85
|
+
return {};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const { theme } = branding.branding;
|
|
89
|
+
return {
|
|
90
|
+
'--swiftshopr-primary': theme.primaryColor,
|
|
91
|
+
'--swiftshopr-secondary': theme.secondaryColor,
|
|
92
|
+
'--swiftshopr-background': theme.backgroundColor,
|
|
93
|
+
'--swiftshopr-text': theme.textColor,
|
|
94
|
+
'--swiftshopr-accent': theme.accentColor,
|
|
95
|
+
...(theme.fontFamily && { '--swiftshopr-font': theme.fontFamily }),
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get CDP/OnchainKit theme tokens
|
|
101
|
+
*
|
|
102
|
+
* @param {Object} branding - Branding object from get()
|
|
103
|
+
* @returns {Object} CDP theme tokens for OnchainKit
|
|
104
|
+
*/
|
|
105
|
+
toCdpTheme(branding) {
|
|
106
|
+
if (branding?.branding?.cdpTheme) {
|
|
107
|
+
return branding.branding.cdpTheme;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Generate from standard theme
|
|
111
|
+
const theme = branding?.branding?.theme;
|
|
112
|
+
if (!theme) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
'colors-bg-primary': theme.backgroundColor,
|
|
118
|
+
'colors-bg-secondary': theme.mode === 'dark' ? '#1a1a1a' : '#F5F5F5',
|
|
119
|
+
'colors-fg-default': theme.textColor,
|
|
120
|
+
'colors-accent': theme.accentColor || theme.primaryColor,
|
|
121
|
+
'colors-accent-foreground': '#FFFFFF',
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
module.exports = { createBrandingAPI };
|
package/src/client.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SwiftShopr Payments Client
|
|
3
|
+
* Main entry point for the SDK
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { createHttpClient, SwiftShoprError } = require('./utils/http');
|
|
7
|
+
const { createPaymentsAPI } = require('./payments');
|
|
8
|
+
const { createRefundsAPI } = require('./refunds');
|
|
9
|
+
const { createDashboardAPI } = require('./dashboard');
|
|
10
|
+
const { createBrandingAPI } = require('./branding');
|
|
11
|
+
const { createConfigAPI } = require('./config');
|
|
12
|
+
const { createWebhooksHelper } = require('./webhooks');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* SwiftShopr Payments Client
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* const client = new SwiftShoprClient({
|
|
19
|
+
* apiKey: 'sk_live_...',
|
|
20
|
+
* webhookSecret: 'whsec_...', // optional
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* // Create payment
|
|
24
|
+
* const session = await client.payments.createSession({
|
|
25
|
+
* amount: 25.00,
|
|
26
|
+
* orderId: 'ORDER-123',
|
|
27
|
+
* storeId: 'STORE001',
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* // Request refund
|
|
31
|
+
* const refund = await client.refunds.create({
|
|
32
|
+
* intentId: session.intentId,
|
|
33
|
+
* reason: 'Customer request',
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // Get dashboard metrics
|
|
37
|
+
* const summary = await client.dashboard.getSummary();
|
|
38
|
+
*/
|
|
39
|
+
class SwiftShoprClient {
|
|
40
|
+
/**
|
|
41
|
+
* Create a new SwiftShopr client
|
|
42
|
+
*
|
|
43
|
+
* @param {Object} config
|
|
44
|
+
* @param {string} config.apiKey - Your SwiftShopr API key (required)
|
|
45
|
+
* @param {string} [config.webhookSecret] - Webhook secret for signature verification
|
|
46
|
+
* @param {string} [config.baseUrl] - API base URL (default: production)
|
|
47
|
+
* @param {number} [config.timeout=30000] - Request timeout in ms
|
|
48
|
+
* @param {number} [config.retries=3] - Number of retries for failed requests
|
|
49
|
+
* @param {Function} [config.onRequest] - Hook called before each request
|
|
50
|
+
* @param {Function} [config.onResponse] - Hook called after each response
|
|
51
|
+
* @param {Function} [config.onError] - Hook called on errors
|
|
52
|
+
*/
|
|
53
|
+
constructor(config) {
|
|
54
|
+
if (!config || !config.apiKey) {
|
|
55
|
+
throw new SwiftShoprError('CONFIG_ERROR', 'API key is required');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this._config = {
|
|
59
|
+
baseUrl: config.baseUrl || 'https://shopr-scanner-backend.onrender.com',
|
|
60
|
+
apiKey: config.apiKey,
|
|
61
|
+
webhookSecret: config.webhookSecret || null,
|
|
62
|
+
timeout: config.timeout || 30000,
|
|
63
|
+
retries: config.retries ?? 3,
|
|
64
|
+
onRequest: config.onRequest || null,
|
|
65
|
+
onResponse: config.onResponse || null,
|
|
66
|
+
onError: config.onError || null,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Create HTTP client
|
|
70
|
+
this._http = createHttpClient(this._config);
|
|
71
|
+
|
|
72
|
+
// Initialize API modules
|
|
73
|
+
this.payments = createPaymentsAPI(this._http);
|
|
74
|
+
this.refunds = createRefundsAPI(this._http);
|
|
75
|
+
this.dashboard = createDashboardAPI(this._http);
|
|
76
|
+
this.branding = createBrandingAPI(this._http);
|
|
77
|
+
this.config = createConfigAPI(this._http);
|
|
78
|
+
|
|
79
|
+
// Webhooks helper (if secret provided)
|
|
80
|
+
if (this._config.webhookSecret) {
|
|
81
|
+
this.webhooks = createWebhooksHelper(this._config.webhookSecret);
|
|
82
|
+
} else {
|
|
83
|
+
// Provide method to create webhooks helper later
|
|
84
|
+
this.webhooks = {
|
|
85
|
+
configure: (secret) => createWebhooksHelper(secret),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get SDK version
|
|
92
|
+
*/
|
|
93
|
+
static get VERSION() {
|
|
94
|
+
return '1.0.0';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get current configuration (without sensitive data)
|
|
99
|
+
*/
|
|
100
|
+
getConfig() {
|
|
101
|
+
return {
|
|
102
|
+
baseUrl: this._config.baseUrl,
|
|
103
|
+
timeout: this._config.timeout,
|
|
104
|
+
retries: this._config.retries,
|
|
105
|
+
hasApiKey: !!this._config.apiKey,
|
|
106
|
+
hasWebhookSecret: !!this._config.webhookSecret,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = { SwiftShoprClient };
|