import type { components } from "@amos.com/node"; import { appearanceWithDefaults } from "./appearance-defaults"; import { hideApplePayWaitingOverlay, setApplePayWaitingOverlayCompleting, showApplePayWaitingOverlay, } from "./apple-pay-waiting-overlay"; import { embedIframeSearchParams } from "./embed-src"; import { armIframeHandshakeReload } from "./handshake-reload"; import { getEmbedOrigin } from "./jwt"; import { confirmPayment, getIframeTargetOrigin, sendParentReadyMessage, updateAmount as sendUpdateAmount, updateAppearance as sendUpdateAppearance, updateApplePayButton as sendUpdateApplePayButton, updateMerchantName as sendUpdateMerchantName, } from "./messaging"; import { type ApplePayButtonElementProps, type ConfirmPaymentResult, createMessage, type Message, type WalletContactRequirements, type WalletCustomerCreateAttributes, } from "./types"; /** * Build the iframe `src` URL for the embedded Apple Pay button. */ export function getApplePayButtonSrc(renderToken: string): string { const params = embedIframeSearchParams({ token: renderToken }); return `${getEmbedOrigin(renderToken)}/iframe/apple-pay?${params}`; } /** * Default iframe pixel height for the Apple Pay button. */ export function getApplePayButtonInitialHeight(): string { return "48px"; } /** * Options accepted by {@link attachApplePayButtonListeners}. */ export type ApplePayButtonListenerOptions = WalletContactRequirements & { /** * Major-currency decimal string shown in the Apple Pay sheet * (e.g. `"50.00"` for $50.00). Converted to cents in * `paymentIntentCreateAttributes.amount`. */ amount: string; /** A user-visible merchant name. */ merchantName: string; /** * Painted Apple Pay button height. CSS length (e.g. `"48px"`). * @default "48px" */ height?: string; /** * Native `` attributes and inner style. Omitted * fields keep Apple's defaults (`black` / `plain` / `en-US`). The * button fills the iframe — size the mount slot, not the button. */ buttonProps?: ApplePayButtonElementProps; /** * Called whenever the iframe asks the host page to resize it. Update * the iframe's `height` style here. */ onHeightChange?: (height: string) => void; /** * Called once the iframe has applied the requested appearance and is * ready to be revealed. */ onAppearanceReady?: () => void; /** * Called when the iframe posts `IFRAME_READY` (embed JS is running). */ onIframeReady?: () => void; /** * Called when the buyer authorizes in the Apple Pay sheet. Create a * payment intent on your server, then `await confirmPayment(token)`. * `customerCreateAttributes` is {@link WalletCustomerCreateAttributes}, * not Amos `CreateCustomerInput`. */ onConfirm: ({ paymentIntentCreateAttributes, customerCreateAttributes, confirmPayment, }: { paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"]; customerCreateAttributes: WalletCustomerCreateAttributes; confirmPayment: (token: string) => Promise; }) => Promise; }; /** * Controller returned by {@link attachApplePayButtonListeners} and * {@link mountAmosApplePayButton}. */ export type ApplePayButtonController = { /** * Update one or more listener options without re-attaching the * message listener. Pass `amount` or `merchantName` to push the new * value into the iframe; pass `height`, `buttonProps`, * `phoneRequired`, or `shippingAddressRequired` to restyle the Apple * Pay button or change sheet contact fields. */ update: (patch: Partial) => void; /** * Detach the iframe message listener. */ destroy: () => void; }; function sendApplePayCancel(iframe: HTMLIFrameElement): void { iframe.contentWindow?.postMessage( createMessage({ type: "APPLE_PAY_CANCEL" }), getIframeTargetOrigin(iframe), ); } /** * Wire up the host-page side of the Apple Pay iframe message protocol * on an existing `