awesome-node-checkout 1.2.5 → 2.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +81 -23
  3. package/dist/adapters/express/index.d.ts +35 -2
  4. package/dist/adapters/express/index.d.ts.map +1 -1
  5. package/dist/adapters/express/index.js +77 -34
  6. package/dist/adapters/express/index.js.map +1 -1
  7. package/dist/checkout-configurator.d.ts +18 -1
  8. package/dist/checkout-configurator.d.ts.map +1 -1
  9. package/dist/checkout-configurator.js +58 -72
  10. package/dist/checkout-configurator.js.map +1 -1
  11. package/dist/events/checkout-event-bus.d.ts +20 -1
  12. package/dist/events/checkout-event-bus.d.ts.map +1 -1
  13. package/dist/events/checkout-event-bus.js +18 -9
  14. package/dist/events/checkout-event-bus.js.map +1 -1
  15. package/dist/index.d.ts +2 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +5 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/models/errors.d.ts +1 -1
  20. package/dist/models/errors.d.ts.map +1 -1
  21. package/dist/models/errors.js.map +1 -1
  22. package/dist/models/payment-result.model.d.ts +14 -1
  23. package/dist/models/payment-result.model.d.ts.map +1 -1
  24. package/dist/providers/nexi/nexi.provider.d.ts +3 -0
  25. package/dist/providers/nexi/nexi.provider.d.ts.map +1 -1
  26. package/dist/providers/nexi/nexi.provider.js +45 -5
  27. package/dist/providers/nexi/nexi.provider.js.map +1 -1
  28. package/dist/providers/paypal/paypal.provider.d.ts.map +1 -1
  29. package/dist/providers/paypal/paypal.provider.js +15 -2
  30. package/dist/providers/paypal/paypal.provider.js.map +1 -1
  31. package/dist/providers/satispay/satispay.provider.d.ts.map +1 -1
  32. package/dist/providers/satispay/satispay.provider.js +43 -4
  33. package/dist/providers/satispay/satispay.provider.js.map +1 -1
  34. package/dist/utils/ids.d.ts +10 -0
  35. package/dist/utils/ids.d.ts.map +1 -0
  36. package/dist/utils/ids.js +16 -0
  37. package/dist/utils/ids.js.map +1 -0
  38. package/dist/utils/money.d.ts +20 -0
  39. package/dist/utils/money.d.ts.map +1 -0
  40. package/dist/utils/money.js +68 -0
  41. package/dist/utils/money.js.map +1 -0
  42. package/dist/utils/parsing.util.d.ts +14 -4
  43. package/dist/utils/parsing.util.d.ts.map +1 -1
  44. package/dist/utils/parsing.util.js +32 -6
  45. package/dist/utils/parsing.util.js.map +1 -1
  46. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,59 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.0.0] - 2026-11-12
