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.
Files changed (31) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +101 -23
  3. package/dist/adapters/express/index.d.ts +64 -7
  4. package/dist/adapters/express/index.d.ts.map +1 -1
  5. package/dist/adapters/express/index.js +127 -25
  6. package/dist/adapters/express/index.js.map +1 -1
  7. package/dist/checkout-configurator.d.ts +5 -1
  8. package/dist/checkout-configurator.d.ts.map +1 -1
  9. package/dist/checkout-configurator.js +28 -3
  10. package/dist/checkout-configurator.js.map +1 -1
  11. package/dist/events/checkout-event-bus.d.ts +1 -0
  12. package/dist/events/checkout-event-bus.d.ts.map +1 -1
  13. package/dist/events/checkout-event-bus.js.map +1 -1
  14. package/dist/interfaces/payment-provider.interface.d.ts +7 -3
  15. package/dist/interfaces/payment-provider.interface.d.ts.map +1 -1
  16. package/dist/models/payment-request.model.d.ts +2 -0
  17. package/dist/models/payment-request.model.d.ts.map +1 -1
  18. package/dist/models/payment-result.model.d.ts +8 -0
  19. package/dist/models/payment-result.model.d.ts.map +1 -1
  20. package/dist/providers/nexi/nexi.provider.d.ts +21 -8
  21. package/dist/providers/nexi/nexi.provider.d.ts.map +1 -1
  22. package/dist/providers/nexi/nexi.provider.js +160 -44
  23. package/dist/providers/nexi/nexi.provider.js.map +1 -1
  24. package/dist/providers/paypal/paypal.provider.d.ts.map +1 -1
  25. package/dist/providers/paypal/paypal.provider.js +17 -0
  26. package/dist/providers/paypal/paypal.provider.js.map +1 -1
  27. package/dist/providers/satispay/satispay.provider.d.ts +15 -5
  28. package/dist/providers/satispay/satispay.provider.d.ts.map +1 -1
  29. package/dist/providers/satispay/satispay.provider.js +54 -13
  30. package/dist/providers/satispay/satispay.provider.js.map +1 -1
  31. 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
- // Mounts all checkout routes under /checkout
72
- app.use('/checkout', createCheckoutRouter(checkout));
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 | 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 |
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 | Provider calls a webhook URL after async confirmation |
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 | 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 |
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 suffixes that bypass `middleware` (e.g. [':provider/webhook']).
11
- * Matched against the path suffix after the mount point.
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,EAAqB,cAAc,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGnE,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,GAAE,sBAA2B,GACnC,MAAM,CA8FR"}
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
- // Apply shared middleware (skipping public paths)
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
- const providerParam = String(req.params?.provider ?? '');
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 result = await checkout.createPayment(String(req.params.provider), req.body);
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
- router.post('/:provider/execute', async (req, res) => {
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
- router.post('/:provider/refund', async (req, res) => {
68
- try {
69
- const { paymentId, amount } = req.body;
70
- const result = await checkout.refundPayment(String(req.params.provider), paymentId, amount);
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
- catch (err) {
74
- sendError(res, err);
75
- }
76
- });
77
- // ---- POST /:provider/webhook — handle webhook ----------------------------
78
- router.post('/:provider/webhook', async (req, res) => {
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
- router.get('/:provider/:id', async (req, res) => {
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] ?? 500;
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":"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"}
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: Record<string, unknown>, headers: Record<string, string>): Promise<WebhookResult>;
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;IAMnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4C;IAEtE,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;IAa1F,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;IAYzB,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;IAYzB;;;OAGG;IACG,aAAa,CACjB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,aAAa,CAAC;IAoBzB;;;OAGG;IACG,cAAc,CAClB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,OAAO,CAAC,aAAa,CAAC;CAkB1B"}
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"}