@agent-cards/sdk 0.23.13 → 0.23.15

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 (41) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/PREFLIGHT.md +3 -1
  3. package/README.md +54 -13
  4. package/dist/adyen-merchant-hosted.generated.js +2 -2
  5. package/dist/amadeus.d.ts +5 -2
  6. package/dist/amadeus.js +17 -3
  7. package/dist/card-fields.generated.js +924 -3
  8. package/dist/cdp.js +83 -19
  9. package/dist/client.d.ts +97 -1
  10. package/dist/client.js +235 -16
  11. package/dist/creditguard.generated.d.ts +100 -2
  12. package/dist/creditguard.generated.js +333 -3
  13. package/dist/datatrans.generated.d.ts +19 -4
  14. package/dist/datatrans.generated.js +15 -3
  15. package/dist/ebanx.d.ts +107 -0
  16. package/dist/ebanx.generated.d.ts +78 -0
  17. package/dist/ebanx.generated.js +577 -0
  18. package/dist/ebanx.js +159 -0
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.js +2 -0
  21. package/dist/lifecycle.d.ts +32 -5
  22. package/dist/lifecycle.js +40 -5
  23. package/dist/paddle-tokenex.d.ts +56 -0
  24. package/dist/paddle-tokenex.generated.d.ts +67 -0
  25. package/dist/paddle-tokenex.generated.js +951 -0
  26. package/dist/paddle-tokenex.js +95 -0
  27. package/dist/paypal-card-forms.d.ts +73 -0
  28. package/dist/paypal-card-forms.js +126 -0
  29. package/dist/pre-claim.d.ts +39 -1
  30. package/dist/pre-claim.js +348 -18
  31. package/dist/preparation.d.ts +13 -0
  32. package/dist/preparation.js +22 -0
  33. package/dist/prepared-processor.d.ts +5 -1
  34. package/dist/prepared-processor.js +17 -2
  35. package/dist/primer.generated.js +960 -39
  36. package/dist/redsys.d.ts +42 -0
  37. package/dist/redsys.js +68 -0
  38. package/dist/stripe-checkout.generated.js +494 -9
  39. package/dist/wix-payments.generated.d.ts +42 -0
  40. package/dist/wix-payments.generated.js +241 -0
  41. package/package.json +8 -5