9
+
10
+ Every permissive default of `createCheckoutRouter` becomes an explicit, named opt-in. Resolves #29.
11
+
12
+ ### Breaking
13
+ Migration list:
14
+ - **The router throws at mount without `buildPaymentRequest`.** `createCheckoutRouter(checkout)` now throws `CheckoutError` with the new code `INSECURE_CONFIGURATION`. Set `buildPaymentRequest` (server-side amount), or, only where the client may choose the amount, `allowClientPaymentRequest: true` (prints one `console.warn` at mount). The old mount warning `the client body decides the amount; set buildPaymentRequest` is gone.
15
+ - **The details route `GET /:provider/:id` is not mounted by default.** Add `details: { middleware: [...] }` to mount it behind your auth. `details: {}` mounts it unprotected and prints one `console.warn`. `details.enabled` is deprecated: `enabled: false` behaves as omitted (Express 404 instead of the former JSON `'Payment details route is disabled'`).
16
+ - **`amount` values with excess decimals now fail instead of being rounded.** Through the router, an amount with more decimals than the currency allows (`19.999` EUR, `10.5` JPY) answers `400 { success: false, code: 'INVALID_AMOUNT', error }` (new `CheckoutErrorCode`) without calling the provider; `0`, negative and non-finite amounts keep their earlier 400 (`INVALID_PAYMENT_REQUEST` from `buildPaymentRequest`, uncoded on the client-body path). Called directly, Nexi, Satispay and PayPal `createPayment` reject all of these (excess decimals, `0`, negative, non-finite) with `INVALID_AMOUNT` and return `{ success: false, status: 'FAILED', error }`, and so does `refundPayment` for a partial amount with excess decimals, `0` or a negative value (only an omitted `amount` refunds in full; Nexi and Satispay previously treated `0` and `null` as a full refund, and now reject them like PayPal). Amounts are checked against the ISO 4217 exponent of the currency (0, 2 or 3). PayPal formats payment and refund amounts with that exponent, so it now receives `'1000'` for 1000 JPY (previously the rejected `'1000.00'`) and `'1.200'` for 1.2 KWD. **Nexi and Satispay `createPayment` now reject currencies whose exponent is not 2** (JPY, KWD, …, and Nexi numeric codes such as `392`) with `{ success: false, status: 'FAILED', error }`: their outcome amounts and refunds are in hundredths, so only 2-decimal currencies keep the created, reported and refunded amounts on the same scale.
17
+ - **500 response bodies are generic.** Unexpected errors answer `{ success: false, error: 'Internal server error' }`. Set `exposeErrorMessages: true` to get the previous messages (including the `'Invalid provider response'` masking). The error is passed to the new `onError(err, req)` option, or logged with `console.error('[awesome-node-checkout]', err)` when `onError` is not set. `CheckoutError` 4xx responses keep their message and code.
18
+ - **Generated order ids changed format.** Without `orderId`, Nexi `codTrans` and Satispay `external_code` are `ORD-` + 24 random hex chars (28 chars) instead of `ORD-<Date.now()>`.
19
+
20
+ ### Security
21
+ - **Express Adapter**: the client body can no longer decide the amount unless `allowClientPaymentRequest: true` is set explicitly; previously a missing `buildPaymentRequest` only logged a warning and `POST /checkout/paypal {"amount":0.01,…}` created a 0.01 payment. Resolves #29.
22
+ - **Express Adapter**: `GET /:provider/:id` is opt-in, so status, amount and currency of a payment are no longer readable by anyone who knows (or, for Nexi, guesses) a payment id. Resolves #29.
23
+ - **Nexi, Satispay**: generated order ids come from `crypto.randomBytes` (96 bits) instead of a millisecond timestamp: they cannot be enumerated and do not collide across instances or within the same millisecond. Resolves #29.
24
+ - **Nexi, Satispay, PayPal**: amounts are converted to exact minor units for the currency (`toMinorUnits`/`toMajorString`, internal); an excess decimal is rejected instead of silently rounded. PayPal no longer formats zero/three-decimal currencies with two decimals; Nexi and Satispay reject them at `createPayment`, so for payments created through this library the created, reported and refunded amounts are on the same scale (outcome amounts are still read in hundredths, whatever the `divisa`/`currency`). A refund `amount` of `0` or `null` no longer turns into a full refund on Nexi and Satispay. Resolves #29.
25
+ - **Express Adapter**: internal error messages (including those thrown by `buildPaymentRequest`, `onBeforeExecute`, `redirect` handlers and event listeners) no longer reach the client in 500 responses by default. Resolves #29.
26
+
27
+ ### Added
28
+ - `ExpressCheckoutOptions.allowClientPaymentRequest`, `exposeErrorMessages` and `onError`. Resolves #29.
29
+ - `CheckoutErrorCode` values `INSECURE_CONFIGURATION` and `INVALID_AMOUNT`. Resolves #29.
30
+
31
+ ### Unchanged
32
+ - `POST /:provider/execute` stays mounted by default: capturing an approved payment only completes the payer's own payment, and since 1.3.0 the outcome is keyed on the provider-authenticated id (#27). Documented in the README.
33
+
34
+ ### Documentation
35
+ - README: "Secure defaults (2.0)" section, details marked *opt-in* in the Routes table, Quick Start and Express examples always build the request server-side. Resolves #29.
36
+
37
+ ## [1.3.0] - 2026-09-29
38
+
39
+ ### Breaking
40
+ - **Custom `IPaymentProvider` implementations must authenticate their outcomes.** Redirect, webhook and execute outcomes from a provider that does not set `verified: true` now fail closed: `success: false`, `verified: false`, no `paymentId`/`orderId`, error `'Payment outcome could not be verified'`.
41
+ - **`orderId` is no longer read from the query or unsigned body fields.** The configurator no longer reads `query.order_id`, `raw.orderId` or `raw.external_code`: a provider that relied on this must return `orderId` itself.
42
+ - **Listener errors are wrapped.** Direct API callers now receive `CheckoutListenerError`; the original value is in `cause`.
43
+ - Released as a minor version because these paths were the security holes fixed here (#27). The built-in Nexi, PayPal and Satispay providers are updated.
44
+
45
+
46
+ ### Security
47
+ - **Nexi Execute**: `executePayment` is keyed on the MAC-covered `codTrans`: result `paymentId`/`orderId`, the local order lookup and the emitted event no longer use the caller's `paymentId`. A non-empty `paymentId` argument different from the outcome's `codTrans` now fails (`success: false`, `verified: false`, error `'Payment id does not match the outcome'`) and emits `payment.failed`, never `payment.completed`. The configurator applies the same check to every provider's execute outcome. Resolves #27.
48
+ - **Core (orderId)**: No provider takes `orderId` from the query string of a redirect or callback, or from unsigned body fields (`orderId`, `order_id`, `external_code`): `orderId` comes only from the local `paymentId -> orderId` map (keyed on the provider-authenticated `paymentId`) or from the provider's authenticated outcome. Covers the PayPal redirect, Satispay unsigned POST without `webhookPublicKey`, and Nexi under any registration name (the rule no longer depends on the provider being registered as `nexi`). Resolves #27.
49
+ - **Core (verified)**: Unverified callback/redirect/execute outcomes carry no `paymentId`/`orderId` and never report `success: true`; a provider outcome counts as verified only when the provider sets `verified: true` (fail closed). Resolves #27.
50
+
51
+ ### Changed
52
+ - **`verified` semantics**: one documented meaning on `PaymentResult`, `WebhookResult` and all events: the outcome was authenticated by a signature/MAC or by an authenticated read from the provider API. `payment.created` (and `payment.failed` from `createPayment`) is now always `verified: false`; redirect/execute outcomes with a valid MAC and `esito=KO` are `verified: true` with an error, like webhooks; `payment.refunded` reflects the provider's `verified` (PayPal/Satispay API response `true`, Nexi `false`). `PaymentResult` gains an optional `verified` field set by the built-in providers. Custom providers must now set `verified: true` on authenticated outcomes. Resolves #27.
53
+ - **Event bus**: errors thrown by listeners are wrapped in the new exported `CheckoutListenerError` (`message` copied, original value in `cause`, `event` name) instead of being mutated; direct API callers now receive the wrapper. Resolves #27.
54
+ - **Satispay Redirect**: `handleRedirect` returns `orderId` from the authenticated API `external_code` or the local transaction store (previously it was filled by the configurator from the query). Resolves #27.
55
+
56
+ ### Fixed
57
+ - **Event bus**: frozen or non-extensible listener errors keep their message (previously replaced by `Cannot add property __isEventListenerError, object is not extensible`). Resolves #27.
58
+ - **Currency**: `parseIsoCurrency`/`parseNexiCurrency` (used by Satispay and Nexi) check alpha-3 codes against the ISO 4217 list of active currencies (`ISO_4217_ALPHA3_CODES`, from ISO 4217 List One published 2026-09-17, non-monetary codes excluded); `'XYZ'` and `'ABC'` are rejected. Resolves #27.
59
+ - **Documentation**: README `verified`/`paymentId`/`orderId` statements aligned with the behaviour, with a per-event `verified` table. Resolves #27.
60
+
8
61
  ## [1.2.5] - 2026-09-28
9
62
 
10
63
  ### Security
package/README.md CHANGED
@@ -46,14 +46,15 @@ checkout
46
46
  callbackPath: '/checkout/satispay/webhook', // Optional: defaults to /checkout/satispay/webhook
47
47
  }));
