/** * SDK-internal identifier for each rendered field. One-to-one with the Clover * element types except `CARD` (composite — we don't use it). */ type FieldKey = 'cardNumber' | 'cardDate' | 'cardCvv' | 'cardPostalCode' | 'cardName' | 'cardEmail' | 'paymentRequestButton'; /** * CSS properties Clover supports inside its iframe ``. Curated from * production usage in the WP plugin + Clover SDK behavior. Properties not * listed here are silently ignored by Clover; we don't pretend they work. */ interface CloverCssProperties { color?: string; fontFamily?: string; fontSize?: string; fontWeight?: string | number; lineHeight?: string | number; letterSpacing?: string; textAlign?: 'left' | 'right' | 'center' | 'inherit' | 'initial'; textIndent?: string; padding?: string; margin?: string; height?: string; width?: string; border?: string; borderRadius?: string; background?: string; backgroundColor?: string; } /** * Element-scoped selectors Clover honors. Each is the lower-kebab form of the * Clover element type (`CARD_EMAIL_ADDRESS` → `card-email-address`). Using a * shortened form (e.g. `card-email`) is silently ignored — Clover does not * warn, the style just never applies. Discovery captured 2026-05-18. */ type CloverElementSelector = 'card-number' | 'card-date' | 'card-cvv' | 'card-postal-code' | 'card-name' | 'card-email-address' | 'card-phone-number' | 'card-street-address'; /** * Placeholder pseudo-classes Clover honors. The vendor-prefixed forms are * required by older Clover versions; modern `::placeholder` is also accepted. * Production code in the WP plugin sets all four prefixed variants. */ type PlaceholderPseudo = '::placeholder' | '::-webkit-input-placeholder' | '::-moz-placeholder' | ':-ms-input-placeholder' | ':-moz-placeholder'; /** * Every selector key Clover's `elements.create(type, styles)` accepts. The * SDK exports this union so consumers get autocomplete and typo safety on * a previously-untyped JSON payload. * * - `'input'` — applies to the input in every element * - `''` — global placeholder rule * - `'card- input'` — per-element input rule * - `'card- input'` — per-element placeholder rule */ type CloverStyleSelector = 'input' | PlaceholderPseudo | CloverElementSelector | `${CloverElementSelector} input` | `${CloverElementSelector} input${PlaceholderPseudo}`; /** * Strongly-typed styles object for `clover.elements().create()`. Replaces * `type CloverElementStyles = object`. * * Most consumers should NOT construct this directly — pass a higher-level * `theme` on `PaymentFieldsConfig` and let `compileTheme()` emit the JSON. */ type CloverElementStyles = Partial>; /** * High-level theme config. The SDK compiles this into a `CloverElementStyles` * JSON object internally — most apps never need to touch the raw selectors. */ interface CloverFieldTheme { readonly fontFamily?: string; readonly fontSize?: string; readonly textColor?: string; readonly placeholderColor?: string; /** * Height of the input inside each Clover iframe. Must match (or slightly * exceed) the host wrapper's height so the entire wrapper is clickable. * Defaults to `'46px'` to match `.wcp-pf__field` in the SDK stylesheet. */ readonly inputHeight?: string; /** Extra style overrides merged on top of the theme-emitted defaults. */ readonly overrides?: CloverElementStyles; } type ThreeDsBrowserInfo = Record; /** * Lifecycle states the SDK transitions through. See the lifecycle preview at * `design-previews/06-states.html` for what the customer sees in each state. */ type PaymentFieldsState = 'idle' | 'gpay_opening' | 'gpay_ready' | 'gpay_cancelled' | 'tokenizing' | 'submitting' | 'threeds_method' | 'threeds_challenge' | 'finalizing' | 'done' | 'error'; /** * Per-field validation state. Two error fields — `error` is the raw signal * from Clover, `displayedError` is what the UI should actually render. They * diverge for the deferred-error UX rule: while the user is mid-typing, raw * `error` may report "incomplete card", but we don't surface it until they * blur once. After first blur, the two stay in sync. See README → Events & * Validation, and the comment block at the top of `validation-machine.ts`. */ interface FieldValidationState { /** Clover-reported: user has interacted with the field. */ readonly touched: boolean; /** Clover-reported: raw error message, fires on every `change` event. */ readonly error?: string; /** SDK-derived: user has blurred this field at least once. */ readonly hasBlurred: boolean; /** SDK-derived: at least one `change` event has been observed for this field. */ readonly hadChangeEver: boolean; /** SDK-derived: the error to render. Undefined until first blur (deferred-error rule). */ readonly displayedError?: string; } interface ValidationSnapshot { /** Per-field touched + error state. Only fields actually mounted appear. */ readonly fields: { readonly [K in FieldKey]?: FieldValidationState; }; /** True when all required fields are valid (no errors, all touched). */ readonly canSubmit: boolean; } interface PaymentFieldsSnapshot { readonly state: PaymentFieldsState; readonly validation: ValidationSnapshot; /** Set when state is 'error' or after a recoverable failure. */ readonly error?: PaymentFieldsError; /** Set after successful tokenization (either path). */ readonly result?: TokenizationResult; /** Set during the 3DS flow. */ readonly threeDs?: ThreeDsInterim; } interface PaymentFieldsError { readonly code: PaymentFieldsErrorCode; readonly message: string; readonly cause?: unknown; } type PaymentFieldsErrorCode = 'clover_load_failed' | 'clover_3ds_load_failed' | 'not_mounted' | 'rate_limited' | 'tokenization_failed' | 'gpay_unavailable' | 'threeds_prerequisites_missing' | 'threeds_timeout' | 'threeds_finalize_failed' | 'unknown'; interface TokenizationResult { /** 'card' = manual entry tokenized via `clover.createToken()`. 'google_pay' = captured from `PAYMENT_REQUEST_BUTTON` paymentMethod event. */ readonly source: 'card' | 'google_pay'; readonly token: string; readonly card: { readonly brand: string; readonly last4: string; readonly expMonth?: string; readonly expYear?: string; readonly first6?: string; readonly addressZip?: string; }; /** 3DS browser fingerprint, collected when 3DS is enabled. */ readonly browserInfo?: ThreeDsBrowserInfo; } interface ThreeDsInterim { readonly state: 'method_required' | 'challenge_required'; readonly chargeId: string; readonly fields: ThreeDsInterimFields; } interface ThreeDsInterimFields { readonly acsUrl?: string; readonly acsTransactionId?: string; readonly methodUrl?: string; readonly methodNotificationUrl?: string; readonly threeDsServerTransactionId?: string; /** Clover varies the field name between `threeds_protocol_version` and `message_version`. The SDK normalizes to this. */ readonly protocolVersion?: string; } type ThreeDsResult = { readonly kind: 'success'; readonly redirect?: string; readonly data?: unknown; } | { readonly kind: 'escalation'; readonly next: ThreeDsInterim; } | { readonly kind: 'failure'; readonly message: string; }; interface PaymentFieldsConfig { readonly pakmsKey: string; readonly merchantId: string; readonly locale: string; readonly cartTotal: number; readonly currency: string; readonly country?: string; readonly cloverSdkUrl: string; readonly clover3DSSdkUrl?: string; readonly features?: PaymentFieldsFeatures; readonly endpoints?: PaymentFieldsEndpoints; readonly theme?: CloverFieldTheme; readonly onTokenized?: (result: TokenizationResult) => void; readonly onThreeDsRequired?: (interim: ThreeDsInterim) => void; readonly onError?: (error: PaymentFieldsError) => void; } interface PaymentFieldsFeatures { readonly googlePay?: boolean; readonly threeDSecure?: boolean; /** * Cardholder name + email field visibility. * - `'auto'` (default) — visible when 3DSecure is enabled * - `'always'` — visible always * - `'hidden'` — never rendered */ readonly cardholderFields?: 'auto' | 'always' | 'hidden'; readonly savedCredentials?: SavedCredential | readonly SavedCredential[]; } interface PaymentFieldsEndpoints { /** Host's POST URL for 3DS finalization (e.g., WC's `/wp-json/.../3ds/finalize`). */ readonly threeDsFinalize?: string; /** Returns headers (nonce, auth, etc.) for the finalize POST. Called per-request. */ readonly headers?: HeadersProvider; } type HeadersProvider = () => Record | Promise>; interface SavedCredential { readonly token: string; readonly last4: string; readonly brand: string; } interface MountTargets { readonly cardNumber: string; readonly cardDate: string; readonly cardCvv: string; readonly cardPostalCode: string; readonly cardName?: string; readonly cardEmail?: string; readonly paymentRequestButton?: string; } type PaymentFieldsListener = (snapshot: PaymentFieldsSnapshot) => void; type Unsubscribe = () => void; declare class PaymentFieldsMachine { /** The config the machine was constructed with. Read-only after construction. */ readonly config: PaymentFieldsConfig; private readonly listeners; private readonly rateLimiter; private snapshot; private mounted; private destroyed; private clover; private threeDsUtil; private registry; private validation; private capturedGpayToken; constructor(config: PaymentFieldsConfig); /** Subscribe to snapshot updates. The listener is called immediately with the current snapshot. */ subscribe(listener: PaymentFieldsListener): Unsubscribe; getSnapshot(): PaymentFieldsSnapshot; /** * Load the Clover SDK(s), create the elements, mount them to the host's DOM * targets, and wire validation + GPay event handlers. Idempotent — calling * again is a no-op. */ mount(targets: MountTargets): Promise; /** * Return a tokenization result the host can POST to the API. * * Two paths: * - **GPay**: if we're in `gpay_ready`, return the already-captured token immediately (no second prompt). * - **Manual card**: call `clover.createToken()`, rate-limited. * * Throws on rate-limit, invalid card, missing token, or unmounted state. */ tokenize(): Promise; /** * Drive the 3DS flow given an interim payload from the host's API response. * Handles method/challenge dispatch, the `executePatch` callback, the * finalize POST, and escalation (method ↔ challenge) internally. * * @param options.extraBody Host-specific fields merged into the finalize POST body. * E.g., WC passes `{ order_id, order_key, nonce }` so the WP REST endpoint * can find and update the order. Keeps WC-specific concerns out of the SDK. */ runThreeDs(interim: ThreeDsInterim, options?: { readonly extraBody?: Record; }): Promise; /** * Restore the form to idle, discarding any captured GPay token. Used by the * "Use card details instead" link on the GPay-ready state. */ resetToIdle(): void; destroy(): void; private shouldShowCardholderFields; private buildPaymentRequestData; private wireGpayEvents; private update; private emitError; } /** * Optional setter for the host's headers provider — must be set BEFORE the * element is connected (e.g., via `el.headersProvider = ...; document.body.appendChild(el)`). */ interface WcpPaymentFieldsElement extends HTMLElement { headersProvider?: HeadersProvider; tokenize: () => Promise; runThreeDs: (interim: ThreeDsInterim, options?: { readonly extraBody?: Record; }) => Promise; resetToIdle: () => void; readonly machine: PaymentFieldsMachine | null; } declare class WcpPaymentFields extends HTMLElement implements WcpPaymentFieldsElement { /** Tells the form machinery that this element participates in form submission. */ static readonly formAssociated = true; private internals; /** Light-DOM mount container for the React tree. NOT a shadowRoot. */ private container; private root; private _machine; private unsubscribe; private lastTokenizedFor; private lastErrorCode; private lastState; /** Caller-provided headers function (for 3DS finalize POST). Property — not an attribute. */ headersProvider?: HeadersProvider; constructor(); connectedCallback(): void; disconnectedCallback(): void; get machine(): PaymentFieldsMachine | null; tokenize(): Promise; runThreeDs(interim: ThreeDsInterim, options?: { readonly extraBody?: Record; }): Promise; resetToIdle(): void; formResetCallback(): void; private subscribeMachineToEvents; private onSnapshot; private dispatchTyped; private parseConfig; } export { type PaymentFieldsConfig, type PaymentFieldsError, type PaymentFieldsSnapshot, type PaymentFieldsState, type ThreeDsInterim, type ThreeDsResult, type TokenizationResult, WcpPaymentFields, type WcpPaymentFieldsElement };