package/dist/ebanx.js ADDED
@@ -0,0 +1,159 @@
1
+ /**
2
+ * EBANX after its card token (payment-core ebanx.js holds the rules; this SDK vendors them as ebanx.generated.ts).
3
+ *
4
+ * The adapters pause EBANX's POST /ws/token, the cardholder's device sends the real card there, and the page
5
+ * receives EBANX's token. EBANX's hosted payment page (payment.ebanx.com, where Nuuvem's Colombia store sends its
6
+ * shoppers) and EBANX.js 1.135.0 then send the card the page holds again, and on a page this SDK is attached to,
7
+ * that card is the agent's placeholder:
8
+ * - 3-D Secure posts paymentInformation.card (number, expiry, holder) to /ws/threedsecureserver-generateToken,
9
+ * -authentications and -authentication-results (up to 48 times while a Netcetera challenge polls) on the host
10
+ * the token request went to;
11
+ * - the hosted page's confirm posts payment.card.card_cvv, the code the agent typed, beside EBANX's token, to
12
+ * /ws/checkout-v2/confirm on the invoice's host.
13
+ * Both adapters arm those requests on every attachment, whatever the synced registry serves, and the pre-claim
14
+ * gate (ebanxPreClaim, pre-claim.ts) judges each POST:
15
+ * - one the approved token request on this attachment covers (EbanxFollowUps.claim: the API said the approval
16
+ * covers sends after it, until when, and payment-core's rule binds the request to that approval): sent from the
17
+ * cardholder's device under that same approval, with no second prompt (VaultClient.sendEbanxFollowUp), and the
18
+ * page receives EBANX's answer. Never after a refused or failed send, a failed handoff of the token's answer, or a
19
+ * final merchant result (completed, failed, declined, timed out, cancelled, unknown): nothing more is covered then;
20
+ * - any other 3-D Secure call, or a confirm whose payment.card names a card code or number: abort, so EBANX never
21
+ * receives the placeholder as a card. The page shows its own payment error and nothing is charged. The checkout
22
+ * reads `unsupported` with reason `unsupported_ebanx_card_resend` and holds, as every unsupported refusal does;
23
+ * after an approval it keeps the approval's state;
24
+ * - a confirm whose body cannot be read: abort that request alone, since nothing proves it carries no card;
25
+ * - any other request (a confirm for a bank transfer, cash or a wallet, -record, a GET, a preflight): continue.
26
+ * A request the synced registry recognizes as a card request belongs to that recognizer instead; no build serves
27
+ * one today.
28
+ */
29
+ import { EBANX_CONFIRM_PATH as CONFIRM_PATH, EBANX_FOLLOW_UP_KINDS, EBANX_RESEND_HOSTS as RESEND_HOSTS, ebanxFollowUpVerdict, ebanxResendKind, ebanxResendRefusal, readEbanxTokenAnswer, readEbanxTokenRequest, } from './ebanx.generated.js';
30
+ export const EBANX_RESEND_REASON = 'unsupported_ebanx_card_resend';
31
+ /** EBANX's hosts for these requests (payment-core EBANX_RESEND_HOSTS). */
32
+ export const EBANX_RESEND_HOSTS = Object.freeze([...RESEND_HOSTS]);
33
+ /** The tenant host only the confirm uses: no card recognizer names it, so its patterns here are the only ones that pause it. */
34
+ const CONFIRM_TENANT_HOST = 'customer-local-latam.ebanx.com';
35
+ /**
36
+ * CDP Fetch patterns for the 3-D Secure calls and the confirm on each of EBANX's hosts, armed on every attachment.
37
+ * The card recognizer already arms every request on the hosts it names; these keep both requests armed for a client
38
+ * whose registry names no EBANX host. The -record call matches the 3-D Secure pattern too and continues untouched.
39
+ * The third pattern arms any address on the host that holds a percent-escape, since CDP matches the address as written
40
+ * and a server may decode /ws/%63heckout-v2/confirm to the confirm: the gate decodes the path the same way
41
+ * (payment-core ebanxResendKind) and continues every one that is not a card send. CDP matches literally and in one
42
+ * letter case, so the tenant host only the confirm uses (CONFIRM_TENANT_HOST) is armed whole, its host text anywhere
43
+ * in the address as the card recognizer arms its own hosts: /WS/CHECKOUT-V2/CONFIRM, //, ;x=1 and a trailing-dot
44
+ * host all pause, and the gate judges each one.
45
+ */
46
+ export const EBANX_RESEND_PATTERNS = Object.freeze([
47
+ ...EBANX_RESEND_HOSTS.flatMap((host) => [`https://${host}/ws/threedsecureserver-*`, `https://${host}${CONFIRM_PATH}*`, `https://${host}/*%*`]),
48
+ `*${CONFIRM_TENANT_HOST}*`,
49
+ ]);
50
+ /**
51
+ * Whether this URL is one of the three 3-D Secure calls that carry the card or the hosted page's confirm on an EBANX
52
+ * host, or an EBANX path still percent-encoded after the last decoding round, which the gate refuses as unreadable.
53
+ */
54
+ export function isEbanxResendUrl(url) {
55
+ return ebanxResendKind(url) !== null;
56
+ }
57
+ /**
58
+ * Why this request must not leave the browser with the card the page holds, or null when it may. The body is read
59
+ * only for a confirm, through `readBody`, and a reader that throws reads as a body nobody could read.
60
+ */
61
+ export function ebanxResendRefusalOf(url, method, readBody) {
62
+ return ebanxResendRefusal({
63
+ url, method,
64
+ get body() { try {
65
+ return readBody();
66
+ }
67
+ catch {
68
+ return null;
69
+ } },
70
+ });
71
+ }
72
+ /**
73
+ * A send the cardholder's device did not answer with EBANX's own answer. `reason` is the API's word for it:
74
+ * `not_picked_up` (no device started it in time: the Vault page was closed or asleep), `not_sent` (the device
75
+ * refused it before the card left), `no_answer`, `answer_withheld` (EBANX's answer carried the card),
76
+ * `answer_refused`, `answer_late`, `response_expired`, or the API's refusal code when it did not take the send at
77
+ * all (`follow_up_refused`, `follow_up_not_covered`, `follow_up_window_closed`). `cardSent` says whether the card
78
+ * may have reached EBANX: false only when the API confirmed it never left the device. Nothing in it names the
79
+ * request, the card or EBANX's answer.
80
+ */
81
+ export class EbanxFollowUpError extends Error {
82
+ reason;
83
+ cardSent;
84
+ authorizationId;
85
+ constructor(reason, cardSent, authorizationId) {
86
+ super(cardSent
87
+ ? `This EBANX request under ${authorizationId} has no answer, and the cardholder's device may have sent it: ${reason}.`
88
+ : `The cardholder's device did not send this EBANX request under ${authorizationId}: ${reason}.`);
89
+ this.reason = reason;
90
+ this.cardSent = cardSent;
91
+ this.authorizationId = authorizationId;
92
+ this.name = 'EbanxFollowUpError';
93
+ }
94
+ }
95
+ /**
96
+ * What one attachment keeps of its approved EBANX token request: the request and EBANX's answer as the page received
97
+ * them, until when the API said the approval covers sends after it, and the sends it claimed since, in order. Only
98
+ * a token approval whose read named that window (`followUpsUntil`, served for a company Agentcard turned it on for)
99
+ * is kept; a later approval replaces it, and a send the window has passed is never claimed. Once the gate refuses a
100
+ * send or a send fails, the attachment stops (stop()): nothing after it is claimed, a later approval included, so
101
+ * a page the controller already reads as stopped cannot finish 3-D Secure and pay through the confirm.
102
+ */
103
+ export class EbanxFollowUps {
104
+ parent = null;
105
+ sent = [];
106
+ stopped = false;
107
+ /** After a refused or failed send: no later request on this attachment is claimed. */
108
+ stop() { this.stopped = true; }
109
+ /**
110
+ * The approval the remembered token request went under, or null when none is remembered. The gate sends nothing
111
+ * unless the checkout's own state names this same approval (pre-claim.ts ebanxMaySend).
112
+ */
113
+ get authorizationId() { return this.parent?.authorizationId ?? null; }
114
+ /**
115
+ * As the adapter hands an approved token request's answer to the page: before the answer lands, since the page may
116
+ * send its first 3-D Secure call at once. A handoff that fails then stops the attachment (stop()).
117
+ */
118
+ remember(request, replay) {
119
+ const until = typeof replay.followUpsUntil === 'string' ? Date.parse(replay.followUpsUntil) : NaN;
120
+ if ((replay.mode ?? 'token') !== 'token' || !Number.isFinite(until))
121
+ return;
122
+ const answer = { status: replay.status, text: replay.body };
123
+ if (!readEbanxTokenRequest({ url: request.url, body: request.body }) || !readEbanxTokenAnswer(answer))
124
+ return;
125
+ this.parent = { authorizationId: replay.authorizationId, url: request.url, body: request.body, answer, until };
126
+ this.sent = [];
127
+ }
128
+ /**
129
+ * The claim for a paused request the remembered approval covers, or null: no approval covers sends here, its
130
+ * window has passed, or payment-core's rule refuses the request against the sends already claimed (the amount
131
+ * is left to the API and the device, which hold the approved figure). Synchronous, and it reserves the send, so
132
+ * two requests can never both be claimed as the next one.
133
+ */
134
+ claim(request, now = Date.now()) {
135
+ const parent = this.parent;
136
+ if (this.stopped || !parent || now >= parent.until || typeof request.body !== 'string')
137
+ return null;
138
+ const verdict = ebanxFollowUpVerdict({ parent, sent: this.sent, request: { url: request.url, method: request.method, body: request.body } }, { skipAmount: true });
139
+ if (!verdict.ok || !EBANX_FOLLOW_UP_KINDS.includes(verdict.kind))
140
+ return null;
141
+ const entry = { kind: verdict.kind, state: 'pending', body: request.body };
142
+ this.sent.push(entry);
143
+ const contentType = Object.entries(request.headers ?? {}).find(([name]) => /^content-type$/i.test(name))?.[1];
144
+ return {
145
+ authorizationId: parent.authorizationId, kind: verdict.kind, until: parent.until,
146
+ request: { url: request.url, method: 'POST', headers: { 'content-type': typeof contentType === 'string' ? contentType : 'text/plain' }, body: request.body },
147
+ settle(answer) {
148
+ if (entry.state !== 'pending')
149
+ return;
150
+ if (answer) {
151
+ entry.state = 'answered';
152
+ entry.answer = answer;
153
+ }
154
+ else
155
+ entry.state = 'failed';
156
+ },
157
+ };
158
+ }
159
+ }
package/dist/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export type { PausedRequest, ReplayResponse, TokenReplay, CseReplay, MerchantHos
14
14
  export type { MicroformField, MicroformSidecar } from './cybersource-flex.js';
15
15
  export { attachToCdp, attachToPlaywright, corsHeadersFor, corsDecision, withCorsHeaders } from './cdp.js';
16
16
  export { CheckoutAttachmentError } from './attachment.js';
17
+ export { EbanxFollowUpError } from './ebanx.js';
17
18
  export { CardEndpointRefusedError, cardEndpointPatterns } from './card-endpoint.js';
18
19
  export { MerchantSessionRefusedError, captureMerchantSession, merchantSessionCapture, merchantSessionReadUrl } from './merchant-session-probe.js';
19
20
  export type { MerchantSessionCapture, MerchantSessionCookie, MerchantSessionCdp, MerchantSessionRefusal } from './merchant-session-probe.js';
package/dist/index.js CHANGED
@@ -5,6 +5,8 @@ export { CardEncryptedError, UnsupportedModeError, UnsupportedCapabilityError, P
5
5
  export { CONVERGE_REFUSAL_REASONS } from './elavon-converge.js';
6
6
  export { attachToCdp, attachToPlaywright, corsHeadersFor, corsDecision, withCorsHeaders } from './cdp.js';
7
7
  export { CheckoutAttachmentError } from './attachment.js';
8
+ // EBANX after its card token: why a send an approved token request covers got no answer from the cardholder's device.
9
+ export { EbanxFollowUpError } from './ebanx.js';
8
10
  export { CardEndpointRefusedError, cardEndpointPatterns } from './card-endpoint.js';
9
11
  // The merchant-session probe's capture (the deterministic merchant total, phase 0): no card, no Pay.
10
12
  export { MerchantSessionRefusedError, captureMerchantSession, merchantSessionCapture, merchantSessionReadUrl } from './merchant-session-probe.js';
@@ -5,6 +5,7 @@ import type { Substitutions } from './substitute.js';
5
5
  import type { GmoUnsupportedReason } from './gmo.js';
6
6
  import type { ShijiStsUnsupportedReason } from './shiji-sts.js';
7
7
  import type { PaddleVgsPayRefusal } from './paddle-vgs-pay.js';
8
+ import type { PaypalCardFormReason } from './paypal-card-forms.js';
8
9
  /** The application's resolver confirmed the payment for this checkout authorization. */
9
10
  export interface MerchantPaymentConfirmation {
10
11
  kind: 'merchant_payment';
@@ -158,6 +159,11 @@ export declare class CheckoutLifecycle implements CheckoutController {
158
159
  private ownedShopOrderId;
159
160
  private readonly handoffs;
160
161
  private reconciliation;
162
+ /**
163
+ * EBANX sends this attachment claimed that are still out (pre-claim.ts ebanxFollowUp): the cardholder's device may be
164
+ * sending a confirm that pays, outside `active`, so reconcile() and retryAfterMerchantFailure() wait for them too.
165
+ */
166
+ private followUpsOut;
161
167
  private preparationHandler?;
162
168
  private preparationUsed;
163
169
  private resumeHandler;
@@ -174,6 +180,21 @@ export declare class CheckoutLifecycle implements CheckoutController {
174
180
  prepared(preparation: PreparedCheckout): void;
175
181
  preparationFailed(error: CheckoutPreparationError): void;
176
182
  isBlocked(): boolean;
183
+ /**
184
+ * An EBANX send left for the cardholder's device under this attachment's approval (pre-claim.ts ebanxFollowUp). Until
185
+ * the returned function runs, once the send's answer reached the page or the send failed, reconcile() and
186
+ * retryAfterMerchantFailure() throw, as they do while a card request is active: a confirm may still pay. The returned
187
+ * function settles the send once, however often it runs.
188
+ */
189
+ followUpStarted(): () => void;
190
+ /** Whether a reconcile() is still waiting on the application's merchant resolver; pre-claim.ts claims no EBANX send then. */
191
+ isReconciling(): boolean;
192
+ /**
193
+ * Whether an EBANX send this attachment claimed is still out (followUpStarted). Both adapters refuse a new card
194
+ * request meanwhile, as they do while an approval is outstanding: a confirm that may pay is never hidden behind
195
+ * another payment's state.
196
+ */
197
+ followUpsInFlight(): boolean;
177
198
  isCancelled(): boolean;
178
199
  /** Whether the application gave a merchant resolver, so reconcile() reads the merchant's own record. */
179
200
  hasMerchantResolver(): boolean;
@@ -242,15 +263,21 @@ export declare class CheckoutLifecycle implements CheckoutController {
242
263
  * shiji-sts.ts reasons), a post to a processor's own card page that only
243
264
  * the cardholder's device can fill (processor_card_page: NMI's), a card
244
265
  * sent to PayPal's legacy Hosted Fields confirm, which no Vault mode takes
245
- * over (unsupported_paypal_hosted_fields, paypal-hosted-fields.ts), or a card
266
+ * over (unsupported_paypal_hosted_fields, paypal-hosted-fields.ts), a card
267
+ * sent through PayPal's Card Fields with no recognizer to pay it, or through
268
+ * PayPal's guest card form (unsupported_paypal_card_fields and
269
+ * unsupported_paypal_guest_checkout, paypal-card-forms.ts), or a card
246
270
  * a merchant's page posts to CyberSource Secure Acceptance's Silent Order
247
271
  * POST, which no Vault mode takes over either
248
- * (unsupported_cybersource_secure_acceptance, cybersource-secure-acceptance.ts), or a
272
+ * (unsupported_cybersource_secure_acceptance, cybersource-secure-acceptance.ts), a
249
273
  * Paddle /pay naming a stored card that its binding does not continue (the
250
- * paddle-vgs-pay.ts reasons): once an approval exists the state keeps it, and only the
251
- * hold changes.
274
+ * paddle-vgs-pay.ts reasons), or the typed card that EBANX's 3-D Secure calls or
275
+ * its hosted page's confirm send again after the token, when no approved token
276
+ * request on this attachment covers that send or the cardholder's device did not
277
+ * send it (unsupported_ebanx_card_resend, ebanx.ts): once an approval exists the
278
+ * state keeps it, and only the hold changes.
252
279
  */
253
- unsupported(reason?: 'unrecognized_payment_endpoint' | 'merchant_profile_observe' | 'merchant_request_unsupported' | GmoUnsupportedReason | 'microform_unsupported' | 'juspay_request_unsupported' | 'merchant_card_endpoint_not_enabled' | 'merchant_card_endpoint_resend_refused' | 'creditguard_three_d_secure' | 'unsupported_primer_sdk' | 'unsupported_primer_request' | PayrailsUnsupportedReason | ShijiStsUnsupportedReason | 'processor_card_page' | 'unsupported_paypal_hosted_fields' | 'unsupported_cybersource_secure_acceptance' | PaddleVgsPayRefusal): void;
280
+ unsupported(reason?: 'unrecognized_payment_endpoint' | 'merchant_profile_observe' | 'merchant_request_unsupported' | GmoUnsupportedReason | 'microform_unsupported' | 'juspay_request_unsupported' | 'merchant_card_endpoint_not_enabled' | 'merchant_card_endpoint_resend_refused' | 'creditguard_three_d_secure' | 'unsupported_primer_sdk' | 'unsupported_primer_request' | PayrailsUnsupportedReason | ShijiStsUnsupportedReason | 'processor_card_page' | 'unsupported_paypal_hosted_fields' | PaypalCardFormReason | 'unsupported_cybersource_secure_acceptance' | PaddleVgsPayRefusal | 'unsupported_ebanx_card_resend'): void;
254
281
  /**
255
282
  * A card request that only a prepared checkout pays (an Adyen merchant
256
283
  * profile's, or a Fiserv card capture) arrived with no preparation on this
package/dist/lifecycle.js CHANGED
@@ -64,6 +64,11 @@ export class CheckoutLifecycle {
64
64
  // Every request this attachment handed the card to: see cardHandoffs().
65
65
  handoffs = [];
66
66
  reconciliation = null;
67
+ /**
68
+ * EBANX sends this attachment claimed that are still out (pre-claim.ts ebanxFollowUp): the cardholder's device may be
69
+ * sending a confirm that pays, outside `active`, so reconcile() and retryAfterMerchantFailure() wait for them too.
70
+ */
71
+ followUpsOut = 0;
67
72
  preparationHandler;
68
73
  preparationUsed = false;
69
74
  resumeHandler = null;
@@ -104,6 +109,28 @@ export class CheckoutLifecycle {
104
109
  this.set({ ...this.state, status: error.reason === 'expired' ? 'timed_out' : error.reason === 'cancelled' ? 'cancelled' : 'failed', reason: error.reason });
105
110
  }
106
111
  isBlocked() { return this.held || this.cancelled; }
112
+ /**
113
+ * An EBANX send left for the cardholder's device under this attachment's approval (pre-claim.ts ebanxFollowUp). Until
114
+ * the returned function runs, once the send's answer reached the page or the send failed, reconcile() and
115
+ * retryAfterMerchantFailure() throw, as they do while a card request is active: a confirm may still pay. The returned
116
+ * function settles the send once, however often it runs.
117
+ */
118
+ followUpStarted() {
119
+ this.followUpsOut += 1;
120
+ let settled = false;
121
+ return () => { if (!settled) {
122
+ settled = true;
123
+ this.followUpsOut -= 1;
124
+ } };
125
+ }
126
+ /** Whether a reconcile() is still waiting on the application's merchant resolver; pre-claim.ts claims no EBANX send then. */
127
+ isReconciling() { return this.reconciliation !== null; }
128
+ /**
129
+ * Whether an EBANX send this attachment claimed is still out (followUpStarted). Both adapters refuse a new card
130
+ * request meanwhile, as they do while an approval is outstanding: a confirm that may pay is never hidden behind
131
+ * another payment's state.
132
+ */
133
+ followUpsInFlight() { return this.followUpsOut > 0; }
107
134
  isCancelled() { return this.cancelled; }
108
135
  /** Whether the application gave a merchant resolver, so reconcile() reads the merchant's own record. */
109
136
  hasMerchantResolver() { return typeof this.options.resolveMerchantResult === 'function'; }
@@ -235,13 +262,19 @@ export class CheckoutLifecycle {
235
262
  * shiji-sts.ts reasons), a post to a processor's own card page that only
236
263
  * the cardholder's device can fill (processor_card_page: NMI's), a card
237
264
  * sent to PayPal's legacy Hosted Fields confirm, which no Vault mode takes
238
- * over (unsupported_paypal_hosted_fields, paypal-hosted-fields.ts), or a card
265
+ * over (unsupported_paypal_hosted_fields, paypal-hosted-fields.ts), a card
266
+ * sent through PayPal's Card Fields with no recognizer to pay it, or through
267
+ * PayPal's guest card form (unsupported_paypal_card_fields and
268
+ * unsupported_paypal_guest_checkout, paypal-card-forms.ts), or a card
239
269
  * a merchant's page posts to CyberSource Secure Acceptance's Silent Order
