@flopay/js 1.2.7 → 1.3.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/README.md +45 -2
- package/dist/index.cjs +559 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +227 -3
- package/dist/index.d.ts +227 -3
- package/dist/index.mjs +554 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _flopay_shared from '@flopay/shared';
|
|
2
|
-
import { PaymentProviderAdapter, ElementOptions, ElementType, MountedElement, FloPayError, FloPayConfig, CreatePaymentMethodResult, ConfirmCardPaymentParams, ConfirmCardPaymentResult, ConfirmPaymentParams, PaymentResult, CheckoutSession, NormalizedCheckoutSession, BillingDetails, CheckoutGateways, ProcessPaymentParams, InlineSessionDraft, CreateSessionParams, CheckoutSessionResult } from '@flopay/shared';
|
|
2
|
+
import { PaymentProviderAdapter, ElementOptions, ElementType, MountedElement, FloPayError, FloPayConfig, CreatePaymentMethodResult, ConfirmCardPaymentParams, ConfirmCardPaymentResult, CardCaptureAdapter, ConfirmPaymentParams, PaymentResult, CheckoutSession, NormalizedCheckoutSession, BillingDetails, CheckoutGateways, VaultCaptureBlock, ProcessPaymentParams, InlineSessionDraft, CardCaptureProviderId, CardCaptureMountOptions, CardCaptureEventType, CardCaptureOutcomeEvent, VaultCardThemeColors, VaultCardFieldKey, CreateSessionParams, CheckoutSessionResult } from '@flopay/shared';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Manages the creation and lifecycle of payment elements.
|
|
@@ -58,6 +58,22 @@ declare class FloPay {
|
|
|
58
58
|
createPaymentMethod(billingDetails?: _flopay_shared.BillingDetails): Promise<CreatePaymentMethodResult>;
|
|
59
59
|
/** Confirm a card payment with a known client secret and payment method ID. */
|
|
60
60
|
confirmCardPayment(params: ConfirmCardPaymentParams): Promise<ConfirmCardPaymentResult>;
|
|
61
|
+
/**
|
|
62
|
+
* Create a {@link CardCaptureAdapter} for collecting card details through the
|
|
63
|
+
* backend-rendered hosted vault PCI widget instead of provider-owned (Stripe)
|
|
64
|
+
* card fields (TeamFloPay/backend#823).
|
|
65
|
+
*
|
|
66
|
+
* The returned adapter injects the server-supplied widget HTML (the session's
|
|
67
|
+
* {@link CheckoutSession.vault} block, or one fetched via
|
|
68
|
+
* `PaymentAPI.getVaultCapture`) and relays the widget's terminal outcome. The
|
|
69
|
+
* backend owns tokenization, the PaymentIntent, 3DS, and fulfilment — no
|
|
70
|
+
* Stripe.js is involved on the card path and PCI-sensitive fields never enter
|
|
71
|
+
* the SDK runtime.
|
|
72
|
+
*/
|
|
73
|
+
cardCapture(options?: {
|
|
74
|
+
/** Checkout session id to bind the capture to (outcome correlation). */
|
|
75
|
+
sessionId?: string;
|
|
76
|
+
}): CardCaptureAdapter;
|
|
61
77
|
/** Confirm a PayPal payment: create intent via billing API → confirm → redirect if needed. */
|
|
62
78
|
confirmPayPalPayment(params: {
|
|
63
79
|
billingApiUrl: string;
|
|
@@ -254,6 +270,12 @@ interface RawCheckoutSession {
|
|
|
254
270
|
totalAmount?: number;
|
|
255
271
|
checkoutMode?: 'full' | 'auto' | 'confirm';
|
|
256
272
|
gateways?: CheckoutGateways;
|
|
273
|
+
/**
|
|
274
|
+
* Generic downstream card-method id for a card already on file
|
|
275
|
+
* (TeamFloPay/backend#823) — present for returning customers so the SDK can
|
|
276
|
+
* skip the vault widget. Absent for first-time buyers.
|
|
277
|
+
*/
|
|
278
|
+
providerPaymentMethodId?: string | null;
|
|
257
279
|
accountData: {
|
|
258
280
|
userId: string;
|
|
259
281
|
firstName: string;
|
|
@@ -320,6 +342,31 @@ declare class PaymentAPI {
|
|
|
320
342
|
* completes; otherwise the TTL handles cleanup.
|
|
321
343
|
*/
|
|
322
344
|
clearSessionDisplayData(sessionId: string): void;
|
|
345
|
+
/**
|
|
346
|
+
* Fetch (re-mint) the hosted vault capture widget for a session
|
|
347
|
+
* (TeamFloPay/backend#823).
|
|
348
|
+
*
|
|
349
|
+
* `POST /v1/checkouts/sessions/{id}/vault/capture` returns the SDK-ready
|
|
350
|
+
* {@link VaultCaptureBlock} (`html` + `url`, plus `messageToken` /
|
|
351
|
+
* `expectedOrigin` once the backend mints them). The SDK injects `html` as
|
|
352
|
+
* the card-capture widget. This is the fallback path for sessions that did
|
|
353
|
+
* not receive the embedded `vault` block on create (e.g. a session loaded by
|
|
354
|
+
* id via `GET`, or a pre-1.3.0 create); the endpoint is idempotent and reuses
|
|
355
|
+
* session-cached creds when available.
|
|
356
|
+
*
|
|
357
|
+
* Because the endpoint is idempotent, the request is wrapped in
|
|
358
|
+
* `fetchWithNetworkRetry`: a transient network blip (dropped connection, DNS
|
|
359
|
+
* hiccup, failed CORS preflight) would otherwise leave the secure card form
|
|
360
|
+
* unable to load and hard-block checkout.
|
|
361
|
+
*
|
|
362
|
+
* The PCIVault submit *secret* the backend may include in the response is
|
|
363
|
+
* intentionally **not** read or surfaced — it is server-only and never enters
|
|
364
|
+
* the SDK runtime.
|
|
365
|
+
*
|
|
366
|
+
* `nonce` is forwarded as `x-checkout-session-token` (required by post-#640
|
|
367
|
+
* backends, matched against the session's stored nonce).
|
|
368
|
+
*/
|
|
369
|
+
getVaultCapture(checkoutSessionId: string, nonce?: string): Promise<VaultCaptureBlock>;
|
|
323
370
|
/**
|
|
324
371
|
* Fetch and normalize a checkout session.
|
|
325
372
|
*
|
|
@@ -348,6 +395,44 @@ declare class PaymentAPI {
|
|
|
348
395
|
processPayment(_userId: string, data: ProcessPaymentParams, options?: {
|
|
349
396
|
pollTimeoutMs?: number;
|
|
350
397
|
}): Promise<Response>;
|
|
398
|
+
/**
|
|
399
|
+
* Patch the buyer's account snapshot (email, name, billing address, AVS
|
|
400
|
+
* intent) onto a checkout session via
|
|
401
|
+
* `PATCH /v1/checkouts/sessions/{id}/account` (TeamFloPay/backend#823).
|
|
402
|
+
*
|
|
403
|
+
* The vault path's hosted form owns the charge end-to-end so the SDK
|
|
404
|
+
* never calls `/process` on this path; the buyer-typed AVS / billing
|
|
405
|
+
* address would otherwise be lost. The SDK calls this just before
|
|
406
|
+
* submitting the vault widget so the downstream listener mints the
|
|
407
|
+
* Stripe PaymentMethod with the right `billing_details.address` and the
|
|
408
|
+
* per-attempt + per-PM address snapshots are populated.
|
|
409
|
+
*
|
|
410
|
+
* Body shape mirrors the relevant subset of `/process`'s
|
|
411
|
+
* `ProcessCheckoutBodyDto` — same keys, same validators. The endpoint
|
|
412
|
+
* is idempotent: empty/undefined fields are not written, addresses are
|
|
413
|
+
* last-writer-wins, AVS analytics are first-writer-wins.
|
|
414
|
+
*
|
|
415
|
+
* Wrapped in `fetchWithNetworkRetry` because a transient blip on this
|
|
416
|
+
* pre-pay PATCH would silently leave AVS unsent and cause an
|
|
417
|
+
* AVS-protected charge to decline downstream.
|
|
418
|
+
*/
|
|
419
|
+
patchAccountSnapshot(sessionId: string, nonce: string, body: {
|
|
420
|
+
accountData: {
|
|
421
|
+
userId: string;
|
|
422
|
+
email: string;
|
|
423
|
+
firstName?: string | null;
|
|
424
|
+
lastName?: string | null;
|
|
425
|
+
addressLine1?: string | null;
|
|
426
|
+
addressLine2?: string | null;
|
|
427
|
+
city?: string | null;
|
|
428
|
+
state?: string | null;
|
|
429
|
+
zip?: string | null;
|
|
430
|
+
country?: string | null;
|
|
431
|
+
gender?: string | null;
|
|
432
|
+
};
|
|
433
|
+
avsCheck?: boolean;
|
|
434
|
+
avsConfig?: Record<string, unknown>;
|
|
435
|
+
}): Promise<void>;
|
|
351
436
|
/**
|
|
352
437
|
* Create a PaymentIntent on the backend.
|
|
353
438
|
*
|
|
@@ -358,8 +443,15 @@ declare class PaymentAPI {
|
|
|
358
443
|
* session-bound checkout token returned by session creation. Post-#640
|
|
359
444
|
* backends reject this call with a 401 when the header is missing or does
|
|
360
445
|
* not match the session's stored nonce.
|
|
446
|
+
*
|
|
447
|
+
* `paymentMethodType` is optional for the vault card-capture flow
|
|
448
|
+
* (TeamFloPay/backend#823): the frontend starts checkout *without* an upfront
|
|
449
|
+
* card payment method, so it may be omitted (or `null`). The hosted vault PCI
|
|
450
|
+
* form captures the card afterwards and the backend attaches the resulting
|
|
451
|
+
* payment method to the PaymentIntent it returns here. Legacy callers keep
|
|
452
|
+
* passing the concrete payment method id / type.
|
|
361
453
|
*/
|
|
362
|
-
createPaymentIntent(sessionId: string, email: string, paymentMethodType
|
|
454
|
+
createPaymentIntent(sessionId: string, email: string, paymentMethodType?: string | null, options?: {
|
|
363
455
|
signal?: AbortSignal;
|
|
364
456
|
isPaypal?: string;
|
|
365
457
|
nonce?: string;
|
|
@@ -411,6 +503,12 @@ declare class PaymentAPI {
|
|
|
411
503
|
private normalizeRawSession;
|
|
412
504
|
/** Convert raw session to the SDK CheckoutSession shape. */
|
|
413
505
|
private toCheckoutSession;
|
|
506
|
+
/**
|
|
507
|
+
* Coerce a raw vault block into a typed {@link VaultCaptureBlock}. The
|
|
508
|
+
* server-only PCIVault submit `secret` is deliberately dropped so it never
|
|
509
|
+
* lands on the public session surface (logs / telemetry / client inspection).
|
|
510
|
+
*/
|
|
511
|
+
private toVaultBlock;
|
|
414
512
|
private toCheckoutSessionStatus;
|
|
415
513
|
private resolveProcessResponse;
|
|
416
514
|
private toCheckoutProcessingPending;
|
|
@@ -432,6 +530,132 @@ declare class PaymentAPI {
|
|
|
432
530
|
private mergeCachedDisplayData;
|
|
433
531
|
}
|
|
434
532
|
|
|
533
|
+
/** Configuration for a {@link PciVaultCardCapture} instance. */
|
|
534
|
+
interface PciVaultCardCaptureConfig {
|
|
535
|
+
/** Checkout session id bound to the capture (for outcome correlation + trust). */
|
|
536
|
+
sessionId?: string;
|
|
537
|
+
/**
|
|
538
|
+
* Default strict origin for vault `postMessage` outcomes. Overridden by
|
|
539
|
+
* {@link CardCaptureMountOptions.expectedOrigin} when that is supplied at
|
|
540
|
+
* mount. When neither is set the origin gate is skipped (the widget posts
|
|
541
|
+
* same-window in the Model-A flow).
|
|
542
|
+
*/
|
|
543
|
+
expectedOrigin?: string;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* {@link CardCaptureAdapter} backed by the backend-rendered PCIVault hosted
|
|
547
|
+
* widget.
|
|
548
|
+
*
|
|
549
|
+
* `mount()` injects the server-supplied widget HTML (re-executing its bundled
|
|
550
|
+
* `<script>` so the form bootstraps) and subscribes to the widget's
|
|
551
|
+
* `postMessage` outcome. The backend owns everything else; this adapter never
|
|
552
|
+
* touches the card data, a payment intent, or 3DS.
|
|
553
|
+
*/
|
|
554
|
+
declare class PciVaultCardCapture implements CardCaptureAdapter {
|
|
555
|
+
readonly provider: CardCaptureProviderId;
|
|
556
|
+
private readonly config;
|
|
557
|
+
private container;
|
|
558
|
+
private messageHandler;
|
|
559
|
+
/**
|
|
560
|
+
* Parent-page-level overlay rendering the provider's verification challenge
|
|
561
|
+
* (3DS-2 iframe) on `action_required`. Owned by the adapter — not the
|
|
562
|
+
* widget — so it can sit above the host SDK's processing backdrop, which
|
|
563
|
+
* would otherwise visually cover an in-widget challenge iframe.
|
|
564
|
+
*/
|
|
565
|
+
private actionOverlay;
|
|
566
|
+
/**
|
|
567
|
+
* Listener that catches the `flopay-vault-3ds-return` postMessage from the
|
|
568
|
+
* provider's challenge return page. When the SDK owns the challenge iframe
|
|
569
|
+
* the return page lives inside *that* iframe (not the widget's), so
|
|
570
|
+
* `window.parent` is the host page — the widget's existing message
|
|
571
|
+
* listener can't see it. The SDK forwards completion into the widget via
|
|
572
|
+
* `action_completed` so the widget kicks `/3ds/complete` immediately
|
|
573
|
+
* instead of waiting on the eventual provider webhook.
|
|
574
|
+
*/
|
|
575
|
+
private threeDsReturnHandler;
|
|
576
|
+
/** Per-session integrity token to require on outcomes (from mount options). */
|
|
577
|
+
private messageToken;
|
|
578
|
+
/** Strict origin to require on outcomes, when configured. */
|
|
579
|
+
private expectedOrigin;
|
|
580
|
+
/** Latest merchant theme to push into the (cross-origin) widget. */
|
|
581
|
+
private theme;
|
|
582
|
+
/** Latest host submit-gate state to push into the widget (block its submit). */
|
|
583
|
+
private submitGateBlocked;
|
|
584
|
+
/** Latest card-field order + autofocus directive to push into the widget. */
|
|
585
|
+
private cardFieldOrder;
|
|
586
|
+
private cardAutoFocus;
|
|
587
|
+
private readonly listeners;
|
|
588
|
+
constructor(config?: PciVaultCardCaptureConfig);
|
|
589
|
+
mount(container: HTMLElement, options: CardCaptureMountOptions): Promise<void>;
|
|
590
|
+
on(event: CardCaptureEventType, handler: (event: CardCaptureOutcomeEvent) => void): () => void;
|
|
591
|
+
unmount(): void;
|
|
592
|
+
/**
|
|
593
|
+
* Inject the server-rendered widget HTML. `innerHTML` does not execute
|
|
594
|
+
* embedded `<script>` tags, so each script node is replaced with a freshly
|
|
595
|
+
* created element that the browser will load and run (this is what boots the
|
|
596
|
+
* PCIVault form bundle against the `data-flopay-config` container).
|
|
597
|
+
*/
|
|
598
|
+
private injectWidget;
|
|
599
|
+
private attachMessageListener;
|
|
600
|
+
/**
|
|
601
|
+
* Push merchant theme colors into the hosted widget (live). The host calls
|
|
602
|
+
* this on a runtime theme switch; the widget applies them to its CSS variables
|
|
603
|
+
* without a remount. Stores the latest theme so `ready` can re-push it.
|
|
604
|
+
*/
|
|
605
|
+
applyTheme(theme: VaultCardThemeColors): void;
|
|
606
|
+
/** postMessage the current theme to the widget's (cross-origin) document. */
|
|
607
|
+
private postTheme;
|
|
608
|
+
/**
|
|
609
|
+
* Gate the widget's submit from the host. When `blocked`, the widget cancels
|
|
610
|
+
* its next submit and emits `'blocked'` instead of `'submitting'` so the host
|
|
611
|
+
* can validate merchant-DOM fields (AVS) first. Stored so `ready` re-pushes it.
|
|
612
|
+
*/
|
|
613
|
+
setSubmitGate(blocked: boolean): void;
|
|
614
|
+
/** postMessage the current submit-gate state to the widget's document. */
|
|
615
|
+
private postSubmitGate;
|
|
616
|
+
/**
|
|
617
|
+
* Push the card-field order + autofocus directive into the widget (live). The
|
|
618
|
+
* widget re-sequences its rows (DOM order, so tab order follows) and focuses
|
|
619
|
+
* its first field unless `autoFocus` is false. Stored so `ready` re-pushes it.
|
|
620
|
+
*/
|
|
621
|
+
setCardFieldOrder(order: VaultCardFieldKey[] | null, autoFocus: boolean): void;
|
|
622
|
+
/** postMessage the current field order + autofocus to the widget's document. */
|
|
623
|
+
private postCardFieldOrder;
|
|
624
|
+
private emit;
|
|
625
|
+
/**
|
|
626
|
+
* Render the provider-hosted verification challenge (e.g. Stripe 3DS-2) in a
|
|
627
|
+
* full-page overlay at the PARENT page level. The widget's inline-iframe
|
|
628
|
+
* approach is unusable because the SDK's processing backdrop sits above the
|
|
629
|
+
* vault iframe, hiding any challenge mounted inside it — by lifting the
|
|
630
|
+
* iframe to the host page the adapter can give it a z-index that wins.
|
|
631
|
+
*
|
|
632
|
+
* The overlay tears down on the next terminal outcome
|
|
633
|
+
* (`complete`/`decline`/`error`) or when the buyer closes it via the backdrop
|
|
634
|
+
* close button. Closing manually is a soft abandon — the next `/status` poll
|
|
635
|
+
* either reveals a real outcome (the challenge completed via the issuer's
|
|
636
|
+
* own redirect to `/vault/3ds/return`, which posts back into the widget) or
|
|
637
|
+
* surfaces `requires_action` again so the host can decide what to do.
|
|
638
|
+
*/
|
|
639
|
+
private showActionRequiredOverlay;
|
|
640
|
+
/**
|
|
641
|
+
* Tell the vault widget that the buyer has completed (or abandoned) the
|
|
642
|
+
* challenge. The widget responds by POSTing `/3ds/complete` — its
|
|
643
|
+
* sub-300ms sync resolver writes the follow-up attempt row immediately,
|
|
644
|
+
* so the next `/status` poll resolves to a terminal outcome instead of
|
|
645
|
+
* waiting for the eventual provider webhook.
|
|
646
|
+
*/
|
|
647
|
+
private postActionCompleted;
|
|
648
|
+
private hideActionRequiredOverlay;
|
|
649
|
+
/**
|
|
650
|
+
* Size the hosted-widget iframe to the height reported by the form inside it.
|
|
651
|
+
* Cross-origin iframes don't auto-size to their content, so the widget posts
|
|
652
|
+
* its measured height and we apply it here (clamped to a sane range). This is
|
|
653
|
+
* what lets the card form shrink/grow to fit instead of sitting at a fixed
|
|
654
|
+
* height.
|
|
655
|
+
*/
|
|
656
|
+
private applyHeight;
|
|
657
|
+
}
|
|
658
|
+
|
|
435
659
|
/**
|
|
436
660
|
* Creates a checkout session via the billing API and redirects the user
|
|
437
661
|
* to the hosted checkout page.
|
|
@@ -473,4 +697,4 @@ declare function createCheckoutSessionWithRetries(options: CreateSessionParams &
|
|
|
473
697
|
maxRetries?: number;
|
|
474
698
|
}): Promise<CheckoutSessionResult>;
|
|
475
699
|
|
|
476
|
-
export { FloPay, FloPayElements, PaymentAPI, type SessionDisplayCacheData, type SessionDisplayProduct, StripeAdapter, cacheSessionDisplayData, clearSessionDisplayData, createCheckoutSession, createCheckoutSessionWithRetries, getSessionDisplayData, loadFloPay };
|
|
700
|
+
export { FloPay, FloPayElements, PaymentAPI, PciVaultCardCapture, type PciVaultCardCaptureConfig, type SessionDisplayCacheData, type SessionDisplayProduct, StripeAdapter, cacheSessionDisplayData, clearSessionDisplayData, createCheckoutSession, createCheckoutSessionWithRetries, getSessionDisplayData, loadFloPay };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _flopay_shared from '@flopay/shared';
|
|
2
|
-
import { PaymentProviderAdapter, ElementOptions, ElementType, MountedElement, FloPayError, FloPayConfig, CreatePaymentMethodResult, ConfirmCardPaymentParams, ConfirmCardPaymentResult, ConfirmPaymentParams, PaymentResult, CheckoutSession, NormalizedCheckoutSession, BillingDetails, CheckoutGateways, ProcessPaymentParams, InlineSessionDraft, CreateSessionParams, CheckoutSessionResult } from '@flopay/shared';
|
|
2
|
+
import { PaymentProviderAdapter, ElementOptions, ElementType, MountedElement, FloPayError, FloPayConfig, CreatePaymentMethodResult, ConfirmCardPaymentParams, ConfirmCardPaymentResult, CardCaptureAdapter, ConfirmPaymentParams, PaymentResult, CheckoutSession, NormalizedCheckoutSession, BillingDetails, CheckoutGateways, VaultCaptureBlock, ProcessPaymentParams, InlineSessionDraft, CardCaptureProviderId, CardCaptureMountOptions, CardCaptureEventType, CardCaptureOutcomeEvent, VaultCardThemeColors, VaultCardFieldKey, CreateSessionParams, CheckoutSessionResult } from '@flopay/shared';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Manages the creation and lifecycle of payment elements.
|
|
@@ -58,6 +58,22 @@ declare class FloPay {
|
|
|
58
58
|
createPaymentMethod(billingDetails?: _flopay_shared.BillingDetails): Promise<CreatePaymentMethodResult>;
|
|
59
59
|
/** Confirm a card payment with a known client secret and payment method ID. */
|
|
60
60
|
confirmCardPayment(params: ConfirmCardPaymentParams): Promise<ConfirmCardPaymentResult>;
|
|
61
|
+
/**
|
|
62
|
+
* Create a {@link CardCaptureAdapter} for collecting card details through the
|
|
63
|
+
* backend-rendered hosted vault PCI widget instead of provider-owned (Stripe)
|
|
64
|
+
* card fields (TeamFloPay/backend#823).
|
|
65
|
+
*
|
|
66
|
+
* The returned adapter injects the server-supplied widget HTML (the session's
|
|
67
|
+
* {@link CheckoutSession.vault} block, or one fetched via
|
|
68
|
+
* `PaymentAPI.getVaultCapture`) and relays the widget's terminal outcome. The
|
|
69
|
+
* backend owns tokenization, the PaymentIntent, 3DS, and fulfilment — no
|
|
70
|
+
* Stripe.js is involved on the card path and PCI-sensitive fields never enter
|
|
71
|
+
* the SDK runtime.
|
|
72
|
+
*/
|
|
73
|
+
cardCapture(options?: {
|
|
74
|
+
/** Checkout session id to bind the capture to (outcome correlation). */
|
|
75
|
+
sessionId?: string;
|
|
76
|
+
}): CardCaptureAdapter;
|
|
61
77
|
/** Confirm a PayPal payment: create intent via billing API → confirm → redirect if needed. */
|
|
62
78
|
confirmPayPalPayment(params: {
|
|
63
79
|
billingApiUrl: string;
|
|
@@ -254,6 +270,12 @@ interface RawCheckoutSession {
|
|
|
254
270
|
totalAmount?: number;
|
|
255
271
|
checkoutMode?: 'full' | 'auto' | 'confirm';
|
|
256
272
|
gateways?: CheckoutGateways;
|
|
273
|
+
/**
|
|
274
|
+
* Generic downstream card-method id for a card already on file
|
|
275
|
+
* (TeamFloPay/backend#823) — present for returning customers so the SDK can
|
|
276
|
+
* skip the vault widget. Absent for first-time buyers.
|
|
277
|
+
*/
|
|
278
|
+
providerPaymentMethodId?: string | null;
|
|
257
279
|
accountData: {
|
|
258
280
|
userId: string;
|
|
259
281
|
firstName: string;
|
|
@@ -320,6 +342,31 @@ declare class PaymentAPI {
|
|
|
320
342
|
* completes; otherwise the TTL handles cleanup.
|
|
321
343
|
*/
|
|
322
344
|
clearSessionDisplayData(sessionId: string): void;
|
|
345
|
+
/**
|
|
346
|
+
* Fetch (re-mint) the hosted vault capture widget for a session
|
|
347
|
+
* (TeamFloPay/backend#823).
|
|
348
|
+
*
|
|
349
|
+
* `POST /v1/checkouts/sessions/{id}/vault/capture` returns the SDK-ready
|
|
350
|
+
* {@link VaultCaptureBlock} (`html` + `url`, plus `messageToken` /
|
|
351
|
+
* `expectedOrigin` once the backend mints them). The SDK injects `html` as
|
|
352
|
+
* the card-capture widget. This is the fallback path for sessions that did
|
|
353
|
+
* not receive the embedded `vault` block on create (e.g. a session loaded by
|
|
354
|
+
* id via `GET`, or a pre-1.3.0 create); the endpoint is idempotent and reuses
|
|
355
|
+
* session-cached creds when available.
|
|
356
|
+
*
|
|
357
|
+
* Because the endpoint is idempotent, the request is wrapped in
|
|
358
|
+
* `fetchWithNetworkRetry`: a transient network blip (dropped connection, DNS
|
|
359
|
+
* hiccup, failed CORS preflight) would otherwise leave the secure card form
|
|
360
|
+
* unable to load and hard-block checkout.
|
|
361
|
+
*
|
|
362
|
+
* The PCIVault submit *secret* the backend may include in the response is
|
|
363
|
+
* intentionally **not** read or surfaced — it is server-only and never enters
|
|
364
|
+
* the SDK runtime.
|
|
365
|
+
*
|
|
366
|
+
* `nonce` is forwarded as `x-checkout-session-token` (required by post-#640
|
|
367
|
+
* backends, matched against the session's stored nonce).
|
|
368
|
+
*/
|
|
369
|
+
getVaultCapture(checkoutSessionId: string, nonce?: string): Promise<VaultCaptureBlock>;
|
|
323
370
|
/**
|
|
324
371
|
* Fetch and normalize a checkout session.
|
|
325
372
|
*
|
|
@@ -348,6 +395,44 @@ declare class PaymentAPI {
|
|
|
348
395
|
processPayment(_userId: string, data: ProcessPaymentParams, options?: {
|
|
349
396
|
pollTimeoutMs?: number;
|
|
350
397
|
}): Promise<Response>;
|
|
398
|
+
/**
|
|
399
|
+
* Patch the buyer's account snapshot (email, name, billing address, AVS
|
|
400
|
+
* intent) onto a checkout session via
|
|
401
|
+
* `PATCH /v1/checkouts/sessions/{id}/account` (TeamFloPay/backend#823).
|
|
402
|
+
*
|
|
403
|
+
* The vault path's hosted form owns the charge end-to-end so the SDK
|
|
404
|
+
* never calls `/process` on this path; the buyer-typed AVS / billing
|
|
405
|
+
* address would otherwise be lost. The SDK calls this just before
|
|
406
|
+
* submitting the vault widget so the downstream listener mints the
|
|
407
|
+
* Stripe PaymentMethod with the right `billing_details.address` and the
|
|
408
|
+
* per-attempt + per-PM address snapshots are populated.
|
|
409
|
+
*
|
|
410
|
+
* Body shape mirrors the relevant subset of `/process`'s
|
|
411
|
+
* `ProcessCheckoutBodyDto` — same keys, same validators. The endpoint
|
|
412
|
+
* is idempotent: empty/undefined fields are not written, addresses are
|
|
413
|
+
* last-writer-wins, AVS analytics are first-writer-wins.
|
|
414
|
+
*
|
|
415
|
+
* Wrapped in `fetchWithNetworkRetry` because a transient blip on this
|
|
416
|
+
* pre-pay PATCH would silently leave AVS unsent and cause an
|
|
417
|
+
* AVS-protected charge to decline downstream.
|
|
418
|
+
*/
|
|
419
|
+
patchAccountSnapshot(sessionId: string, nonce: string, body: {
|
|
420
|
+
accountData: {
|
|
421
|
+
userId: string;
|
|
422
|
+
email: string;
|
|
423
|
+
firstName?: string | null;
|
|
424
|
+
lastName?: string | null;
|
|
425
|
+
addressLine1?: string | null;
|
|
426
|
+
addressLine2?: string | null;
|
|
427
|
+
city?: string | null;
|
|
428
|
+
state?: string | null;
|
|
429
|
+
zip?: string | null;
|
|
430
|
+
country?: string | null;
|
|
431
|
+
gender?: string | null;
|
|
432
|
+
};
|
|
433
|
+
avsCheck?: boolean;
|
|
434
|
+
avsConfig?: Record<string, unknown>;
|
|
435
|
+
}): Promise<void>;
|
|
351
436
|
/**
|
|
352
437
|
* Create a PaymentIntent on the backend.
|
|
353
438
|
*
|
|
@@ -358,8 +443,15 @@ declare class PaymentAPI {
|
|
|
358
443
|
* session-bound checkout token returned by session creation. Post-#640
|
|
359
444
|
* backends reject this call with a 401 when the header is missing or does
|
|
360
445
|
* not match the session's stored nonce.
|
|
446
|
+
*
|
|
447
|
+
* `paymentMethodType` is optional for the vault card-capture flow
|
|
448
|
+
* (TeamFloPay/backend#823): the frontend starts checkout *without* an upfront
|
|
449
|
+
* card payment method, so it may be omitted (or `null`). The hosted vault PCI
|
|
450
|
+
* form captures the card afterwards and the backend attaches the resulting
|
|
451
|
+
* payment method to the PaymentIntent it returns here. Legacy callers keep
|
|
452
|
+
* passing the concrete payment method id / type.
|
|
361
453
|
*/
|
|
362
|
-
createPaymentIntent(sessionId: string, email: string, paymentMethodType
|
|
454
|
+
createPaymentIntent(sessionId: string, email: string, paymentMethodType?: string | null, options?: {
|
|
363
455
|
signal?: AbortSignal;
|
|
364
456
|
isPaypal?: string;
|
|
365
457
|
nonce?: string;
|
|
@@ -411,6 +503,12 @@ declare class PaymentAPI {
|
|
|
411
503
|
private normalizeRawSession;
|
|
412
504
|
/** Convert raw session to the SDK CheckoutSession shape. */
|
|
413
505
|
private toCheckoutSession;
|
|
506
|
+
/**
|
|
507
|
+
* Coerce a raw vault block into a typed {@link VaultCaptureBlock}. The
|
|
508
|
+
* server-only PCIVault submit `secret` is deliberately dropped so it never
|
|
509
|
+
* lands on the public session surface (logs / telemetry / client inspection).
|
|
510
|
+
*/
|
|
511
|
+
private toVaultBlock;
|
|
414
512
|
private toCheckoutSessionStatus;
|
|
415
513
|
private resolveProcessResponse;
|
|
416
514
|
private toCheckoutProcessingPending;
|
|
@@ -432,6 +530,132 @@ declare class PaymentAPI {
|
|
|
432
530
|
private mergeCachedDisplayData;
|
|
433
531
|
}
|
|
434
532
|
|
|
533
|
+
/** Configuration for a {@link PciVaultCardCapture} instance. */
|
|
534
|
+
interface PciVaultCardCaptureConfig {
|
|
535
|
+
/** Checkout session id bound to the capture (for outcome correlation + trust). */
|
|
536
|
+
sessionId?: string;
|
|
537
|
+
/**
|
|
538
|
+
* Default strict origin for vault `postMessage` outcomes. Overridden by
|
|
539
|
+
* {@link CardCaptureMountOptions.expectedOrigin} when that is supplied at
|
|
540
|
+
* mount. When neither is set the origin gate is skipped (the widget posts
|
|
541
|
+
* same-window in the Model-A flow).
|
|
542
|
+
*/
|
|
543
|
+
expectedOrigin?: string;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* {@link CardCaptureAdapter} backed by the backend-rendered PCIVault hosted
|
|
547
|
+
* widget.
|
|
548
|
+
*
|
|
549
|
+
* `mount()` injects the server-supplied widget HTML (re-executing its bundled
|
|
550
|
+
* `<script>` so the form bootstraps) and subscribes to the widget's
|
|
551
|
+
* `postMessage` outcome. The backend owns everything else; this adapter never
|
|
552
|
+
* touches the card data, a payment intent, or 3DS.
|
|
553
|
+
*/
|
|
554
|
+
declare class PciVaultCardCapture implements CardCaptureAdapter {
|
|
555
|
+
readonly provider: CardCaptureProviderId;
|
|
556
|
+
private readonly config;
|
|
557
|
+
private container;
|
|
558
|
+
private messageHandler;
|
|
559
|
+
/**
|
|
560
|
+
* Parent-page-level overlay rendering the provider's verification challenge
|
|
561
|
+
* (3DS-2 iframe) on `action_required`. Owned by the adapter — not the
|
|
562
|
+
* widget — so it can sit above the host SDK's processing backdrop, which
|
|
563
|
+
* would otherwise visually cover an in-widget challenge iframe.
|
|
564
|
+
*/
|
|
565
|
+
private actionOverlay;
|
|
566
|
+
/**
|
|
567
|
+
* Listener that catches the `flopay-vault-3ds-return` postMessage from the
|
|
568
|
+
* provider's challenge return page. When the SDK owns the challenge iframe
|
|
569
|
+
* the return page lives inside *that* iframe (not the widget's), so
|
|
570
|
+
* `window.parent` is the host page — the widget's existing message
|
|
571
|
+
* listener can't see it. The SDK forwards completion into the widget via
|
|
572
|
+
* `action_completed` so the widget kicks `/3ds/complete` immediately
|
|
573
|
+
* instead of waiting on the eventual provider webhook.
|
|
574
|
+
*/
|
|
575
|
+
private threeDsReturnHandler;
|
|
576
|
+
/** Per-session integrity token to require on outcomes (from mount options). */
|
|
577
|
+
private messageToken;
|
|
578
|
+
/** Strict origin to require on outcomes, when configured. */
|
|
579
|
+
private expectedOrigin;
|
|
580
|
+
/** Latest merchant theme to push into the (cross-origin) widget. */
|
|
581
|
+
private theme;
|
|
582
|
+
/** Latest host submit-gate state to push into the widget (block its submit). */
|
|
583
|
+
private submitGateBlocked;
|
|
584
|
+
/** Latest card-field order + autofocus directive to push into the widget. */
|
|
585
|
+
private cardFieldOrder;
|
|
586
|
+
private cardAutoFocus;
|
|
587
|
+
private readonly listeners;
|
|
588
|
+
constructor(config?: PciVaultCardCaptureConfig);
|
|
589
|
+
mount(container: HTMLElement, options: CardCaptureMountOptions): Promise<void>;
|
|
590
|
+
on(event: CardCaptureEventType, handler: (event: CardCaptureOutcomeEvent) => void): () => void;
|
|
591
|
+
unmount(): void;
|
|
592
|
+
/**
|
|
593
|
+
* Inject the server-rendered widget HTML. `innerHTML` does not execute
|
|
594
|
+
* embedded `<script>` tags, so each script node is replaced with a freshly
|
|
595
|
+
* created element that the browser will load and run (this is what boots the
|
|
596
|
+
* PCIVault form bundle against the `data-flopay-config` container).
|
|
597
|
+
*/
|
|
598
|
+
private injectWidget;
|
|
599
|
+
private attachMessageListener;
|
|
600
|
+
/**
|
|
601
|
+
* Push merchant theme colors into the hosted widget (live). The host calls
|
|
602
|
+
* this on a runtime theme switch; the widget applies them to its CSS variables
|
|
603
|
+
* without a remount. Stores the latest theme so `ready` can re-push it.
|
|
604
|
+
*/
|
|
605
|
+
applyTheme(theme: VaultCardThemeColors): void;
|
|
606
|
+
/** postMessage the current theme to the widget's (cross-origin) document. */
|
|
607
|
+
private postTheme;
|
|
608
|
+
/**
|
|
609
|
+
* Gate the widget's submit from the host. When `blocked`, the widget cancels
|
|
610
|
+
* its next submit and emits `'blocked'` instead of `'submitting'` so the host
|
|
611
|
+
* can validate merchant-DOM fields (AVS) first. Stored so `ready` re-pushes it.
|
|
612
|
+
*/
|
|
613
|
+
setSubmitGate(blocked: boolean): void;
|
|
614
|
+
/** postMessage the current submit-gate state to the widget's document. */
|
|
615
|
+
private postSubmitGate;
|
|
616
|
+
/**
|
|
617
|
+
* Push the card-field order + autofocus directive into the widget (live). The
|
|
618
|
+
* widget re-sequences its rows (DOM order, so tab order follows) and focuses
|
|
619
|
+
* its first field unless `autoFocus` is false. Stored so `ready` re-pushes it.
|
|
620
|
+
*/
|
|
621
|
+
setCardFieldOrder(order: VaultCardFieldKey[] | null, autoFocus: boolean): void;
|
|
622
|
+
/** postMessage the current field order + autofocus to the widget's document. */
|
|
623
|
+
private postCardFieldOrder;
|
|
624
|
+
private emit;
|
|
625
|
+
/**
|
|
626
|
+
* Render the provider-hosted verification challenge (e.g. Stripe 3DS-2) in a
|
|
627
|
+
* full-page overlay at the PARENT page level. The widget's inline-iframe
|
|
628
|
+
* approach is unusable because the SDK's processing backdrop sits above the
|
|
629
|
+
* vault iframe, hiding any challenge mounted inside it — by lifting the
|
|
630
|
+
* iframe to the host page the adapter can give it a z-index that wins.
|
|
631
|
+
*
|
|
632
|
+
* The overlay tears down on the next terminal outcome
|
|
633
|
+
* (`complete`/`decline`/`error`) or when the buyer closes it via the backdrop
|
|
634
|
+
* close button. Closing manually is a soft abandon — the next `/status` poll
|
|
635
|
+
* either reveals a real outcome (the challenge completed via the issuer's
|
|
636
|
+
* own redirect to `/vault/3ds/return`, which posts back into the widget) or
|
|
637
|
+
* surfaces `requires_action` again so the host can decide what to do.
|
|
638
|
+
*/
|
|
639
|
+
private showActionRequiredOverlay;
|
|
640
|
+
/**
|
|
641
|
+
* Tell the vault widget that the buyer has completed (or abandoned) the
|
|
642
|
+
* challenge. The widget responds by POSTing `/3ds/complete` — its
|
|
643
|
+
* sub-300ms sync resolver writes the follow-up attempt row immediately,
|
|
644
|
+
* so the next `/status` poll resolves to a terminal outcome instead of
|
|
645
|
+
* waiting for the eventual provider webhook.
|
|
646
|
+
*/
|
|
647
|
+
private postActionCompleted;
|
|
648
|
+
private hideActionRequiredOverlay;
|
|
649
|
+
/**
|
|
650
|
+
* Size the hosted-widget iframe to the height reported by the form inside it.
|
|
651
|
+
* Cross-origin iframes don't auto-size to their content, so the widget posts
|
|
652
|
+
* its measured height and we apply it here (clamped to a sane range). This is
|
|
653
|
+
* what lets the card form shrink/grow to fit instead of sitting at a fixed
|
|
654
|
+
* height.
|
|
655
|
+
*/
|
|
656
|
+
private applyHeight;
|
|
657
|
+
}
|
|
658
|
+
|
|
435
659
|
/**
|
|
436
660
|
* Creates a checkout session via the billing API and redirects the user
|
|
437
661
|
* to the hosted checkout page.
|
|
@@ -473,4 +697,4 @@ declare function createCheckoutSessionWithRetries(options: CreateSessionParams &
|
|
|
473
697
|
maxRetries?: number;
|
|
474
698
|
}): Promise<CheckoutSessionResult>;
|
|
475
699
|
|
|
476
|
-
export { FloPay, FloPayElements, PaymentAPI, type SessionDisplayCacheData, type SessionDisplayProduct, StripeAdapter, cacheSessionDisplayData, clearSessionDisplayData, createCheckoutSession, createCheckoutSessionWithRetries, getSessionDisplayData, loadFloPay };
|
|
700
|
+
export { FloPay, FloPayElements, PaymentAPI, PciVaultCardCapture, type PciVaultCardCaptureConfig, type SessionDisplayCacheData, type SessionDisplayProduct, StripeAdapter, cacheSessionDisplayData, clearSessionDisplayData, createCheckoutSession, createCheckoutSessionWithRetries, getSessionDisplayData, loadFloPay };
|