48
48
 
49
- // Use directly — no HTTP framework needed
49
+ // Use directly — no HTTP framework needed. The amount comes from your own order, never from the client.
50
+ const order = await myOrderService.getOrder('ORD-1234');
50
51
  const result = await checkout.createPayment('paypal', {
51
- amount: 49.99,
52
- currency: 'EUR',
53
- description: 'Order #1234',
52
+ amount: order.totalAmount, // e.g. 49.99: at most as many decimals as the currency allows
53
+ currency: order.currency, // e.g. 'EUR'
54
+ description: `Order #${order.id}`,
54
55
  returnUrl: 'https://myapp.com/payment/success',
55
56
  cancelUrl: 'https://myapp.com/payment/cancel',
56
- orderId: 'ORD-1234',
57
+ orderId: order.id,
57
58
  });
58
59
 
59
60
  if (result.approvalUrl) {
@@ -81,7 +82,7 @@ app.use(express.urlencoded({ extended: false }));
81
82
  app.use(
82
83
  '/checkout',
83
84
  createCheckoutRouter(checkout, {
84
- // Recommended: verify order and compute amount on the server
85
+ // Required: verify the order and compute the amount on the server
85
86
  buildPaymentRequest: async (req, { provider }) => {
86
87
  const order = await myOrderService.getOrder(req.body.orderId);
87
88
  return {
@@ -99,10 +100,6 @@ app.use(
99
100
  onSuccess: (result, req) => `/orders/${result.orderId}?status=success`,
100
101
  onFailure: (result, req) => `/orders/${result.orderId}?status=failed&error=${encodeURIComponent(result.error || '')}`,
101
102
  },
102
- // Optional: gate or disable public access to GET /:provider/:id
103
- details: {
104
- enabled: false, // or provide middleware: [requireAuth]
105
- },
106
103
  // Opt-in: mount POST /:provider/refund protected by admin middleware
107
104
  refund: {
108
105
  middleware: [requireAdminAuth],
@@ -118,13 +115,24 @@ app.use(
118
115
  ':provider/webhook',
119
116
  ':provider/redirect',
120
117
  ],
118
+ // Optional: report unexpected (500) errors; the client only sees 'Internal server error'
119
+ onError: (err, req) => logger.error({ err, path: req.path }, 'checkout error'),
121
120
  }),
122
121
  );
123
122
 
124
123
  app.listen(3000);
125
124
  ```
126
125
 
127
- > **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.
126
+ > **Security Note**: Never trust client-sent amounts. `buildPaymentRequest` derives the amount and order parameters server-side, and since 2.0.0 it is mandatory: `createCheckoutRouter` throws `CheckoutError('INSECURE_CONFIGURATION')` at mount without it. See [Secure defaults (2.0)](#secure-defaults-20).
127
+
128
+ To expose payment status to your own front end, mount the details route explicitly and protect it:
129
+
130
+ ```typescript
131
+ createCheckoutRouter(checkout, {
132
+ buildPaymentRequest,
133
+ details: { middleware: [requireAuth] }, // GET /checkout/:provider/:id
134
+ });
135
+ ```
128
136
 
129
137
  ### With Fastify (or any other framework)
130
138
 
@@ -132,8 +140,17 @@ Use the `CheckoutConfigurator` methods directly in your own routes:
132
140
 
133
141
  ```typescript
134
142
  fastify.post('/checkout/:provider', async (req, reply) => {
135
- const result = await checkout.createPayment(req.params.provider, req.body);
136
- reply.status(result.success ? 201 : 400).send(result);
143
+ // Build the request from your own order: never pass req.body to createPayment
144
+ const order = await myOrderService.getOrder(req.body.orderId);
145
+ const result = await checkout.createPayment(req.params.provider, {
146
+ amount: order.totalAmount,
147
+ currency: order.currency,
148
+ orderId: order.id,
149
+ returnUrl: `https://myapp.com/checkout/${req.params.provider}/redirect`,
150
+ cancelUrl: 'https://myapp.com/payment/cancel',
151
+ });
152
+ const { raw, ...safeResult } = result;
153
+ reply.status(result.success ? 201 : 400).send(safeResult);
137
154
  });
138
155
 
139
156
  // Handle both POST and GET webhooks (e.g. Satispay GET callback vs Nexi/Satispay POST notification)
@@ -165,15 +182,38 @@ A full-featured reference implementation using Express 5, SQLite (`ITransactionS
165
182
 
166
183
  | Method | Path | Description |
167
184
  |-------------|-----------------------------|----------------------------------------------------------------|
168
- | POST | `/:provider` | Create a payment (server-built or validated) |
185
+ | POST | `/:provider` | Create a payment (built by `buildPaymentRequest`) |
169
186
  | POST | `/:provider/execute` | Execute/capture a payment (supports `onBeforeExecute`) |
170
187
  | GET | `/:provider/redirect` | Handle provider redirect callback (supports 302 via `redirect`)|
171
- | GET | `/:provider/:id` | Get payment details (*configurable*: can disable or protect via `details`)|
188
+ | GET | `/:provider/:id` | Get payment details (*opt-in*: mounted only when `details` option is set; protect it with `details.middleware`)|
172
189
  | POST | `/:provider/refund` | Refund a payment (*opt-in*: mounted only when `refund` option is set)|
173
190
  | GET / POST | `/:provider/webhook` | Handle provider webhook (POST for Nexi/Satispay, GET for Satispay)|
174
191
 
175
192
  ---
176
193
 
194
+ ## Secure defaults (2.0)
195
+
196
+ Since 2.0.0 every permissive behaviour of `createCheckoutRouter` is an explicit, named opt-in that shows up in code review.
197
+
198
+ 1. **`buildPaymentRequest` is mandatory.** Without it, `createCheckoutRouter` throws `CheckoutError` with code `INSECURE_CONFIGURATION` at mount. The opt-out is `allowClientPaymentRequest: true`: the client request body becomes the `PaymentRequest`, so **the browser chooses the amount**. Never use it for a shop. It prints one `console.warn` at mount.
199
+ 2. **`GET /:provider/:id` is opt-in.** The details route returns `success`, `status`, `amount`, `currency` and `paymentId` for any id it is given (for Nexi, the id is your order code). It is mounted only when `details` is set: `details: { middleware: [requireAuth] }`. `details: {}` mounts it unprotected and prints one `console.warn`. The old `details: { enabled: false }` is deprecated and behaves as omitted.
200
+ 3. **Generated order ids are unpredictable.** When `orderId` is omitted, Nexi (`codTrans`) and Satispay (`external_code`) use `ORD-` + 24 random hex chars instead of `ORD-<timestamp>`, so ids cannot be enumerated and do not collide.
201
+ 4. **Amounts are exact, in the currency's minor units.** Amounts are checked against the ISO 4217 exponent (0 for JPY, KRW, CLP…; 3 for KWD, BHD, JOD…; 2 otherwise) and never rounded: `19.999 EUR` or `10.5 JPY` fails with `INVALID_AMOUNT` instead of charging a rounded amount. The router answers `400 { success: false, code: 'INVALID_AMOUNT', error }` without calling the provider; a provider called directly returns `{ success: false, status: 'FAILED', error }`. PayPal formats payment and refund amounts with the exponent of the order's currency: it receives `'1000'` for 1000 JPY and `'1.200'` for 1.2 KWD. Nexi and Satispay accept only currencies with 2 decimal places: `createPayment` in JPY, KWD or another 0- or 3-decimal currency (including Nexi numeric codes such as `392`) returns `{ success: false, status: 'FAILED', error }`, because their outcome amounts and refund amounts are in hundredths. A refund `amount` of `0` (or `null`) fails like any invalid amount; only an omitted amount refunds in full.
202
+ 5. **500 bodies are generic.** An unexpected error (a throwing `buildPaymentRequest`, `onBeforeExecute`, `redirect.onSuccess`/`onFailure`, event listener, or provider) answers `500 { success: false, error: 'Internal server error' }`. The error goes to `onError(err, req)`, or to `console.error` when `onError` is not set. `exposeErrorMessages: true` restores the message in the body (for development). `CheckoutError` responses (4xx) keep their message and code and are not passed to `onError`.
203
+
204
+ | Option | Default | Effect |
205
+ |--------|---------|--------|
206
+ | `buildPaymentRequest` | — (required) | Server-side `PaymentRequest` |
207
+ | `allowClientPaymentRequest: true` | off | Client body decides the amount (insecure) |
208
+ | `details: { middleware }` | not mounted | Mounts `GET /:provider/:id` |
209
+ | `refund: { middleware }` | not mounted | Mounts `POST /:provider/refund` |
210
+ | `exposeErrorMessages: true` | off | Error messages in 500 bodies |
211
+ | `onError(err, req)` | `console.error` | Receives every 500 error |
212
+
213
+ **`POST /:provider/execute` stays mounted by default.** Capturing an approved payment only completes the payer's own payment, and since 1.3.0 the outcome is keyed on the provider-authenticated payment id (#27), so a forged `paymentId` cannot confirm another order. Use `execute.middleware` or `execute.onBeforeExecute` to tie the capture to the current session.
214
+
215
+ ---
216
+
177
217
  ## Security: A Redirect Is Not Proof of Payment
178
218
 
179
219
  Relying solely on front-end browser redirects (`GET /:provider/redirect`) to fulfill orders introduces significant risk:
@@ -182,7 +222,7 @@ Relying solely on front-end browser redirects (`GET /:provider/redirect`) to ful
182
222
  - **Amount Mismatch**: Always verify that the captured payment amount matches your order ledger before fulfilling goods or services. In `awesome-node-checkout`, `success: true` strictly requires that a payment is confirmed with a valid amount.
183
223
 
184
224
  To ensure safe fulfillment:
185
- 1. **Verify Amount & Currency**: `PaymentResult` and `WebhookResult` return `amount` and `currency` extracted directly from the provider. Compare amounts in minor units (cents) or with rounding to prevent floating-point discrepancies:
225
+ 1. **Verify Amount & Currency**: `PaymentResult` and `WebhookResult` return `amount` and `currency` extracted directly from the provider. Compare amounts in minor units (cents) or with rounding to prevent floating-point discrepancies. The example below scales by 100, which is exact for currencies with at most 2 decimal places (every Nexi and Satispay payment created through this library); for a PayPal order in a 3-decimal currency such as KWD, scale by 1000:
186
226
  ```typescript
187
227
  const result = await checkout.handleRedirect(provider, req.query);
188
228
  if (result.success) {
@@ -229,13 +269,29 @@ checkout.events
229
269
  .on('webhook.received', ({ provider, paymentId, orderId, status, error, verified, data, raw }) => { /* ... */ });
230
270
  ```
231
271
 
232
- ### Understanding `verified` vs `error` in `WebhookResult` and Events
272
+ An error thrown by a listener propagates to the caller wrapped in a `CheckoutListenerError` (exported): its `message` is the original message (or `String(value)` for non-Error values), `cause` is the original value, untouched (frozen errors are fine), and `event` is the event name. The Express adapter answers `500` with a generic body (the message only with `exposeErrorMessages: true`) and passes the error to `onError`.
273
+
274
+ Currencies are validated against the ISO 4217 list of active alpha-3 codes (`ISO_4217_ALPHA3_CODES`, plus the mapped Nexi numeric codes such as `978`); shape-only codes like `'XYZ'` or `'ABC'` and non-monetary codes (`XXX`, `XTS`, precious metals) are rejected.
275
+
276
+ ### Understanding `verified` vs `error` in Results and Events
277
+
278
+ `verified` has one meaning everywhere (`PaymentResult`, `WebhookResult` and every event payload):
279
+
280
+ > **`verified: true` means the outcome was authenticated**, either by a provider signature/MAC checked by the library (Nexi 7-field outcome MAC, Satispay HTTP Signature) or by an authenticated server-to-server read from the provider API (PayPal capture/order read with OAuth credentials, Satispay `GET /payments/{id}` signed with the merchant key). Anything else is `verified: false`.
281
+
282
+ - `success` and `verified` are independent: a genuine cancellation or failed payment (user canceled, card declined) is `verified: true, success: false` with `error: 'Payment is CANCELED'` or `error: 'Payment failed with outcome KO'`. This holds for webhooks, redirects and `executePayment` alike (e.g. a Nexi redirect or execute with `esito=KO` and a valid MAC emits `payment.failed` with `verified: true`).
283
+ - On a callback, redirect or execute outcome with `verified: false` (missing/tampered MAC or signature, failed API read, provider that does not assert `verified: true`), the result and the event carry **no `paymentId` and no `orderId`**, and `success` is always `false` (error e.g. `'MAC verification failed'`, `'Webhook signature verification failed'`, `'Payment outcome could not be verified'`).
284
+ - `orderId` is never taken from the query string of a redirect or callback, nor from unsigned body fields, for any provider and under any registration name. It comes from the local `paymentId → orderId` map filled by `createPayment` (keyed on the provider-authenticated `paymentId`), or from the provider's authenticated outcome (Nexi MAC-covered `codTrans`, Satispay API `external_code` / transaction store).
285
+ - `executePayment(provider, paymentId, data)` is keyed on the `paymentId` authenticated by the provider (for Nexi the MAC-covered `codTrans`), never on the argument. If a non-empty `paymentId` argument differs from the authenticated one, the call fails with `success: false, verified: false, error: 'Payment id does not match the outcome'` and emits `payment.failed` (never `payment.completed`).
286
+
287
+ | Event | `verified` |
288
+ |-------|------------|
289
+ | `payment.created` (and `payment.failed` from `createPayment`) | always `false`: creation reports no payment outcome. `paymentId`/`orderId` are the ones you just created. |
290
+ | `payment.completed` / `payment.failed` from `handleRedirect` / `executePayment` | `true` only for a MAC-verified (Nexi) or API-read (PayPal, Satispay) outcome, whatever its `success` |
291
+ | `webhook.received` | `true` only for a MAC/signature-verified notification or an authenticated API re-read |
292
+ | `payment.refunded` | `true` when the refund outcome comes from an authenticated provider API response (PayPal, Satispay); `false` for Nexi, whose refund response carries no MAC checked by the library |
233
293
 
234
- The `verified: boolean` field indicates whether the incoming request was verified as authentic:
235
- - **`verified: true`**: The notification was cryptographically verified (e.g. Nexi 7-field outcome MAC or Satispay HTTP Signature) or verified via authenticated server-to-server API re-read.
236
- - A genuine cancellation or failed payment (e.g. user canceled on gateway, card declined) has `verified: true, success: false, error: 'Payment is CANCELED'` or `error: 'Payment failed with outcome KO'`.
237
- - **`verified: false`**: The signature/MAC was missing, tampered with, or invalid. The payload is untrusted.
238
- - In this case, `success: false, verified: false, error: 'MAC verification failed'` (or `'Webhook signature verification failed'`), and `orderId` / `paymentId` from untrusted query/body are stripped to prevent parameter injection attacks.
294
+ Custom providers must set `verified: true` on the outcomes they have authenticated; an outcome without it is treated as unverified.
239
295
 
240
296
  #### Satispay `verified` Semantics
241
297
  - **With `webhookPublicKey` configured**: Inbound POST webhooks must carry a valid HTTP Signature matching Satispay's RSA public key, correct SHA-256 body digest, and fresh `Date` header. `verified: true` guarantees cryptographic authenticity.
@@ -284,7 +340,9 @@ export class StripeProvider extends BasePaymentProvider {
284
340
  // ... implement other methods
285
341
 
286
342
  async handleRedirect(query: Record<string, any>): Promise<PaymentResult> {
287
- // ... handle Stripe redirect
343
+ // ... handle Stripe redirect: re-read the session from the Stripe API and
344
+ // return { success, verified: true, paymentId, orderId, amount, currency }
345
+ // only for an authenticated outcome (see "Understanding `verified`")
288
346
  }
289
347
  }
290
348
 
@@ -22,8 +22,18 @@ export interface ExpressCheckoutOptions {
22
22
  * Builds the PaymentRequest on the server (amount from your own order), ignoring the client body.
23
23
  * If the hook sends an HTTP response directly (e.g. via `ctx.res.status(403)...`),
24
24
  * returning `null` or `undefined` halts further adapter processing without error.
25
+ *
26
+ * Required: `createCheckoutRouter` throws `CheckoutError('INSECURE_CONFIGURATION')` at mount
27
+ * when it is missing, unless `allowClientPaymentRequest: true` is set.
25
28
  */
26
29
  buildPaymentRequest?: (req: Request, ctx: PaymentRequestContext) => PaymentRequest | null | undefined | Promise<PaymentRequest | null | undefined>;
30
+ /**
31
+ * **Insecure.** Without `buildPaymentRequest`, sends the client request body to the provider
32
+ * as the PaymentRequest: the browser chooses the amount, the currency and the order id.
33
+ * Never use this for a shop or for anything with a price; it exists for donations-style
34
+ * flows and tests. Ignored when `buildPaymentRequest` is set.
35
+ */
36
+ allowClientPaymentRequest?: true;
27
37
  /**
28
38
  * When configured, GET /:provider/redirect responds with a 302 redirect
29
39
  * to the URL returned by onSuccess or onFailure instead of JSON.
@@ -34,9 +44,15 @@ export interface ExpressCheckoutOptions {
34
44
  };
35
45
  /**
36
46
  * Configuration for GET /:provider/:id (getPaymentDetails).
37
- * Default: enabled: true. Set enabled: false to return 404.
47
+ * If omitted, the details route is NOT mounted (returns 404), like `refund`.
48
+ * The route returns status, amount and currency for any payment id it is given:
49
+ * protect it with `middleware` (a console warning is printed at mount when it has none).
38
50
  */
39
51
  details?: {
52
+ /**
53
+ * @deprecated Since 2.0.0 the route is mounted only when `details` is set.
54
+ * `enabled: false` behaves as if `details` were omitted; any other value is ignored.
55
+ */
40
56
  enabled?: boolean;
41
57
  middleware?: RequestHandler[];
42
58
  };
@@ -54,6 +70,20 @@ export interface ExpressCheckoutOptions {
54
70
  middleware?: RequestHandler[];
55
71
  onBeforeExecute?: (req: Request, paymentId: string) => void | Promise<void>;
56
72
  };
73
+ /**
74
+ * When `true`, 500 responses carry the error message (masked to 'Invalid provider response'
75
+ * for provider parse errors). Default `false`: 500 bodies are always
76
+ * `{ success: false, error: 'Internal server error' }`. `CheckoutError` 4xx responses keep
77
+ * their message and code either way.
78
+ */
79
+ exposeErrorMessages?: boolean;
80
+ /**
81
+ * Called with the original error (and the request) for every error answered with a 500,
82
+ * whatever `exposeErrorMessages` says. Not called for 4xx `CheckoutError` responses, which are
83
+ * client-triggerable (e.g. an unknown provider name). When omitted, the error is logged with
84
+ * `console.error('[awesome-node-checkout]', err)`.
85
+ */
86
+ onError?: (err: unknown, req: Request) => void;
57
87
  }
58
88
  /**
59
89
  * Matches a request path against public path patterns by segments.
@@ -72,9 +102,12 @@ export declare function isPathPublic(reqPath: string, publicPaths: (string | str
72
102
  * GET /:provider/webhook → handleWebhook
73
103
  * POST /:provider/webhook → handleWebhook
74
104
  * GET /:provider/redirect → handleRedirect (must come before /:provider/:id)
75
- * GET /:provider/:id → getPaymentDetails
105
+ * GET /:provider/:id → getPaymentDetails (only if options.details is configured)
76
106
  * ```
77
107
  *
108
+ * Throws `CheckoutError('INSECURE_CONFIGURATION')` when neither `buildPaymentRequest` nor
109
+ * `allowClientPaymentRequest: true` is set.
110
+ *
78
111
  * Usage:
79
112
  * ```typescript
80
113
  * import { createCheckoutRouter } from 'awesome-node-checkout/express';
@@ -1 +1 @@
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;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,CAAC;IAEpC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,CACpB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,qBAAqB,KACvB,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAEpF;;;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;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,GAAG,OAAO,CAgBzF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,GAAE,sBAA2B,GACnC,MAAM,CAiNR"}
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;AAIlE,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;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,CAAC;IAEpC;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,CACpB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,qBAAqB,KACvB,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAEpF;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,IAAI,CAAC;IAEjC;;;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;;;;;OAKG;IACH,OAAO,CAAC,EAAE;QACR;;;WAGG;QACH,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;IAEF;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAChD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,GAAG,OAAO,CAgBzF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,GAAE,sBAA2B,GACnC,MAAM,CAmOR"}
@@ -4,6 +4,8 @@ exports.isPathPublic = isPathPublic;
4
4
  exports.createCheckoutRouter = createCheckoutRouter;
5
5
  const express_1 = require("express");
6
6
  const errors_1 = require("../../models/errors");
7
+ const checkout_event_bus_1 = require("../../events/checkout-event-bus");
8
+ const money_1 = require("../../utils/money");
7
9
  /**
8
10
  * Matches a request path against public path patterns by segments.
9
11
  * ':provider' matches any single non-empty segment.
@@ -37,9 +39,12 @@ function isPathPublic(reqPath, publicPaths) {
37
39
  * GET /:provider/webhook → handleWebhook
38
40
  * POST /:provider/webhook → handleWebhook
39
41
  * GET /:provider/redirect → handleRedirect (must come before /:provider/:id)
40
- * GET /:provider/:id → getPaymentDetails
42
+ * GET /:provider/:id → getPaymentDetails (only if options.details is configured)
41
43
  * ```
42
44
  *
45
+ * Throws `CheckoutError('INSECURE_CONFIGURATION')` when neither `buildPaymentRequest` nor
46
+ * `allowClientPaymentRequest: true` is set.
47
+ *
43
48
  * Usage:
44
49
  * ```typescript
45
50
  * import { createCheckoutRouter } from 'awesome-node-checkout/express';
@@ -58,10 +63,14 @@ function isPathPublic(reqPath, publicPaths) {
58
63
  * ```
59
64
  */
60
65
  function createCheckoutRouter(checkout, options = {}) {
61
- const router = (0, express_1.Router)();
66
+ if (!options.buildPaymentRequest && options.allowClientPaymentRequest !== true) {
67
+ throw new errors_1.CheckoutError('createCheckoutRouter: set buildPaymentRequest (server-side amount) or allowClientPaymentRequest: true', 'INSECURE_CONFIGURATION');
68
+ }
62
69
  if (!options.buildPaymentRequest) {
63
- console.warn('[awesome-node-checkout] createCheckoutRouter: the client body decides the amount; set buildPaymentRequest');
70
+ console.warn('[awesome-node-checkout] allowClientPaymentRequest: the client body decides the amount');
64
71
  }
72
+ const router = (0, express_1.Router)();
73
+ const sendError = (req, res, err, isProvider = true) => sendErrorResponse(req, res, options, err, isProvider);
65
74
  // Apply shared middleware (skipping public paths by segment match)
66
75
  if (options.middleware?.length) {
67
76
  const publicPaths = options.publicPaths ?? [];
@@ -92,7 +101,7 @@ function createCheckoutRouter(checkout, options = {}) {
92
101
  });
93
102
  }
94
103
  catch (consumerErr) {
95
- sendError(res, consumerErr, false);
104
+ sendError(req, res, consumerErr, false);
96
105
  return;
97
106
  }
98
107
  if (res.headersSent) {
@@ -133,12 +142,22 @@ function createCheckoutRouter(checkout, options = {}) {
133
142
  }
134
143
  paymentRequest = body;
135
144
  }
145
+ // Exact minor units: an amount with more decimals than the currency allows is rejected,
146
+ // never rounded
147
+ try {
148
+ (0, money_1.toMinorUnits)(paymentRequest.amount, paymentRequest.currency);
149
+ }
150
+ catch (amountErr) {
151
+ if (!(0, money_1.isInvalidAmountError)(amountErr))
152
+ throw amountErr;
153
+ return res.status(400).json({ success: false, code: 'INVALID_AMOUNT', error: amountErr.message });
154
+ }
136
155
  const result = await checkout.createPayment(provider, paymentRequest);
137
156
  const { raw, ...safeResult } = result;
138
157
  res.status(result.success ? 201 : 400).json(safeResult);
139
158
  }
140
159
  catch (err) {
141
- sendError(res, err, true);
160
+ sendError(req, res, err, true);
142
161
  }
143
162
  });
144
163
  // ---- POST /:provider/execute — execute payment ---------------------------
@@ -154,7 +173,7 @@ function createCheckoutRouter(checkout, options = {}) {
154
173
  await options.execute.onBeforeExecute(req, paymentId);
155
174
  }
156
175
  catch (consumerErr) {
157
- sendError(res, consumerErr, false);
176
+ sendError(req, res, consumerErr, false);
158
177
  return;
159
178
  }
160
179
  }
@@ -163,7 +182,7 @@ function createCheckoutRouter(checkout, options = {}) {
163
182
  res.status(result.success ? 200 : 400).json(safeResult);
164
183
  }
165
184
  catch (err) {
166
- sendError(res, err, true);
185
+ sendError(req, res, err, true);
167
186
  }
168
187
  });