240
270
  * POST, which no Vault mode takes over either
241
- * (unsupported_cybersource_secure_acceptance, cybersource-secure-acceptance.ts), or a
271
+ * (unsupported_cybersource_secure_acceptance, cybersource-secure-acceptance.ts), a
242
272
  * Paddle /pay naming a stored card that its binding does not continue (the
243
- * paddle-vgs-pay.ts reasons): once an approval exists the state keeps it, and only the
244
- * hold changes.
273
+ * paddle-vgs-pay.ts reasons), or the typed card that EBANX's 3-D Secure calls or
274
+ * its hosted page's confirm send again after the token, when no approved token
275
+ * request on this attachment covers that send or the cardholder's device did not
276
+ * send it (unsupported_ebanx_card_resend, ebanx.ts): once an approval exists the
277
+ * state keeps it, and only the hold changes.
245
278
  */
246
279
  unsupported(reason = 'unrecognized_payment_endpoint') {
247
280
  this.held = true;
@@ -467,6 +500,8 @@ export class CheckoutLifecycle {
467
500
  return Promise.resolve(this.getState());
468
501
  if (this.active)
469
502
  throw new Error('Wait for the paused request to finish before reconciling the merchant order.');
503
+ if (this.followUpsOut > 0)
504
+ throw new Error('Wait for the EBANX send in flight to finish before reconciling the merchant order.');
470
505
  this.reconciliation = this.resolve().finally(() => { this.reconciliation = null; });
471
506
  return this.reconciliation;
472
507
  }
@@ -520,7 +555,7 @@ export class CheckoutLifecycle {
520
555
  throw new Error('This shop payment already has a receipt; another payment is not permitted.');
521
556
  if (this.preparationUsed)
522
557
  throw new Error('Prepared checkouts are single use. Reconcile this attempt and create a new attachment.');
523
- if (this.active || this.reconciliation)
558
+ if (this.active || this.reconciliation || this.followUpsOut > 0)
524
559
  throw new Error('Cannot start another attempt while payment or reconciliation is in progress.');
525
560
  if (this.cancelled)
526
561
  throw new Error('This attachment was cancelled; attach again after reconciling the merchant order.');
@@ -0,0 +1,56 @@
1
+ /** The PSP id the API and the recognizer name this lane, re-exported so the client dispatches by it. */
2
+ export { PADDLE_TOKENEX_PSP } from './paddle-tokenex.generated.js';
3
+ /** The dark-launch capability a build declares when it fills a Paddle TokenEx /pay with the device's card. */
4
+ export declare const PADDLE_TOKENEX_CAPABILITY = "paddle_tokenex_pay";
5
+ /** A cse substitution as the API serves it (substitute.ts Substitutions): here the two ciphertexts only. */
6
+ interface PaddleTokenexServedSubstitution {
7
+ encoding: string;
8
+ at: string;
9
+ fields: Record<string, string>;
10
+ remove?: string[];
11
+ }
12
+ /**
13
+ * Whether an approved Paddle TokenEx authorization's served substitution is one this SDK can continue: JSON
14
+ * at the frame's tokenex_card holder, no sibling to remove, and exactly the two ciphertext fields, each a
15
+ * non-empty string and distinct from the other. substitutePaddleTokenex checks each against the pinned key
16
+ * for the /pay's environment; this is the shape gate the client runs before it acts.
17
+ */
18
+ export declare function isPaddleTokenexServedSubstitution(sub: unknown): sub is PaddleTokenexServedSubstitution;
19
+ /** The five metadata facts the device read from the real card, served beside the ciphertexts. */
20
+ export interface PaddleTokenexServedFacts {
21
+ card_first_six: string;
22
+ card_last_four: string;
23
+ expiry_month: number;
24
+ expiry_year: number;
25
+ card_brand: string;
26
+ }
27
+ /**
28
+ * Whether the API's `paddle_tokenex_facts` beside an approved set is the five facts this SDK can write over
29
+ * the placeholder's: exactly the five keys, the three strings as strings and the two expiry parts as
30
+ * numbers. paddleTokenexSubstitutionOf checks the digits, range and network at the swap; this is the shape
31
+ * gate the client runs before it acts, so a malformed approval is refused before anything is written.
32
+ */
33
+ export declare function isPaddleTokenexServedFacts(value: unknown): value is PaddleTokenexServedFacts;
34
+ /** The paused request an approval was created from: the URL and body the API reviewed at create. */
35
+ export interface PaddleTokenexApprovedRequest {
36
+ url: string;
37
+ body: string;
38
+ }
39
+ /**
40
+ * The continuation of an approved Paddle TokenEx /pay: the paused body with the device's two ciphertexts
41
+ * written over the placeholder's at tokenex_card and the five facts over the placeholder's at metadata
42
+ * (payment-core substitutePaddleTokenex, which refuses a ciphertext that is not one under the pinned key
43
+ * for the /pay's environment, or one already in the paused body).
44
+ *
45
+ * Only into `approved`, the paused /pay the approval was created from: `url` and `body` must equal it byte
46
+ * for byte. The account-level TokenEx key is the same for every checkout of that seller, so the device's
47
+ * ciphertext could be decrypted in any later /pay of the same shape; binding it to the one request keeps
48
+ * this lane from ever submitting one checkout's ciphertext to another.
49
+ *
50
+ * Null when neither URL is a TokenEx /pay, so every other processor keeps the generic swap. Throws for any
51
+ * other body or URL, and for a substitution or facts the shape gates refuse, in each case before anything
52
+ * continues.
53
+ */
54
+ export declare function paddleTokenexTokenContinuation(url: string, body: string, sub: unknown, facts: unknown, approved: PaddleTokenexApprovedRequest): {
55
+ body: string;
56
+ } | null;
@@ -0,0 +1,67 @@
1
+ declare function paddleVgsCardFactsAgree(facts: any, stored: any): boolean;
2
+ declare var PADDLE_TOKENEX_PSP: string;
3
+ declare var PADDLE_TOKENEX_CAPABILITY: string;
4
+ declare var PADDLE_TOKENEX_OPERATION: string;
5
+ declare var PADDLE_TOKENEX_SCHEME: string;
6
+ declare var PADDLE_TOKENEX_FIELDS: readonly string[];
7
+ declare var PADDLE_TOKENEX_FACT_KEYS: readonly string[];
8
+ declare var PADDLE_TOKENEX_CARD_NETWORKS: readonly string[];
9
+ declare var PADDLE_TOKENEX_REFUSAL_CODES: readonly string[];
10
+ declare function paddleTokenexPayTarget(url: any): Readonly<{
11
+ environment: "production" | "sandbox";
12
+ line: "classic" | "billing";
13
+ }> | null;
14
+ declare function paddleTokenexPayCarriesCard(body: any): boolean;
15
+ declare function isPaddleTokenexCiphertextUnderKey(value: any, environment: any): boolean;
16
+ declare function isPaddleTokenexCiphertext(value: any, environment: any): boolean;
17
+ declare function paddleTokenexRequestRefusal(request: any, environment: any): "paddle_tokenex_pay_unsupported" | null;
18
+ declare function isPaddleTokenexCardRequest(request: any): boolean;
19
+ declare function paddleTokenexBodyVerdict(body: any, line: any): Readonly<{
20
+ verdict: "continue";
21
+ }> | Readonly<{
22
+ verdict: "card";
23
+ }> | Readonly<{
24
+ verdict: "refuse";
25
+ code: any;
26
+ }>;
27
+ declare function paddleTokenexRefusalMessage(code: any): any;
28
+ declare function paddleTokenexStoredCardRefusal(brand: any): "paddle_tokenex_card_unsupported" | null;
29
+ declare function encryptPaddleTokenexCard(card: any, environment: any, facilities?: {}): Readonly<{
30
+ card_first_six: string;
31
+ card_last_four: string;
32
+ expiry_month: number;
33
+ expiry_year: number;
34
+ card_brand: "visa" | "master" | "american_express";
35
+ encrypted_card_number: string;
36
+ encrypted_cvv: string;
37
+ }>;
38
+ declare function paddleTokenexSubstitutionOf(value: any, environment: any): Readonly<{
39
+ card_first_six: any;
40
+ card_last_four: string;
41
+ expiry_month: any;
42
+ expiry_year: any;
43
+ card_brand: any;
44
+ encrypted_card_number: any;
45
+ encrypted_cvv: any;
46
+ }> | null;
47
+ declare function substitutePaddleTokenex(url: any, body: any, substitution: any): string;
48
+ declare function paddleTokenexKeyUsable(authorization: any): boolean;
49
+ declare function paddleTokenexSubstitutionsRefusal(template: any, substitution: any): {
50
+ code: string;
51
+ message: any;
52
+ } | null;
53
+ declare function paddleTokenexRefusalCode(text: any): string | null;
54
+ declare function paddleTokenexAnswerOutcome(status: any, text: any): {
55
+ outcome: string;
56
+ reason: string;
57
+ code?: undefined;
58
+ } | {
59
+ outcome: string;
60
+ code: string;
61
+ reason?: undefined;
62
+ } | {
63
+ outcome: string;
64
+ reason?: undefined;
65
+ code?: undefined;
66
+ };
67
+ export { PADDLE_TOKENEX_CAPABILITY, PADDLE_TOKENEX_CARD_NETWORKS, PADDLE_TOKENEX_FACT_KEYS, PADDLE_TOKENEX_FIELDS, PADDLE_TOKENEX_OPERATION, PADDLE_TOKENEX_PSP, PADDLE_TOKENEX_REFUSAL_CODES, PADDLE_TOKENEX_SCHEME, encryptPaddleTokenexCard, isPaddleTokenexCardRequest, isPaddleTokenexCiphertext, isPaddleTokenexCiphertextUnderKey, paddleTokenexAnswerOutcome, paddleTokenexBodyVerdict, paddleVgsCardFactsAgree as paddleTokenexCardFactsAgree, paddleTokenexKeyUsable, paddleTokenexPayCarriesCard, paddleTokenexPayTarget, paddleTokenexRefusalCode, paddleTokenexRefusalMessage, paddleTokenexRequestRefusal, paddleTokenexStoredCardRefusal, paddleTokenexSubstitutionOf, paddleTokenexSubstitutionsRefusal, substitutePaddleTokenex };