@amos.com/amos-js 0.6.1 → 0.7.1

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,9 @@
1
+ /**
2
+ * Create (or return existing) full-viewport waiting UI on the host page while
3
+ * Apple Pay Code runs in a separate window. Cancel invokes `onCancel`.
4
+ */
5
+ export declare function showApplePayWaitingOverlay({ onCancel, }: {
6
+ onCancel: () => void;
7
+ }): HTMLElement;
8
+ /** Remove the host-page Apple Pay waiting overlay if present. */
9
+ export declare function hideApplePayWaitingOverlay(): void;
@@ -74,8 +74,8 @@ export type ApplePayButtonController = {
74
74
  * correct `src` (see {@link getApplePayButtonSrc}).
75
75
  *
76
76
  * The Apple Pay button and `ApplePaySession` run inside the Amos embed
77
- * iframe (so only Amos domains need Apple merchant registration). On
78
- * `EXPAND_IFRAME`, the parent temporarily overlays that iframe
79
- * full-viewport for Chrome's in-iframe QR handoff UI.
77
+ * iframe so only Amos domains need Apple merchant registration. While
78
+ * Apple Pay Code is open in a separate window, this host paints a
79
+ * waiting overlay and can cancel via {@link Message} `APPLE_PAY_CANCEL`.
80
80
  */
81
81
  export declare function attachApplePayButtonListeners(iframe: HTMLIFrameElement, options: ApplePayButtonListenerOptions): ApplePayButtonController;
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { attachApplePayButtonListeners, getApplePayButtonInitialHeight, getApple
4
4
  export type { FormattedGooglePayPaymentData, GooglePayButtonController, GooglePayButtonListenerOptions, } from './google-pay';
5
5
  export { attachGooglePayButtonListeners, formatGooglePayPaymentData, getGooglePayButtonInitialHeight, getGooglePayButtonSrc, } from './google-pay';
6
6
  export { decodeJwt, getEmbedOrigin } from './jwt';
7
- export { confirmPaymentIntent, confirmSetupIntent, hasNativeApplePaySession, sendConfirmationFailed, sendParentReadyMessage, updateAmount, updateAppearance, updateMerchantName, updateNativeApplePaySession, validateForm, } from './messaging';
7
+ export { confirmPaymentIntent, confirmSetupIntent, sendConfirmationFailed, sendParentReadyMessage, updateAmount, updateAppearance, updateMerchantName, validateForm, } from './messaging';
8
8
  export type { AmosApplePayButtonMountController, AmosApplePayButtonOptions, AmosBankAccountPaymentMethodFormOptions, AmosCreditCardPaymentMethodFormOptions, AmosGooglePayButtonMountController, AmosGooglePayButtonOptions, AmosPaymentMethodFormMountController, } from './mount';
9
9
  export { mountAmosApplePayButton, mountAmosBankAccountPaymentMethodForm, mountAmosCreditCardPaymentMethodForm, mountAmosGooglePayButton, } from './mount';
10
10
  export type { BillingAddressRequirement, CreditCardAdditionalFields, PaymentMethodFormController, PaymentMethodFormListenerOptions, } from './payment-method-form';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e){let[t=``,n=``,r=``]=e?.split(`.`)??[],i=typeof atob==`function`?atob:e=>Buffer.from(e,`base64`).toString(`utf8`);return{header:JSON.parse(i(t)),payload:JSON.parse(i(n)),signature:r}}function t(t){let{env:n=`sandbox`}=e(t).payload;switch(n){case`production`:return`https://embed.amos.com`;case`sandbox`:return`https://embed-sandbox.amos.com`;default:return`https://embed-sandbox.amos.com`}}function n(e){return e}function r(e){e?.contentWindow?.postMessage(n({type:`PARENT_ACKNOWLEDGED_IFRAME_READY`}),`*`)}function i({iframe:e,appearance:t={}}){e?.contentWindow?.postMessage(n({type:`UPDATE_APPEARANCE`,appearance:t}),`*`)}function a({iframe:e,amount:t}){e?.contentWindow?.postMessage(n({type:`UPDATE_AMOUNT`,amount:t}),`*`)}function o({iframe:e,merchantName:t}){e?.contentWindow?.postMessage(n({type:`UPDATE_MERCHANT_NAME`,merchantName:t}),`*`)}function s(){return`ApplePaySession`in globalThis}function c({iframe:e,hasNativeApplePaySession:t}){e?.contentWindow?.postMessage(n({type:`UPDATE_NATIVE_APPLE_PAY_SESSION`,hasNativeApplePaySession:t}),`*`)}function l({iframe:e}){let t=crypto.randomUUID();return new Promise(r=>{e?.contentWindow?.postMessage(n({type:`VALIDATE_FORM`,requestId:t}),`*`);let i=setTimeout(()=>{window.removeEventListener(`message`,a),r(!1)},5e3);function a(e){e.data.type===`VALIDATE_FORM`&&e.data.requestId===t&&(window.removeEventListener(`message`,a),clearTimeout(i),r(e.data.isValid??!1))}window.addEventListener(`message`,a)})}function u({iframe:t,token:r}){let{payment_intent_id:i}=e(r).payload;t?.contentWindow?.postMessage(n({type:`CONFIRM_PAYMENT_INTENT`,token:r,id:i??void 0}),`*`)}function d({iframe:t,token:r}){let{setup_intent_id:i}=e(r).payload;t?.contentWindow?.postMessage(n({type:`CONFIRM_SETUP_INTENT`,token:r,id:i??void 0}),`*`)}function f({iframe:e,errorMessage:t}){e?.contentWindow?.postMessage(n({type:`CONFIRMATION_FAILED`,errorMessage:t}),`*`)}function p(e){return`${t(e)}/iframe/apple-pay?token=${e}`}function m(){return`40px`}function h(e){let t={cssText:e.style.cssText,bodyOverflow:document.body.style.overflow};return document.body.style.overflow=`hidden`,Object.assign(e.style,{position:`fixed`,inset:`0px`,width:`100vw`,height:`100vh`,maxWidth:`none`,maxHeight:`none`,margin:`0`,border:`0`,zIndex:`2147483647`,opacity:`1`,background:`#ffffff`}),t}function g(e,t){t&&(document.body.style.overflow=t.bodyOverflow,e.style.cssText=t.cssText)}function _(e,t){let n={...t},l=null;function d(){a({iframe:e,amount:n.amount})}function p(){o({iframe:e,merchantName:n.merchantName})}function m(){c({iframe:e,hasNativeApplePaySession:s()})}function _(t){if(t.source===e.contentWindow)switch(t.data.type){case`IFRAME_READY`:r(e),i({iframe:e,appearance:n.appearance}),m(),d(),p();break;case`UPDATE_HEIGHT`:l||n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:i({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`EXPAND_IFRAME`:l||=h(e);break;case`COLLAPSE_IFRAME`:g(e,l),l=null;break;case`CREATE_PAYMENT_INTENT`:n.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:t.data.paymentIntentCreateAttributes,customerCreateAttributes:t.data.customerCreateAttributes}).then(t=>{u({iframe:e,token:t})}).catch(t=>{f({iframe:e,errorMessage:t instanceof Error?t.message:`Unknown error`})});break;case`PAYMENT_INTENT_CONFIRMATION_SUCCEEDED`:n.onPaymentIntentConfirmationSucceeded(t.data.paymentIntent);break;case`CONFIRMATION_FAILED`:n.onConfirmationFailed(t.data.errorMessage);break}}return window.addEventListener(`message`,_),{update(t){let r=`appearance`in t,a=`amount`in t,o=`merchantName`in t;n={...n,...t},r&&i({iframe:e,appearance:n.appearance}),a&&d(),o&&p()},destroy(){window.removeEventListener(`message`,_),g(e,l),l=null}}}function v(e){return`${t(e)}/iframe/google-pay?token=${e}`}function y(){return`40px`}function b(e,t){let n={...t};function s(){a({iframe:e,amount:n.amount})}function c(){o({iframe:e,merchantName:n.merchantName})}function l(t){switch(t.data.type){case`IFRAME_READY`:r(e),i({iframe:e,appearance:n.appearance}),s(),c();break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:i({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`CREATE_PAYMENT_INTENT`:n.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:t.data.paymentIntentCreateAttributes,customerCreateAttributes:t.data.customerCreateAttributes}).then(t=>{u({iframe:e,token:t})}).catch(t=>{f({iframe:e,errorMessage:t instanceof Error?t.message:`Unknown error`})});break;case`PAYMENT_INTENT_CONFIRMATION_SUCCEEDED`:n.onPaymentIntentConfirmationSucceeded(t.data.paymentIntent);break;case`CONFIRMATION_FAILED`:n.onConfirmationFailed(t.data.errorMessage);break}}return window.addEventListener(`message`,l),{update(t){let r=`appearance`in t,a=`amount`in t,o=`merchantName`in t;n={...n,...t},r&&i({iframe:e,appearance:n.appearance}),a&&s(),o&&c()},destroy(){window.removeEventListener(`message`,l)}}}function x({paymentData:e}){return{paymentMethod:{type:`googlepay`,billing_address_attributes:{name:e.shippingAddress?.name,address_line1:e.shippingAddress?.address1,address_line2:e.shippingAddress?.address2,city:e.shippingAddress?.locality,state:e.shippingAddress?.administrativeArea,postal_code:e.shippingAddress?.postalCode,country:e.shippingAddress?.countryCode,email:e.email,phone:e.shippingAddress?.phoneNumber},card_profile_attributes:{wallet_provider:`googlepay`,wallet_payload:e.paymentMethodData.tokenizationData.token,wallet_last4:e.paymentMethodData.info?.cardDetails,wallet_brand:(()=>{switch(e.paymentMethodData.info?.cardNetwork){case`AMEX`:return`american_express`;case`VISA`:return`visa`;case`MASTERCARD`:return`master`;case`DISCOVER`:return`discover`;default:return}})()}}}}var S={country:212,full:452},C=80,w={country:400,full:640};function T(e,n={cardholderName:!1},r=`country`){let i=Object.entries(n).filter(([,e])=>e).map(([e])=>e).join(`,`),a=new URLSearchParams({token:e,additionalFields:i,billingAddressRequirement:r});return`${t(e)}/iframe/card?${a}`}function E(e,n=`country`){let r=new URLSearchParams({token:e,billingAddressRequirement:n});return`${t(e)}/iframe/bank?${r}`}function D(e={cardholderName:!1},t=`country`){return`${(S[t]??S.country)+(e.cardholderName?C:0)}px`}function O(e=`country`){return`${w[e]??w.country}px`}function k(e,t){let n={...t};function a(t){switch(t.data.type){case`IFRAME_READY`:r(e),i({iframe:e,appearance:n.appearance});break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:i({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`PAYMENT_INTENT_CONFIRMATION_SUCCEEDED`:n.onPaymentIntentConfirmationSucceeded?.(t.data.paymentIntent);break;case`SETUP_INTENT_CONFIRMATION_SUCCEEDED`:n.onSetupIntentConfirmationSucceeded?.(t.data.setupIntent);break;case`CONFIRMATION_FAILED`:n.onConfirmationFailed(t.data.errorMessage);break}}return window.addEventListener(`message`,a),{update(t){let r=`appearance`in t;n={...n,...t},r&&i({iframe:e,appearance:n.appearance})},destroy(){window.removeEventListener(`message`,a)}}}function A(e){if(typeof e==`string`){let t=document.querySelector(e);if(!(t instanceof HTMLElement))throw Error(`[amos-js] Container "${e}" did not match any HTMLElement.`);return t}return e}var j={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`};function M({src:e,title:t,name:n,height:r,allow:i}){let a=document.createElement(`iframe`);return a.src=e,a.title=t,a.name=n,a.setAttribute(`role`,`presentation`),a.scrolling=`no`,i&&(a.allow=i),Object.assign(a.style,j,{height:r}),a}function N(e,t){let n=A(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t,s=M({src:T(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:D(i,a)});n.appendChild(s);let c=k(s,{...o,onHeightChange:e=>{s.style.height=e,o.onHeightChange?.(e)},onAppearanceReady:()=>{s.style.opacity=`1`,o.onAppearanceReady?.()}});return{iframe:s,update:c.update,destroy(){c.destroy(),s.remove()}}}function P(e,t){let n=A(e),{renderToken:r,billingAddressRequirement:i=`country`,...a}=t,o=M({src:E(r,i),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:O(i)});n.appendChild(o);let s=k(o,{...a,onHeightChange:e=>{o.style.height=e,a.onHeightChange?.(e)},onAppearanceReady:()=>{o.style.opacity=`1`,a.onAppearanceReady?.()}});return{iframe:o,update:s.update,destroy(){s.destroy(),o.remove()}}}function F(e,t){let n=A(e),{renderToken:r,...i}=t,a=M({src:v(r),title:`Secure Google Pay button powered by Amos`,name:`amos-google-pay-button`,height:y(),allow:`payment`});n.appendChild(a);let o=b(a,{...i,onHeightChange:e=>{a.style.height=e,i.onHeightChange?.(e)},onAppearanceReady:()=>{a.style.opacity=`1`,i.onAppearanceReady?.()}});return{iframe:a,update:o.update,destroy(){o.destroy(),a.remove()}}}function I(e,t){let n=A(e),{renderToken:r,...i}=t,a=M({src:p(r),title:`Secure Apple Pay button powered by Amos`,name:`amos-apple-pay-button`,height:m(),allow:`payment`});n.appendChild(a);let o=_(a,{...i,onHeightChange:e=>{a.style.height=e,i.onHeightChange?.(e)},onAppearanceReady:()=>{a.style.opacity=`1`,i.onAppearanceReady?.()}});return{iframe:a,update:o.update,destroy(){o.destroy(),a.remove()}}}exports.attachApplePayButtonListeners=_,exports.attachGooglePayButtonListeners=b,exports.attachPaymentMethodFormListeners=k,exports.confirmPaymentIntent=u,exports.confirmSetupIntent=d,exports.createMessage=n,exports.decodeJwt=e,exports.formatGooglePayPaymentData=x,exports.getApplePayButtonInitialHeight=m,exports.getApplePayButtonSrc=p,exports.getBankAccountFormInitialHeight=O,exports.getBankAccountFormSrc=E,exports.getCreditCardFormInitialHeight=D,exports.getCreditCardFormSrc=T,exports.getEmbedOrigin=t,exports.getGooglePayButtonInitialHeight=y,exports.getGooglePayButtonSrc=v,exports.hasNativeApplePaySession=s,exports.mountAmosApplePayButton=I,exports.mountAmosBankAccountPaymentMethodForm=P,exports.mountAmosCreditCardPaymentMethodForm=N,exports.mountAmosGooglePayButton=F,exports.sendConfirmationFailed=f,exports.sendParentReadyMessage=r,exports.updateAmount=a,exports.updateAppearance=i,exports.updateMerchantName=o,exports.updateNativeApplePaySession=c,exports.validateForm=l;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`data-amos-apple-pay-waiting`;function t({onCancel:t}){let n=document.querySelector(`[${e}]`);if(n)return n;let r=document.createElement(`div`);r.setAttribute(e,`true`),r.setAttribute(`role`,`dialog`),r.setAttribute(`aria-modal`,`true`),r.setAttribute(`aria-labelledby`,`amos-apple-pay-waiting-title`),Object.assign(r.style,{position:`fixed`,inset:`0`,zIndex:`2147483646`,display:`flex`,alignItems:`center`,justifyContent:`center`,padding:`24px`,boxSizing:`border-box`,background:`rgba(0, 0, 0, 0.55)`,fontFamily:`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif`});let i=document.createElement(`div`);Object.assign(i.style,{width:`100%`,maxWidth:`360px`,borderRadius:`12px`,background:`#fff`,padding:`28px 24px 20px`,boxSizing:`border-box`,textAlign:`center`,boxShadow:`0 12px 40px rgba(0, 0, 0, 0.25)`});let a=document.createElement(`div`);a.setAttribute(`aria-hidden`,`true`),Object.assign(a.style,{display:`inline-flex`,alignItems:`center`,justifyContent:`center`,gap:`6px`,marginBottom:`16px`,fontSize:`28px`,fontWeight:`600`,letterSpacing:`-0.02em`,color:`#000`,lineHeight:`1`}),a.innerHTML=`<svg width="22" height="26" viewBox="0 0 14 17" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M13.072 5.846c-.1.08-1.873 1.09-1.873 3.34 0 2.61 2.29 3.53 2.36 3.55-.04.1-.368 1.27-.766 2.52-.35 1.09-.72 2.18-1.28 2.18-.55 0-.73-.36-1.43-.36-.71 0-.93.37-1.48.37-.55 0-.93-.99-1.35-2.01-.5-1.2-.88-2.43-.88-3.85 0-2.26 1.47-3.46 2.91-3.46.57 0 1.11.38 1.49.38.37 0 .98-.45 1.7-.45.28 0 1.27.03 1.97 1.01ZM9.52 3.37c.3-.36.52-.86.52-1.36 0-.07 0-.14-.01-.2-.5.02-1.1.33-1.46.75-.28.32-.55.84-.55 1.35 0 .07.01.15.02.17.04.01.1.02.16.02.45 0 1.02-.3 1.32-.73Z"/></svg><span>Pay</span>`;let o=document.createElement(`p`);o.id=`amos-apple-pay-waiting-title`,Object.assign(o.style,{margin:`0 0 20px`,fontSize:`15px`,lineHeight:`1.45`,color:`#1a1a1a`}),o.textContent=`Complete your payment in the open Apple Pay window, or close Apple Pay to continue paying another way.`;let s=document.createElement(`button`);return s.type=`button`,s.textContent=`Cancel payment`,Object.assign(s.style,{display:`block`,width:`100%`,border:`none`,borderRadius:`8px`,padding:`12px 16px`,background:`#2c2c2e`,color:`#fff`,fontSize:`15px`,fontWeight:`500`,cursor:`pointer`}),s.addEventListener(`click`,t),i.append(a,o,s),r.append(i),document.body.append(r),r}function n(){document.querySelector(`[${e}]`)?.remove()}function r(e){let[t=``,n=``,r=``]=e?.split(`.`)??[],i=typeof atob==`function`?atob:e=>Buffer.from(e,`base64`).toString(`utf8`);return{header:JSON.parse(i(t)),payload:JSON.parse(i(n)),signature:r}}function i(e){let{env:t=`sandbox`}=r(e).payload;switch(t){case`production`:return`https://embed.amos.com`;case`sandbox`:return`https://embed-sandbox.amos.com`;default:return`https://embed-sandbox.amos.com`}}function a(e){return e}function o(e){e?.contentWindow?.postMessage(a({type:`PARENT_ACKNOWLEDGED_IFRAME_READY`}),`*`)}function s({iframe:e,appearance:t={}}){e?.contentWindow?.postMessage(a({type:`UPDATE_APPEARANCE`,appearance:t}),`*`)}function c({iframe:e,amount:t}){e?.contentWindow?.postMessage(a({type:`UPDATE_AMOUNT`,amount:t}),`*`)}function l({iframe:e,merchantName:t}){e?.contentWindow?.postMessage(a({type:`UPDATE_MERCHANT_NAME`,merchantName:t}),`*`)}function u({iframe:e}){let t=crypto.randomUUID();return new Promise(n=>{e?.contentWindow?.postMessage(a({type:`VALIDATE_FORM`,requestId:t}),`*`);let r=setTimeout(()=>{window.removeEventListener(`message`,i),n(!1)},5e3);function i(e){e.data.type===`VALIDATE_FORM`&&e.data.requestId===t&&(window.removeEventListener(`message`,i),clearTimeout(r),n(e.data.isValid??!1))}window.addEventListener(`message`,i)})}function d({iframe:e,token:t}){let{payment_intent_id:n}=r(t).payload;e?.contentWindow?.postMessage(a({type:`CONFIRM_PAYMENT_INTENT`,token:t,id:n??void 0}),`*`)}function f({iframe:e,token:t}){let{setup_intent_id:n}=r(t).payload;e?.contentWindow?.postMessage(a({type:`CONFIRM_SETUP_INTENT`,token:t,id:n??void 0}),`*`)}function p({iframe:e,errorMessage:t}){e?.contentWindow?.postMessage(a({type:`CONFIRMATION_FAILED`,errorMessage:t}),`*`)}function m(e){return`${i(e)}/iframe/apple-pay?token=${e}`}function h(){return`40px`}function g(e){e.contentWindow?.postMessage(a({type:`APPLE_PAY_CANCEL`}),`*`)}function _(e,r){let i={...r};function a(){c({iframe:e,amount:i.amount})}function u(){l({iframe:e,merchantName:i.merchantName})}function f(r){if(r.source===e.contentWindow)switch(r.data.type){case`IFRAME_READY`:o(e),s({iframe:e,appearance:i.appearance}),a(),u();break;case`UPDATE_HEIGHT`:i.onHeightChange?.(r.data.height);break;case`UPDATE_APPEARANCE`:s({iframe:e,appearance:r.data.appearance});break;case`UPDATED_APPEARANCE`:i.onAppearanceReady?.();break;case`APPLE_PAY_WINDOW_OPEN`:t({onCancel:()=>{g(e),n()}});break;case`APPLE_PAY_WINDOW_CLOSE`:n();break;case`CREATE_PAYMENT_INTENT`:i.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:r.data.paymentIntentCreateAttributes,customerCreateAttributes:r.data.customerCreateAttributes}).then(t=>{d({iframe:e,token:t})}).catch(t=>{p({iframe:e,errorMessage:t instanceof Error?t.message:`Unknown error`})});break;case`PAYMENT_INTENT_CONFIRMATION_SUCCEEDED`:n(),i.onPaymentIntentConfirmationSucceeded(r.data.paymentIntent);break;case`CONFIRMATION_FAILED`:n(),i.onConfirmationFailed(r.data.errorMessage);break}}return window.addEventListener(`message`,f),{update(t){let n=`appearance`in t,r=`amount`in t,o=`merchantName`in t;i={...i,...t},n&&s({iframe:e,appearance:i.appearance}),r&&a(),o&&u()},destroy(){window.removeEventListener(`message`,f),n()}}}function v(e){return`${i(e)}/iframe/google-pay?token=${e}`}function y(){return`40px`}function b(e,t){let n={...t};function r(){c({iframe:e,amount:n.amount})}function i(){l({iframe:e,merchantName:n.merchantName})}function a(t){switch(t.data.type){case`IFRAME_READY`:o(e),s({iframe:e,appearance:n.appearance}),r(),i();break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:s({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`CREATE_PAYMENT_INTENT`:n.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:t.data.paymentIntentCreateAttributes,customerCreateAttributes:t.data.customerCreateAttributes}).then(t=>{d({iframe:e,token:t})}).catch(t=>{p({iframe:e,errorMessage:t instanceof Error?t.message:`Unknown error`})});break;case`PAYMENT_INTENT_CONFIRMATION_SUCCEEDED`:n.onPaymentIntentConfirmationSucceeded(t.data.paymentIntent);break;case`CONFIRMATION_FAILED`:n.onConfirmationFailed(t.data.errorMessage);break}}return window.addEventListener(`message`,a),{update(t){let a=`appearance`in t,o=`amount`in t,c=`merchantName`in t;n={...n,...t},a&&s({iframe:e,appearance:n.appearance}),o&&r(),c&&i()},destroy(){window.removeEventListener(`message`,a)}}}function x({paymentData:e}){return{paymentMethod:{type:`googlepay`,billing_address_attributes:{name:e.shippingAddress?.name,address_line1:e.shippingAddress?.address1,address_line2:e.shippingAddress?.address2,city:e.shippingAddress?.locality,state:e.shippingAddress?.administrativeArea,postal_code:e.shippingAddress?.postalCode,country:e.shippingAddress?.countryCode,email:e.email,phone:e.shippingAddress?.phoneNumber},card_profile_attributes:{wallet_provider:`googlepay`,wallet_payload:e.paymentMethodData.tokenizationData.token,wallet_last4:e.paymentMethodData.info?.cardDetails,wallet_brand:(()=>{switch(e.paymentMethodData.info?.cardNetwork){case`AMEX`:return`american_express`;case`VISA`:return`visa`;case`MASTERCARD`:return`master`;case`DISCOVER`:return`discover`;default:return}})()}}}}var S={country:212,full:452},C=80,w={country:400,full:640};function T(e,t={cardholderName:!1},n=`country`){let r=Object.entries(t).filter(([,e])=>e).map(([e])=>e).join(`,`),a=new URLSearchParams({token:e,additionalFields:r,billingAddressRequirement:n});return`${i(e)}/iframe/card?${a}`}function E(e,t=`country`){let n=new URLSearchParams({token:e,billingAddressRequirement:t});return`${i(e)}/iframe/bank?${n}`}function D(e={cardholderName:!1},t=`country`){return`${(S[t]??S.country)+(e.cardholderName?C:0)}px`}function O(e=`country`){return`${w[e]??w.country}px`}function k(e,t){let n={...t};function r(t){switch(t.data.type){case`IFRAME_READY`:o(e),s({iframe:e,appearance:n.appearance});break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:s({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`PAYMENT_INTENT_CONFIRMATION_SUCCEEDED`:n.onPaymentIntentConfirmationSucceeded?.(t.data.paymentIntent);break;case`SETUP_INTENT_CONFIRMATION_SUCCEEDED`:n.onSetupIntentConfirmationSucceeded?.(t.data.setupIntent);break;case`CONFIRMATION_FAILED`:n.onConfirmationFailed(t.data.errorMessage);break}}return window.addEventListener(`message`,r),{update(t){let r=`appearance`in t;n={...n,...t},r&&s({iframe:e,appearance:n.appearance})},destroy(){window.removeEventListener(`message`,r)}}}function A(e){if(typeof e==`string`){let t=document.querySelector(e);if(!(t instanceof HTMLElement))throw Error(`[amos-js] Container "${e}" did not match any HTMLElement.`);return t}return e}var j={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`};function M({src:e,title:t,name:n,height:r,allow:i}){let a=document.createElement(`iframe`);return a.src=e,a.title=t,a.name=n,a.setAttribute(`role`,`presentation`),a.scrolling=`no`,i&&(a.allow=i),Object.assign(a.style,j,{height:r}),a}function N(e,t){let n=A(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t,s=M({src:T(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:D(i,a)});n.appendChild(s);let c=k(s,{...o,onHeightChange:e=>{s.style.height=e,o.onHeightChange?.(e)},onAppearanceReady:()=>{s.style.opacity=`1`,o.onAppearanceReady?.()}});return{iframe:s,update:c.update,destroy(){c.destroy(),s.remove()}}}function P(e,t){let n=A(e),{renderToken:r,billingAddressRequirement:i=`country`,...a}=t,o=M({src:E(r,i),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:O(i)});n.appendChild(o);let s=k(o,{...a,onHeightChange:e=>{o.style.height=e,a.onHeightChange?.(e)},onAppearanceReady:()=>{o.style.opacity=`1`,a.onAppearanceReady?.()}});return{iframe:o,update:s.update,destroy(){s.destroy(),o.remove()}}}function F(e,t){let n=A(e),{renderToken:r,...i}=t,a=M({src:v(r),title:`Secure Google Pay button powered by Amos`,name:`amos-google-pay-button`,height:y(),allow:`payment`});n.appendChild(a);let o=b(a,{...i,onHeightChange:e=>{a.style.height=e,i.onHeightChange?.(e)},onAppearanceReady:()=>{a.style.opacity=`1`,i.onAppearanceReady?.()}});return{iframe:a,update:o.update,destroy(){o.destroy(),a.remove()}}}function I(e,t){let n=A(e),{renderToken:r,...i}=t,a=M({src:m(r),title:`Secure Apple Pay button powered by Amos`,name:`amos-apple-pay-button`,height:h(),allow:`payment`});n.appendChild(a);let o=_(a,{...i,onHeightChange:e=>{a.style.height=e,i.onHeightChange?.(e)},onAppearanceReady:()=>{a.style.opacity=`1`,i.onAppearanceReady?.()}});return{iframe:a,update:o.update,destroy(){o.destroy(),a.remove()}}}exports.attachApplePayButtonListeners=_,exports.attachGooglePayButtonListeners=b,exports.attachPaymentMethodFormListeners=k,exports.confirmPaymentIntent=d,exports.confirmSetupIntent=f,exports.createMessage=a,exports.decodeJwt=r,exports.formatGooglePayPaymentData=x,exports.getApplePayButtonInitialHeight=h,exports.getApplePayButtonSrc=m,exports.getBankAccountFormInitialHeight=O,exports.getBankAccountFormSrc=E,exports.getCreditCardFormInitialHeight=D,exports.getCreditCardFormSrc=T,exports.getEmbedOrigin=i,exports.getGooglePayButtonInitialHeight=y,exports.getGooglePayButtonSrc=v,exports.mountAmosApplePayButton=I,exports.mountAmosBankAccountPaymentMethodForm=P,exports.mountAmosCreditCardPaymentMethodForm=N,exports.mountAmosGooglePayButton=F,exports.sendConfirmationFailed=p,exports.sendParentReadyMessage=o,exports.updateAmount=c,exports.updateAppearance=s,exports.updateMerchantName=l,exports.validateForm=u;
package/dist/index.mjs CHANGED
@@ -1,5 +1,72 @@
1
+ //#region src/apple-pay-waiting-overlay.ts
2
+ var e = "data-amos-apple-pay-waiting";
3
+ function t({ onCancel: t }) {
4
+ let n = document.querySelector(`[${e}]`);
5
+ if (n) return n;
6
+ let r = document.createElement("div");
7
+ r.setAttribute(e, "true"), r.setAttribute("role", "dialog"), r.setAttribute("aria-modal", "true"), r.setAttribute("aria-labelledby", "amos-apple-pay-waiting-title"), Object.assign(r.style, {
8
+ position: "fixed",
9
+ inset: "0",
10
+ zIndex: "2147483646",
11
+ display: "flex",
12
+ alignItems: "center",
13
+ justifyContent: "center",
14
+ padding: "24px",
15
+ boxSizing: "border-box",
16
+ background: "rgba(0, 0, 0, 0.55)",
17
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif"
18
+ });
19
+ let i = document.createElement("div");
20
+ Object.assign(i.style, {
21
+ width: "100%",
22
+ maxWidth: "360px",
23
+ borderRadius: "12px",
24
+ background: "#fff",
25
+ padding: "28px 24px 20px",
26
+ boxSizing: "border-box",
27
+ textAlign: "center",
28
+ boxShadow: "0 12px 40px rgba(0, 0, 0, 0.25)"
29
+ });
30
+ let a = document.createElement("div");
31
+ a.setAttribute("aria-hidden", "true"), Object.assign(a.style, {
32
+ display: "inline-flex",
33
+ alignItems: "center",
34
+ justifyContent: "center",
35
+ gap: "6px",
36
+ marginBottom: "16px",
37
+ fontSize: "28px",
38
+ fontWeight: "600",
39
+ letterSpacing: "-0.02em",
40
+ color: "#000",
41
+ lineHeight: "1"
42
+ }), a.innerHTML = "<svg width=\"22\" height=\"26\" viewBox=\"0 0 14 17\" fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M13.072 5.846c-.1.08-1.873 1.09-1.873 3.34 0 2.61 2.29 3.53 2.36 3.55-.04.1-.368 1.27-.766 2.52-.35 1.09-.72 2.18-1.28 2.18-.55 0-.73-.36-1.43-.36-.71 0-.93.37-1.48.37-.55 0-.93-.99-1.35-2.01-.5-1.2-.88-2.43-.88-3.85 0-2.26 1.47-3.46 2.91-3.46.57 0 1.11.38 1.49.38.37 0 .98-.45 1.7-.45.28 0 1.27.03 1.97 1.01ZM9.52 3.37c.3-.36.52-.86.52-1.36 0-.07 0-.14-.01-.2-.5.02-1.1.33-1.46.75-.28.32-.55.84-.55 1.35 0 .07.01.15.02.17.04.01.1.02.16.02.45 0 1.02-.3 1.32-.73Z\"/></svg><span>Pay</span>";
43
+ let o = document.createElement("p");
44
+ o.id = "amos-apple-pay-waiting-title", Object.assign(o.style, {
45
+ margin: "0 0 20px",
46
+ fontSize: "15px",
47
+ lineHeight: "1.45",
48
+ color: "#1a1a1a"
49
+ }), o.textContent = "Complete your payment in the open Apple Pay window, or close Apple Pay to continue paying another way.";
50
+ let s = document.createElement("button");
51
+ return s.type = "button", s.textContent = "Cancel payment", Object.assign(s.style, {
52
+ display: "block",
53
+ width: "100%",
54
+ border: "none",
55
+ borderRadius: "8px",
56
+ padding: "12px 16px",
57
+ background: "#2c2c2e",
58
+ color: "#fff",
59
+ fontSize: "15px",
60
+ fontWeight: "500",
61
+ cursor: "pointer"
62
+ }), s.addEventListener("click", t), i.append(a, o, s), r.append(i), document.body.append(r), r;
63
+ }
64
+ function n() {
65
+ document.querySelector(`[${e}]`)?.remove();
66
+ }
67
+ //#endregion
1
68
  //#region src/jwt.ts
2
- function e(e) {
69
+ function r(e) {
3
70
  let [t = "", n = "", r = ""] = e?.split(".") ?? [], i = typeof atob == "function" ? atob : (e) => Buffer.from(e, "base64").toString("utf8");
4
71
  return {
5
72
  header: JSON.parse(i(t)),
@@ -7,9 +74,9 @@ function e(e) {
7
74
  signature: r
8
75
  };
9
76
  }
10
- function t(t) {
11
- let { env: n = "sandbox" } = e(t).payload;
12
- switch (n) {
77
+ function i(e) {
78
+ let { env: t = "sandbox" } = r(e).payload;
79
+ switch (t) {
13
80
  case "production": return "https://embed.amos.com";
14
81
  case "sandbox": return "https://embed-sandbox.amos.com";
15
82
  default: return "https://embed-sandbox.amos.com";
@@ -17,230 +84,198 @@ function t(t) {
17
84
  }
18
85
  //#endregion
19
86
  //#region src/types.ts
20
- function n(e) {
87
+ function a(e) {
21
88
  return e;
22
89
  }
23
90
  //#endregion
24
91
  //#region src/messaging.ts
25
- function r(e) {
26
- e?.contentWindow?.postMessage(n({ type: "PARENT_ACKNOWLEDGED_IFRAME_READY" }), "*");
92
+ function o(e) {
93
+ e?.contentWindow?.postMessage(a({ type: "PARENT_ACKNOWLEDGED_IFRAME_READY" }), "*");
27
94
  }
28
- function i({ iframe: e, appearance: t = {} }) {
29
- e?.contentWindow?.postMessage(n({
95
+ function s({ iframe: e, appearance: t = {} }) {
96
+ e?.contentWindow?.postMessage(a({
30
97
  type: "UPDATE_APPEARANCE",
31
98
  appearance: t
32
99
  }), "*");
33
100
  }
34
- function a({ iframe: e, amount: t }) {
35
- e?.contentWindow?.postMessage(n({
101
+ function c({ iframe: e, amount: t }) {
102
+ e?.contentWindow?.postMessage(a({
36
103
  type: "UPDATE_AMOUNT",
37
104
  amount: t
38
105
  }), "*");
39
106
  }
40
- function o({ iframe: e, merchantName: t }) {
41
- e?.contentWindow?.postMessage(n({
107
+ function l({ iframe: e, merchantName: t }) {
108
+ e?.contentWindow?.postMessage(a({
42
109
  type: "UPDATE_MERCHANT_NAME",
43
110
  merchantName: t
44
111
  }), "*");
45
112
  }
46
- function s() {
47
- return "ApplePaySession" in globalThis;
48
- }
49
- function c({ iframe: e, hasNativeApplePaySession: t }) {
50
- e?.contentWindow?.postMessage(n({
51
- type: "UPDATE_NATIVE_APPLE_PAY_SESSION",
52
- hasNativeApplePaySession: t
53
- }), "*");
54
- }
55
- function l({ iframe: e }) {
113
+ function u({ iframe: e }) {
56
114
  let t = crypto.randomUUID();
57
- return new Promise((r) => {
58
- e?.contentWindow?.postMessage(n({
115
+ return new Promise((n) => {
116
+ e?.contentWindow?.postMessage(a({
59
117
  type: "VALIDATE_FORM",
60
118
  requestId: t
61
119
  }), "*");
62
- let i = setTimeout(() => {
63
- window.removeEventListener("message", a), r(!1);
120
+ let r = setTimeout(() => {
121
+ window.removeEventListener("message", i), n(!1);
64
122
  }, 5e3);
65
- function a(e) {
66
- e.data.type === "VALIDATE_FORM" && e.data.requestId === t && (window.removeEventListener("message", a), clearTimeout(i), r(e.data.isValid ?? !1));
123
+ function i(e) {
124
+ e.data.type === "VALIDATE_FORM" && e.data.requestId === t && (window.removeEventListener("message", i), clearTimeout(r), n(e.data.isValid ?? !1));
67
125
  }
68
- window.addEventListener("message", a);
126
+ window.addEventListener("message", i);
69
127
  });
70
128
  }
71
- function u({ iframe: t, token: r }) {
72
- let { payment_intent_id: i } = e(r).payload;
73
- t?.contentWindow?.postMessage(n({
129
+ function d({ iframe: e, token: t }) {
130
+ let { payment_intent_id: n } = r(t).payload;
131
+ e?.contentWindow?.postMessage(a({
74
132
  type: "CONFIRM_PAYMENT_INTENT",
75
- token: r,
76
- id: i ?? void 0
133
+ token: t,
134
+ id: n ?? void 0
77
135
  }), "*");
78
136
  }
79
- function d({ iframe: t, token: r }) {
80
- let { setup_intent_id: i } = e(r).payload;
81
- t?.contentWindow?.postMessage(n({
137
+ function f({ iframe: e, token: t }) {
138
+ let { setup_intent_id: n } = r(t).payload;
139
+ e?.contentWindow?.postMessage(a({
82
140
  type: "CONFIRM_SETUP_INTENT",
83
- token: r,
84
- id: i ?? void 0
141
+ token: t,
142
+ id: n ?? void 0
85
143
  }), "*");
86
144
  }
87
- function f({ iframe: e, errorMessage: t }) {
88
- e?.contentWindow?.postMessage(n({
145
+ function p({ iframe: e, errorMessage: t }) {
146
+ e?.contentWindow?.postMessage(a({
89
147
  type: "CONFIRMATION_FAILED",
90
148
  errorMessage: t
91
149
  }), "*");
92
150
  }
93
151
  //#endregion
94
152
  //#region src/apple-pay.ts
95
- function p(e) {
96
- return `${t(e)}/iframe/apple-pay?token=${e}`;
153
+ function m(e) {
154
+ return `${i(e)}/iframe/apple-pay?token=${e}`;
97
155
  }
98
- function m() {
156
+ function h() {
99
157
  return "40px";
100
158
  }
101
- function h(e) {
102
- let t = {
103
- cssText: e.style.cssText,
104
- bodyOverflow: document.body.style.overflow
105
- };
106
- return document.body.style.overflow = "hidden", Object.assign(e.style, {
107
- position: "fixed",
108
- inset: "0px",
109
- width: "100vw",
110
- height: "100vh",
111
- maxWidth: "none",
112
- maxHeight: "none",
113
- margin: "0",
114
- border: "0",
115
- zIndex: "2147483647",
116
- opacity: "1",
117
- background: "#ffffff"
118
- }), t;
119
- }
120
- function g(e, t) {
121
- t && (document.body.style.overflow = t.bodyOverflow, e.style.cssText = t.cssText);
122
- }
123
- function _(e, t) {
124
- let n = { ...t }, l = null;
125
- function d() {
126
- a({
127
- iframe: e,
128
- amount: n.amount
129
- });
130
- }
131
- function p() {
132
- o({
159
+ function g(e) {
160
+ e.contentWindow?.postMessage(a({ type: "APPLE_PAY_CANCEL" }), "*");
161
+ }
162
+ function _(e, r) {
163
+ let i = { ...r };
164
+ function a() {
165
+ c({
133
166
  iframe: e,
134
- merchantName: n.merchantName
167
+ amount: i.amount
135
168
  });
136
169
  }
137
- function m() {
138
- c({
170
+ function u() {
171
+ l({
139
172
  iframe: e,
140
- hasNativeApplePaySession: s()
173
+ merchantName: i.merchantName
141
174
  });
142
175
  }
143
- function _(t) {
144
- if (t.source === e.contentWindow) switch (t.data.type) {
176
+ function f(r) {
177
+ if (r.source === e.contentWindow) switch (r.data.type) {
145
178
  case "IFRAME_READY":
146
- r(e), i({
179
+ o(e), s({
147
180
  iframe: e,
148
- appearance: n.appearance
149
- }), m(), d(), p();
181
+ appearance: i.appearance
182
+ }), a(), u();
150
183
  break;
151
184
  case "UPDATE_HEIGHT":
152
- l || n.onHeightChange?.(t.data.height);
185
+ i.onHeightChange?.(r.data.height);
153
186
  break;
154
187
  case "UPDATE_APPEARANCE":
155
- i({
188
+ s({
156
189
  iframe: e,
157
- appearance: t.data.appearance
190
+ appearance: r.data.appearance
158
191
  });
159
192
  break;
160
193
  case "UPDATED_APPEARANCE":
161
- n.onAppearanceReady?.();
194
+ i.onAppearanceReady?.();
162
195
  break;
163
- case "EXPAND_IFRAME":
164
- l ||= h(e);
196
+ case "APPLE_PAY_WINDOW_OPEN":
197
+ t({ onCancel: () => {
198
+ g(e), n();
199
+ } });
165
200
  break;
166
- case "COLLAPSE_IFRAME":
167
- g(e, l), l = null;
201
+ case "APPLE_PAY_WINDOW_CLOSE":
202
+ n();
168
203
  break;
169
204
  case "CREATE_PAYMENT_INTENT":
170
- n.onInitiatePaymentIntentRequest({
171
- paymentIntentCreateAttributes: t.data.paymentIntentCreateAttributes,
172
- customerCreateAttributes: t.data.customerCreateAttributes
205
+ i.onInitiatePaymentIntentRequest({
206
+ paymentIntentCreateAttributes: r.data.paymentIntentCreateAttributes,
207
+ customerCreateAttributes: r.data.customerCreateAttributes
173
208
  }).then((t) => {
174
- u({
209
+ d({
175
210
  iframe: e,
176
211
  token: t
177
212
  });
178
213
  }).catch((t) => {
179
- f({
214
+ p({
180
215
  iframe: e,
181
216
  errorMessage: t instanceof Error ? t.message : "Unknown error"
182
217
  });
183
218
  });
184
219
  break;
185
220
  case "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED":
186
- n.onPaymentIntentConfirmationSucceeded(t.data.paymentIntent);
221
+ n(), i.onPaymentIntentConfirmationSucceeded(r.data.paymentIntent);
187
222
  break;
188
223
  case "CONFIRMATION_FAILED":
189
- n.onConfirmationFailed(t.data.errorMessage);
224
+ n(), i.onConfirmationFailed(r.data.errorMessage);
190
225
  break;
191
226
  }
192
227
  }
193
- return window.addEventListener("message", _), {
228
+ return window.addEventListener("message", f), {
194
229
  update(t) {
195
- let r = "appearance" in t, a = "amount" in t, o = "merchantName" in t;
196
- n = {
197
- ...n,
230
+ let n = "appearance" in t, r = "amount" in t, o = "merchantName" in t;
231
+ i = {
232
+ ...i,
198
233
  ...t
199
- }, r && i({
234
+ }, n && s({
200
235
  iframe: e,
201
- appearance: n.appearance
202
- }), a && d(), o && p();
236
+ appearance: i.appearance
237
+ }), r && a(), o && u();
203
238
  },
204
239
  destroy() {
205
- window.removeEventListener("message", _), g(e, l), l = null;
240
+ window.removeEventListener("message", f), n();
206
241
  }
207
242
  };
208
243
  }
209
244
  //#endregion
210
245
  //#region src/google-pay.ts
211
246
  function v(e) {
212
- return `${t(e)}/iframe/google-pay?token=${e}`;
247
+ return `${i(e)}/iframe/google-pay?token=${e}`;
213
248
  }
214
249
  function y() {
215
250
  return "40px";
216
251
  }
217
252
  function b(e, t) {
218
253
  let n = { ...t };
219
- function s() {
220
- a({
254
+ function r() {
255
+ c({
221
256
  iframe: e,
222
257
  amount: n.amount
223
258
  });
224
259
  }
225
- function c() {
226
- o({
260
+ function i() {
261
+ l({
227
262
  iframe: e,
228
263
  merchantName: n.merchantName
229
264
  });
230
265
  }
231
- function l(t) {
266
+ function a(t) {
232
267
  switch (t.data.type) {
233
268
  case "IFRAME_READY":
234
- r(e), i({
269
+ o(e), s({
235
270
  iframe: e,
236
271
  appearance: n.appearance
237
- }), s(), c();
272
+ }), r(), i();
238
273
  break;
239
274
  case "UPDATE_HEIGHT":
240
275
  n.onHeightChange?.(t.data.height);
241
276
  break;
242
277
  case "UPDATE_APPEARANCE":
243
- i({
278
+ s({
244
279
  iframe: e,
245
280
  appearance: t.data.appearance
246
281
  });
@@ -253,12 +288,12 @@ function b(e, t) {
253
288
  paymentIntentCreateAttributes: t.data.paymentIntentCreateAttributes,
254
289
  customerCreateAttributes: t.data.customerCreateAttributes
255
290
  }).then((t) => {
256
- u({
291
+ d({
257
292
  iframe: e,
258
293
  token: t
259
294
  });
260
295
  }).catch((t) => {
261
- f({
296
+ p({
262
297
  iframe: e,
263
298
  errorMessage: t instanceof Error ? t.message : "Unknown error"
264
299
  });
@@ -272,19 +307,19 @@ function b(e, t) {
272
307
  break;
273
308
  }
274
309
  }
275
- return window.addEventListener("message", l), {
310
+ return window.addEventListener("message", a), {
276
311
  update(t) {
277
- let r = "appearance" in t, a = "amount" in t, o = "merchantName" in t;
312
+ let a = "appearance" in t, o = "amount" in t, c = "merchantName" in t;
278
313
  n = {
279
314
  ...n,
280
315
  ...t
281
- }, r && i({
316
+ }, a && s({
282
317
  iframe: e,
283
318
  appearance: n.appearance
284
- }), a && s(), o && c();
319
+ }), o && r(), c && i();
285
320
  },
286
321
  destroy() {
287
- window.removeEventListener("message", l);
322
+ window.removeEventListener("message", a);
288
323
  }
289
324
  };
290
325
  }
@@ -327,20 +362,20 @@ var S = {
327
362
  country: 400,
328
363
  full: 640
329
364
  };
330
- function T(e, n = { cardholderName: !1 }, r = "country") {
331
- let i = Object.entries(n).filter(([, e]) => e).map(([e]) => e).join(","), a = new URLSearchParams({
365
+ function T(e, t = { cardholderName: !1 }, n = "country") {
366
+ let r = Object.entries(t).filter(([, e]) => e).map(([e]) => e).join(","), a = new URLSearchParams({
332
367
  token: e,
333
- additionalFields: i,
334
- billingAddressRequirement: r
368
+ additionalFields: r,
369
+ billingAddressRequirement: n
335
370
  });
336
- return `${t(e)}/iframe/card?${a}`;
371
+ return `${i(e)}/iframe/card?${a}`;
337
372
  }
338
- function E(e, n = "country") {
339
- let r = new URLSearchParams({
373
+ function E(e, t = "country") {
374
+ let n = new URLSearchParams({
340
375
  token: e,
341
- billingAddressRequirement: n
376
+ billingAddressRequirement: t
342
377
  });
343
- return `${t(e)}/iframe/bank?${r}`;
378
+ return `${i(e)}/iframe/bank?${n}`;
344
379
  }
345
380
  function D(e = { cardholderName: !1 }, t = "country") {
346
381
  return `${(S[t] ?? S.country) + (e.cardholderName ? C : 0)}px`;
@@ -350,10 +385,10 @@ function O(e = "country") {
350
385
  }
351
386
  function k(e, t) {
352
387
  let n = { ...t };
353
- function a(t) {
388
+ function r(t) {
354
389
  switch (t.data.type) {
355
390
  case "IFRAME_READY":
356
- r(e), i({
391
+ o(e), s({
357
392
  iframe: e,
358
393
  appearance: n.appearance
359
394
  });
@@ -362,7 +397,7 @@ function k(e, t) {
362
397
  n.onHeightChange?.(t.data.height);
363
398
  break;
364
399
  case "UPDATE_APPEARANCE":
365
- i({
400
+ s({
366
401
  iframe: e,
367
402
  appearance: t.data.appearance
368
403
  });
@@ -381,19 +416,19 @@ function k(e, t) {
381
416
  break;
382
417
  }
383
418
  }
384
- return window.addEventListener("message", a), {
419
+ return window.addEventListener("message", r), {
385
420
  update(t) {
386
421
  let r = "appearance" in t;
387
422
  n = {
388
423
  ...n,
389
424
  ...t
390
- }, r && i({
425
+ }, r && s({
391
426
  iframe: e,
392
427
  appearance: n.appearance
393
428
  });
394
429
  },
395
430
  destroy() {
396
- window.removeEventListener("message", a);
431
+ window.removeEventListener("message", r);
397
432
  }
398
433
  };
399
434
  }
@@ -496,10 +531,10 @@ function F(e, t) {
496
531
  }
497
532
  function I(e, t) {
498
533
  let n = A(e), { renderToken: r, ...i } = t, a = M({
499
- src: p(r),
534
+ src: m(r),
500
535
  title: "Secure Apple Pay button powered by Amos",
501
536
  name: "amos-apple-pay-button",
502
- height: m(),
537
+ height: h(),
503
538
  allow: "payment"
504
539
  });
505
540
  n.appendChild(a);
@@ -521,4 +556,4 @@ function I(e, t) {
521
556
  };
522
557
  }
523
558
  //#endregion
524
- export { _ as attachApplePayButtonListeners, b as attachGooglePayButtonListeners, k as attachPaymentMethodFormListeners, u as confirmPaymentIntent, d as confirmSetupIntent, n as createMessage, e as decodeJwt, x as formatGooglePayPaymentData, m as getApplePayButtonInitialHeight, p as getApplePayButtonSrc, O as getBankAccountFormInitialHeight, E as getBankAccountFormSrc, D as getCreditCardFormInitialHeight, T as getCreditCardFormSrc, t as getEmbedOrigin, y as getGooglePayButtonInitialHeight, v as getGooglePayButtonSrc, s as hasNativeApplePaySession, I as mountAmosApplePayButton, P as mountAmosBankAccountPaymentMethodForm, N as mountAmosCreditCardPaymentMethodForm, F as mountAmosGooglePayButton, f as sendConfirmationFailed, r as sendParentReadyMessage, a as updateAmount, i as updateAppearance, o as updateMerchantName, c as updateNativeApplePaySession, l as validateForm };
559
+ export { _ as attachApplePayButtonListeners, b as attachGooglePayButtonListeners, k as attachPaymentMethodFormListeners, d as confirmPaymentIntent, f as confirmSetupIntent, a as createMessage, r as decodeJwt, x as formatGooglePayPaymentData, h as getApplePayButtonInitialHeight, m as getApplePayButtonSrc, O as getBankAccountFormInitialHeight, E as getBankAccountFormSrc, D as getCreditCardFormInitialHeight, T as getCreditCardFormSrc, i as getEmbedOrigin, y as getGooglePayButtonInitialHeight, v as getGooglePayButtonSrc, I as mountAmosApplePayButton, P as mountAmosBankAccountPaymentMethodForm, N as mountAmosCreditCardPaymentMethodForm, F as mountAmosGooglePayButton, p as sendConfirmationFailed, o as sendParentReadyMessage, c as updateAmount, s as updateAppearance, l as updateMerchantName, u as validateForm };
@@ -34,19 +34,6 @@ export declare function updateMerchantName({ iframe, merchantName, }: {
34
34
  iframe: Iframe;
35
35
  merchantName: string;
36
36
  }): void;
37
- /**
38
- * Whether the host page exposes a native `ApplePaySession` (Safari).
39
- * Non-Safari browsers load Apple's SDK inside the embed iframe instead.
40
- */
41
- export declare function hasNativeApplePaySession(): boolean;
42
- /**
43
- * Tell the Apple Pay iframe whether the parent has a native
44
- * `ApplePaySession`. Sent during the `IFRAME_READY` handshake.
45
- */
46
- export declare function updateNativeApplePaySession({ iframe, hasNativeApplePaySession, }: {
47
- iframe: Iframe;
48
- hasNativeApplePaySession: boolean;
49
- }): void;
50
37
  /**
51
38
  * Ask the embedded credit-card or bank-account iframe form to validate
52
39
  * its inputs.
package/dist/types.d.ts CHANGED
@@ -42,14 +42,6 @@ export type Message = {
42
42
  } | {
43
43
  type: "UPDATE_MERCHANT_NAME";
44
44
  merchantName: string;
45
- } | {
46
- /**
47
- * Parent → iframe: whether the host page has a native
48
- * `ApplePaySession` (Safari). When `false`, the iframe should
49
- * expand for Chrome's in-iframe QR handoff UI.
50
- */
51
- type: "UPDATE_NATIVE_APPLE_PAY_SESSION";
52
- hasNativeApplePaySession: boolean;
53
45
  } | {
54
46
  type: "UPDATE_APPEARANCE";
55
47
  appearance: Appearance;
@@ -77,15 +69,14 @@ export type Message = {
77
69
  } | {
78
70
  type: "UPDATED_APPEARANCE";
79
71
  } | {
80
- /**
81
- * Iframe → parent: expand the Apple Pay iframe to a full-viewport
82
- * overlay so Chrome's QR handoff UI is not clipped by the button
83
- * height. The Apple Pay session stays on the Amos embed origin.
84
- */
85
- type: "EXPAND_IFRAME";
72
+ /** Embed → parent: Apple Pay Code window / waiting UI should show. */
73
+ type: "APPLE_PAY_WINDOW_OPEN";
74
+ } | {
75
+ /** Embed parent: waiting UI should dismiss. */
76
+ type: "APPLE_PAY_WINDOW_CLOSE";
86
77
  } | {
87
- /** Iframeparent: restore the Apple Pay iframe to its button size. */
88
- type: "COLLAPSE_IFRAME";
78
+ /** Parentembed: user cancelled from the host-page waiting overlay. */
79
+ type: "APPLE_PAY_CANCEL";
89
80
  };
90
81
  /**
91
82
  * Identity helper that brands an object as a typed `Message`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amos.com/amos-js",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "main": "dist/index.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,103 @@
1
+ const OVERLAY_ATTRIBUTE = "data-amos-apple-pay-waiting";
2
+
3
+ /**
4
+ * Create (or return existing) full-viewport waiting UI on the host page while
5
+ * Apple Pay Code runs in a separate window. Cancel invokes `onCancel`.
6
+ */
7
+ export function showApplePayWaitingOverlay({
8
+ onCancel,
9
+ }: {
10
+ onCancel: () => void;
11
+ }): HTMLElement {
12
+ const existing = document.querySelector<HTMLElement>(
13
+ `[${OVERLAY_ATTRIBUTE}]`,
14
+ );
15
+ if (existing) {
16
+ return existing;
17
+ }
18
+
19
+ const root = document.createElement("div");
20
+ root.setAttribute(OVERLAY_ATTRIBUTE, "true");
21
+ root.setAttribute("role", "dialog");
22
+ root.setAttribute("aria-modal", "true");
23
+ root.setAttribute("aria-labelledby", "amos-apple-pay-waiting-title");
24
+ Object.assign(root.style, {
25
+ position: "fixed",
26
+ inset: "0",
27
+ zIndex: "2147483646",
28
+ display: "flex",
29
+ alignItems: "center",
30
+ justifyContent: "center",
31
+ padding: "24px",
32
+ boxSizing: "border-box",
33
+ background: "rgba(0, 0, 0, 0.55)",
34
+ fontFamily:
35
+ '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
36
+ } satisfies Partial<CSSStyleDeclaration>);
37
+
38
+ const card = document.createElement("div");
39
+ Object.assign(card.style, {
40
+ width: "100%",
41
+ maxWidth: "360px",
42
+ borderRadius: "12px",
43
+ background: "#fff",
44
+ padding: "28px 24px 20px",
45
+ boxSizing: "border-box",
46
+ textAlign: "center",
47
+ boxShadow: "0 12px 40px rgba(0, 0, 0, 0.25)",
48
+ } satisfies Partial<CSSStyleDeclaration>);
49
+
50
+ const mark = document.createElement("div");
51
+ mark.setAttribute("aria-hidden", "true");
52
+ Object.assign(mark.style, {
53
+ display: "inline-flex",
54
+ alignItems: "center",
55
+ justifyContent: "center",
56
+ gap: "6px",
57
+ marginBottom: "16px",
58
+ fontSize: "28px",
59
+ fontWeight: "600",
60
+ letterSpacing: "-0.02em",
61
+ color: "#000",
62
+ lineHeight: "1",
63
+ } satisfies Partial<CSSStyleDeclaration>);
64
+ mark.innerHTML = `<svg width="22" height="26" viewBox="0 0 14 17" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M13.072 5.846c-.1.08-1.873 1.09-1.873 3.34 0 2.61 2.29 3.53 2.36 3.55-.04.1-.368 1.27-.766 2.52-.35 1.09-.72 2.18-1.28 2.18-.55 0-.73-.36-1.43-.36-.71 0-.93.37-1.48.37-.55 0-.93-.99-1.35-2.01-.5-1.2-.88-2.43-.88-3.85 0-2.26 1.47-3.46 2.91-3.46.57 0 1.11.38 1.49.38.37 0 .98-.45 1.7-.45.28 0 1.27.03 1.97 1.01ZM9.52 3.37c.3-.36.52-.86.52-1.36 0-.07 0-.14-.01-.2-.5.02-1.1.33-1.46.75-.28.32-.55.84-.55 1.35 0 .07.01.15.02.17.04.01.1.02.16.02.45 0 1.02-.3 1.32-.73Z"/></svg><span>Pay</span>`;
65
+
66
+ const title = document.createElement("p");
67
+ title.id = "amos-apple-pay-waiting-title";
68
+ Object.assign(title.style, {
69
+ margin: "0 0 20px",
70
+ fontSize: "15px",
71
+ lineHeight: "1.45",
72
+ color: "#1a1a1a",
73
+ } satisfies Partial<CSSStyleDeclaration>);
74
+ title.textContent =
75
+ "Complete your payment in the open Apple Pay window, or close Apple Pay to continue paying another way.";
76
+
77
+ const cancel = document.createElement("button");
78
+ cancel.type = "button";
79
+ cancel.textContent = "Cancel payment";
80
+ Object.assign(cancel.style, {
81
+ display: "block",
82
+ width: "100%",
83
+ border: "none",
84
+ borderRadius: "8px",
85
+ padding: "12px 16px",
86
+ background: "#2c2c2e",
87
+ color: "#fff",
88
+ fontSize: "15px",
89
+ fontWeight: "500",
90
+ cursor: "pointer",
91
+ } satisfies Partial<CSSStyleDeclaration>);
92
+ cancel.addEventListener("click", onCancel);
93
+
94
+ card.append(mark, title, cancel);
95
+ root.append(card);
96
+ document.body.append(root);
97
+ return root;
98
+ }
99
+
100
+ /** Remove the host-page Apple Pay waiting overlay if present. */
101
+ export function hideApplePayWaitingOverlay(): void {
102
+ document.querySelector(`[${OVERLAY_ATTRIBUTE}]`)?.remove();
103
+ }
package/src/apple-pay.ts CHANGED
@@ -1,16 +1,18 @@
1
1
  import type { components } from "@amos.com/node";
2
+ import {
3
+ hideApplePayWaitingOverlay,
4
+ showApplePayWaitingOverlay,
5
+ } from "./apple-pay-waiting-overlay";
2
6
  import { getEmbedOrigin } from "./jwt";
3
7
  import {
4
8
  confirmPaymentIntent,
5
- hasNativeApplePaySession,
6
9
  sendConfirmationFailed,
7
10
  sendParentReadyMessage,
8
11
  updateAmount as sendUpdateAmount,
9
12
  updateAppearance as sendUpdateAppearance,
10
13
  updateMerchantName as sendUpdateMerchantName,
11
- updateNativeApplePaySession as sendUpdateNativeApplePaySession,
12
14
  } from "./messaging";
13
- import type { Appearance, Message } from "./types";
15
+ import { type Appearance, createMessage, type Message } from "./types";
14
16
 
15
17
  /**
16
18
  * Build the iframe `src` URL for the embedded Apple Pay button.
@@ -90,47 +92,11 @@ export type ApplePayButtonController = {
90
92
  destroy: () => void;
91
93
  };
92
94
 
93
- type SavedIframeLayout = {
94
- cssText: string;
95
- bodyOverflow: string;
96
- };
97
-
98
- /**
99
- * Expand the Apple Pay iframe to a full-viewport overlay so Chrome's QR
100
- * handoff UI (rendered inside the iframe) is not clipped to the button
101
- * height. Safari's native sheet is OS-level and unaffected.
102
- */
103
- function expandApplePayIframe(iframe: HTMLIFrameElement): SavedIframeLayout {
104
- const saved: SavedIframeLayout = {
105
- cssText: iframe.style.cssText,
106
- bodyOverflow: document.body.style.overflow,
107
- };
108
- document.body.style.overflow = "hidden";
109
- Object.assign(iframe.style, {
110
- position: "fixed",
111
- inset: "0px",
112
- width: "100vw",
113
- height: "100vh",
114
- maxWidth: "none",
115
- maxHeight: "none",
116
- margin: "0",
117
- border: "0",
118
- zIndex: "2147483647",
119
- opacity: "1",
120
- background: "#ffffff",
121
- });
122
- return saved;
123
- }
124
-
125
- function collapseApplePayIframe(
126
- iframe: HTMLIFrameElement,
127
- saved: SavedIframeLayout | null,
128
- ): void {
129
- if (!saved) {
130
- return;
131
- }
132
- document.body.style.overflow = saved.bodyOverflow;
133
- iframe.style.cssText = saved.cssText;
95
+ function sendApplePayCancel(iframe: HTMLIFrameElement): void {
96
+ iframe.contentWindow?.postMessage(
97
+ createMessage({ type: "APPLE_PAY_CANCEL" }),
98
+ "*",
99
+ );
134
100
  }
135
101
 
136
102
  /**
@@ -142,16 +108,15 @@ function collapseApplePayIframe(
142
108
  * correct `src` (see {@link getApplePayButtonSrc}).
143
109
  *
144
110
  * The Apple Pay button and `ApplePaySession` run inside the Amos embed
145
- * iframe (so only Amos domains need Apple merchant registration). On
146
- * `EXPAND_IFRAME`, the parent temporarily overlays that iframe
147
- * full-viewport for Chrome's in-iframe QR handoff UI.
111
+ * iframe so only Amos domains need Apple merchant registration. While
112
+ * Apple Pay Code is open in a separate window, this host paints a
113
+ * waiting overlay and can cancel via {@link Message} `APPLE_PAY_CANCEL`.
148
114
  */
149
115
  export function attachApplePayButtonListeners(
150
116
  iframe: HTMLIFrameElement,
151
117
  options: ApplePayButtonListenerOptions,
152
118
  ): ApplePayButtonController {
153
119
  let current = { ...options };
154
- let savedLayout: SavedIframeLayout | null = null;
155
120
 
156
121
  function pushAmount() {
157
122
  sendUpdateAmount({ iframe, amount: current.amount });
@@ -161,13 +126,6 @@ export function attachApplePayButtonListeners(
161
126
  sendUpdateMerchantName({ iframe, merchantName: current.merchantName });
162
127
  }
163
128
 
164
- function pushNativeApplePaySession() {
165
- sendUpdateNativeApplePaySession({
166
- iframe,
167
- hasNativeApplePaySession: hasNativeApplePaySession(),
168
- });
169
- }
170
-
171
129
  function handleMessage(event: MessageEvent<Message>) {
172
130
  // Ignore messages from other frames / windows.
173
131
  if (event.source !== iframe.contentWindow) {
@@ -178,16 +136,12 @@ export function attachApplePayButtonListeners(
178
136
  case "IFRAME_READY":
179
137
  sendParentReadyMessage(iframe);
180
138
  sendUpdateAppearance({ iframe, appearance: current.appearance });
181
- pushNativeApplePaySession();
182
139
  pushAmount();
183
140
  pushMerchantName();
184
141
  break;
185
142
 
186
143
  case "UPDATE_HEIGHT":
187
- // Ignore height updates while the session overlay is open.
188
- if (!savedLayout) {
189
- current.onHeightChange?.(event.data.height);
190
- }
144
+ current.onHeightChange?.(event.data.height);
191
145
  break;
192
146
 
193
147
  case "UPDATE_APPEARANCE":
@@ -198,15 +152,17 @@ export function attachApplePayButtonListeners(
198
152
  current.onAppearanceReady?.();
199
153
  break;
200
154
 
201
- case "EXPAND_IFRAME":
202
- if (!savedLayout) {
203
- savedLayout = expandApplePayIframe(iframe);
204
- }
155
+ case "APPLE_PAY_WINDOW_OPEN":
156
+ showApplePayWaitingOverlay({
157
+ onCancel: () => {
158
+ sendApplePayCancel(iframe);
159
+ hideApplePayWaitingOverlay();
160
+ },
161
+ });
205
162
  break;
206
163
 
207
- case "COLLAPSE_IFRAME":
208
- collapseApplePayIframe(iframe, savedLayout);
209
- savedLayout = null;
164
+ case "APPLE_PAY_WINDOW_CLOSE":
165
+ hideApplePayWaitingOverlay();
210
166
  break;
211
167
 
212
168
  case "CREATE_PAYMENT_INTENT":
@@ -229,10 +185,12 @@ export function attachApplePayButtonListeners(
229
185
  break;
230
186
 
231
187
  case "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED":
188
+ hideApplePayWaitingOverlay();
232
189
  current.onPaymentIntentConfirmationSucceeded(event.data.paymentIntent);
233
190
  break;
234
191
 
235
192
  case "CONFIRMATION_FAILED":
193
+ hideApplePayWaitingOverlay();
236
194
  current.onConfirmationFailed(event.data.errorMessage);
237
195
  break;
238
196
  }
@@ -258,8 +216,7 @@ export function attachApplePayButtonListeners(
258
216
  },
259
217
  destroy() {
260
218
  window.removeEventListener("message", handleMessage);
261
- collapseApplePayIframe(iframe, savedLayout);
262
- savedLayout = null;
219
+ hideApplePayWaitingOverlay();
263
220
  },
264
221
  };
265
222
  }
package/src/index.ts CHANGED
@@ -27,13 +27,11 @@ export { decodeJwt, getEmbedOrigin } from "./jwt";
27
27
  export {
28
28
  confirmPaymentIntent,
29
29
  confirmSetupIntent,
30
- hasNativeApplePaySession,
31
30
  sendConfirmationFailed,
32
31
  sendParentReadyMessage,
33
32
  updateAmount,
34
33
  updateAppearance,
35
34
  updateMerchantName,
36
- updateNativeApplePaySession,
37
35
  validateForm,
38
36
  } from "./messaging";
39
37
  export type {
package/src/messaging.ts CHANGED
@@ -70,34 +70,6 @@ export function updateMerchantName({
70
70
  );
71
71
  }
72
72
 
73
- /**
74
- * Whether the host page exposes a native `ApplePaySession` (Safari).
75
- * Non-Safari browsers load Apple's SDK inside the embed iframe instead.
76
- */
77
- export function hasNativeApplePaySession(): boolean {
78
- return "ApplePaySession" in globalThis;
79
- }
80
-
81
- /**
82
- * Tell the Apple Pay iframe whether the parent has a native
83
- * `ApplePaySession`. Sent during the `IFRAME_READY` handshake.
84
- */
85
- export function updateNativeApplePaySession({
86
- iframe,
87
- hasNativeApplePaySession,
88
- }: {
89
- iframe: Iframe;
90
- hasNativeApplePaySession: boolean;
91
- }): void {
92
- iframe?.contentWindow?.postMessage(
93
- createMessage({
94
- type: "UPDATE_NATIVE_APPLE_PAY_SESSION",
95
- hasNativeApplePaySession,
96
- }),
97
- "*",
98
- );
99
- }
100
-
101
73
  /**
102
74
  * Ask the embedded credit-card or bank-account iframe form to validate
103
75
  * its inputs.
package/src/types.ts CHANGED
@@ -155,15 +155,6 @@ export type Message =
155
155
  type: "UPDATE_MERCHANT_NAME";
156
156
  merchantName: string;
157
157
  }
158
- | {
159
- /**
160
- * Parent → iframe: whether the host page has a native
161
- * `ApplePaySession` (Safari). When `false`, the iframe should
162
- * expand for Chrome's in-iframe QR handoff UI.
163
- */
164
- type: "UPDATE_NATIVE_APPLE_PAY_SESSION";
165
- hasNativeApplePaySession: boolean;
166
- }
167
158
  | {
168
159
  type: "UPDATE_APPEARANCE";
169
160
  appearance: Appearance;
@@ -202,16 +193,16 @@ export type Message =
202
193
  type: "UPDATED_APPEARANCE";
203
194
  }
204
195
  | {
205
- /**
206
- * Iframe → parent: expand the Apple Pay iframe to a full-viewport
207
- * overlay so Chrome's QR handoff UI is not clipped by the button
208
- * height. The Apple Pay session stays on the Amos embed origin.
209
- */
210
- type: "EXPAND_IFRAME";
196
+ /** Embed → parent: Apple Pay Code window / waiting UI should show. */
197
+ type: "APPLE_PAY_WINDOW_OPEN";
198
+ }
199
+ | {
200
+ /** Embed → parent: waiting UI should dismiss. */
201
+ type: "APPLE_PAY_WINDOW_CLOSE";
211
202
  }
212
203
  | {
213
- /** Iframeparent: restore the Apple Pay iframe to its button size. */
214
- type: "COLLAPSE_IFRAME";
204
+ /** Parentembed: user cancelled from the host-page waiting overlay. */
205
+ type: "APPLE_PAY_CANCEL";
215
206
  };
216
207
 
217
208
  /**