169
188
  // ---- POST /:provider/refund — refund payment (opt-in) --------------------
@@ -180,7 +199,7 @@ function createCheckoutRouter(checkout, options = {}) {
180
199
  res.status(result.success ? 200 : 400).json(safeResult);
181
200
  }
182
201
  catch (err) {
183
- sendError(res, err, true);
202
+ sendError(req, res, err, true);
184
203
  }
185
204
  });
186
205
  }
@@ -197,7 +216,7 @@ function createCheckoutRouter(checkout, options = {}) {
197
216
  res.status(result.success ? 200 : 400).json(safeResult);
198
217
  }
199
218
  catch (err) {
200
- sendError(res, err, true);
219
+ sendError(req, res, err, true);
201
220
  }
202
221
  };
203
222
  router.get('/:provider/webhook', webhookHandler);
@@ -212,7 +231,7 @@ function createCheckoutRouter(checkout, options = {}) {
212
231
  result = await checkout.handleRedirect(String(req.params.provider), req.query);
213
232
  }
214
233
  catch (err) {
215
- sendError(res, err, true);
234
+ sendError(req, res, err, true);
216
235
  return;
217
236
  }
218
237
  if (options.redirect) {
@@ -223,7 +242,7 @@ function createCheckoutRouter(checkout, options = {}) {
223
242
  : options.redirect.onFailure(result, req);
224
243
  }
225
244
  catch (consumerErr) {
226
- sendError(res, consumerErr, false);
245
+ sendError(req, res, consumerErr, false);
227
246
  return;
228
247
  }
229
248
  return res.redirect(302, targetUrl);
@@ -231,34 +250,42 @@ function createCheckoutRouter(checkout, options = {}) {
231
250
  const { raw, ...safeResult } = result;
232
251
  res.status(result.success ? 200 : 400).json(safeResult);
233
252
  });
