awesome-node-checkout 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +192 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# awesome-node-checkout
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/awesome-node-checkout)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
A **framework-agnostic** payment checkout library for Node.js, written in TypeScript.
|
|
7
|
+
Drop-in payment orchestration for Express, NestJS, Fastify and any other Node.js framework — connect any payment provider through a single interface.
|
|
8
|
+
|
|
9
|
+
> Inspired by [awesome-node-auth](https://github.com/nik2208/awesome-node-auth). Same philosophy: no framework lock-in, no DB lock-in, implement one interface and you're done.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install awesome-node-checkout
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { CheckoutConfigurator, PayPalProvider, NexiProvider, SatispayProvider } from 'awesome-node-checkout';
|
|
25
|
+
import * as fs from 'fs';
|
|
26
|
+
|
|
27
|
+
const checkout = new CheckoutConfigurator();
|
|
28
|
+
|
|
29
|
+
checkout
|
|
30
|
+
.registerProvider(new PayPalProvider({
|
|
31
|
+
clientId: process.env.PAYPAL_CLIENT_ID!,
|
|
32
|
+
clientSecret: process.env.PAYPAL_CLIENT_SECRET!,
|
|
33
|
+
environment: 'sandbox',
|
|
34
|
+
}))
|
|
35
|
+
.registerProvider(new NexiProvider({
|
|
36
|
+
merchantId: process.env.NEXI_MERCHANT_ID!,
|
|
37
|
+
macKey: process.env.NEXI_MAC_KEY!,
|
|
38
|
+
environment: 'sandbox',
|
|
39
|
+
}))
|
|
40
|
+
.registerProvider(new SatispayProvider({
|
|
41
|
+
keyId: process.env.SATISPAY_KEY_ID!,
|
|
42
|
+
privateKey: fs.readFileSync('private.pem', 'utf8'),
|
|
43
|
+
environment: 'sandbox',
|
|
44
|
+
serverUrl: 'https://myapp.com',
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
// Use directly — no HTTP framework needed
|
|
48
|
+
const result = await checkout.createPayment('paypal', {
|
|
49
|
+
amount: 49.99,
|
|
50
|
+
currency: 'EUR',
|
|
51
|
+
description: 'Order #1234',
|
|
52
|
+
returnUrl: 'https://myapp.com/payment/success',
|
|
53
|
+
cancelUrl: 'https://myapp.com/payment/cancel',
|
|
54
|
+
orderId: 'ORD-1234',
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (result.approvalUrl) {
|
|
58
|
+
// redirect the user to result.approvalUrl
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### With Express adapter
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import express from 'express';
|
|
66
|
+
import { createCheckoutRouter } from 'awesome-node-checkout/express';
|
|
67
|
+
|
|
68
|
+
const app = express();
|
|
69
|
+
app.use(express.json());
|
|
70
|
+
|
|
71
|
+
// Mounts all checkout routes under /checkout
|
|
72
|
+
app.use('/checkout', createCheckoutRouter(checkout));
|
|
73
|
+
|
|
74
|
+
app.listen(3000);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### With Fastify (or any other framework)
|
|
78
|
+
|
|
79
|
+
Use the `CheckoutConfigurator` methods directly in your own routes:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
fastify.post('/checkout/:provider', async (req, reply) => {
|
|
83
|
+
const result = await checkout.createPayment(req.params.provider, req.body);
|
|
84
|
+
reply.status(result.success ? 201 : 400).send(result);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
fastify.post('/checkout/:provider/webhook', async (req, reply) => {
|
|
88
|
+
const result = await checkout.handleWebhook(req.params.provider, req.body, req.headers);
|
|
89
|
+
reply.send(result);
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Routes (Express adapter)
|
|
96
|
+
|
|
97
|
+
| Method | Path | Description |
|
|
98
|
+
|--------|-----------------------------|----------------------------------|
|
|
99
|
+
| POST | `/:provider` | Create a payment |
|
|
100
|
+
| POST | `/:provider/execute` | Execute/capture a payment |
|
|
101
|
+
| GET | `/:provider/redirect` | Handle provider redirect callback|
|
|
102
|
+
| GET | `/:provider/:id` | Get payment details |
|
|
103
|
+
| POST | `/:provider/refund` | Refund a payment |
|
|
104
|
+
| POST | `/:provider/webhook` | Handle provider webhook |
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Payment Flows
|
|
109
|
+
|
|
110
|
+
| Flow | Providers | Description |
|
|
111
|
+
|------------|------------------|----------------------------------------------------------|
|
|
112
|
+
| `redirect` | PayPal, Nexi | User is redirected to provider, returns with query params|
|
|
113
|
+
| `webhook` | Satispay | Provider calls a webhook URL after async confirmation |
|
|
114
|
+
| `direct` | *(future)* | Synchronous processing (card tokenization, etc.) |
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Events
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
checkout.events
|
|
122
|
+
.on('payment.created', ({ provider, paymentId }) => { /* ... */ })
|
|
123
|
+
.on('payment.completed', ({ provider, paymentId }) => { /* ... */ })
|
|
124
|
+
.on('payment.failed', ({ provider, error }) => { /* ... */ })
|
|
125
|
+
.on('payment.refunded', ({ provider, paymentId }) => { /* ... */ })
|
|
126
|
+
.on('webhook.received', ({ provider, data }) => { /* ... */ });
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Custom Transaction Store
|
|
132
|
+
|
|
133
|
+
By default, `SatispayProvider` uses an in-memory store to correlate webhooks with orders.
|
|
134
|
+
For multi-instance deployments, implement `ITransactionStore`:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { ITransactionStore, TransactionData } from 'awesome-node-checkout';
|
|
138
|
+
|
|
139
|
+
class RedisTransactionStore implements ITransactionStore {
|
|
140
|
+
async save(key: string, data: TransactionData): Promise<void> { /* ... */ }
|
|
141
|
+
async get(key: string): Promise<TransactionData | null> { /* ... */ }
|
|
142
|
+
async delete(key: string): Promise<void> { /* ... */ }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
new SatispayProvider({
|
|
146
|
+
keyId: '...',
|
|
147
|
+
privateKey: '...',
|
|
148
|
+
transactionStore: new RedisTransactionStore(),
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Custom Provider
|
|
155
|
+
|
|
156
|
+
Extend `BasePaymentProvider` to add any payment provider:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { BasePaymentProvider, PaymentRequest, PaymentResult } from 'awesome-node-checkout';
|
|
160
|
+
|
|
161
|
+
export class StripeProvider extends BasePaymentProvider {
|
|
162
|
+
readonly name = 'stripe';
|
|
163
|
+
readonly flow = 'redirect' as const;
|
|
164
|
+
|
|
165
|
+
async createPayment(request: PaymentRequest): Promise<PaymentResult> {
|
|
166
|
+
// ... call Stripe API
|
|
167
|
+
}
|
|
168
|
+
// ... implement other methods
|
|
169
|
+
|
|
170
|
+
async handleRedirect(query: Record<string, any>): Promise<PaymentResult> {
|
|
171
|
+
// ... handle Stripe redirect
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
checkout.registerProvider(new StripeProvider({ secretKey: '...' }));
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Built-in Providers
|
|
181
|
+
|
|
182
|
+
| Provider | Flow | Notes |
|
|
183
|
+
|-----------|-----------|--------------------------------------------|
|
|
184
|
+
| PayPal | redirect | Orders API v2 |
|
|
185
|
+
| Nexi | redirect | eCommerce DispatcherServlet + MAC SHA-1 |
|
|
186
|
+
| Satispay | webhook | Business API v1, RSA-SHA256 signature |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "awesome-node-checkout",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Framework-agnostic payment checkout library for Node.js",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js",
|
|
10
|
+
"./express": "./dist/adapters/express/index.js"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"test:coverage": "vitest run --coverage",
|
|
16
|
+
"typecheck": "tsc --noEmit"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"keywords": [
|
|
24
|
+
"payment",
|
|
25
|
+
"checkout",
|
|
26
|
+
"paypal",
|
|
27
|
+
"nexi",
|
|
28
|
+
"satispay",
|
|
29
|
+
"stripe",
|
|
30
|
+
"node",
|
|
31
|
+
"typescript",
|
|
32
|
+
"framework-agnostic"
|
|
33
|
+
],
|
|
34
|
+
"author": "",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/express": "^5.0.0",
|
|
38
|
+
"@types/node": "^22.0.0",
|
|
39
|
+
"@types/supertest": "^7.2.0",
|
|
40
|
+
"express": "^5.0.0",
|
|
41
|
+
"supertest": "^7.2.2",
|
|
42
|
+
"typescript": "^5.8.0",
|
|
43
|
+
"vitest": "^4.1.1"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@paypal/paypal-server-sdk": "^2.2.0"
|
|
47
|
+
}
|
|
48
|
+
}
|