awesome-node-checkout 1.3.0 → 2.1.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 +64 -0
- package/README.md +335 -17
- package/dist/adapters/express/index.d.ts +103 -2
- package/dist/adapters/express/index.d.ts.map +1 -1
- package/dist/adapters/express/index.js +213 -30
- package/dist/adapters/express/index.js.map +1 -1
- package/dist/checkout-configurator.d.ts +106 -0
- package/dist/checkout-configurator.d.ts.map +1 -1
- package/dist/checkout-configurator.js +515 -0
- package/dist/checkout-configurator.js.map +1 -1
- package/dist/events/checkout-event-bus.d.ts +11 -1
- package/dist/events/checkout-event-bus.d.ts.map +1 -1
- package/dist/events/checkout-event-bus.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/mandate-provider.interface.d.ts +40 -0
- package/dist/interfaces/mandate-provider.interface.d.ts.map +1 -0
- package/dist/interfaces/mandate-provider.interface.js +18 -0
- package/dist/interfaces/mandate-provider.interface.js.map +1 -0
- package/dist/models/checkout-config.model.d.ts +16 -0
- package/dist/models/checkout-config.model.d.ts.map +1 -1
- package/dist/models/errors.d.ts +1 -1
- package/dist/models/errors.d.ts.map +1 -1
- package/dist/models/errors.js.map +1 -1
- package/dist/models/mandate.model.d.ts +166 -0
- package/dist/models/mandate.model.d.ts.map +1 -0
- package/dist/models/mandate.model.js +19 -0
- package/dist/models/mandate.model.js.map +1 -0
- package/dist/providers/nexi/nexi.provider.d.ts +125 -1
- package/dist/providers/nexi/nexi.provider.d.ts.map +1 -1
- package/dist/providers/nexi/nexi.provider.js +677 -13
- package/dist/providers/nexi/nexi.provider.js.map +1 -1
- package/dist/providers/paypal/paypal.provider.d.ts +44 -1
- package/dist/providers/paypal/paypal.provider.d.ts.map +1 -1
- package/dist/providers/paypal/paypal.provider.js +529 -2
- package/dist/providers/paypal/paypal.provider.js.map +1 -1
- package/dist/providers/satispay/satispay.provider.d.ts +86 -1
- package/dist/providers/satispay/satispay.provider.d.ts.map +1 -1
- package/dist/providers/satispay/satispay.provider.js +440 -3
- package/dist/providers/satispay/satispay.provider.js.map +1 -1
- package/dist/utils/ids.d.ts +10 -0
- package/dist/utils/ids.d.ts.map +1 -0
- package/dist/utils/ids.js +16 -0
- package/dist/utils/ids.js.map +1 -0
- package/dist/utils/money.d.ts +20 -0
- package/dist/utils/money.d.ts.map +1 -0
- package/dist/utils/money.js +68 -0
- package/dist/utils/money.js.map +1 -0
- package/dist/utils/redact.d.ts +15 -0
- package/dist/utils/redact.d.ts.map +1 -0
- package/dist/utils/redact.js +60 -0
- package/dist/utils/redact.js.map +1 -0
- package/dist/utils/url.d.ts +12 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/url.js +19 -0
- package/dist/utils/url.js.map +1 -0
- package/package.json +2 -2
|
@@ -2,6 +2,8 @@ import { BasePaymentProvider } from '../../abstract/base-payment-provider.abstra
|
|
|
2
2
|
import { PaymentRequest } from '../../models/payment-request.model';
|
|
3
3
|
import { PaymentResult, WebhookResult } from '../../models/payment-result.model';
|
|
4
4
|
import { ITransactionStore } from '../../interfaces/transaction-store.interface';
|
|
5
|
+
import { IMandateProvider } from '../../interfaces/mandate-provider.interface';
|
|
6
|
+
import { ChargeRequest, ChargeResult, Mandate, MandateCallbackInput, MandatePendingState, MandateRevokeResult, MandateSetupOutcome, MandateSetupRequest, MandateSetupStart, MandateStatusResult } from '../../models/mandate.model';
|
|
5
7
|
export interface SatispayProviderConfig {
|
|
6
8
|
keyId: string;
|
|
7
9
|
/**
|
|
@@ -42,14 +44,30 @@ export interface SatispayProviderConfig {
|
|
|
42
44
|
* Use a persistent store (Redis, DB) in multi-instance deployments.
|
|
43
45
|
*/
|
|
44
46
|
transactionStore?: ITransactionStore;
|
|
47
|
+
/**
|
|
48
|
+
* Timeout of the mandate API calls (`createMandate`, `confirmMandate`, `chargeMandate`,
|
|
49
|
+
* `getMandate`) in milliseconds. A timeout is reported as `unknown`, never `failed`.
|
|
50
|
+
* @default 30000
|
|
51
|
+
*/
|
|
52
|
+
timeoutMs?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Path of the mandate callback route, appended to `serverUrl` to build the authorization's
|
|
55
|
+
* `callback_url` when `MandateSetupRequest.notifyUrl` is not set.
|
|
56
|
+
* @default '/checkout/satispay/mandate/callback'
|
|
57
|
+
*/
|
|
58
|
+
mandateCallbackPath?: string;
|
|
45
59
|
}
|
|
46
60
|
/**
|
|
47
61
|
* Satispay Business API provider.
|
|
48
62
|
* Flow: `webhook` — creates a MATCH_CODE payment, user pays via Satispay app,
|
|
49
63
|
* Satispay calls the `callback_url` webhook, which is correlated to the order
|
|
50
64
|
* via the `ITransactionStore`. The redirect is then verified via `handleRedirect`.
|
|
65
|
+
*
|
|
66
|
+
* Recurring payments (`IMandateProvider`): Automatic Payments, web-redirect flow. A setup creates
|
|
67
|
+
* a pre-authorized payment token, the customer approves it in Satispay, and every charge (the
|
|
68
|
+
* first one included) is a synchronous `PRE_AUTHORIZED` payment. EUR only.
|
|
51
69
|
*/
|
|
52
|
-
export declare class SatispayProvider extends BasePaymentProvider {
|
|
70
|
+
export declare class SatispayProvider extends BasePaymentProvider implements IMandateProvider {
|
|
53
71
|
private readonly config;
|
|
54
72
|
readonly name = "satispay";
|
|
55
73
|
readonly flow: "webhook";
|
|
@@ -87,6 +105,13 @@ export declare class SatispayProvider extends BasePaymentProvider {
|
|
|
87
105
|
rawBody?: Buffer | string;
|
|
88
106
|
}): boolean;
|
|
89
107
|
private request;
|
|
108
|
+
/**
|
|
109
|
+
* Signed request that never throws and keeps the HTTP status and the parsed body, for the
|
|
110
|
+
* mandate methods (which must tell 4xx from 5xx from a timeout). `extraHeaders` are merged after
|
|
111
|
+
* the signature headers but can never override `Host`, `Date`, `Digest` or `Authorization`
|
|
112
|
+
* (case-insensitively). `request()` keeps its throwing behaviour for the one-off payment flow.
|
|
113
|
+
*/
|
|
114
|
+
private send;
|
|
90
115
|
createPayment(request: PaymentRequest): Promise<PaymentResult>;
|
|
91
116
|
/** For Satispay, execute is equivalent to a status check */
|
|
92
117
|
executePayment(paymentId: string): Promise<PaymentResult>;
|
|
@@ -117,5 +142,65 @@ export declare class SatispayProvider extends BasePaymentProvider {
|
|
|
117
142
|
* Looks up the transaction by `order_id` in the store, then verifies status.
|
|
118
143
|
*/
|
|
119
144
|
handleRedirect(query: Record<string, string>): Promise<PaymentResult>;
|
|
145
|
+
/**
|
|
146
|
+
* Creates a pre-authorized payment token (`POST /pre_authorized_payment_tokens`) and returns
|
|
147
|
+
* its `redirect_url` as `approvalUrl`. Never open that URL in a WebView.
|
|
148
|
+
*
|
|
149
|
+
* - EUR only.
|
|
150
|
+
* - `callback_url` is `notifyUrl` (or `serverUrl + mandateCallbackPath`) with `mandate_ref`
|
|
151
|
+
* and the raw `token_id={uuid}` placeholder, which Satispay substitutes with the token id.
|
|
152
|
+
* - `redirect_url` is `returnUrl` with `mandate_ref`.
|
|
153
|
+
* - `cancelUrl` is unused: Satispay has no cancel redirect (a canceled authorization is
|
|
154
|
+
* reported through the callback and re-read as `CANCELED`).
|
|
155
|
+
* - `Idempotency-Key: setup-<orderId>`.
|
|
156
|
+
*/
|
|
157
|
+
createMandate(request: MandateSetupRequest): Promise<MandateSetupStart>;
|
|
158
|
+
/**
|
|
159
|
+
* Re-reads the authorization server-to-server (the callback is unsigned) and, once it is
|
|
160
|
+
* `ACCEPTED`, makes the first `PRE_AUTHORIZED` payment with `Idempotency-Key = orderId`. A second
|
|
161
|
+
* confirm (a second callback, or a re-confirm job with `{}`) replays that key and gets Satispay's
|
|
162
|
+
* original response instead of charging twice. The token id is always `pending.providerRef`;
|
|
163
|
+
* a callback `token_id` only has to match it.
|
|
164
|
+
*
|
|
165
|
+
* `CANCELED` is terminal with no mandate. The first payment is replayed with the same body and
|
|
166
|
+
* `Idempotency-Key = orderId` (Satispay returns the original response for a reused key), so a
|
|
167
|
+
* re-confirm after an `unknown` first charge learns whether it was taken:
|
|
168
|
+
* - `ACCEPTED` (the authorization was canceled after the first charge): `success: false`,
|
|
169
|
+
* verified, terminal, `succeeded` first charge, error 'Authorization canceled after the first
|
|
170
|
+
* charge'. The app refunds it or keeps it as a one-off payment.
|
|
171
|
+
* - a 4xx (no payment exists for that key, e.g. the customer declined the authorization):
|
|
172
|
+
* `success: false`, verified, terminal, `failed` first charge ('Authorization canceled').
|
|
173
|
+
* - 401, 403, 408, 409, 429, 5xx, a network error or an unexpected 2xx: unverified, non-terminal,
|
|
174
|
+
* `unknown` first charge.
|
|
175
|
+
* The replay is only authoritative while Satispay keeps the key (retention not documented).
|
|
176
|
+
*/
|
|
177
|
+
confirmMandate(pending: MandatePendingState, input: MandateCallbackInput): Promise<MandateSetupOutcome>;
|
|
178
|
+
/**
|
|
179
|
+
* Merchant-initiated `PRE_AUTHORIZED` payment, synchronous: Satispay creates it `ACCEPTED` or
|
|
180
|
+
* answers 4xx without creating a payment. `Idempotency-Key = chargeRef`: the same `chargeRef`
|
|
181
|
+
* gets Satispay's original response (retention not documented: retry `unknown` promptly).
|
|
182
|
+
* `providerPaymentId` is the Satispay payment id, refundable with `refundPayment`.
|
|
183
|
+
* 408 and 409 are `unknown`, not a refusal: they may answer a concurrent request with the same
|
|
184
|
+
* key that is still in flight (Satispay documents neither the behaviour nor the status).
|
|
185
|
+
*/
|
|
186
|
+
chargeMandate(mandate: Mandate, charge: ChargeRequest): Promise<ChargeResult>;
|
|
187
|
+
/**
|
|
188
|
+
* `POST /payments` (`PRE_AUTHORIZED`, `Idempotency-Key = chargeRef`) mapped to a `ChargeResult`,
|
|
189
|
+
* without the token re-read that sets `mandateUnusable`. A verified `failed` is always a 4xx.
|
|
190
|
+
*/
|
|
191
|
+
private postPayment;
|
|
192
|
+
/** Re-reads the authorization: ACCEPTED → active, CANCELED or 404 → revoked, PENDING → unknown. */
|
|
193
|
+
getMandate(mandate: Mandate): Promise<MandateStatusResult>;
|
|
194
|
+
/**
|
|
195
|
+
* Makes no network call: Satispay documents no merchant-side revocation (the token API has only
|
|
196
|
+
* GET). The undocumented `PUT /pre_authorized_payment_tokens/{id}` is deliberately not used.
|
|
197
|
+
* Stop charging the mandate; the customer can revoke it from the Satispay app.
|
|
198
|
+
*/
|
|
199
|
+
revokeMandate(_mandate: Mandate): Promise<MandateRevokeResult>;
|
|
200
|
+
/**
|
|
201
|
+
* `GET /pre_authorized_payment_tokens/{id}`. A 2xx whose `id` is not `tokenId` or whose `status`
|
|
202
|
+
* is not a string, a network error, a 5xx and any other non-2xx except 404 are `unavailable`.
|
|
203
|
+
*/
|
|
204
|
+
private readToken;
|
|
120
205
|
}
|
|
121
206
|
//# sourceMappingURL=satispay.provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"satispay.provider.d.ts","sourceRoot":"","sources":["../../../src/providers/satispay/satispay.provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;
|
|
1
|
+
{"version":3,"file":"satispay.provider.d.ts","sourceRoot":"","sources":["../../../src/providers/satispay/satispay.provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -38,11 +38,22 @@ const crypto = __importStar(require("crypto"));
|
|
|
38
38
|
const base_payment_provider_abstract_1 = require("../../abstract/base-payment-provider.abstract");
|
|
39
39
|
const in_memory_transaction_store_1 = require("../../stores/in-memory-transaction.store");
|
|
40
40
|
const parsing_util_1 = require("../../utils/parsing.util");
|
|
41
|
+
const ids_1 = require("../../utils/ids");
|
|
42
|
+
const money_1 = require("../../utils/money");
|
|
43
|
+
const url_1 = require("../../utils/url");
|
|
44
|
+
/** Signature headers that `extraHeaders` may never override (compared case-insensitively). */
|
|
45
|
+
const PROTECTED_HEADERS = new Set(['host', 'date', 'digest', 'authorization']);
|
|
46
|
+
const REVOKE_UNSUPPORTED = 'Satispay does not document a merchant-side revocation; stop charging this mandate. ' +
|
|
47
|
+
'The customer can revoke it from the Satispay app.';
|
|
41
48
|
/**
|
|
42
49
|
* Satispay Business API provider.
|
|
43
50
|
* Flow: `webhook` — creates a MATCH_CODE payment, user pays via Satispay app,
|
|
44
51
|
* Satispay calls the `callback_url` webhook, which is correlated to the order
|
|
45
52
|
* via the `ITransactionStore`. The redirect is then verified via `handleRedirect`.
|
|
53
|
+
*
|
|
54
|
+
* Recurring payments (`IMandateProvider`): Automatic Payments, web-redirect flow. A setup creates
|
|
55
|
+
* a pre-authorized payment token, the customer approves it in Satispay, and every charge (the
|
|
56
|
+
* first one included) is a synchronous `PRE_AUTHORIZED` payment. EUR only.
|
|
46
57
|
*/
|
|
47
58
|
class SatispayProvider extends base_payment_provider_abstract_1.BasePaymentProvider {
|
|
48
59
|
constructor(config) {
|
|
@@ -266,12 +277,59 @@ class SatispayProvider extends base_payment_provider_abstract_1.BasePaymentProvi
|
|
|
266
277
|
throw new Error('Invalid provider response');
|
|
267
278
|
}
|
|
268
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* Signed request that never throws and keeps the HTTP status and the parsed body, for the
|
|
282
|
+
* mandate methods (which must tell 4xx from 5xx from a timeout). `extraHeaders` are merged after
|
|
283
|
+
* the signature headers but can never override `Host`, `Date`, `Digest` or `Authorization`
|
|
284
|
+
* (case-insensitively). `request()` keeps its throwing behaviour for the one-off payment flow.
|
|
285
|
+
*/
|
|
286
|
+
async send(method, url, body, extraHeaders = {}) {
|
|
287
|
+
try {
|
|
288
|
+
const parsed = new URL(url);
|
|
289
|
+
const headers = this.buildSignatureHeaders(method, parsed.pathname, parsed.host, body);
|
|
290
|
+
for (const [name, value] of Object.entries(extraHeaders)) {
|
|
291
|
+
if (PROTECTED_HEADERS.has(name.toLowerCase()))
|
|
292
|
+
continue;
|
|
293
|
+
headers[name] = value;
|
|
294
|
+
}
|
|
295
|
+
const response = await fetch(url, {
|
|
296
|
+
method,
|
|
297
|
+
headers,
|
|
298
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
299
|
+
signal: AbortSignal.timeout(this.config.timeoutMs ?? 30000),
|
|
300
|
+
});
|
|
301
|
+
let text;
|
|
302
|
+
try {
|
|
303
|
+
text = await response.text();
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
// The body could not be read (connection reset, timeout while streaming)
|
|
307
|
+
return { ok: false, status: 0, networkError: true };
|
|
308
|
+
}
|
|
309
|
+
const status = typeof response.status === 'number' ? response.status : 0;
|
|
310
|
+
const ok = response.ok === true;
|
|
311
|
+
let json;
|
|
312
|
+
try {
|
|
313
|
+
const value = text ? JSON.parse(text) : undefined;
|
|
314
|
+
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
315
|
+
json = value;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch {
|
|
319
|
+
json = undefined;
|
|
320
|
+
}
|
|
321
|
+
return json ? { ok, status, json } : { ok, status };
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
return { ok: false, status: 0, networkError: true };
|
|
325
|
+
}
|
|
326
|
+
}
|
|
269
327
|
// ---------------------------------------------------------------------------
|
|
270
328
|
// IPaymentProvider implementation
|
|
271
329
|
// ---------------------------------------------------------------------------
|
|
272
330
|
async createPayment(request) {
|
|
273
331
|
try {
|
|
274
|
-
const orderId = request.orderId ??
|
|
332
|
+
const orderId = request.orderId ?? (0, ids_1.generateOrderId)();
|
|
275
333
|
const baseUrl = this.config.serverUrl ?? '';
|
|
276
334
|
const callbackPath = this.config.callbackPath ?? '/checkout/satispay/webhook';
|
|
277
335
|
// Satispay replaces {uuid} at runtime with the actual payment ID
|
|
@@ -284,9 +342,18 @@ class SatispayProvider extends base_payment_provider_abstract_1.BasePaymentProvi
|
|
|
284
342
|
status: 'FAILED',
|
|
285
343
|
};
|
|
286
344
|
}
|
|
345
|
+
// Payment details and refunds are read and sent in hundredths: only 2-decimal currencies
|
|
346
|
+
// keep create, read-back and refund on the same scale
|
|
347
|
+
if ((0, money_1.currencyExponent)(validatedCurrency) !== 2) {
|
|
348
|
+
return {
|
|
349
|
+
success: false,
|
|
350
|
+
error: 'Payment currency is not supported by Satispay: only currencies with 2 decimal places are accepted',
|
|
351
|
+
status: 'FAILED',
|
|
352
|
+
};
|
|
353
|
+
}
|
|
287
354
|
const body = {
|
|
288
355
|
flow: 'MATCH_CODE',
|
|
289
|
-
amount_unit:
|
|
356
|
+
amount_unit: (0, money_1.toMinorUnits)(request.amount, validatedCurrency),
|
|
290
357
|
currency: validatedCurrency,
|
|
291
358
|
external_code: orderId,
|
|
292
359
|
callback_url: callbackUrl,
|
|
@@ -310,6 +377,9 @@ class SatispayProvider extends base_payment_provider_abstract_1.BasePaymentProvi
|
|
|
310
377
|
};
|
|
311
378
|
}
|
|
312
379
|
catch (error) {
|
|
380
|
+
if ((0, money_1.isInvalidAmountError)(error)) {
|
|
381
|
+
return { success: false, error: error.message, status: 'FAILED' };
|
|
382
|
+
}
|
|
313
383
|
return this.errorResult(error, 'Failed to create Satispay payment');
|
|
314
384
|
}
|
|
315
385
|
}
|
|
@@ -367,7 +437,10 @@ class SatispayProvider extends base_payment_provider_abstract_1.BasePaymentProvi
|
|
|
367
437
|
};
|
|
368
438
|
}
|
|
369
439
|
try {
|
|
370
|
-
|
|
440
|
+
// The refund call carries no currency. createPayment accepts only 2-decimal currencies,
|
|
441
|
+
// so a partial amount is always in hundredths. Only an omitted (undefined) amount means a
|
|
442
|
+
// full refund, as in PayPal: 0 and null are rejected by toMinorUnits like any invalid amount.
|
|
443
|
+
const body = amount !== undefined ? { amount_unit: (0, money_1.toMinorUnits)(amount, 'EUR') } : {};
|
|
371
444
|
const refund = await this.request('POST', `${this.apiUrl}/payments/${encodeURIComponent(paymentId)}/refunds`, body);
|
|
372
445
|
return {
|
|
373
446
|
success: true,
|
|
@@ -378,6 +451,9 @@ class SatispayProvider extends base_payment_provider_abstract_1.BasePaymentProvi
|
|
|
378
451
|
};
|
|
379
452
|
}
|
|
380
453
|
catch (error) {
|
|
454
|
+
if ((0, money_1.isInvalidAmountError)(error)) {
|
|
455
|
+
return { success: false, error: error.message, status: 'FAILED' };
|
|
456
|
+
}
|
|
381
457
|
return this.errorResult(error, 'Failed to refund Satispay payment');
|
|
382
458
|
}
|
|
383
459
|
}
|
|
@@ -498,6 +574,367 @@ class SatispayProvider extends base_payment_provider_abstract_1.BasePaymentProvi
|
|
|
498
574
|
...(details.success ? {} : { error: details.error }),
|
|
499
575
|
};
|
|
500
576
|
}
|
|
577
|
+
// ---------------------------------------------------------------------------
|
|
578
|
+
// IMandateProvider implementation (Automatic Payments, web-redirect flow)
|
|
579
|
+
// ---------------------------------------------------------------------------
|
|
580
|
+
/**
|
|
581
|
+
* Creates a pre-authorized payment token (`POST /pre_authorized_payment_tokens`) and returns
|
|
582
|
+
* its `redirect_url` as `approvalUrl`. Never open that URL in a WebView.
|
|
583
|
+
*
|
|
584
|
+
* - EUR only.
|
|
585
|
+
* - `callback_url` is `notifyUrl` (or `serverUrl + mandateCallbackPath`) with `mandate_ref`
|
|
586
|
+
* and the raw `token_id={uuid}` placeholder, which Satispay substitutes with the token id.
|
|
587
|
+
* - `redirect_url` is `returnUrl` with `mandate_ref`.
|
|
588
|
+
* - `cancelUrl` is unused: Satispay has no cancel redirect (a canceled authorization is
|
|
589
|
+
* reported through the callback and re-read as `CANCELED`).
|
|
590
|
+
* - `Idempotency-Key: setup-<orderId>`.
|
|
591
|
+
*/
|
|
592
|
+
async createMandate(request) {
|
|
593
|
+
if (request.currency !== 'EUR') {
|
|
594
|
+
return { success: false, error: 'Satispay mandates support EUR only' };
|
|
595
|
+
}
|
|
596
|
+
try {
|
|
597
|
+
// The first charge is made later from the pending state: reject an invalid amount now
|
|
598
|
+
(0, money_1.toMinorUnits)(request.amount, 'EUR');
|
|
599
|
+
}
|
|
600
|
+
catch (error) {
|
|
601
|
+
return {
|
|
602
|
+
success: false,
|
|
603
|
+
error: (0, money_1.isInvalidAmountError)(error) ? error.message : 'Invalid mandate amount',
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
const base = request.notifyUrl ??
|
|
607
|
+
(this.config.serverUrl
|
|
608
|
+
? this.config.serverUrl +
|
|
609
|
+
(this.config.mandateCallbackPath ?? '/checkout/satispay/mandate/callback')
|
|
610
|
+
: undefined);
|
|
611
|
+
if (!base) {
|
|
612
|
+
return { success: false, error: 'Satispay mandates require notifyUrl or serverUrl' };
|
|
613
|
+
}
|
|
614
|
+
let callbackUrl;
|
|
615
|
+
let redirectUrl;
|
|
616
|
+
try {
|
|
617
|
+
const callback = new URL((0, url_1.appendMandateRef)(base, request.mandateRef));
|
|
618
|
+
callback.searchParams.delete('token_id');
|
|
619
|
+
// A fragment is never sent to a server; dropping it keeps the placeholder in the query
|
|
620
|
+
callback.hash = '';
|
|
621
|
+
// `{uuid}` is appended raw AFTER serialization: URLSearchParams would percent-encode the
|
|
622
|
+
// braces and Satispay would no longer substitute the token id
|
|
623
|
+
callbackUrl = callback.toString() + '&token_id={uuid}';
|
|
624
|
+
redirectUrl = (0, url_1.appendMandateRef)(request.returnUrl, request.mandateRef);
|
|
625
|
+
}
|
|
626
|
+
catch {
|
|
627
|
+
return { success: false, error: 'Satispay mandate callback or return URL is not an absolute URL' };
|
|
628
|
+
}
|
|
629
|
+
const res = await this.send('POST', `${this.apiUrl}/pre_authorized_payment_tokens`, { reason: request.description, callback_url: callbackUrl, redirect_url: redirectUrl }, { 'Idempotency-Key': 'setup-' + request.orderId });
|
|
630
|
+
const id = res.json?.['id'];
|
|
631
|
+
const approvalUrl = res.json?.['redirect_url'];
|
|
632
|
+
if (!res.ok || typeof id !== 'string' || id === '' || typeof approvalUrl !== 'string' || approvalUrl === '') {
|
|
633
|
+
// Generic: never the response body, which may carry the token id
|
|
634
|
+
return {
|
|
635
|
+
success: false,
|
|
636
|
+
error: res.networkError
|
|
637
|
+
? 'Satispay authorization could not be created (network error or timeout)'
|
|
638
|
+
: `Satispay authorization could not be created (HTTP ${res.status})`,
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
return {
|
|
642
|
+
success: true,
|
|
643
|
+
approvalUrl,
|
|
644
|
+
pending: {
|
|
645
|
+
provider: this.name,
|
|
646
|
+
mandateRef: request.mandateRef,
|
|
647
|
+
orderId: request.orderId,
|
|
648
|
+
amount: request.amount,
|
|
649
|
+
currency: 'EUR',
|
|
650
|
+
providerRef: id,
|
|
651
|
+
createdAt: new Date().toISOString(),
|
|
652
|
+
},
|
|
653
|
+
raw: res.json,
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Re-reads the authorization server-to-server (the callback is unsigned) and, once it is
|
|
658
|
+
* `ACCEPTED`, makes the first `PRE_AUTHORIZED` payment with `Idempotency-Key = orderId`. A second
|
|
659
|
+
* confirm (a second callback, or a re-confirm job with `{}`) replays that key and gets Satispay's
|
|
660
|
+
* original response instead of charging twice. The token id is always `pending.providerRef`;
|
|
661
|
+
* a callback `token_id` only has to match it.
|
|
662
|
+
*
|
|
663
|
+
* `CANCELED` is terminal with no mandate. The first payment is replayed with the same body and
|
|
664
|
+
* `Idempotency-Key = orderId` (Satispay returns the original response for a reused key), so a
|
|
665
|
+
* re-confirm after an `unknown` first charge learns whether it was taken:
|
|
666
|
+
* - `ACCEPTED` (the authorization was canceled after the first charge): `success: false`,
|
|
667
|
+
* verified, terminal, `succeeded` first charge, error 'Authorization canceled after the first
|
|
668
|
+
* charge'. The app refunds it or keeps it as a one-off payment.
|
|
669
|
+
* - a 4xx (no payment exists for that key, e.g. the customer declined the authorization):
|
|
670
|
+
* `success: false`, verified, terminal, `failed` first charge ('Authorization canceled').
|
|
671
|
+
* - 401, 403, 408, 409, 429, 5xx, a network error or an unexpected 2xx: unverified, non-terminal,
|
|
672
|
+
* `unknown` first charge.
|
|
673
|
+
* The replay is only authoritative while Satispay keeps the key (retention not documented).
|
|
674
|
+
*/
|
|
675
|
+
async confirmMandate(pending, input) {
|
|
676
|
+
const unverified = (error) => ({
|
|
677
|
+
success: false,
|
|
678
|
+
verified: false,
|
|
679
|
+
terminal: false,
|
|
680
|
+
firstCharge: { status: 'unknown', verified: false, chargeRef: pending.orderId },
|
|
681
|
+
error,
|
|
682
|
+
});
|
|
683
|
+
const callbackTokenId = input?.query?.['token_id'];
|
|
684
|
+
if (callbackTokenId !== undefined && callbackTokenId !== pending.providerRef) {
|
|
685
|
+
return unverified('Callback token does not match the pending setup');
|
|
686
|
+
}
|
|
687
|
+
const read = await this.readToken(pending.providerRef);
|
|
688
|
+
if (read.kind !== 'found') {
|
|
689
|
+
return unverified('Satispay authorization could not be read');
|
|
690
|
+
}
|
|
691
|
+
const firstChargeRequest = {
|
|
692
|
+
chargeRef: pending.orderId,
|
|
693
|
+
amount: pending.amount,
|
|
694
|
+
currency: 'EUR',
|
|
695
|
+
};
|
|
696
|
+
switch (read.status) {
|
|
697
|
+
case 'PENDING':
|
|
698
|
+
return {
|
|
699
|
+
success: false,
|
|
700
|
+
verified: true,
|
|
701
|
+
terminal: false,
|
|
702
|
+
error: 'AUTHORIZATION_PENDING',
|
|
703
|
+
firstCharge: {
|
|
704
|
+
status: 'unknown',
|
|
705
|
+
verified: false,
|
|
706
|
+
chargeRef: pending.orderId,
|
|
707
|
+
error: 'Authorization still pending',
|
|
708
|
+
},
|
|
709
|
+
raw: read.json,
|
|
710
|
+
};
|
|
711
|
+
case 'CANCELED': {
|
|
712
|
+
// Replay the first payment exactly as the ACCEPTED branch sends it (same body, same key)
|
|
713
|
+
const replay = await this.postPayment(pending.providerRef, firstChargeRequest);
|
|
714
|
+
if (replay.status === 'succeeded') {
|
|
715
|
+
return {
|
|
716
|
+
success: false,
|
|
717
|
+
verified: true,
|
|
718
|
+
terminal: true,
|
|
719
|
+
error: 'Authorization canceled after the first charge',
|
|
720
|
+
firstCharge: replay,
|
|
721
|
+
raw: read.json,
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
if (replay.status === 'failed') {
|
|
725
|
+
// A 4xx: Satispay holds no payment for this key. (A local amount or currency check that
|
|
726
|
+
// failed means no request with this body could ever have been sent.)
|
|
727
|
+
return {
|
|
728
|
+
success: false,
|
|
729
|
+
verified: true,
|
|
730
|
+
terminal: true,
|
|
731
|
+
error: 'Authorization canceled',
|
|
732
|
+
firstCharge: {
|
|
733
|
+
status: 'failed',
|
|
734
|
+
verified: true,
|
|
735
|
+
chargeRef: pending.orderId,
|
|
736
|
+
error: 'Authorization canceled',
|
|
737
|
+
},
|
|
738
|
+
raw: read.json,
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
return {
|
|
742
|
+
...unverified('Authorization canceled; the first charge outcome is unknown'),
|
|
743
|
+
firstCharge: replay,
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
case 'ACCEPTED': {
|
|
747
|
+
const mandate = {
|
|
748
|
+
provider: this.name,
|
|
749
|
+
mandateRef: pending.mandateRef,
|
|
750
|
+
providerMandateId: pending.providerRef,
|
|
751
|
+
status: 'active',
|
|
752
|
+
createdAt: new Date().toISOString(),
|
|
753
|
+
};
|
|
754
|
+
const firstCharge = await this.chargeMandate(mandate, firstChargeRequest);
|
|
755
|
+
return { success: true, verified: true, terminal: true, mandate, firstCharge, raw: read.json };
|
|
756
|
+
}
|
|
757
|
+
default:
|
|
758
|
+
return unverified('Satispay authorization status is not recognised');
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Merchant-initiated `PRE_AUTHORIZED` payment, synchronous: Satispay creates it `ACCEPTED` or
|
|
763
|
+
* answers 4xx without creating a payment. `Idempotency-Key = chargeRef`: the same `chargeRef`
|
|
764
|
+
* gets Satispay's original response (retention not documented: retry `unknown` promptly).
|
|
765
|
+
* `providerPaymentId` is the Satispay payment id, refundable with `refundPayment`.
|
|
766
|
+
* 408 and 409 are `unknown`, not a refusal: they may answer a concurrent request with the same
|
|
767
|
+
* key that is still in flight (Satispay documents neither the behaviour nor the status).
|
|
768
|
+
*/
|
|
769
|
+
async chargeMandate(mandate, charge) {
|
|
770
|
+
const result = await this.postPayment(mandate.providerMandateId, charge);
|
|
771
|
+
if (result.status === 'failed' && result.verified) {
|
|
772
|
+
// A refusal (4xx): tell the app whether the authorization itself is gone
|
|
773
|
+
const read = await this.readToken(mandate.providerMandateId);
|
|
774
|
+
if (read.kind === 'not_found' || (read.kind === 'found' && read.status === 'CANCELED')) {
|
|
775
|
+
result.mandateUnusable = true;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
return result;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* `POST /payments` (`PRE_AUTHORIZED`, `Idempotency-Key = chargeRef`) mapped to a `ChargeResult`,
|
|
782
|
+
* without the token re-read that sets `mandateUnusable`. A verified `failed` is always a 4xx.
|
|
783
|
+
*/
|
|
784
|
+
async postPayment(tokenId, charge) {
|
|
785
|
+
const chargeRef = charge.chargeRef;
|
|
786
|
+
if (charge.currency !== 'EUR') {
|
|
787
|
+
return { status: 'failed', verified: false, chargeRef, error: 'Satispay mandates support EUR only' };
|
|
788
|
+
}
|
|
789
|
+
let amountUnit;
|
|
790
|
+
try {
|
|
791
|
+
amountUnit = (0, money_1.toMinorUnits)(charge.amount, 'EUR');
|
|
792
|
+
}
|
|
793
|
+
catch (error) {
|
|
794
|
+
return {
|
|
795
|
+
status: 'failed',
|
|
796
|
+
verified: false,
|
|
797
|
+
chargeRef,
|
|
798
|
+
error: (0, money_1.isInvalidAmountError)(error) ? error.message : 'Invalid charge amount',
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
const res = await this.send('POST', `${this.apiUrl}/payments`, {
|
|
802
|
+
flow: 'PRE_AUTHORIZED',
|
|
803
|
+
token: tokenId,
|
|
804
|
+
amount_unit: amountUnit,
|
|
805
|
+
currency: 'EUR',
|
|
806
|
+
external_code: chargeRef,
|
|
807
|
+
...(charge.description ? { metadata: { description: charge.description } } : {}),
|
|
808
|
+
}, { 'Idempotency-Key': chargeRef });
|
|
809
|
+
if (res.networkError) {
|
|
810
|
+
return { status: 'unknown', verified: false, chargeRef, error: 'Satispay charge timed out or failed to connect' };
|
|
811
|
+
}
|
|
812
|
+
if (res.ok) {
|
|
813
|
+
const json = res.json;
|
|
814
|
+
if (!json) {
|
|
815
|
+
return { status: 'unknown', verified: false, chargeRef, error: 'Invalid provider response' };
|
|
816
|
+
}
|
|
817
|
+
const externalCode = json['external_code'];
|
|
818
|
+
if (externalCode !== undefined && externalCode !== null && externalCode !== chargeRef) {
|
|
819
|
+
return {
|
|
820
|
+
status: 'unknown',
|
|
821
|
+
verified: false,
|
|
822
|
+
chargeRef,
|
|
823
|
+
error: 'Satispay payment does not match the charge reference',
|
|
824
|
+
raw: json,
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
const paymentId = json['id'];
|
|
828
|
+
if (json['status'] !== 'ACCEPTED' || typeof paymentId !== 'string' || paymentId === '') {
|
|
829
|
+
return {
|
|
830
|
+
status: 'unknown',
|
|
831
|
+
verified: false,
|
|
832
|
+
chargeRef,
|
|
833
|
+
error: `Satispay payment is ${typeof json['status'] === 'string' ? json['status'] : 'unknown'}`,
|
|
834
|
+
raw: json,
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
const rawAmount = json['amount_unit'];
|
|
838
|
+
const amount = (0, parsing_util_1.parseAmountFromCents)(rawAmount);
|
|
839
|
+
const currency = json['currency'];
|
|
840
|
+
if ((rawAmount != null && amount === undefined) || (currency != null && typeof currency !== 'string')) {
|
|
841
|
+
return { status: 'unknown', verified: false, chargeRef, error: 'Invalid provider response', raw: json };
|
|
842
|
+
}
|
|
843
|
+
return {
|
|
844
|
+
status: 'succeeded',
|
|
845
|
+
// Authenticated server-to-server response, as in getPaymentDetails
|
|
846
|
+
verified: true,
|
|
847
|
+
chargeRef,
|
|
848
|
+
providerPaymentId: paymentId,
|
|
849
|
+
amount,
|
|
850
|
+
currency: currency ?? undefined,
|
|
851
|
+
raw: json,
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
if (res.status === 401 || res.status === 403 || res.status === 429) {
|
|
855
|
+
// Merchant-side (credentials, rate limit): not a refusal of this customer's charge
|
|
856
|
+
return {
|
|
857
|
+
status: 'unknown',
|
|
858
|
+
verified: false,
|
|
859
|
+
chargeRef,
|
|
860
|
+
error: `Satispay rejected the request (HTTP ${res.status})`,
|
|
861
|
+
raw: res.json,
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
if (res.status === 408 || res.status === 409) {
|
|
865
|
+
// Possibly a same-key request still in flight: the original may succeed
|
|
866
|
+
return {
|
|
867
|
+
status: 'unknown',
|
|
868
|
+
verified: false,
|
|
869
|
+
chargeRef,
|
|
870
|
+
error: `Satispay charge outcome is unknown (HTTP ${res.status})`,
|
|
871
|
+
raw: res.json,
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
if (res.status >= 400 && res.status < 500) {
|
|
875
|
+
const json = res.json;
|
|
876
|
+
return {
|
|
877
|
+
status: 'failed',
|
|
878
|
+
verified: true,
|
|
879
|
+
chargeRef,
|
|
880
|
+
providerCode: String(json?.['code'] ?? res.status),
|
|
881
|
+
error: String(json?.['message'] ?? 'Satispay refused the charge'),
|
|
882
|
+
raw: json,
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
return {
|
|
886
|
+
status: 'unknown',
|
|
887
|
+
verified: false,
|
|
888
|
+
chargeRef,
|
|
889
|
+
error: `Satispay charge outcome is unknown (HTTP ${res.status})`,
|
|
890
|
+
raw: res.json,
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
/** Re-reads the authorization: ACCEPTED → active, CANCELED or 404 → revoked, PENDING → unknown. */
|
|
894
|
+
async getMandate(mandate) {
|
|
895
|
+
const read = await this.readToken(mandate.providerMandateId);
|
|
896
|
+
if (read.kind === 'not_found')
|
|
897
|
+
return { status: 'revoked', verified: true };
|
|
898
|
+
if (read.kind === 'unavailable')
|
|
899
|
+
return { status: 'unknown', verified: false };
|
|
900
|
+
switch (read.status) {
|
|
901
|
+
case 'ACCEPTED':
|
|
902
|
+
return { status: 'active', verified: true, raw: read.json };
|
|
903
|
+
case 'CANCELED':
|
|
904
|
+
return { status: 'revoked', verified: true, raw: read.json };
|
|
905
|
+
case 'PENDING':
|
|
906
|
+
return { status: 'unknown', verified: true, raw: read.json };
|
|
907
|
+
default:
|
|
908
|
+
return { status: 'unknown', verified: false, raw: read.json };
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* Makes no network call: Satispay documents no merchant-side revocation (the token API has only
|
|
913
|
+
* GET). The undocumented `PUT /pre_authorized_payment_tokens/{id}` is deliberately not used.
|
|
914
|
+
* Stop charging the mandate; the customer can revoke it from the Satispay app.
|
|
915
|
+
*/
|
|
916
|
+
async revokeMandate(_mandate) {
|
|
917
|
+
return { revokedAtProvider: false, error: REVOKE_UNSUPPORTED };
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* `GET /pre_authorized_payment_tokens/{id}`. A 2xx whose `id` is not `tokenId` or whose `status`
|
|
921
|
+
* is not a string, a network error, a 5xx and any other non-2xx except 404 are `unavailable`.
|
|
922
|
+
*/
|
|
923
|
+
async readToken(tokenId) {
|
|
924
|
+
if (typeof tokenId !== 'string' || tokenId === '')
|
|
925
|
+
return { kind: 'unavailable' };
|
|
926
|
+
const res = await this.send('GET', `${this.apiUrl}/pre_authorized_payment_tokens/${encodeURIComponent(tokenId)}`);
|
|
927
|
+
if (res.networkError)
|
|
928
|
+
return { kind: 'unavailable' };
|
|
929
|
+
if (res.status === 404)
|
|
930
|
+
return { kind: 'not_found' };
|
|
931
|
+
if (!res.ok || !res.json)
|
|
932
|
+
return { kind: 'unavailable' };
|
|
933
|
+
const status = res.json['status'];
|
|
934
|
+
if (res.json['id'] !== tokenId || typeof status !== 'string')
|
|
935
|
+
return { kind: 'unavailable' };
|
|
936
|
+
return { kind: 'found', status, json: res.json };
|
|
937
|
+
}
|
|
501
938
|
}
|
|
502
939
|
exports.SatispayProvider = SatispayProvider;
|
|
503
940
|
//# sourceMappingURL=satispay.provider.js.map
|