234
- // ---- GET /:provider/:id — get payment details ----------------------------
235
- const detailsHandlers = [];
236
- if (options.details?.middleware?.length) {
237
- detailsHandlers.push(...options.details.middleware);
238
- }
239
- router.get('/:provider/:id', ...detailsHandlers, async (req, res) => {
240
- if (options.details?.enabled === false) {
241
- return res.status(404).json({ success: false, error: 'Payment details route is disabled' });
253
+ // ---- GET /:provider/:id — get payment details (opt-in) -------------------
254
+ // Registered after /:provider/redirect and /:provider/webhook so that those win.
255
+ if (options.details && options.details.enabled !== false) {
256
+ const detailsHandlers = [];
257
+ if (options.details.middleware?.length) {
258
+ detailsHandlers.push(...options.details.middleware);
242
259
  }
243
- try {
244
- const result = await checkout.getPaymentDetails(String(req.params.provider), String(req.params.id));
245
- const { raw, ...safeResult } = result;
246
- res.status(result.success ? 200 : 404).json(safeResult);
247
- }
248
- catch (err) {
249
- sendError(res, err, true);
260
+ else {
261
+ console.warn('[awesome-node-checkout] details route mounted without middleware: payment status and amount are readable by anyone who knows a payment id');
250
262
  }
251
- });
263
+ router.get('/:provider/:id', ...detailsHandlers, async (req, res) => {
264
+ try {
265
+ const result = await checkout.getPaymentDetails(String(req.params.provider), String(req.params.id));
266
+ const { raw, ...safeResult } = result;
267
+ res.status(result.success ? 200 : 404).json(safeResult);
268
+ }
269
+ catch (err) {
270
+ sendError(req, res, err, true);
271
+ }
272
+ });
273
+ }
252
274
  return router;
253
275
  }
254
276
  // ---------------------------------------------------------------------------
255
277
  // Helpers
256
278
  // ---------------------------------------------------------------------------
257
- function sendError(res, err, isProvider = true) {
258
- if (res.headersSent)
259
- return;
260
- const isListenerError = !!(err && typeof err === 'object' && err.__isEventListenerError);
279
+ function sendErrorResponse(req, res, options, originalErr, isProvider = true) {
280
+ let err = originalErr;
281
+ const isListenerError = err instanceof checkout_event_bus_1.CheckoutListenerError;
282
+ if (err instanceof checkout_event_bus_1.CheckoutListenerError && err.cause instanceof errors_1.CheckoutError) {
283
+ // A listener that throws a CheckoutError keeps its status mapping
284
+ err = err.cause;
285
+ }
261
286
  if (err instanceof errors_1.CheckoutError) {
287
+ if (res.headersSent)
288
+ return;
262
289
  const statusMap = {
263
290
  PROVIDER_NOT_FOUND: 404,
264
291
  WEBHOOK_NOT_SUPPORTED: 422,
@@ -266,13 +293,29 @@ function sendError(res, err, isProvider = true) {
266
293
  };
267
294
  const status = statusMap[err.code] ?? 400;
268
295
  res.status(status).json({ success: false, error: err.message, code: err.code });
296
+ return;
297
+ }
298
+ // Unexpected error (500): report it to the app, never to the client unless asked to
299
+ try {
300
+ if (options.onError) {
301
+ options.onError(originalErr, req);
302
+ }
303
+ else {
304
+ console.error('[awesome-node-checkout]', originalErr);
305
+ }
269
306
  }
270
- else {
271
- let message = err instanceof Error ? err.message : String(err ?? 'Internal server error');
307
+ catch {
308
+ // A throwing onError must not prevent the response
309
+ }
310
+ if (res.headersSent)
311
+ return;
312
+ let message = 'Internal server error';
313
+ if (options.exposeErrorMessages === true) {
314
+ message = err instanceof Error ? err.message : String(err ?? 'Internal server error');
272
315
  if (!isListenerError && isProvider && (err instanceof SyntaxError || /JSON|Unexpected token/i.test(message))) {
273
316
  message = 'Invalid provider response';
274
317
  }
275
- res.status(500).json({ success: false, error: message });
276
318
  }
319
+ res.status(500).json({ success: false, error: message });
277
320
  }
278
321
  //# sourceMappingURL=index.js.map
@@ -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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"}