@flopay/js 1.4.23 → 1.5.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.
@@ -0,0 +1,589 @@
1
+ import { CheckoutSessionMode, CheckoutGateways, VaultCaptureBlock, NormalizedCheckoutSession, ProcessPaymentParams, CreateSessionIntentRequest, SessionIntent, SessionIntentDeclineRequest, InlineSessionDraft, DetachedCheckoutSession, CardCaptureAdapter, CardCaptureProviderId, CaptureMethod, CardCaptureMountOptions, CardCaptureEventType, CardCaptureOutcomeEvent, VaultCardThemeColors, VaultCardFieldKey } from '@flopay/shared';
2
+
3
+ /**
4
+ * Client-side cache for display-only checkout fields the backend no longer
5
+ * persists (`overrideAmount`, `totalAmount`, `providerItemName`,
6
+ * `providerPlanName`, per-line `currency`).
7
+ *
8
+ * The cache lives in `sessionStorage` so it survives the navigation from the
9
+ * page that creates the session to the checkout page that fetches it, but
10
+ * dies on tab close. An in-memory fallback keeps the SDK working in Node /
11
+ * SSR contexts where `sessionStorage` is unavailable.
12
+ *
13
+ * Values from the server response always win — cached values fill in only
14
+ * where the server returned `null` or `undefined`.
15
+ */
16
+ /** Display-only fields per product that can be cached and merged back later. */
17
+ interface SessionDisplayProduct {
18
+ /** Catalog code (match key). */
19
+ code?: string;
20
+ /** Whether this product is a one-time item or a recurring subscription. */
21
+ type?: 'item' | 'subscription';
22
+ /** Display-only name for the product. */
23
+ name?: string | null;
24
+ totalAmount?: number;
25
+ overrideAmount?: number | null;
26
+ currency?: string;
27
+ }
28
+ /** Display-only payload that can be stashed for later merge into a session response. */
29
+ interface SessionDisplayCacheData {
30
+ /** Session-level currency (falls into the response only when the server omits it). */
31
+ currency?: string;
32
+ products?: SessionDisplayProduct[];
33
+ }
34
+ /**
35
+ * Stash display-only data for a session. Called client-side right after the
36
+ * server returns a session ID, so the values survive the redirect to the
37
+ * checkout page.
38
+ */
39
+ declare function cacheSessionDisplayData(sessionId: string, data: SessionDisplayCacheData, options?: {
40
+ ttlMs?: number;
41
+ }): void;
42
+ /**
43
+ * Read previously-cached display data for a session, or `null` if nothing
44
+ * is cached (or the TTL has elapsed).
45
+ */
46
+ declare function getSessionDisplayData(sessionId: string): SessionDisplayCacheData | null;
47
+ /**
48
+ * Drop any cached display data for a session. Call from the success page
49
+ * after the payment completes; otherwise the TTL handles cleanup.
50
+ */
51
+ declare function clearSessionDisplayData(sessionId: string): void;
52
+
53
+ /** Raw billing API response wrapper. */
54
+ interface BillingResponse<T> {
55
+ data: T;
56
+ }
57
+ /** Raw checkout session from the billing API. */
58
+ interface RawCheckoutSession {
59
+ uuid: string;
60
+ nonce: string;
61
+ status: 'pending' | 'authorized' | 'completed' | 'expired';
62
+ successUrl: string;
63
+ cancelUrl: string;
64
+ /** Session-level currency. */
65
+ currency?: string;
66
+ createdAt?: string;
67
+ checkoutUrl?: string;
68
+ /** Unified products list returned by the billing API (post-#760). */
69
+ products?: Array<{
70
+ uuid: string;
71
+ checkoutSessionId: string;
72
+ /** 'item' or 'subscription'. */
73
+ type: 'item' | 'subscription';
74
+ code?: string;
75
+ name?: string | null;
76
+ description?: string | null;
77
+ quantity: number;
78
+ totalAmount?: number;
79
+ overrideAmount?: number | null;
80
+ currency?: string;
81
+ metadata?: Record<string, unknown> | null;
82
+ }>;
83
+ coupons?: string[];
84
+ /**
85
+ * Pre-discount total in cart-currency major units. Populated by billing
86
+ * API ≥ v1.1.2; absent on older backends.
87
+ */
88
+ subtotalAmount?: number;
89
+ /** Total reduction from applied coupons (cart-currency major units). */
90
+ discountAmount?: number;
91
+ /** Final charge amount after coupon discount (cart-currency major units). */
92
+ totalAmount?: number;
93
+ checkoutMode?: CheckoutSessionMode;
94
+ captureMethod?: 'automatic' | 'manual';
95
+ paymentId?: string;
96
+ authorizationExpiresAt?: string;
97
+ /** Backend authorization/capture lifecycle reason, normalized before exposure. */
98
+ failureReason?: string;
99
+ outcome?: string;
100
+ gateways?: CheckoutGateways;
101
+ /**
102
+ * Generic downstream card-method id for a card already on file
103
+ * (TeamFloPay/backend#823) — present for returning customers so the SDK can
104
+ * skip the vault widget. Absent for first-time buyers.
105
+ */
106
+ providerPaymentMethodId?: string | null;
107
+ accountData: {
108
+ userId: string;
109
+ firstName: string;
110
+ lastName: string;
111
+ email: string;
112
+ gender?: string | null;
113
+ city?: string | null;
114
+ state?: string | null;
115
+ country?: string | null;
116
+ zip?: string | null;
117
+ addressLine1?: string | null;
118
+ addressLine2?: string | null;
119
+ };
120
+ tagsData: {
121
+ googleContainerId?: string | null;
122
+ sessionId?: string | null;
123
+ testEventCode?: string | null;
124
+ };
125
+ }
126
+ type AccountSnapshotTelemetryMode = 'blocking' | 'best_effort';
127
+ interface PaymentAPIOptions {
128
+ /** Flo-owned privacy-safe telemetry is enabled by default; set false to opt out. */
129
+ telemetry?: boolean;
130
+ }
131
+ declare const SESSION_CREATE_TELEMETRY: unique symbol;
132
+ /**
133
+ * Client-side payment API service.
134
+ *
135
+ * Mirrors the `PaymentAPI` class from the checkout project's
136
+ * `src/service/api.ts`. All methods call the billing API endpoints
137
+ * that the checkout backend exposes.
138
+ */
139
+ declare class PaymentAPI {
140
+ private static readonly activeVaultCaptureRequests;
141
+ private readonly baseUrl;
142
+ private readonly directTelemetry?;
143
+ private readonly telemetryHooks?;
144
+ private directTelemetryCheckoutId?;
145
+ constructor(billingApiUrl: string, options?: PaymentAPIOptions);
146
+ /** Dispose the reporter owned by direct public usage. Internal hooks are never disposed here. */
147
+ destroy(): void;
148
+ private reportDirectFailure;
149
+ /**
150
+ * A hosted-vault snapshot timeout is an observed fallback, not a checkout
151
+ * failure: the widget charge is already proceeding with the session baseline.
152
+ * Every other snapshot failure and every default/direct timeout remains an
153
+ * alert-level technical error.
154
+ */
155
+ private reportAccountSnapshotFailure;
156
+ private telemetryTimestamp;
157
+ private beginDirectTelemetryCheckout;
158
+ private beginDirectTelemetryOperation;
159
+ private adoptDirectTelemetryCheckout;
160
+ /**
161
+ * Fetch a raw checkout session by ID.
162
+ *
163
+ * `nonce` is the session-bound checkout token returned when the session
164
+ * was created. When supplied it is sent as the `x-checkout-session-token`
165
+ * header that post-#640 backends match against `checkout_session.nonce`
166
+ * before returning the row — the UUID alone is no longer sufficient.
167
+ * Backends that don't yet enforce it ignore the extra header.
168
+ */
169
+ getCheckoutSession(checkoutSessionId: string, nonce?: string): Promise<BillingResponse<RawCheckoutSession>>;
170
+ /**
171
+ * Stash display-only data for a session so subsequent fetches can fill in
172
+ * fields the backend no longer persists (`overrideAmount`, `totalAmount`,
173
+ * `providerItemName`, `providerPlanName`).
174
+ *
175
+ * Backed by `sessionStorage` in the browser, with an in-memory fallback in
176
+ * Node/SSR contexts. Default TTL: 1 hour.
177
+ *
178
+ * Server-returned values always win — cached values fill in only where the
179
+ * server returned `null` / `undefined`.
180
+ *
181
+ * @example
182
+ * ```ts
183
+ * paymentAPI.cacheSessionDisplayData(sessionId, {
184
+ * currency: 'USD',
185
+ * items: [{ code: 'pro_plan', overrideAmount: 24.99, providerItemName: 'Pro' }],
186
+ * });
187
+ * ```
188
+ */
189
+ cacheSessionDisplayData(sessionId: string, data: SessionDisplayCacheData, options?: {
190
+ ttlMs?: number;
191
+ }): void;
192
+ /**
193
+ * Drop any cached display data for a session. Call after the payment
194
+ * completes; otherwise the TTL handles cleanup.
195
+ */
196
+ clearSessionDisplayData(sessionId: string): void;
197
+ /**
198
+ * Fetch (re-mint) the hosted vault capture widget for a session
199
+ * (TeamFloPay/backend#823).
200
+ *
201
+ * `POST /v1/checkouts/sessions/{id}/vault/capture` returns the SDK-ready
202
+ * {@link VaultCaptureBlock} (`html` + `url`, plus `messageToken` /
203
+ * `expectedOrigin` once the backend mints them). The SDK injects `html` as
204
+ * the card-capture widget. This is the lazy path for explicitly card-capable
205
+ * sessions that do not receive an embedded `vault` block; the endpoint is
206
+ * idempotent and reuses session-cached creds when available.
207
+ *
208
+ * Because the endpoint is idempotent, transient network failures receive a
209
+ * bounded retry and a stalled request aborts after ten seconds. Concurrent
210
+ * callers for the same base URL, session, and nonce share the active promise,
211
+ * preventing React renders/remounts from racing competing recovery POSTs.
212
+ *
213
+ * The PCIVault submit *secret* the backend may include in the response is
214
+ * intentionally **not** read or surfaced — it is server-only and never enters
215
+ * the SDK runtime.
216
+ *
217
+ * `nonce` is forwarded as `x-checkout-session-token` (required by post-#640
218
+ * backends, matched against the session's stored nonce).
219
+ */
220
+ getVaultCapture(checkoutSessionId: string, nonce?: string): Promise<VaultCaptureBlock>;
221
+ private requestVaultCapture;
222
+ /**
223
+ * Fetch and normalize a checkout session.
224
+ *
225
+ * Reads the backend's `gateways` map to enumerate provider-specific data,
226
+ * then wraps the session in a `NormalizedCheckoutSession` for provider-
227
+ * agnostic consumption.
228
+ */
229
+ getUnifiedCheckoutSession(checkoutSessionId: string, nonce?: string): Promise<NormalizedCheckoutSession>;
230
+ /**
231
+ * Submit a tokenized payment to the billing backend.
232
+ *
233
+ * The backend will either succeed, return `type: '3ds_required'`
234
+ * (with a `threeDSecureToken`), or return `type: 'paypal_redirect_required'`.
235
+ *
236
+ * Hits the session-scoped route `POST /v1/checkouts/sessions/:id/process`
237
+ * and forwards `data.nonce` as `x-checkout-session-token`. Backend
238
+ * `TeamFloPay/backend#640` rejects callers without a matching nonce with a
239
+ * 401 — this method throws synchronously when `data.nonce` is missing so the
240
+ * problem surfaces before the network round trip.
241
+ *
242
+ * @param userId Vestigial — backend's GatewayInterceptor routes via session,
243
+ * not headers, so this value is no longer sent on the wire. Kept in the
244
+ * signature for back-compat with existing callers; will be removed in a
245
+ * future major version.
246
+ */
247
+ processPayment(_userId: string, data: ProcessPaymentParams, options?: {
248
+ pollTimeoutMs?: number;
249
+ }): Promise<Response>;
250
+ /**
251
+ * Patch the buyer's account snapshot (email, name, billing address, AVS
252
+ * intent) onto a checkout session via
253
+ * `PATCH /v1/checkouts/sessions/{id}/account` (TeamFloPay/backend#823).
254
+ *
255
+ * The vault path's hosted form owns the charge end-to-end so the SDK
256
+ * never calls `/process` on this path; the buyer-typed AVS / billing
257
+ * address would otherwise be lost. The SDK calls this just before
258
+ * submitting the vault widget so the downstream listener mints the
259
+ * Stripe PaymentMethod with the right `billing_details.address` and the
260
+ * per-attempt + per-PM address snapshots are populated.
261
+ *
262
+ * Body shape mirrors the relevant subset of `/process`'s
263
+ * `ProcessCheckoutBodyDto` — same keys, same validators. The endpoint
264
+ * is idempotent: empty/undefined fields are not written, addresses are
265
+ * last-writer-wins, AVS analytics are first-writer-wins.
266
+ *
267
+ * Wrapped in `fetchWithNetworkRetry` because a transient blip on this
268
+ * pre-pay PATCH would silently leave AVS unsent and cause an
269
+ * AVS-protected charge to decline downstream.
270
+ */
271
+ patchAccountSnapshot(sessionId: string, nonce: string, body: {
272
+ accountData: {
273
+ userId: string;
274
+ email: string;
275
+ firstName?: string | null;
276
+ lastName?: string | null;
277
+ addressLine1?: string | null;
278
+ addressLine2?: string | null;
279
+ city?: string | null;
280
+ state?: string | null;
281
+ zip?: string | null;
282
+ country?: string | null;
283
+ gender?: string | null;
284
+ };
285
+ avsCheck?: boolean;
286
+ avsConfig?: Record<string, unknown>;
287
+ }, options?: {
288
+ signal?: AbortSignal;
289
+ timeoutMs?: number;
290
+ /**
291
+ * Downgrade only a timeout to `operation.fallback` when the caller can
292
+ * continue safely. The promise still rejects and all other failures stay
293
+ * technical errors. Defaults to `blocking`.
294
+ */
295
+ telemetryMode?: AccountSnapshotTelemetryMode;
296
+ }): Promise<void>;
297
+ /** Create a wallet/APM/PayPal intent through the session-scoped contract. */
298
+ createSessionIntent(sessionId: string, nonce: string, request: CreateSessionIntentRequest, options?: {
299
+ signal?: AbortSignal;
300
+ idempotencyKey?: string;
301
+ }): Promise<SessionIntent>;
302
+ /** Record a provider-neutral non-card decline without sensitive identifiers. */
303
+ reportSessionIntentDecline(sessionId: string, nonce: string, request: SessionIntentDeclineRequest, options?: {
304
+ signal?: AbortSignal;
305
+ }): Promise<void>;
306
+ /**
307
+ * Fetch user's prior payments by email.
308
+ * Used to determine if saved card UX should be shown.
309
+ */
310
+ getPaymentsByEmail(email: string, options?: {
311
+ signal?: AbortSignal;
312
+ page?: number;
313
+ limit?: number;
314
+ }): Promise<{
315
+ data: Array<{
316
+ id: string;
317
+ }>;
318
+ total: number;
319
+ page: number;
320
+ limit: number;
321
+ }>;
322
+ /**
323
+ * Create a checkout session AND return the full session data in one call.
324
+ * Uses `?expand=true` so the backend returns the complete session
325
+ * instead of just a UUID — eliminating the need for a second GET.
326
+ *
327
+ * Falls back to create + GET if the backend doesn't support `expand`.
328
+ *
329
+ * Eligible sessions are created through the **detached** shell + claim flow
330
+ * (see {@link PaymentAPI.createDetachedSession}) and this method awaits the
331
+ * claim, so its resolved value is unchanged — callers still receive one
332
+ * fully-populated session. The win here is server-side: the create no longer
333
+ * contends on buyer-identity advisory locks. Callers that want to render from
334
+ * the shell *before* the claim lands — mounting the card form early — should
335
+ * call {@link PaymentAPI.createDetachedSession} directly. Pass
336
+ * `deferDataAttachment: false` to force the original one-shot create.
337
+ */
338
+ createAndFetchSession(params: InlineSessionDraft): Promise<NormalizedCheckoutSession>;
339
+ private createAndFetchSessionRequest;
340
+ /**
341
+ * `POST /v1/checkouts/sessions` with the SDK's bounded retry budget.
342
+ *
343
+ * Network failures and the backend's documented in-progress replay share one
344
+ * attempt budget and one operation-wide abort signal, so the two retry modes
345
+ * cannot multiply into nine POSTs during an outage. The idempotency key is
346
+ * resolved once, before the loop — an invalid merchant-supplied key throws
347
+ * before any request, and every attempt of this logical create replays the
348
+ * same key so a timeout cannot mint a second session
349
+ * (TeamFloPay/backend#972).
350
+ */
351
+ private postCheckoutSessionCreate;
352
+ /**
353
+ * Create a checkout session **detached** from its buyer and catalog data
354
+ * (TeamFloPay/backend#1099).
355
+ *
356
+ * Resolves as soon as the lightweight *shell* exists. That create runs no
357
+ * catalog validation and takes none of the buyer-identity advisory locks that
358
+ * serialise concurrent checkouts for the same customer, and the backend routes
359
+ * a gateway for it from `currency` + the buyer's country — so the shell
360
+ * already carries the session id, nonce, `gateways` and the hosted `vault`
361
+ * block. The card form can mount from it immediately.
362
+ *
363
+ * Buyer identity, address, products and coupons are attached by the returned
364
+ * {@link DetachedCheckoutSession.claimed} promise, which is already in flight
365
+ * when this resolves. **Nothing may be charged until it settles** — the
366
+ * billing API rejects process / intent / decline calls on an unclaimed
367
+ * session with `409 checkout_session_data_attachment_required`, and holds an
368
+ * unclaimed vault charge with a retryable `503`.
369
+ *
370
+ * Requires a billing API with `PATCH /v1/checkouts/sessions/{id}/claim`; there
371
+ * is no fallback to the one-shot create. Callers that want the original
372
+ * single-request behaviour should pass `deferDataAttachment: false` and use
373
+ * {@link PaymentAPI.createAndFetchSession}.
374
+ */
375
+ createDetachedSession(params: InlineSessionDraft): Promise<DetachedCheckoutSession>;
376
+ /**
377
+ * `PATCH /v1/checkouts/sessions/{id}/claim` — attach buyer identity, address,
378
+ * products and coupons to a detached session shell.
379
+ *
380
+ * The backend fingerprints the payload, so a transport retry replaying the
381
+ * identical body returns the same claimed session rather than conflicting; a
382
+ * *materially different* claim for an already-claimed session returns `409`,
383
+ * which is surfaced without retrying. Invalid catalog data surfaces here as
384
+ * the same `422` the one-shot create would have returned — later in the flow,
385
+ * but with identical semantics.
386
+ */
387
+ claimCheckoutSession(checkoutSessionId: string, nonce: string, payload: Record<string, unknown>, internal?: {
388
+ params: InlineSessionDraft;
389
+ startedAt: number;
390
+ deadline: {
391
+ signal: AbortSignal;
392
+ clear(): void;
393
+ };
394
+ /**
395
+ * Attempts the shell create needed. The `session_create` rollup below
396
+ * reports this rather than the claim's own attempt count, so an
397
+ * end-to-end span keeps meaning "attempts to create this session".
398
+ */
399
+ createAttempt: number;
400
+ }): Promise<NormalizedCheckoutSession>;
401
+ /** Shared create/claim failure reporting so both phases classify identically. */
402
+ private reportSessionCreateFailure;
403
+ waitForCheckoutSessionCompletion(checkoutSessionId: string, options?: {
404
+ initialDelayMs?: number;
405
+ timeoutMs?: number;
406
+ /**
407
+ * Session-bound checkout token; forwarded on the poll's
408
+ * `GET /v1/checkouts/sessions/:id`. Required by post-#640 backends.
409
+ */
410
+ nonce?: string;
411
+ }): Promise<NormalizedCheckoutSession>;
412
+ /** Normalize a raw session into a provider-agnostic shape. */
413
+ private normalizeRawSession;
414
+ /** Convert raw session to the SDK CheckoutSession shape. */
415
+ private toCheckoutSession;
416
+ /**
417
+ * Coerce a raw vault block into a typed {@link VaultCaptureBlock}. The
418
+ * server-only PCIVault submit `secret` is deliberately dropped so it never
419
+ * lands on the public session surface (logs / telemetry / client inspection).
420
+ */
421
+ private toVaultBlock;
422
+ private toCheckoutSessionStatus;
423
+ private resolveProcessResponse;
424
+ private toCheckoutProcessingPending;
425
+ private clampRetryAfterMs;
426
+ /**
427
+ * Stash the display-only fields the consumer passed into a create-session
428
+ * call. Runs after the backend assigns a UUID so a later GET on the same
429
+ * session (typically after a redirect) can fill in fields the backend no
430
+ * longer persists — `overrideAmount`, `totalAmount`, `name`, etc.
431
+ *
432
+ * No-op when no UUID is available.
433
+ */
434
+ private autoCacheDisplayData;
435
+ /**
436
+ * Merge cached display-only fields (set by {@link cacheSessionDisplayData})
437
+ * into a raw session response. Server values always win — cache fills in
438
+ * only where the server returned `null` / `undefined`.
439
+ */
440
+ private mergeCachedDisplayData;
441
+ }
442
+
443
+ /** Browser operation hosted by the PCIVault card-capture adapter. */
444
+ type CardCaptureOperation = 'checkout' | 'card_setup';
445
+ /** Configuration for a {@link PciVaultCardCapture} instance. */
446
+ interface PciVaultCardCaptureConfig {
447
+ /** Checkout session id bound to the capture (for outcome correlation + trust). */
448
+ sessionId?: string;
449
+ /** Capture behavior of the checkout session, used to classify legacy outcomes safely. */
450
+ captureMethod?: CaptureMethod;
451
+ /** Distinguishes no-charge card verification telemetry from checkout payment telemetry. */
452
+ operation?: CardCaptureOperation;
453
+ /**
454
+ * Default strict origin for vault `postMessage` outcomes. Overridden by
455
+ * {@link CardCaptureMountOptions.expectedOrigin} when that is supplied at
456
+ * mount. When neither is set the origin gate is skipped (the widget posts
457
+ * same-window in the Model-A flow).
458
+ */
459
+ expectedOrigin?: string;
460
+ /** Flo-owned privacy-safe telemetry is enabled by default; set false to opt out. */
461
+ telemetry?: boolean;
462
+ }
463
+ /**
464
+ * {@link CardCaptureAdapter} backed by the backend-rendered PCIVault hosted
465
+ * widget.
466
+ *
467
+ * `mount()` injects the server-supplied widget HTML (re-executing its bundled
468
+ * `<script>` so the form bootstraps) and subscribes to the widget's
469
+ * `postMessage` outcome. The backend owns everything else; this adapter never
470
+ * touches the card data, a payment intent, or 3DS.
471
+ */
472
+ declare class PciVaultCardCapture implements CardCaptureAdapter {
473
+ readonly provider: CardCaptureProviderId;
474
+ private readonly config;
475
+ private telemetryReporter?;
476
+ /** Reporter already initialized for this adapter's setup operation. */
477
+ private setupTelemetryReporter?;
478
+ private readonly ownsTelemetryReporter;
479
+ private container;
480
+ private messageHandler;
481
+ /**
482
+ * Parent-page-level overlay rendering the provider's verification challenge
483
+ * (3DS-2 iframe) on `action_required`. Owned by the adapter — not the
484
+ * widget — so it can sit above the host SDK's processing backdrop, which
485
+ * would otherwise visually cover an in-widget challenge iframe.
486
+ */
487
+ private actionOverlay;
488
+ /**
489
+ * Listener that catches the `flopay-vault-3ds-return` postMessage from the
490
+ * provider's challenge return page. When the SDK owns the challenge iframe
491
+ * the return page lives inside *that* iframe (not the widget's), so
492
+ * `window.parent` is the host page — the widget's existing message
493
+ * listener can't see it. The SDK forwards completion into the widget via
494
+ * `action_completed` so the widget kicks `/3ds/complete` immediately
495
+ * instead of waiting on the eventual provider webhook.
496
+ */
497
+ private threeDsReturnHandler;
498
+ /** Per-session integrity token to require on outcomes (from mount options). */
499
+ private messageToken;
500
+ /** Strict origin to require on outcomes, when configured. */
501
+ private expectedOrigin;
502
+ /** Latest merchant theme to push into the (cross-origin) widget. */
503
+ private theme;
504
+ /** Latest host submit-gate state to push into the widget (block its submit). */
505
+ private submitGateBlocked;
506
+ /** Latest card-field order + autofocus directive to push into the widget. */
507
+ private cardFieldOrder;
508
+ private cardAutoFocus;
509
+ /** Monotonic start of the current widget mount-to-ready machine interval. */
510
+ private mountStartedAt;
511
+ private vaultReadyReported;
512
+ private submissionStarted;
513
+ private submissionStartedAt;
514
+ private readonly listeners;
515
+ constructor(config?: PciVaultCardCaptureConfig);
516
+ mount(container: HTMLElement, options: CardCaptureMountOptions): Promise<void>;
517
+ private reportVaultLoadFailure;
518
+ on(event: CardCaptureEventType, handler: (event: CardCaptureOutcomeEvent) => void): () => void;
519
+ unmount(): void;
520
+ /**
521
+ * Inject the server-rendered widget HTML. `innerHTML` does not execute
522
+ * embedded `<script>` tags, so each script node is replaced with a freshly
523
+ * created element that the browser will load and run (this is what boots the
524
+ * PCIVault form bundle against the `data-flopay-config` container).
525
+ */
526
+ private injectWidget;
527
+ private attachMessageListener;
528
+ private reportOutcome;
529
+ /**
530
+ * Push merchant theme colors into the hosted widget (live). The host calls
531
+ * this on a runtime theme switch; the widget applies them to its CSS variables
532
+ * without a remount. Stores the latest theme so `ready` can re-push it.
533
+ */
534
+ applyTheme(theme: VaultCardThemeColors): void;
535
+ /** postMessage the current theme to the widget's (cross-origin) document. */
536
+ private postTheme;
537
+ /**
538
+ * Gate the widget's submit from the host. When `blocked`, the widget cancels
539
+ * its next submit and emits `'blocked'` instead of `'submitting'` so the host
540
+ * can validate merchant-DOM fields (AVS) first. Stored so `ready` re-pushes it.
541
+ */
542
+ setSubmitGate(blocked: boolean): void;
543
+ /** postMessage the current submit-gate state to the widget's document. */
544
+ private postSubmitGate;
545
+ /**
546
+ * Push the card-field order + autofocus directive into the widget (live). The
547
+ * widget re-sequences its rows (DOM order, so tab order follows) and focuses
548
+ * its first field unless `autoFocus` is false. Stored so `ready` re-pushes it.
549
+ */
550
+ setCardFieldOrder(order: VaultCardFieldKey[] | null, autoFocus: boolean): void;
551
+ /** postMessage the current field order + autofocus to the widget's document. */
552
+ private postCardFieldOrder;
553
+ private emit;
554
+ /**
555
+ * Render the provider-hosted verification challenge (e.g. Stripe 3DS-2) in a
556
+ * full-page overlay at the PARENT page level. The widget's inline-iframe
557
+ * approach is unusable because the SDK's processing backdrop sits above the
558
+ * vault iframe, hiding any challenge mounted inside it — by lifting the
559
+ * iframe to the host page the adapter can give it a z-index that wins.
560
+ *
561
+ * The overlay tears down on the next terminal outcome
562
+ * (`complete`/`decline`/`error`) or when the buyer closes it via the backdrop
563
+ * close button. Closing manually is a soft abandon — the next `/status` poll
564
+ * either reveals a real outcome (the challenge completed via the issuer's
565
+ * own redirect to `/vault/3ds/return`, which posts back into the widget) or
566
+ * surfaces `requires_action` again so the host can decide what to do.
567
+ */
568
+ private showActionRequiredOverlay;
569
+ /**
570
+ * Tell the vault widget that the buyer has completed (or abandoned) the
571
+ * challenge. The widget responds by POSTing `/3ds/complete` — its
572
+ * sub-300ms sync resolver writes the follow-up attempt row immediately,
573
+ * so the next `/status` poll resolves to a terminal outcome instead of
574
+ * waiting for the eventual provider webhook.
575
+ */
576
+ private postActionCompleted;
577
+ private abandonActionRequiredOverlay;
578
+ private hideActionRequiredOverlay;
579
+ /**
580
+ * Size the hosted-widget iframe to the height reported by the form inside it.
581
+ * Cross-origin iframes don't auto-size to their content, so the widget posts
582
+ * its measured height and we apply it here (clamped to a sane range). This is
583
+ * what lets the card form shrink/grow to fit instead of sitting at a fixed
584
+ * height.
585
+ */
586
+ private applyHeight;
587
+ }
588
+
589
+ export { type CardCaptureOperation as C, PaymentAPI as P, SESSION_CREATE_TELEMETRY as S, PciVaultCardCapture as a, type PciVaultCardCaptureConfig as b, type SessionDisplayCacheData as c, type SessionDisplayProduct as d, cacheSessionDisplayData as e, clearSessionDisplayData as f, getSessionDisplayData as g };