awesome-node-checkout 1.0.2 → 1.2.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/CHANGELOG.md +61 -0
- package/README.md +101 -23
- package/dist/adapters/express/index.d.ts +64 -7
- package/dist/adapters/express/index.d.ts.map +1 -1
- package/dist/adapters/express/index.js +127 -25
- package/dist/adapters/express/index.js.map +1 -1
- package/dist/checkout-configurator.d.ts +5 -1
- package/dist/checkout-configurator.d.ts.map +1 -1
- package/dist/checkout-configurator.js +28 -3
- package/dist/checkout-configurator.js.map +1 -1
- package/dist/events/checkout-event-bus.d.ts +1 -0
- package/dist/events/checkout-event-bus.d.ts.map +1 -1
- package/dist/events/checkout-event-bus.js.map +1 -1
- package/dist/interfaces/payment-provider.interface.d.ts +7 -3
- package/dist/interfaces/payment-provider.interface.d.ts.map +1 -1
- package/dist/models/payment-request.model.d.ts +2 -0
- package/dist/models/payment-request.model.d.ts.map +1 -1
- package/dist/models/payment-result.model.d.ts +8 -0
- package/dist/models/payment-result.model.d.ts.map +1 -1
- package/dist/providers/nexi/nexi.provider.d.ts +21 -8
- package/dist/providers/nexi/nexi.provider.d.ts.map +1 -1
- package/dist/providers/nexi/nexi.provider.js +160 -44
- package/dist/providers/nexi/nexi.provider.js.map +1 -1
- package/dist/providers/paypal/paypal.provider.d.ts.map +1 -1
- package/dist/providers/paypal/paypal.provider.js +17 -0
- package/dist/providers/paypal/paypal.provider.js.map +1 -1
- package/dist/providers/satispay/satispay.provider.d.ts +15 -5
- package/dist/providers/satispay/satispay.provider.d.ts.map +1 -1
- package/dist/providers/satispay/satispay.provider.js +54 -13
- package/dist/providers/satispay/satispay.provider.js.map +1 -1
- package/package.json +19 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.2.0] - 2026-09-27
|
|
9
|
+
|
|
10
|
+
### Security
|
|
11
|
+
- **Nexi**: Fail-closed outcome MAC verification on redirect and webhook. Missing or invalid `mac` parameter rejects payment with status `FAILED` and error `'MAC missing'`. Verifies 7-field formula (`codTrans`, `esito`, `importo`, `divisa`, `data`, `orario`, `codAut`, `macKey`) using constant-time comparison `crypto.timingSafeEqual`. Resolves #6.
|
|
12
|
+
- **Express Adapter**: `publicPaths` now uses segment-based path matching rather than substring matching, preventing subpath bypasses such as `/webhook/execute` or `/redirect/execute` when `/webhook` or `/redirect` is marked public. Resolves #13.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- **Nexi**: Updated `getPaymentDetails` to query the official BackOffice endpoint `POST /ecomm/api/bo/situazioneOrdine` with JSON payload and response MAC verification instead of the non-existent IGFS endpoint. Resolves #7.
|
|
16
|
+
- **Satispay**: Fixed webhook handling for GET callbacks containing `payment_id` query parameter, ensuring callbacks routed to `handleWebhook` correctly extract payment details and verify signatures. Added configurable `callbackPath` (defaulting to `/checkout/satispay/webhook`). Resolves #10.
|
|
17
|
+
- **Satispay**: Fixed HTTP signature verification to support `(request-target)` pseudo-header via request context, signature header without `(request-target)`, flexible header key order, and body digest verification. Resolves #11.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- **Nexi**: Added server-to-server outcome notification support (`urlpost`) configured via `PaymentRequest.notifyUrl` in `createPayment`, and handled via `NexiProvider.handleWebhook`. Resolves #8.
|
|
21
|
+
- **Core**: Exposed `amount` and `currency` in `PaymentResult` and `WebhookResult` across all providers (Nexi, PayPal, Satispay) to enable post-payment amount verification. Resolves #9.
|
|
22
|
+
- **Core**: Propagated `orderId` and `raw` provider response data through `CheckoutConfigurator` event bus payloads (`payment.created`, `payment.completed`, `payment.failed`, `payment.refunded`, `webhook.received`). Resolves #12.
|
|
23
|
+
- **Express Adapter**: Added `options.redirect` for automatic 302 HTTP redirects to `onSuccess(result, req)` or `onFailure(result, req)` on browser return. Resolves #12.
|
|
24
|
+
- **Express Adapter**: Added `options.details` configuration to gate or disable `GET /:provider/:id` (`enabled: false` returns 404, or custom `middleware`). Resolves #12.
|
|
25
|
+
- **Express Adapter**: Added context argument `{ provider, res }` to `buildPaymentRequest(req, ctx)` and strict validation of returned `PaymentRequest`. Resolves #12.
|
|
26
|
+
- **Express Adapter**: Mounted both `GET` and `POST` routes for `/:provider/webhook`. Resolves #10.
|
|
27
|
+
- **Packaging**: Added `"types"` condition to `exports` in `package.json` for TypeScript package resolution under `node16`/`nodenext`. Resolves #12.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- **Nexi**: Breaking change in outcome verification: previously `handleRedirect` accepted outcomes without a `mac` field. It is now strictly required (fail-closed). Any integration testing Nexi callbacks must supply a valid `mac`.
|
|
31
|
+
|
|
32
|
+
## [1.1.0] - 2026-09-27
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
- **Security**: Added `buildPaymentRequest` hook in `createCheckoutRouter` options to build payment requests securely server-side (preventing clients from tampering with amounts and order parameters). Resolves #3.
|
|
36
|
+
- **Security**: Added mount-time warning when `createCheckoutRouter` is used without `buildPaymentRequest`.
|
|
37
|
+
- **Validation**: Added input validation on `POST /:provider` when `buildPaymentRequest` is not configured (requires finite positive number `amount` and non-empty `currency`).
|
|
38
|
+
- **Gating**: Gated `POST /:provider/refund` behind `options.refund` (returns 404 unless explicitly configured with optional middleware).
|
|
39
|
+
- **Hooks**: Added `onBeforeExecute` and dedicated `middleware` support in `options.execute` for `POST /:provider/execute`.
|
|
40
|
+
- **Examples**: Added reference Express implementation under `examples/express` demonstrating SQLite store, Handlebars UI, and full checkout flow.
|
|
41
|
+
|
|
42
|
+
## [1.0.2] - 2026-04-23
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
- Removed compiled `dist/` artifacts from git tracking.
|
|
46
|
+
- Added GitHub Actions publish workflow.
|
|
47
|
+
- Updated dependencies.
|
|
48
|
+
|
|
49
|
+
## [1.0.1] - 2026-04-13
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
- Satispay provider warning at construction time when `webhookPublicKey` is not configured.
|
|
53
|
+
- PayPal refund implementation and security improvements.
|
|
54
|
+
|
|
55
|
+
## [1.0.0] - 2026-03-30
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
- Initial release of `awesome-node-checkout`.
|
|
59
|
+
- Framework-agnostic `CheckoutConfigurator`.
|
|
60
|
+
- PayPal, Nexi, and Satispay providers.
|
|
61
|
+
- Express adapter with `createCheckoutRouter`.
|
package/README.md
CHANGED
|
@@ -67,13 +67,58 @@ import { createCheckoutRouter } from 'awesome-node-checkout/express';
|
|
|
67
67
|
|
|
68
68
|
const app = express();
|
|
69
69
|
app.use(express.json());
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
// If using Nexi server notifications (urlpost), urlencoded parser is required:
|
|
71
|
+
app.use(express.urlencoded({ extended: false }));
|
|
72
|
+
|
|
73
|
+
// Mount checkout routes with secure server-side request builder and browser redirects
|
|
74
|
+
app.use(
|
|
75
|
+
'/checkout',
|
|
76
|
+
createCheckoutRouter(checkout, {
|
|
77
|
+
// Recommended: verify order and compute amount on the server
|
|
78
|
+
buildPaymentRequest: async (req, { provider }) => {
|
|
79
|
+
const order = await myOrderService.getOrder(req.body.orderId);
|
|
80
|
+
return {
|
|
81
|
+
amount: order.totalAmount,
|
|
82
|
+
currency: order.currency, // e.g. 'EUR'
|
|
83
|
+
orderId: order.id,
|
|
84
|
+
returnUrl: 'https://myapp.com/checkout/' + provider + '/redirect',
|
|
85
|
+
cancelUrl: 'https://myapp.com/payment/cancel',
|
|
86
|
+
notifyUrl: 'https://myapp.com/checkout/' + provider + '/webhook',
|
|
87
|
+
description: `Order #${order.id}`,
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
// Optional: automatic 302 redirects for browser-based flows
|
|
91
|
+
redirect: {
|
|
92
|
+
onSuccess: (result, req) => `/orders/${result.orderId}?status=success`,
|
|
93
|
+
onFailure: (result, req) => `/orders/${result.orderId}?status=failed&error=${encodeURIComponent(result.error || '')}`,
|
|
94
|
+
},
|
|
95
|
+
// Optional: gate or disable public access to GET /:provider/:id
|
|
96
|
+
details: {
|
|
97
|
+
enabled: false, // or provide middleware: [requireAuth]
|
|
98
|
+
},
|
|
99
|
+
// Opt-in: mount POST /:provider/refund protected by admin middleware
|
|
100
|
+
refund: {
|
|
101
|
+
middleware: [requireAdminAuth],
|
|
102
|
+
},
|
|
103
|
+
// Optional: guard execution before capturing payment
|
|
104
|
+
execute: {
|
|
105
|
+
onBeforeExecute: async (req, paymentId) => {
|
|
106
|
+
// Verify payment belongs to current session or user
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
// Public paths matching segments safely without substring bypasses
|
|
110
|
+
publicPaths: [
|
|
111
|
+
[':provider', 'webhook'],
|
|
112
|
+
[':provider', 'redirect'],
|
|
113
|
+
],
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
73
116
|
|
|
74
117
|
app.listen(3000);
|
|
75
118
|
```
|
|
76
119
|
|
|
120
|
+
> **Security Note**: Never trust client-sent amounts directly. Always define `buildPaymentRequest` so the payment amount and order parameters are derived server-side. If `buildPaymentRequest` is omitted, the router will issue a warning at mount time and validate that client bodies contain positive finite amounts and valid currencies.
|
|
121
|
+
|
|
77
122
|
### With Fastify (or any other framework)
|
|
78
123
|
|
|
79
124
|
Use the `CheckoutConfigurator` methods directly in your own routes:
|
|
@@ -85,23 +130,56 @@ fastify.post('/checkout/:provider', async (req, reply) => {
|
|
|
85
130
|
});
|
|
86
131
|
|
|
87
132
|
fastify.post('/checkout/:provider/webhook', async (req, reply) => {
|
|
88
|
-
const result = await checkout.handleWebhook(req.params.provider, req.body, req.headers
|
|
133
|
+
const result = await checkout.handleWebhook(req.params.provider, req.body, req.headers, req.query, {
|
|
134
|
+
method: req.method,
|
|
135
|
+
path: req.url,
|
|
136
|
+
});
|
|
89
137
|
reply.send(result);
|
|
90
138
|
});
|
|
91
139
|
```
|
|
92
140
|
|
|
93
141
|
---
|
|
94
142
|
|
|
143
|
+
## Example Application
|
|
144
|
+
|
|
145
|
+
A full-featured reference implementation using Express 5, SQLite (`ITransactionStore`), and Handlebars is available in [examples/express](./examples/express).
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
95
149
|
## Routes (Express adapter)
|
|
96
150
|
|
|
97
|
-
| Method
|
|
98
|
-
|
|
99
|
-
| POST
|
|
100
|
-
| POST
|
|
101
|
-
| GET
|
|
102
|
-
| GET
|
|
103
|
-
| POST
|
|
104
|
-
| POST
|
|
151
|
+
| Method | Path | Description |
|
|
152
|
+
|-------------|-----------------------------|----------------------------------------------------------------|
|
|
153
|
+
| POST | `/:provider` | Create a payment (server-built or validated) |
|
|
154
|
+
| POST | `/:provider/execute` | Execute/capture a payment (supports `onBeforeExecute`) |
|
|
155
|
+
| GET | `/:provider/redirect` | Handle provider redirect callback (supports 302 via `redirect`)|
|
|
156
|
+
| GET | `/:provider/:id` | Get payment details (*configurable*: can disable or protect via `details`)|
|
|
157
|
+
| POST | `/:provider/refund` | Refund a payment (*opt-in*: mounted only when `refund` option is set)|
|
|
158
|
+
| GET / POST | `/:provider/webhook` | Handle provider webhook (POST for Nexi/Satispay, GET for Satispay)|
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Security: A Redirect Is Not Proof of Payment
|
|
163
|
+
|
|
164
|
+
Relying solely on front-end browser redirects (`GET /:provider/redirect`) to fulfill orders introduces significant risk:
|
|
165
|
+
- **Drop-off**: Shoppers may close the tab, lose connectivity, or navigate away before reaching your redirect URL.
|
|
166
|
+
- **Tampering**: Unless protected by cryptographic signatures (such as Nexi's mandatory outcome MAC), client-controlled URL parameters can be manipulated.
|
|
167
|
+
- **Amount Mismatch**: Always verify that the captured payment amount matches your order ledger before fulfilling goods or services.
|
|
168
|
+
|
|
169
|
+
To ensure safe fulfillment:
|
|
170
|
+
1. **Verify Amount & Currency**: `PaymentResult` and `WebhookResult` return `amount` and `currency` extracted directly from the provider.
|
|
171
|
+
```typescript
|
|
172
|
+
const result = await checkout.handleRedirect(provider, req.query);
|
|
173
|
+
if (result.success && result.status === 'COMPLETED') {
|
|
174
|
+
if (result.amount !== order.totalAmount || result.currency !== order.currency) {
|
|
175
|
+
throw new Error('Authorized amount does not match order total');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
2. **Use Server Notifications / Webhooks**:
|
|
180
|
+
- For **Nexi**: Pass `notifyUrl` in `PaymentRequest` (e.g. `https://myapp.com/checkout/nexi/webhook`). Nexi sends a server-to-server POST notification (`urlpost`) with the 7-field outcome MAC. Ensure your app includes `app.use(express.urlencoded({ extended: false }))`.
|
|
181
|
+
- For **Satispay**: Use `callbackPath` or webhook callbacks; signatures are verified against Satispay's RSA public key with `(request-target)` HTTP signature support.
|
|
182
|
+
3. **Idempotency**: Because both the redirect callback and the webhook notification may arrive for the same order, ensure your fulfillment handler is idempotent.
|
|
105
183
|
|
|
106
184
|
---
|
|
107
185
|
|
|
@@ -110,7 +188,7 @@ fastify.post('/checkout/:provider/webhook', async (req, reply) => {
|
|
|
110
188
|
| Flow | Providers | Description |
|
|
111
189
|
|------------|------------------|----------------------------------------------------------|
|
|
112
190
|
| `redirect` | PayPal, Nexi | User is redirected to provider, returns with query params|
|
|
113
|
-
| `webhook` | Satispay
|
|
191
|
+
| `webhook` | Satispay, Nexi | Provider calls a webhook URL for async confirmation |
|
|
114
192
|
| `direct` | *(future)* | Synchronous processing (card tokenization, etc.) |
|
|
115
193
|
|
|
116
194
|
---
|
|
@@ -119,11 +197,11 @@ fastify.post('/checkout/:provider/webhook', async (req, reply) => {
|
|
|
119
197
|
|
|
120
198
|
```typescript
|
|
121
199
|
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 }) => { /* ... */ });
|
|
200
|
+
.on('payment.created', ({ provider, paymentId, orderId, raw }) => { /* ... */ })
|
|
201
|
+
.on('payment.completed', ({ provider, paymentId, orderId, raw }) => { /* ... */ })
|
|
202
|
+
.on('payment.failed', ({ provider, error, orderId, raw }) => { /* ... */ })
|
|
203
|
+
.on('payment.refunded', ({ provider, paymentId, orderId, raw }) => { /* ... */ })
|
|
204
|
+
.on('webhook.received', ({ provider, data, orderId, raw }) => { /* ... */ });
|
|
127
205
|
```
|
|
128
206
|
|
|
129
207
|
---
|
|
@@ -179,11 +257,11 @@ checkout.registerProvider(new StripeProvider({ secretKey: '...' }));
|
|
|
179
257
|
|
|
180
258
|
## Built-in Providers
|
|
181
259
|
|
|
182
|
-
| Provider | Flow
|
|
183
|
-
|
|
184
|
-
| PayPal | redirect
|
|
185
|
-
| Nexi | redirect | eCommerce DispatcherServlet + MAC SHA-1
|
|
186
|
-
| Satispay | webhook
|
|
260
|
+
| Provider | Flow | Notes |
|
|
261
|
+
|-----------|---------------------|---------------------------------------------------------------------------------------------|
|
|
262
|
+
| PayPal | redirect | Orders API v2 (`return=representation`, captures expose `amount` and `currency`) |
|
|
263
|
+
| Nexi | redirect + webhook | eCommerce DispatcherServlet + MAC SHA-1 (mandatory 7-field outcome MAC, `urlpost`, BackOffice `situazioneOrdine` API) |
|
|
264
|
+
| Satispay | webhook | Business API v1, RSA-SHA256 HTTP signature, GET and POST callbacks, configurable `callbackPath` |
|
|
187
265
|
|
|
188
266
|
---
|
|
189
267
|
|
|
@@ -1,17 +1,62 @@
|
|
|
1
|
-
import { Router, RequestHandler } from 'express';
|
|
1
|
+
import { Router, Request, Response, RequestHandler } from 'express';
|
|
2
2
|
import { CheckoutConfigurator } from '../../checkout-configurator';
|
|
3
|
+
import { PaymentRequest } from '../../models/payment-request.model';
|
|
4
|
+
import { PaymentResult } from '../../models/payment-result.model';
|
|
5
|
+
export interface PaymentRequestContext {
|
|
6
|
+
provider: string;
|
|
7
|
+
res: Response;
|
|
8
|
+
}
|
|
3
9
|
export interface ExpressCheckoutOptions {
|
|
4
10
|
/**
|
|
5
11
|
* Middleware applied to ALL checkout routes (e.g. API key auth).
|
|
6
|
-
* Webhooks are typically public — use `publicPaths` to exclude them.
|
|
12
|
+
* Webhooks and redirects are typically public — use `publicPaths` to exclude them.
|
|
7
13
|
*/
|
|
8
14
|
middleware?: RequestHandler[];
|
|
9
15
|
/**
|
|
10
|
-
* Route
|
|
11
|
-
* Matched
|
|
16
|
+
* Route patterns that bypass `middleware` (e.g. [':provider/webhook', ':provider/redirect']).
|
|
17
|
+
* Matched by path segments after the mount point (:provider matches any single segment).
|
|
12
18
|
*/
|
|
13
19
|
publicPaths?: string[];
|
|
20
|
+
/**
|
|
21
|
+
* Builds the PaymentRequest on the server (amount from your own order), ignoring the client body.
|
|
22
|
+
*/
|
|
23
|
+
buildPaymentRequest?: (req: Request, ctx: PaymentRequestContext) => PaymentRequest | Promise<PaymentRequest>;
|
|
24
|
+
/**
|
|
25
|
+
* When configured, GET /:provider/redirect responds with a 302 redirect
|
|
26
|
+
* to the URL returned by onSuccess or onFailure instead of JSON.
|
|
27
|
+
*/
|
|
28
|
+
redirect?: {
|
|
29
|
+
onSuccess: (result: PaymentResult, req: Request) => string;
|
|
30
|
+
onFailure: (result: PaymentResult, req: Request) => string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Configuration for GET /:provider/:id (getPaymentDetails).
|
|
34
|
+
* Default: enabled: true. Set enabled: false to return 404.
|
|
35
|
+
*/
|
|
36
|
+
details?: {
|
|
37
|
+
enabled?: boolean;
|
|
38
|
+
middleware?: RequestHandler[];
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Configuration for POST /:provider/refund.
|
|
42
|
+
* If omitted, the refund route is NOT mounted (returns 404).
|
|
43
|
+
*/
|
|
44
|
+
refund?: {
|
|
45
|
+
middleware?: RequestHandler[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Configuration for POST /:provider/execute.
|
|
49
|
+
*/
|
|
50
|
+
execute?: {
|
|
51
|
+
middleware?: RequestHandler[];
|
|
52
|
+
onBeforeExecute?: (req: Request, paymentId: string) => void | Promise<void>;
|
|
53
|
+
};
|
|
14
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Matches a request path against public path patterns by segments.
|
|
57
|
+
* ':provider' matches any single non-empty segment.
|
|
58
|
+
*/
|
|
59
|
+
export declare function isPathPublic(reqPath: string, publicPaths: string[]): boolean;
|
|
15
60
|
/**
|
|
16
61
|
* Creates an Express Router with all checkout endpoints pre-wired.
|
|
17
62
|
*
|
|
@@ -19,16 +64,28 @@ export interface ExpressCheckoutOptions {
|
|
|
19
64
|
* ```
|
|
20
65
|
* POST /:provider → createPayment
|
|
21
66
|
* POST /:provider/execute → executePayment
|
|
67
|
+
* POST /:provider/refund → refundPayment (only if options.refund is configured)
|
|
68
|
+
* GET /:provider/webhook → handleWebhook
|
|
69
|
+
* POST /:provider/webhook → handleWebhook
|
|
22
70
|
* GET /:provider/redirect → handleRedirect (must come before /:provider/:id)
|
|
23
71
|
* GET /:provider/:id → getPaymentDetails
|
|
24
|
-
* POST /:provider/refund → refundPayment
|
|
25
|
-
* POST /:provider/webhook → handleWebhook
|
|
26
72
|
* ```
|
|
27
73
|
*
|
|
28
74
|
* Usage:
|
|
29
75
|
* ```typescript
|
|
30
76
|
* import { createCheckoutRouter } from 'awesome-node-checkout/express';
|
|
31
|
-
* app.use('/checkout', createCheckoutRouter(checkout
|
|
77
|
+
* app.use('/checkout', createCheckoutRouter(checkout, {
|
|
78
|
+
* buildPaymentRequest: async (req, ctx) => {
|
|
79
|
+
* const order = await getOrder(req.body.orderId);
|
|
80
|
+
* return {
|
|
81
|
+
* amount: order.total,
|
|
82
|
+
* currency: 'EUR',
|
|
83
|
+
* orderId: order.id,
|
|
84
|
+
* returnUrl: 'https://example.com/success',
|
|
85
|
+
* cancelUrl: 'https://example.com/cancel',
|
|
86
|
+
* };
|
|
87
|
+
* },
|
|
88
|
+
* }));
|
|
32
89
|
* ```
|
|
33
90
|
*/
|
|
34
91
|
export declare function createCheckoutRouter(checkout: CheckoutConfigurator, options?: ExpressCheckoutOptions): Router;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/express/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/express/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,QAAQ,CAAC;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAEvB;;OAEG;IACH,mBAAmB,CAAC,EAAE,CACpB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,qBAAqB,KACvB,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAE9C;;;OAGG;IACH,QAAQ,CAAC,EAAE;QACT,SAAS,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;QAC3D,SAAS,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;KAC5D,CAAC;IAEF;;;OAGG;IACH,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;KAC/B,CAAC;IAEF;;;OAGG;IACH,MAAM,CAAC,EAAE;QACP,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;KAC/B,CAAC;IAEF;;OAEG;IACH,OAAO,CAAC,EAAE;QACR,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;QAC9B,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC7E,CAAC;CACH;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAc5E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,GAAE,sBAA2B,GACnC,MAAM,CA6KR"}
|
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isPathPublic = isPathPublic;
|
|
3
4
|
exports.createCheckoutRouter = createCheckoutRouter;
|
|
4
5
|
const express_1 = require("express");
|
|
5
6
|
const errors_1 = require("../../models/errors");
|
|
7
|
+
/**
|
|
8
|
+
* Matches a request path against public path patterns by segments.
|
|
9
|
+
* ':provider' matches any single non-empty segment.
|
|
10
|
+
*/
|
|
11
|
+
function isPathPublic(reqPath, publicPaths) {
|
|
12
|
+
const reqSegments = reqPath.split('/').filter(Boolean);
|
|
13
|
+
return publicPaths.some((pattern) => {
|
|
14
|
+
const patternSegments = pattern.split('/').filter(Boolean);
|
|
15
|
+
if (reqSegments.length !== patternSegments.length) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return patternSegments.every((patSeg, i) => {
|
|
19
|
+
if (patSeg === ':provider') {
|
|
20
|
+
return reqSegments[i].length > 0;
|
|
21
|
+
}
|
|
22
|
+
return patSeg === reqSegments[i];
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
}
|
|
6
26
|
/**
|
|
7
27
|
* Creates an Express Router with all checkout endpoints pre-wired.
|
|
8
28
|
*
|
|
@@ -10,27 +30,40 @@ const errors_1 = require("../../models/errors");
|
|
|
10
30
|
* ```
|
|
11
31
|
* POST /:provider → createPayment
|
|
12
32
|
* POST /:provider/execute → executePayment
|
|
33
|
+
* POST /:provider/refund → refundPayment (only if options.refund is configured)
|
|
34
|
+
* GET /:provider/webhook → handleWebhook
|
|
35
|
+
* POST /:provider/webhook → handleWebhook
|
|
13
36
|
* GET /:provider/redirect → handleRedirect (must come before /:provider/:id)
|
|
14
37
|
* GET /:provider/:id → getPaymentDetails
|
|
15
|
-
* POST /:provider/refund → refundPayment
|
|
16
|
-
* POST /:provider/webhook → handleWebhook
|
|
17
38
|
* ```
|
|
18
39
|
*
|
|
19
40
|
* Usage:
|
|
20
41
|
* ```typescript
|
|
21
42
|
* import { createCheckoutRouter } from 'awesome-node-checkout/express';
|
|
22
|
-
* app.use('/checkout', createCheckoutRouter(checkout
|
|
43
|
+
* app.use('/checkout', createCheckoutRouter(checkout, {
|
|
44
|
+
* buildPaymentRequest: async (req, ctx) => {
|
|
45
|
+
* const order = await getOrder(req.body.orderId);
|
|
46
|
+
* return {
|
|
47
|
+
* amount: order.total,
|
|
48
|
+
* currency: 'EUR',
|
|
49
|
+
* orderId: order.id,
|
|
50
|
+
* returnUrl: 'https://example.com/success',
|
|
51
|
+
* cancelUrl: 'https://example.com/cancel',
|
|
52
|
+
* };
|
|
53
|
+
* },
|
|
54
|
+
* }));
|
|
23
55
|
* ```
|
|
24
56
|
*/
|
|
25
57
|
function createCheckoutRouter(checkout, options = {}) {
|
|
26
58
|
const router = (0, express_1.Router)();
|
|
27
|
-
|
|
59
|
+
if (!options.buildPaymentRequest) {
|
|
60
|
+
console.warn('[awesome-node-checkout] createCheckoutRouter: the client body decides the amount; set buildPaymentRequest');
|
|
61
|
+
}
|
|
62
|
+
// Apply shared middleware (skipping public paths by segment match)
|
|
28
63
|
if (options.middleware?.length) {
|
|
29
64
|
const publicPaths = options.publicPaths ?? [];
|
|
30
65
|
router.use((req, res, next) => {
|
|
31
|
-
|
|
32
|
-
const isPublic = publicPaths.some((p) => req.path.endsWith(p) || req.path.includes(p.replace(':provider', providerParam)));
|
|
33
|
-
if (isPublic)
|
|
66
|
+
if (isPathPublic(req.path, publicPaths))
|
|
34
67
|
return next();
|
|
35
68
|
// Chain all middleware in sequence
|
|
36
69
|
const handlers = options.middleware;
|
|
@@ -45,7 +78,48 @@ function createCheckoutRouter(checkout, options = {}) {
|
|
|
45
78
|
// ---- POST /:provider — create payment ------------------------------------
|
|
46
79
|
router.post('/:provider', async (req, res) => {
|
|
47
80
|
try {
|
|
48
|
-
const
|
|
81
|
+
const provider = String(req.params.provider);
|
|
82
|
+
let paymentRequest;
|
|
83
|
+
if (options.buildPaymentRequest) {
|
|
84
|
+
paymentRequest = await options.buildPaymentRequest(req, {
|
|
85
|
+
provider,
|
|
86
|
+
res,
|
|
87
|
+
});
|
|
88
|
+
if (!paymentRequest ||
|
|
89
|
+
typeof paymentRequest !== 'object' ||
|
|
90
|
+
typeof paymentRequest.amount !== 'number' ||
|
|
91
|
+
!Number.isFinite(paymentRequest.amount) ||
|
|
92
|
+
paymentRequest.amount <= 0 ||
|
|
93
|
+
typeof paymentRequest.currency !== 'string' ||
|
|
94
|
+
paymentRequest.currency.trim() === '' ||
|
|
95
|
+
typeof paymentRequest.returnUrl !== 'string' ||
|
|
96
|
+
paymentRequest.returnUrl.trim() === '' ||
|
|
97
|
+
typeof paymentRequest.cancelUrl !== 'string' ||
|
|
98
|
+
paymentRequest.cancelUrl.trim() === '') {
|
|
99
|
+
return res.status(400).json({
|
|
100
|
+
success: false,
|
|
101
|
+
code: 'INVALID_PAYMENT_REQUEST',
|
|
102
|
+
error: 'Invalid payment request returned by buildPaymentRequest: amount must be a positive number, currency, returnUrl, and cancelUrl are required strings',
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const body = req.body;
|
|
108
|
+
const amount = body?.amount;
|
|
109
|
+
const currency = body?.currency;
|
|
110
|
+
if (typeof amount !== 'number' ||
|
|
111
|
+
!Number.isFinite(amount) ||
|
|
112
|
+
amount <= 0 ||
|
|
113
|
+
typeof currency !== 'string' ||
|
|
114
|
+
currency.trim() === '') {
|
|
115
|
+
return res.status(400).json({
|
|
116
|
+
success: false,
|
|
117
|
+
error: 'Invalid payment request: amount must be a positive number and currency is required',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
paymentRequest = body;
|
|
121
|
+
}
|
|
122
|
+
const result = await checkout.createPayment(provider, paymentRequest);
|
|
49
123
|
res.status(result.success ? 201 : 400).json(result);
|
|
50
124
|
}
|
|
51
125
|
catch (err) {
|
|
@@ -53,9 +127,16 @@ function createCheckoutRouter(checkout, options = {}) {
|
|
|
53
127
|
}
|
|
54
128
|
});
|
|
55
129
|
// ---- POST /:provider/execute — execute payment ---------------------------
|
|
56
|
-
|
|
130
|
+
const executeHandlers = [];
|
|
131
|
+
if (options.execute?.middleware?.length) {
|
|
132
|
+
executeHandlers.push(...options.execute.middleware);
|
|
133
|
+
}
|
|
134
|
+
router.post('/:provider/execute', ...executeHandlers, async (req, res) => {
|
|
57
135
|
try {
|
|
58
136
|
const { paymentId, data } = req.body;
|
|
137
|
+
if (options.execute?.onBeforeExecute) {
|
|
138
|
+
await options.execute.onBeforeExecute(req, paymentId);
|
|
139
|
+
}
|
|
59
140
|
const result = await checkout.executePayment(String(req.params.provider), paymentId, data);
|
|
60
141
|
res.status(result.success ? 200 : 400).json(result);
|
|
61
142
|
}
|
|
@@ -63,33 +144,47 @@ function createCheckoutRouter(checkout, options = {}) {
|
|
|
63
144
|
sendError(res, err);
|
|
64
145
|
}
|
|
65
146
|
});
|
|
66
|
-
// ---- POST /:provider/refund — refund payment
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
res.status(result.success ? 200 : 400).json(result);
|
|
147
|
+
// ---- POST /:provider/refund — refund payment (opt-in) --------------------
|
|
148
|
+
if (options.refund) {
|
|
149
|
+
const refundHandlers = [];
|
|
150
|
+
if (options.refund.middleware?.length) {
|
|
151
|
+
refundHandlers.push(...options.refund.middleware);
|
|
72
152
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
153
|
+
router.post('/:provider/refund', ...refundHandlers, async (req, res) => {
|
|
154
|
+
try {
|
|
155
|
+
const { paymentId, amount } = req.body;
|
|
156
|
+
const result = await checkout.refundPayment(String(req.params.provider), paymentId, amount);
|
|
157
|
+
res.status(result.success ? 200 : 400).json(result);
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
sendError(res, err);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
// ---- GET & POST /:provider/webhook — handle webhook ----------------------
|
|
165
|
+
const webhookHandler = async (req, res) => {
|
|
79
166
|
try {
|
|
80
|
-
const result = await checkout.handleWebhook(String(req.params.provider), req.body, req.headers);
|
|
167
|
+
const result = await checkout.handleWebhook(String(req.params.provider), req.body, req.headers, req.query, { method: req.method, path: req.originalUrl || req.url });
|
|
81
168
|
res.status(result.success ? 200 : 400).json(result);
|
|
82
169
|
}
|
|
83
170
|
catch (err) {
|
|
84
171
|
sendError(res, err);
|
|
85
172
|
}
|
|
86
|
-
}
|
|
173
|
+
};
|
|
174
|
+
router.get('/:provider/webhook', webhookHandler);
|
|
175
|
+
router.post('/:provider/webhook', webhookHandler);
|
|
87
176
|
// ---- GET /:provider/redirect — handle redirect callback ------------------
|
|
88
177
|
// NOTE: must be defined BEFORE /:provider/:id to avoid "redirect" being
|
|
89
178
|
// treated as a paymentId.
|
|
90
179
|
router.get('/:provider/redirect', async (req, res) => {
|
|
91
180
|
try {
|
|
92
181
|
const result = await checkout.handleRedirect(String(req.params.provider), req.query);
|
|
182
|
+
if (options.redirect) {
|
|
183
|
+
const targetUrl = result.success
|
|
184
|
+
? options.redirect.onSuccess(result, req)
|
|
185
|
+
: options.redirect.onFailure(result, req);
|
|
186
|
+
return res.redirect(302, targetUrl);
|
|
187
|
+
}
|
|
93
188
|
res.status(result.success ? 200 : 400).json(result);
|
|
94
189
|
}
|
|
95
190
|
catch (err) {
|
|
@@ -97,7 +192,14 @@ function createCheckoutRouter(checkout, options = {}) {
|
|
|
97
192
|
}
|
|
98
193
|
});
|
|
99
194
|
// ---- GET /:provider/:id — get payment details ----------------------------
|
|
100
|
-
|
|
195
|
+
const detailsHandlers = [];
|
|
196
|
+
if (options.details?.middleware?.length) {
|
|
197
|
+
detailsHandlers.push(...options.details.middleware);
|
|
198
|
+
}
|
|
199
|
+
router.get('/:provider/:id', ...detailsHandlers, async (req, res) => {
|
|
200
|
+
if (options.details?.enabled === false) {
|
|
201
|
+
return res.status(404).json({ success: false, error: 'Payment details route is disabled' });
|
|
202
|
+
}
|
|
101
203
|
try {
|
|
102
204
|
const result = await checkout.getPaymentDetails(String(req.params.provider), String(req.params.id));
|
|
103
205
|
res.status(result.success ? 200 : 404).json(result);
|
|
@@ -118,7 +220,7 @@ function sendError(res, err) {
|
|
|
118
220
|
WEBHOOK_NOT_SUPPORTED: 422,
|
|
119
221
|
REDIRECT_NOT_SUPPORTED: 422,
|
|
120
222
|
};
|
|
121
|
-
const status = statusMap[err.code] ??
|
|
223
|
+
const status = statusMap[err.code] ?? 400;
|
|
122
224
|
res.status(status).json({ success: false, error: err.message, code: err.code });
|
|
123
225
|
}
|
|
124
226
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/express/index.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/express/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,6 +27,7 @@ import { CheckoutEventBus } from './events/checkout-event-bus';
|
|
|
27
27
|
export declare class CheckoutConfigurator {
|
|
28
28
|
private readonly config;
|
|
29
29
|
private readonly providers;
|
|
30
|
+
private readonly paymentOrders;
|
|
30
31
|
/** Event bus — subscribe to payment lifecycle events */
|
|
31
32
|
readonly events: CheckoutEventBus;
|
|
32
33
|
constructor(config?: CheckoutConfig);
|
|
@@ -56,7 +57,10 @@ export declare class CheckoutConfigurator {
|
|
|
56
57
|
* Handle an incoming webhook from the provider.
|
|
57
58
|
* @throws CheckoutError if the provider does not support webhooks.
|
|
58
59
|
*/
|
|
59
|
-
handleWebhook(providerName: string, body
|
|
60
|
+
handleWebhook(providerName: string, body?: Record<string, unknown>, headers?: Record<string, string>, query?: Record<string, string>, context?: {
|
|
61
|
+
method?: string;
|
|
62
|
+
path?: string;
|
|
63
|
+
}): Promise<WebhookResult>;
|
|
60
64
|
/**
|
|
61
65
|
* Handle the redirect callback from the provider (query params).
|
|
62
66
|
* @throws CheckoutError if the provider does not support redirect handling.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkout-configurator.d.ts","sourceRoot":"","sources":["../src/checkout-configurator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,OAAO,EAAE,gBAAgB,EAA2C,MAAM,6BAA6B,CAAC;AAExG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,oBAAoB;
|
|
1
|
+
{"version":3,"file":"checkout-configurator.d.ts","sourceRoot":"","sources":["../src/checkout-configurator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,OAAO,EAAE,gBAAgB,EAA2C,MAAM,6BAA6B,CAAC;AAExG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,oBAAoB;IAOnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IANnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4C;IACtE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkC;IAEhE,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAA0B;gBAE9B,MAAM,GAAE,cAAmB;IAExD,8EAA8E;YAChE,IAAI;IASlB;;;OAGG;IACH,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAalD;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB;IAY3C,oDAAoD;IACpD,sBAAsB,IAAI,MAAM,EAAE;IAIlC,sDAAsD;IAChD,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAiB1F,mDAAmD;IAC7C,cAAc,CAClB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,OAAO,CAAC,aAAa,CAAC;IAezB,2DAA2D;IACrD,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAKxF,qCAAqC;IAC/B,aAAa,CACjB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,CAAC;IAezB;;;OAGG;IACG,aAAa,CACjB,YAAY,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACpC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3C,OAAO,CAAC,aAAa,CAAC;IA+BzB;;;OAGG;IACG,cAAc,CAClB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,OAAO,CAAC,aAAa,CAAC;CAyB1B"}
|