@amos.com/amos-js 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/apple-pay.d.ts +81 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +168 -32
- package/dist/mount.d.ts +28 -0
- package/dist/types.d.ts +10 -0
- package/package.json +1 -1
- package/src/apple-pay.ts +255 -0
- package/src/index.ts +13 -0
- package/src/mount.ts +73 -0
- package/src/types.ts +12 -0
package/README.md
CHANGED
|
@@ -96,7 +96,7 @@ The following flow is for credit card and bank account payment method types only
|
|
|
96
96
|
|
|
97
97
|
### Google Pay
|
|
98
98
|
|
|
99
|
-
Google Pay
|
|
99
|
+
Google Pay and Apple Pay are forms of express checkout. Their buttons are alternatives to the "Pay now" button in your payment forms. Users can make a payment with either flow.
|
|
100
100
|
|
|
101
101
|
The key differences between the express and non-express payment flows are:
|
|
102
102
|
|
|
@@ -266,6 +266,10 @@ Mount the secure Google Pay button (express checkout) into a container element.
|
|
|
266
266
|
|
|
267
267
|
- `iframe`, `update(patch)`, `destroy()`. Use `update({ amount, merchantName })` to push new values into the iframe.
|
|
268
268
|
|
|
269
|
+
### `mountAmosApplePayButton(container, options)`
|
|
270
|
+
|
|
271
|
+
Mount the secure Apple Pay button (express checkout). Same options and return shape as `mountAmosGooglePayButton`.
|
|
272
|
+
|
|
269
273
|
### `validateForm({ iframe })`
|
|
270
274
|
|
|
271
275
|
Validates the embedded card/bank iframe form. Returns `Promise<boolean>` (resolves to `false` after 5 seconds if the iframe does not respond).
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { components } from '@amos.com/node';
|
|
2
|
+
import { Appearance } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Build the iframe `src` URL for the embedded Apple Pay button.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getApplePayButtonSrc(renderToken: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Default iframe pixel height for the Apple Pay button.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getApplePayButtonInitialHeight(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Options accepted by {@link attachApplePayButtonListeners}.
|
|
13
|
+
*/
|
|
14
|
+
export type ApplePayButtonListenerOptions = {
|
|
15
|
+
/** The amount of the payment, in the same format passed in props. */
|
|
16
|
+
amount: string;
|
|
17
|
+
/** A user-visible merchant name. */
|
|
18
|
+
merchantName: string;
|
|
19
|
+
/**
|
|
20
|
+
* Custom appearance to apply when the iframe first becomes ready and
|
|
21
|
+
* whenever the appearance changes.
|
|
22
|
+
*/
|
|
23
|
+
appearance?: Appearance;
|
|
24
|
+
/**
|
|
25
|
+
* Called whenever the iframe asks the host page to resize it. Update
|
|
26
|
+
* the iframe's `height` style here.
|
|
27
|
+
*/
|
|
28
|
+
onHeightChange?: (height: string) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Called once the iframe has applied the requested appearance and is
|
|
31
|
+
* ready to be revealed.
|
|
32
|
+
*/
|
|
33
|
+
onAppearanceReady?: () => void;
|
|
34
|
+
/**
|
|
35
|
+
* Called when the user initiates a payment intent request via the
|
|
36
|
+
* Apple Pay button. Your implementation should create a payment
|
|
37
|
+
* intent on your server and resolve with the resulting embed token.
|
|
38
|
+
*/
|
|
39
|
+
onInitiatePaymentIntentRequest: ({ paymentIntentCreateAttributes, customerCreateAttributes, }: {
|
|
40
|
+
paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"];
|
|
41
|
+
customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
|
|
42
|
+
}) => Promise<components["schemas"]["EmbedToken"]["token"]>;
|
|
43
|
+
/**
|
|
44
|
+
* Called when payment intent confirmation succeeds.
|
|
45
|
+
*/
|
|
46
|
+
onPaymentIntentConfirmationSucceeded: (paymentIntent: components["schemas"]["PaymentIntent"]) => void;
|
|
47
|
+
/**
|
|
48
|
+
* Called when payment intent confirmation fails.
|
|
49
|
+
*/
|
|
50
|
+
onConfirmationFailed: (errorMessage: string) => void;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Controller returned by {@link attachApplePayButtonListeners} and
|
|
54
|
+
* {@link mountAmosApplePayButton}.
|
|
55
|
+
*/
|
|
56
|
+
export type ApplePayButtonController = {
|
|
57
|
+
/**
|
|
58
|
+
* Update one or more listener options without re-attaching the
|
|
59
|
+
* message listener. Pass `amount` or `merchantName` to push the new
|
|
60
|
+
* value into the iframe; pass `appearance` to update theme variables.
|
|
61
|
+
*/
|
|
62
|
+
update: (patch: Partial<ApplePayButtonListenerOptions>) => void;
|
|
63
|
+
/**
|
|
64
|
+
* Detach the iframe message listener.
|
|
65
|
+
*/
|
|
66
|
+
destroy: () => void;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Wire up the host-page side of the Apple Pay iframe message protocol
|
|
70
|
+
* on an existing `<iframe>` element. Returns a controller for updating
|
|
71
|
+
* options and tearing down the listener.
|
|
72
|
+
*
|
|
73
|
+
* The iframe is expected to have already been added to the DOM with the
|
|
74
|
+
* correct `src` (see {@link getApplePayButtonSrc}).
|
|
75
|
+
*
|
|
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.
|
|
80
|
+
*/
|
|
81
|
+
export declare function attachApplePayButtonListeners(iframe: HTMLIFrameElement, options: ApplePayButtonListenerOptions): ApplePayButtonController;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/// <reference types="googlepay" />
|
|
2
|
+
export type { ApplePayButtonController, ApplePayButtonListenerOptions, } from './apple-pay';
|
|
3
|
+
export { attachApplePayButtonListeners, getApplePayButtonInitialHeight, getApplePayButtonSrc, } from './apple-pay';
|
|
2
4
|
export type { FormattedGooglePayPaymentData, GooglePayButtonController, GooglePayButtonListenerOptions, } from './google-pay';
|
|
3
5
|
export { attachGooglePayButtonListeners, formatGooglePayPaymentData, getGooglePayButtonInitialHeight, getGooglePayButtonSrc, } from './google-pay';
|
|
4
6
|
export { decodeJwt, getEmbedOrigin } from './jwt';
|
|
5
7
|
export { confirmPaymentIntent, confirmSetupIntent, sendConfirmationFailed, sendParentReadyMessage, updateAmount, updateAppearance, updateMerchantName, validateForm, } from './messaging';
|
|
6
|
-
export type { AmosBankAccountPaymentMethodFormOptions, AmosCreditCardPaymentMethodFormOptions, AmosGooglePayButtonMountController, AmosGooglePayButtonOptions, AmosPaymentMethodFormMountController, } from './mount';
|
|
7
|
-
export { mountAmosBankAccountPaymentMethodForm, mountAmosCreditCardPaymentMethodForm, mountAmosGooglePayButton, } from './mount';
|
|
8
|
+
export type { AmosApplePayButtonMountController, AmosApplePayButtonOptions, AmosBankAccountPaymentMethodFormOptions, AmosCreditCardPaymentMethodFormOptions, AmosGooglePayButtonMountController, AmosGooglePayButtonOptions, AmosPaymentMethodFormMountController, } from './mount';
|
|
9
|
+
export { mountAmosApplePayButton, mountAmosBankAccountPaymentMethodForm, mountAmosCreditCardPaymentMethodForm, mountAmosGooglePayButton, } from './mount';
|
|
8
10
|
export type { BillingAddressRequirement, CreditCardAdditionalFields, PaymentMethodFormController, PaymentMethodFormListenerOptions, } from './payment-method-form';
|
|
9
11
|
export { attachPaymentMethodFormListeners, getBankAccountFormInitialHeight, getBankAccountFormSrc, getCreditCardFormInitialHeight, getCreditCardFormSrc, } from './payment-method-form';
|
|
10
12
|
export type { Appearance, AppearanceLabels, Message, ThemeVariable, } from './types';
|
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({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 c({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 l({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 u({iframe:e,errorMessage:t}){e?.contentWindow?.postMessage(n({type:`CONFIRMATION_FAILED`,errorMessage:t}),`*`)}function d(e){return`${t(e)}/iframe/google-pay?token=${e}`}function f(){return`40px`}function p(e,t){let n={...t};function s(){a({iframe:e,amount:n.amount})}function l(){o({iframe:e,merchantName:n.merchantName})}function d(t){switch(t.data.type){case`IFRAME_READY`:r(e),i({iframe:e,appearance:n.appearance}),s(),l();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=>{c({iframe:e,token:t})}).catch(t=>{u({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`,d),{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&&l()},destroy(){window.removeEventListener(`message`,d)}}}function m({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 h={country:212,full:452},g=80,_={country:400,full:640};function v(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 y(e,n=`country`){let r=new URLSearchParams({token:e,billingAddressRequirement:n});return`${t(e)}/iframe/bank?${r}`}function b(e={cardholderName:!1},t=`country`){return`${(h[t]??h.country)+(e.cardholderName?g:0)}px`}function x(e=`country`){return`${_[e]??_.country}px`}function S(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 C(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 w={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`};function T({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,w,{height:r}),a}function E(e,t){let n=C(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t,s=T({src:v(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:b(i,a)});n.appendChild(s);let c=S(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 D(e,t){let n=C(e),{renderToken:r,billingAddressRequirement:i=`country`,...a}=t,o=T({src:y(r,i),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:x(i)});n.appendChild(o);let s=S(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 O(e,t){let n=C(e),{renderToken:r,...i}=t,a=T({src:d(r),title:`Secure Google Pay button powered by Amos`,name:`amos-google-pay-button`,height:f(),allow:`payment`});n.appendChild(a);let o=p(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.attachGooglePayButtonListeners=p,exports.attachPaymentMethodFormListeners=S,exports.confirmPaymentIntent=c,exports.confirmSetupIntent=l,exports.createMessage=n,exports.decodeJwt=e,exports.formatGooglePayPaymentData=m,exports.getBankAccountFormInitialHeight=x,exports.getBankAccountFormSrc=y,exports.getCreditCardFormInitialHeight=b,exports.getCreditCardFormSrc=v,exports.getEmbedOrigin=t,exports.getGooglePayButtonInitialHeight=f,exports.getGooglePayButtonSrc=d,exports.mountAmosBankAccountPaymentMethodForm=D,exports.mountAmosCreditCardPaymentMethodForm=E,exports.mountAmosGooglePayButton=O,exports.sendConfirmationFailed=u,exports.sendParentReadyMessage=r,exports.updateAmount=a,exports.updateAppearance=i,exports.updateMerchantName=o,exports.validateForm=s;
|
|
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({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 c({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 l({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 u({iframe:e,errorMessage:t}){e?.contentWindow?.postMessage(n({type:`CONFIRMATION_FAILED`,errorMessage:t}),`*`)}function d(e){return`${t(e)}/iframe/apple-pay?token=${e}`}function f(){return`40px`}function p(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 m(e,t){t&&(document.body.style.overflow=t.bodyOverflow,e.style.cssText=t.cssText)}function h(e,t){let n={...t},s=null;function l(){a({iframe:e,amount:n.amount})}function d(){o({iframe:e,merchantName:n.merchantName})}function f(t){if(t.source===e.contentWindow)switch(t.data.type){case`IFRAME_READY`:r(e),i({iframe:e,appearance:n.appearance}),l(),d();break;case`UPDATE_HEIGHT`:s||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`:s||=p(e);break;case`COLLAPSE_IFRAME`:m(e,s),s=null;break;case`CREATE_PAYMENT_INTENT`:n.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:t.data.paymentIntentCreateAttributes,customerCreateAttributes:t.data.customerCreateAttributes}).then(t=>{c({iframe:e,token:t})}).catch(t=>{u({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`,f),{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&&l(),o&&d()},destroy(){window.removeEventListener(`message`,f),m(e,s),s=null}}}function g(e){return`${t(e)}/iframe/google-pay?token=${e}`}function _(){return`40px`}function v(e,t){let n={...t};function s(){a({iframe:e,amount:n.amount})}function l(){o({iframe:e,merchantName:n.merchantName})}function d(t){switch(t.data.type){case`IFRAME_READY`:r(e),i({iframe:e,appearance:n.appearance}),s(),l();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=>{c({iframe:e,token:t})}).catch(t=>{u({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`,d),{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&&l()},destroy(){window.removeEventListener(`message`,d)}}}function y({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 b={country:212,full:452},x=80,S={country:400,full:640};function C(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 w(e,n=`country`){let r=new URLSearchParams({token:e,billingAddressRequirement:n});return`${t(e)}/iframe/bank?${r}`}function T(e={cardholderName:!1},t=`country`){return`${(b[t]??b.country)+(e.cardholderName?x:0)}px`}function E(e=`country`){return`${S[e]??S.country}px`}function D(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 O(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 k={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`};function A({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,k,{height:r}),a}function j(e,t){let n=O(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t,s=A({src:C(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:T(i,a)});n.appendChild(s);let c=D(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 M(e,t){let n=O(e),{renderToken:r,billingAddressRequirement:i=`country`,...a}=t,o=A({src:w(r,i),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:E(i)});n.appendChild(o);let s=D(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 N(e,t){let n=O(e),{renderToken:r,...i}=t,a=A({src:g(r),title:`Secure Google Pay button powered by Amos`,name:`amos-google-pay-button`,height:_(),allow:`payment`});n.appendChild(a);let o=v(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 P(e,t){let n=O(e),{renderToken:r,...i}=t,a=A({src:d(r),title:`Secure Apple Pay button powered by Amos`,name:`amos-apple-pay-button`,height:f(),allow:`payment`});n.appendChild(a);let o=h(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=h,exports.attachGooglePayButtonListeners=v,exports.attachPaymentMethodFormListeners=D,exports.confirmPaymentIntent=c,exports.confirmSetupIntent=l,exports.createMessage=n,exports.decodeJwt=e,exports.formatGooglePayPaymentData=y,exports.getApplePayButtonInitialHeight=f,exports.getApplePayButtonSrc=d,exports.getBankAccountFormInitialHeight=E,exports.getBankAccountFormSrc=w,exports.getCreditCardFormInitialHeight=T,exports.getCreditCardFormSrc=C,exports.getEmbedOrigin=t,exports.getGooglePayButtonInitialHeight=_,exports.getGooglePayButtonSrc=g,exports.mountAmosApplePayButton=P,exports.mountAmosBankAccountPaymentMethodForm=M,exports.mountAmosCreditCardPaymentMethodForm=j,exports.mountAmosGooglePayButton=N,exports.sendConfirmationFailed=u,exports.sendParentReadyMessage=r,exports.updateAmount=a,exports.updateAppearance=i,exports.updateMerchantName=o,exports.validateForm=s;
|
package/dist/index.mjs
CHANGED
|
@@ -82,14 +82,124 @@ function u({ iframe: e, errorMessage: t }) {
|
|
|
82
82
|
}), "*");
|
|
83
83
|
}
|
|
84
84
|
//#endregion
|
|
85
|
-
//#region src/
|
|
85
|
+
//#region src/apple-pay.ts
|
|
86
86
|
function d(e) {
|
|
87
|
-
return `${t(e)}/iframe/
|
|
87
|
+
return `${t(e)}/iframe/apple-pay?token=${e}`;
|
|
88
88
|
}
|
|
89
89
|
function f() {
|
|
90
90
|
return "40px";
|
|
91
91
|
}
|
|
92
|
-
function p(e
|
|
92
|
+
function p(e) {
|
|
93
|
+
let t = {
|
|
94
|
+
cssText: e.style.cssText,
|
|
95
|
+
bodyOverflow: document.body.style.overflow
|
|
96
|
+
};
|
|
97
|
+
return document.body.style.overflow = "hidden", Object.assign(e.style, {
|
|
98
|
+
position: "fixed",
|
|
99
|
+
inset: "0px",
|
|
100
|
+
width: "100vw",
|
|
101
|
+
height: "100vh",
|
|
102
|
+
maxWidth: "none",
|
|
103
|
+
maxHeight: "none",
|
|
104
|
+
margin: "0",
|
|
105
|
+
border: "0",
|
|
106
|
+
zIndex: "2147483647",
|
|
107
|
+
opacity: "1",
|
|
108
|
+
background: "#ffffff"
|
|
109
|
+
}), t;
|
|
110
|
+
}
|
|
111
|
+
function m(e, t) {
|
|
112
|
+
t && (document.body.style.overflow = t.bodyOverflow, e.style.cssText = t.cssText);
|
|
113
|
+
}
|
|
114
|
+
function h(e, t) {
|
|
115
|
+
let n = { ...t }, s = null;
|
|
116
|
+
function l() {
|
|
117
|
+
a({
|
|
118
|
+
iframe: e,
|
|
119
|
+
amount: n.amount
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function d() {
|
|
123
|
+
o({
|
|
124
|
+
iframe: e,
|
|
125
|
+
merchantName: n.merchantName
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function f(t) {
|
|
129
|
+
if (t.source === e.contentWindow) switch (t.data.type) {
|
|
130
|
+
case "IFRAME_READY":
|
|
131
|
+
r(e), i({
|
|
132
|
+
iframe: e,
|
|
133
|
+
appearance: n.appearance
|
|
134
|
+
}), l(), d();
|
|
135
|
+
break;
|
|
136
|
+
case "UPDATE_HEIGHT":
|
|
137
|
+
s || n.onHeightChange?.(t.data.height);
|
|
138
|
+
break;
|
|
139
|
+
case "UPDATE_APPEARANCE":
|
|
140
|
+
i({
|
|
141
|
+
iframe: e,
|
|
142
|
+
appearance: t.data.appearance
|
|
143
|
+
});
|
|
144
|
+
break;
|
|
145
|
+
case "UPDATED_APPEARANCE":
|
|
146
|
+
n.onAppearanceReady?.();
|
|
147
|
+
break;
|
|
148
|
+
case "EXPAND_IFRAME":
|
|
149
|
+
s ||= p(e);
|
|
150
|
+
break;
|
|
151
|
+
case "COLLAPSE_IFRAME":
|
|
152
|
+
m(e, s), s = null;
|
|
153
|
+
break;
|
|
154
|
+
case "CREATE_PAYMENT_INTENT":
|
|
155
|
+
n.onInitiatePaymentIntentRequest({
|
|
156
|
+
paymentIntentCreateAttributes: t.data.paymentIntentCreateAttributes,
|
|
157
|
+
customerCreateAttributes: t.data.customerCreateAttributes
|
|
158
|
+
}).then((t) => {
|
|
159
|
+
c({
|
|
160
|
+
iframe: e,
|
|
161
|
+
token: t
|
|
162
|
+
});
|
|
163
|
+
}).catch((t) => {
|
|
164
|
+
u({
|
|
165
|
+
iframe: e,
|
|
166
|
+
errorMessage: t instanceof Error ? t.message : "Unknown error"
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
break;
|
|
170
|
+
case "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED":
|
|
171
|
+
n.onPaymentIntentConfirmationSucceeded(t.data.paymentIntent);
|
|
172
|
+
break;
|
|
173
|
+
case "CONFIRMATION_FAILED":
|
|
174
|
+
n.onConfirmationFailed(t.data.errorMessage);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return window.addEventListener("message", f), {
|
|
179
|
+
update(t) {
|
|
180
|
+
let r = "appearance" in t, a = "amount" in t, o = "merchantName" in t;
|
|
181
|
+
n = {
|
|
182
|
+
...n,
|
|
183
|
+
...t
|
|
184
|
+
}, r && i({
|
|
185
|
+
iframe: e,
|
|
186
|
+
appearance: n.appearance
|
|
187
|
+
}), a && l(), o && d();
|
|
188
|
+
},
|
|
189
|
+
destroy() {
|
|
190
|
+
window.removeEventListener("message", f), m(e, s), s = null;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
//#endregion
|
|
195
|
+
//#region src/google-pay.ts
|
|
196
|
+
function g(e) {
|
|
197
|
+
return `${t(e)}/iframe/google-pay?token=${e}`;
|
|
198
|
+
}
|
|
199
|
+
function _() {
|
|
200
|
+
return "40px";
|
|
201
|
+
}
|
|
202
|
+
function v(e, t) {
|
|
93
203
|
let n = { ...t };
|
|
94
204
|
function s() {
|
|
95
205
|
a({
|
|
@@ -163,7 +273,7 @@ function p(e, t) {
|
|
|
163
273
|
}
|
|
164
274
|
};
|
|
165
275
|
}
|
|
166
|
-
function
|
|
276
|
+
function y({ paymentData: e }) {
|
|
167
277
|
return { paymentMethod: {
|
|
168
278
|
type: "googlepay",
|
|
169
279
|
billing_address_attributes: {
|
|
@@ -195,14 +305,14 @@ function m({ paymentData: e }) {
|
|
|
195
305
|
}
|
|
196
306
|
//#endregion
|
|
197
307
|
//#region src/payment-method-form.ts
|
|
198
|
-
var
|
|
308
|
+
var b = {
|
|
199
309
|
country: 212,
|
|
200
310
|
full: 452
|
|
201
|
-
},
|
|
311
|
+
}, x = 80, S = {
|
|
202
312
|
country: 400,
|
|
203
313
|
full: 640
|
|
204
314
|
};
|
|
205
|
-
function
|
|
315
|
+
function C(e, n = { cardholderName: !1 }, r = "country") {
|
|
206
316
|
let i = Object.entries(n).filter(([, e]) => e).map(([e]) => e).join(","), a = new URLSearchParams({
|
|
207
317
|
token: e,
|
|
208
318
|
additionalFields: i,
|
|
@@ -210,20 +320,20 @@ function v(e, n = { cardholderName: !1 }, r = "country") {
|
|
|
210
320
|
});
|
|
211
321
|
return `${t(e)}/iframe/card?${a}`;
|
|
212
322
|
}
|
|
213
|
-
function
|
|
323
|
+
function w(e, n = "country") {
|
|
214
324
|
let r = new URLSearchParams({
|
|
215
325
|
token: e,
|
|
216
326
|
billingAddressRequirement: n
|
|
217
327
|
});
|
|
218
328
|
return `${t(e)}/iframe/bank?${r}`;
|
|
219
329
|
}
|
|
220
|
-
function
|
|
221
|
-
return `${(
|
|
330
|
+
function T(e = { cardholderName: !1 }, t = "country") {
|
|
331
|
+
return `${(b[t] ?? b.country) + (e.cardholderName ? x : 0)}px`;
|
|
222
332
|
}
|
|
223
|
-
function
|
|
224
|
-
return `${
|
|
333
|
+
function E(e = "country") {
|
|
334
|
+
return `${S[e] ?? S.country}px`;
|
|
225
335
|
}
|
|
226
|
-
function
|
|
336
|
+
function D(e, t) {
|
|
227
337
|
let n = { ...t };
|
|
228
338
|
function a(t) {
|
|
229
339
|
switch (t.data.type) {
|
|
@@ -274,7 +384,7 @@ function S(e, t) {
|
|
|
274
384
|
}
|
|
275
385
|
//#endregion
|
|
276
386
|
//#region src/mount.ts
|
|
277
|
-
function
|
|
387
|
+
function O(e) {
|
|
278
388
|
if (typeof e == "string") {
|
|
279
389
|
let t = document.querySelector(e);
|
|
280
390
|
if (!(t instanceof HTMLElement)) throw Error(`[amos-js] Container "${e}" did not match any HTMLElement.`);
|
|
@@ -282,26 +392,26 @@ function C(e) {
|
|
|
282
392
|
}
|
|
283
393
|
return e;
|
|
284
394
|
}
|
|
285
|
-
var
|
|
395
|
+
var k = {
|
|
286
396
|
width: "calc(100% + 8px)",
|
|
287
397
|
transition: "opacity 150ms ease-in, height 200ms ease-in-out",
|
|
288
398
|
margin: "0 -4px",
|
|
289
399
|
opacity: "0",
|
|
290
400
|
border: "0"
|
|
291
401
|
};
|
|
292
|
-
function
|
|
402
|
+
function A({ src: e, title: t, name: n, height: r, allow: i }) {
|
|
293
403
|
let a = document.createElement("iframe");
|
|
294
|
-
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,
|
|
404
|
+
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, k, { height: r }), a;
|
|
295
405
|
}
|
|
296
|
-
function
|
|
297
|
-
let n =
|
|
298
|
-
src:
|
|
406
|
+
function j(e, t) {
|
|
407
|
+
let n = O(e), { renderToken: r, additionalFields: i = { cardholderName: !1 }, billingAddressRequirement: a = "country", ...o } = t, s = A({
|
|
408
|
+
src: C(r, i, a),
|
|
299
409
|
title: "Secure credit card payment method form powered by Amos",
|
|
300
410
|
name: "amos-credit-card-payment-method-form",
|
|
301
|
-
height:
|
|
411
|
+
height: T(i, a)
|
|
302
412
|
});
|
|
303
413
|
n.appendChild(s);
|
|
304
|
-
let c =
|
|
414
|
+
let c = D(s, {
|
|
305
415
|
...o,
|
|
306
416
|
onHeightChange: (e) => {
|
|
307
417
|
s.style.height = e, o.onHeightChange?.(e);
|
|
@@ -318,15 +428,15 @@ function E(e, t) {
|
|
|
318
428
|
}
|
|
319
429
|
};
|
|
320
430
|
}
|
|
321
|
-
function
|
|
322
|
-
let n =
|
|
323
|
-
src:
|
|
431
|
+
function M(e, t) {
|
|
432
|
+
let n = O(e), { renderToken: r, billingAddressRequirement: i = "country", ...a } = t, o = A({
|
|
433
|
+
src: w(r, i),
|
|
324
434
|
title: "Secure bank account payment method form powered by Amos",
|
|
325
435
|
name: "amos-bank-account-payment-method-form",
|
|
326
|
-
height:
|
|
436
|
+
height: E(i)
|
|
327
437
|
});
|
|
328
438
|
n.appendChild(o);
|
|
329
|
-
let s =
|
|
439
|
+
let s = D(o, {
|
|
330
440
|
...a,
|
|
331
441
|
onHeightChange: (e) => {
|
|
332
442
|
o.style.height = e, a.onHeightChange?.(e);
|
|
@@ -343,16 +453,42 @@ function D(e, t) {
|
|
|
343
453
|
}
|
|
344
454
|
};
|
|
345
455
|
}
|
|
346
|
-
function
|
|
347
|
-
let n =
|
|
348
|
-
src:
|
|
456
|
+
function N(e, t) {
|
|
457
|
+
let n = O(e), { renderToken: r, ...i } = t, a = A({
|
|
458
|
+
src: g(r),
|
|
349
459
|
title: "Secure Google Pay button powered by Amos",
|
|
350
460
|
name: "amos-google-pay-button",
|
|
461
|
+
height: _(),
|
|
462
|
+
allow: "payment"
|
|
463
|
+
});
|
|
464
|
+
n.appendChild(a);
|
|
465
|
+
let o = v(a, {
|
|
466
|
+
...i,
|
|
467
|
+
onHeightChange: (e) => {
|
|
468
|
+
a.style.height = e, i.onHeightChange?.(e);
|
|
469
|
+
},
|
|
470
|
+
onAppearanceReady: () => {
|
|
471
|
+
a.style.opacity = "1", i.onAppearanceReady?.();
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
return {
|
|
475
|
+
iframe: a,
|
|
476
|
+
update: o.update,
|
|
477
|
+
destroy() {
|
|
478
|
+
o.destroy(), a.remove();
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
function P(e, t) {
|
|
483
|
+
let n = O(e), { renderToken: r, ...i } = t, a = A({
|
|
484
|
+
src: d(r),
|
|
485
|
+
title: "Secure Apple Pay button powered by Amos",
|
|
486
|
+
name: "amos-apple-pay-button",
|
|
351
487
|
height: f(),
|
|
352
488
|
allow: "payment"
|
|
353
489
|
});
|
|
354
490
|
n.appendChild(a);
|
|
355
|
-
let o =
|
|
491
|
+
let o = h(a, {
|
|
356
492
|
...i,
|
|
357
493
|
onHeightChange: (e) => {
|
|
358
494
|
a.style.height = e, i.onHeightChange?.(e);
|
|
@@ -370,4 +506,4 @@ function O(e, t) {
|
|
|
370
506
|
};
|
|
371
507
|
}
|
|
372
508
|
//#endregion
|
|
373
|
-
export {
|
|
509
|
+
export { h as attachApplePayButtonListeners, v as attachGooglePayButtonListeners, D as attachPaymentMethodFormListeners, c as confirmPaymentIntent, l as confirmSetupIntent, n as createMessage, e as decodeJwt, y as formatGooglePayPaymentData, f as getApplePayButtonInitialHeight, d as getApplePayButtonSrc, E as getBankAccountFormInitialHeight, w as getBankAccountFormSrc, T as getCreditCardFormInitialHeight, C as getCreditCardFormSrc, t as getEmbedOrigin, _ as getGooglePayButtonInitialHeight, g as getGooglePayButtonSrc, P as mountAmosApplePayButton, M as mountAmosBankAccountPaymentMethodForm, j as mountAmosCreditCardPaymentMethodForm, N as mountAmosGooglePayButton, u as sendConfirmationFailed, r as sendParentReadyMessage, a as updateAmount, i as updateAppearance, o as updateMerchantName, s as validateForm };
|
package/dist/mount.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ApplePayButtonController, ApplePayButtonListenerOptions } from './apple-pay';
|
|
1
2
|
import { GooglePayButtonController, GooglePayButtonListenerOptions } from './google-pay';
|
|
2
3
|
import { BillingAddressRequirement, CreditCardAdditionalFields, PaymentMethodFormController, PaymentMethodFormListenerOptions } from './payment-method-form';
|
|
3
4
|
type Container = HTMLElement | string;
|
|
@@ -104,4 +105,31 @@ export type AmosGooglePayButtonMountController = GooglePayButtonController & {
|
|
|
104
105
|
* iframe, an `update()` method, and a `destroy()` method.
|
|
105
106
|
*/
|
|
106
107
|
export declare function mountAmosGooglePayButton(container: Container, options: AmosGooglePayButtonOptions): AmosGooglePayButtonMountController;
|
|
108
|
+
/**
|
|
109
|
+
* Options accepted by {@link mountAmosApplePayButton}.
|
|
110
|
+
*/
|
|
111
|
+
export type AmosApplePayButtonOptions = ApplePayButtonListenerOptions & {
|
|
112
|
+
/**
|
|
113
|
+
* The Amos render token for the Apple Pay button.
|
|
114
|
+
*
|
|
115
|
+
* It is safe to pass this to the client. Create this on
|
|
116
|
+
* https://dashboard.amos.com.
|
|
117
|
+
*/
|
|
118
|
+
renderToken: string;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Controller returned by {@link mountAmosApplePayButton}.
|
|
122
|
+
*/
|
|
123
|
+
export type AmosApplePayButtonMountController = ApplePayButtonController & {
|
|
124
|
+
/**
|
|
125
|
+
* The underlying `<iframe>` element.
|
|
126
|
+
*/
|
|
127
|
+
iframe: HTMLIFrameElement;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Mount the secure Apple Pay button (express checkout) into a
|
|
131
|
+
* container element. Returns a controller exposing the underlying
|
|
132
|
+
* iframe, an `update()` method, and a `destroy()` method.
|
|
133
|
+
*/
|
|
134
|
+
export declare function mountAmosApplePayButton(container: Container, options: AmosApplePayButtonOptions): AmosApplePayButtonMountController;
|
|
107
135
|
export {};
|
package/dist/types.d.ts
CHANGED
|
@@ -68,6 +68,16 @@ export type Message = {
|
|
|
68
68
|
errorMessage: string;
|
|
69
69
|
} | {
|
|
70
70
|
type: "UPDATED_APPEARANCE";
|
|
71
|
+
} | {
|
|
72
|
+
/**
|
|
73
|
+
* Iframe → parent: expand the Apple Pay iframe to a full-viewport
|
|
74
|
+
* overlay so Chrome's QR handoff UI is not clipped by the button
|
|
75
|
+
* height. The Apple Pay session stays on the Amos embed origin.
|
|
76
|
+
*/
|
|
77
|
+
type: "EXPAND_IFRAME";
|
|
78
|
+
} | {
|
|
79
|
+
/** Iframe → parent: restore the Apple Pay iframe to its button size. */
|
|
80
|
+
type: "COLLAPSE_IFRAME";
|
|
71
81
|
};
|
|
72
82
|
/**
|
|
73
83
|
* Identity helper that brands an object as a typed `Message`.
|
package/package.json
CHANGED
package/src/apple-pay.ts
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import type { components } from "@amos.com/node";
|
|
2
|
+
import { getEmbedOrigin } from "./jwt";
|
|
3
|
+
import {
|
|
4
|
+
confirmPaymentIntent,
|
|
5
|
+
sendConfirmationFailed,
|
|
6
|
+
sendParentReadyMessage,
|
|
7
|
+
updateAmount as sendUpdateAmount,
|
|
8
|
+
updateAppearance as sendUpdateAppearance,
|
|
9
|
+
updateMerchantName as sendUpdateMerchantName,
|
|
10
|
+
} from "./messaging";
|
|
11
|
+
import type { Appearance, Message } from "./types";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Build the iframe `src` URL for the embedded Apple Pay button.
|
|
15
|
+
*/
|
|
16
|
+
export function getApplePayButtonSrc(renderToken: string): string {
|
|
17
|
+
return `${getEmbedOrigin(renderToken)}/iframe/apple-pay?token=${renderToken}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Default iframe pixel height for the Apple Pay button.
|
|
22
|
+
*/
|
|
23
|
+
export function getApplePayButtonInitialHeight(): string {
|
|
24
|
+
return "40px";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Options accepted by {@link attachApplePayButtonListeners}.
|
|
29
|
+
*/
|
|
30
|
+
export type ApplePayButtonListenerOptions = {
|
|
31
|
+
/** The amount of the payment, in the same format passed in props. */
|
|
32
|
+
amount: string;
|
|
33
|
+
/** A user-visible merchant name. */
|
|
34
|
+
merchantName: string;
|
|
35
|
+
/**
|
|
36
|
+
* Custom appearance to apply when the iframe first becomes ready and
|
|
37
|
+
* whenever the appearance changes.
|
|
38
|
+
*/
|
|
39
|
+
appearance?: Appearance;
|
|
40
|
+
/**
|
|
41
|
+
* Called whenever the iframe asks the host page to resize it. Update
|
|
42
|
+
* the iframe's `height` style here.
|
|
43
|
+
*/
|
|
44
|
+
onHeightChange?: (height: string) => void;
|
|
45
|
+
/**
|
|
46
|
+
* Called once the iframe has applied the requested appearance and is
|
|
47
|
+
* ready to be revealed.
|
|
48
|
+
*/
|
|
49
|
+
onAppearanceReady?: () => void;
|
|
50
|
+
/**
|
|
51
|
+
* Called when the user initiates a payment intent request via the
|
|
52
|
+
* Apple Pay button. Your implementation should create a payment
|
|
53
|
+
* intent on your server and resolve with the resulting embed token.
|
|
54
|
+
*/
|
|
55
|
+
onInitiatePaymentIntentRequest: ({
|
|
56
|
+
paymentIntentCreateAttributes,
|
|
57
|
+
customerCreateAttributes,
|
|
58
|
+
}: {
|
|
59
|
+
paymentIntentCreateAttributes: components["schemas"]["CreatePaymentIntentInput"];
|
|
60
|
+
customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
|
|
61
|
+
}) => Promise<components["schemas"]["EmbedToken"]["token"]>;
|
|
62
|
+
/**
|
|
63
|
+
* Called when payment intent confirmation succeeds.
|
|
64
|
+
*/
|
|
65
|
+
onPaymentIntentConfirmationSucceeded: (
|
|
66
|
+
paymentIntent: components["schemas"]["PaymentIntent"],
|
|
67
|
+
) => void;
|
|
68
|
+
/**
|
|
69
|
+
* Called when payment intent confirmation fails.
|
|
70
|
+
*/
|
|
71
|
+
onConfirmationFailed: (errorMessage: string) => void;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Controller returned by {@link attachApplePayButtonListeners} and
|
|
76
|
+
* {@link mountAmosApplePayButton}.
|
|
77
|
+
*/
|
|
78
|
+
export type ApplePayButtonController = {
|
|
79
|
+
/**
|
|
80
|
+
* Update one or more listener options without re-attaching the
|
|
81
|
+
* message listener. Pass `amount` or `merchantName` to push the new
|
|
82
|
+
* value into the iframe; pass `appearance` to update theme variables.
|
|
83
|
+
*/
|
|
84
|
+
update: (patch: Partial<ApplePayButtonListenerOptions>) => void;
|
|
85
|
+
/**
|
|
86
|
+
* Detach the iframe message listener.
|
|
87
|
+
*/
|
|
88
|
+
destroy: () => void;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
type SavedIframeLayout = {
|
|
92
|
+
cssText: string;
|
|
93
|
+
bodyOverflow: string;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Expand the Apple Pay iframe to a full-viewport overlay so Chrome's QR
|
|
98
|
+
* handoff UI (rendered inside the iframe) is not clipped to the button
|
|
99
|
+
* height. Safari's native sheet is OS-level and unaffected.
|
|
100
|
+
*/
|
|
101
|
+
function expandApplePayIframe(iframe: HTMLIFrameElement): SavedIframeLayout {
|
|
102
|
+
const saved: SavedIframeLayout = {
|
|
103
|
+
cssText: iframe.style.cssText,
|
|
104
|
+
bodyOverflow: document.body.style.overflow,
|
|
105
|
+
};
|
|
106
|
+
document.body.style.overflow = "hidden";
|
|
107
|
+
Object.assign(iframe.style, {
|
|
108
|
+
position: "fixed",
|
|
109
|
+
inset: "0px",
|
|
110
|
+
width: "100vw",
|
|
111
|
+
height: "100vh",
|
|
112
|
+
maxWidth: "none",
|
|
113
|
+
maxHeight: "none",
|
|
114
|
+
margin: "0",
|
|
115
|
+
border: "0",
|
|
116
|
+
zIndex: "2147483647",
|
|
117
|
+
opacity: "1",
|
|
118
|
+
background: "#ffffff",
|
|
119
|
+
});
|
|
120
|
+
return saved;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function collapseApplePayIframe(
|
|
124
|
+
iframe: HTMLIFrameElement,
|
|
125
|
+
saved: SavedIframeLayout | null,
|
|
126
|
+
): void {
|
|
127
|
+
if (!saved) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
document.body.style.overflow = saved.bodyOverflow;
|
|
131
|
+
iframe.style.cssText = saved.cssText;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Wire up the host-page side of the Apple Pay iframe message protocol
|
|
136
|
+
* on an existing `<iframe>` element. Returns a controller for updating
|
|
137
|
+
* options and tearing down the listener.
|
|
138
|
+
*
|
|
139
|
+
* The iframe is expected to have already been added to the DOM with the
|
|
140
|
+
* correct `src` (see {@link getApplePayButtonSrc}).
|
|
141
|
+
*
|
|
142
|
+
* The Apple Pay button and `ApplePaySession` run inside the Amos embed
|
|
143
|
+
* iframe (so only Amos domains need Apple merchant registration). On
|
|
144
|
+
* `EXPAND_IFRAME`, the parent temporarily overlays that iframe
|
|
145
|
+
* full-viewport for Chrome's in-iframe QR handoff UI.
|
|
146
|
+
*/
|
|
147
|
+
export function attachApplePayButtonListeners(
|
|
148
|
+
iframe: HTMLIFrameElement,
|
|
149
|
+
options: ApplePayButtonListenerOptions,
|
|
150
|
+
): ApplePayButtonController {
|
|
151
|
+
let current = { ...options };
|
|
152
|
+
let savedLayout: SavedIframeLayout | null = null;
|
|
153
|
+
|
|
154
|
+
function pushAmount() {
|
|
155
|
+
sendUpdateAmount({ iframe, amount: current.amount });
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function pushMerchantName() {
|
|
159
|
+
sendUpdateMerchantName({ iframe, merchantName: current.merchantName });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function handleMessage(event: MessageEvent<Message>) {
|
|
163
|
+
// Ignore messages from other frames / windows.
|
|
164
|
+
if (event.source !== iframe.contentWindow) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
switch (event.data.type) {
|
|
169
|
+
case "IFRAME_READY":
|
|
170
|
+
sendParentReadyMessage(iframe);
|
|
171
|
+
sendUpdateAppearance({ iframe, appearance: current.appearance });
|
|
172
|
+
pushAmount();
|
|
173
|
+
pushMerchantName();
|
|
174
|
+
break;
|
|
175
|
+
|
|
176
|
+
case "UPDATE_HEIGHT":
|
|
177
|
+
// Ignore height updates while the session overlay is open.
|
|
178
|
+
if (!savedLayout) {
|
|
179
|
+
current.onHeightChange?.(event.data.height);
|
|
180
|
+
}
|
|
181
|
+
break;
|
|
182
|
+
|
|
183
|
+
case "UPDATE_APPEARANCE":
|
|
184
|
+
sendUpdateAppearance({ iframe, appearance: event.data.appearance });
|
|
185
|
+
break;
|
|
186
|
+
|
|
187
|
+
case "UPDATED_APPEARANCE":
|
|
188
|
+
current.onAppearanceReady?.();
|
|
189
|
+
break;
|
|
190
|
+
|
|
191
|
+
case "EXPAND_IFRAME":
|
|
192
|
+
if (!savedLayout) {
|
|
193
|
+
savedLayout = expandApplePayIframe(iframe);
|
|
194
|
+
}
|
|
195
|
+
break;
|
|
196
|
+
|
|
197
|
+
case "COLLAPSE_IFRAME":
|
|
198
|
+
collapseApplePayIframe(iframe, savedLayout);
|
|
199
|
+
savedLayout = null;
|
|
200
|
+
break;
|
|
201
|
+
|
|
202
|
+
case "CREATE_PAYMENT_INTENT":
|
|
203
|
+
current
|
|
204
|
+
.onInitiatePaymentIntentRequest({
|
|
205
|
+
paymentIntentCreateAttributes:
|
|
206
|
+
event.data.paymentIntentCreateAttributes,
|
|
207
|
+
customerCreateAttributes: event.data.customerCreateAttributes,
|
|
208
|
+
})
|
|
209
|
+
.then((token) => {
|
|
210
|
+
confirmPaymentIntent({ iframe, token });
|
|
211
|
+
})
|
|
212
|
+
.catch((error: unknown) => {
|
|
213
|
+
sendConfirmationFailed({
|
|
214
|
+
iframe,
|
|
215
|
+
errorMessage:
|
|
216
|
+
error instanceof Error ? error.message : "Unknown error",
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
break;
|
|
220
|
+
|
|
221
|
+
case "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED":
|
|
222
|
+
current.onPaymentIntentConfirmationSucceeded(event.data.paymentIntent);
|
|
223
|
+
break;
|
|
224
|
+
|
|
225
|
+
case "CONFIRMATION_FAILED":
|
|
226
|
+
current.onConfirmationFailed(event.data.errorMessage);
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
window.addEventListener("message", handleMessage);
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
update(patch) {
|
|
235
|
+
const hadAppearance = "appearance" in patch;
|
|
236
|
+
const hadAmount = "amount" in patch;
|
|
237
|
+
const hadMerchantName = "merchantName" in patch;
|
|
238
|
+
current = { ...current, ...patch };
|
|
239
|
+
if (hadAppearance) {
|
|
240
|
+
sendUpdateAppearance({ iframe, appearance: current.appearance });
|
|
241
|
+
}
|
|
242
|
+
if (hadAmount) {
|
|
243
|
+
pushAmount();
|
|
244
|
+
}
|
|
245
|
+
if (hadMerchantName) {
|
|
246
|
+
pushMerchantName();
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
destroy() {
|
|
250
|
+
window.removeEventListener("message", handleMessage);
|
|
251
|
+
collapseApplePayIframe(iframe, savedLayout);
|
|
252
|
+
savedLayout = null;
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
/// <reference types="googlepay" />
|
|
2
2
|
|
|
3
|
+
export type {
|
|
4
|
+
ApplePayButtonController,
|
|
5
|
+
ApplePayButtonListenerOptions,
|
|
6
|
+
} from "./apple-pay";
|
|
7
|
+
export {
|
|
8
|
+
attachApplePayButtonListeners,
|
|
9
|
+
getApplePayButtonInitialHeight,
|
|
10
|
+
getApplePayButtonSrc,
|
|
11
|
+
} from "./apple-pay";
|
|
12
|
+
|
|
3
13
|
export type {
|
|
4
14
|
FormattedGooglePayPaymentData,
|
|
5
15
|
GooglePayButtonController,
|
|
@@ -25,6 +35,8 @@ export {
|
|
|
25
35
|
validateForm,
|
|
26
36
|
} from "./messaging";
|
|
27
37
|
export type {
|
|
38
|
+
AmosApplePayButtonMountController,
|
|
39
|
+
AmosApplePayButtonOptions,
|
|
28
40
|
AmosBankAccountPaymentMethodFormOptions,
|
|
29
41
|
AmosCreditCardPaymentMethodFormOptions,
|
|
30
42
|
AmosGooglePayButtonMountController,
|
|
@@ -32,6 +44,7 @@ export type {
|
|
|
32
44
|
AmosPaymentMethodFormMountController,
|
|
33
45
|
} from "./mount";
|
|
34
46
|
export {
|
|
47
|
+
mountAmosApplePayButton,
|
|
35
48
|
mountAmosBankAccountPaymentMethodForm,
|
|
36
49
|
mountAmosCreditCardPaymentMethodForm,
|
|
37
50
|
mountAmosGooglePayButton,
|
package/src/mount.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
attachApplePayButtonListeners,
|
|
3
|
+
type ApplePayButtonController,
|
|
4
|
+
type ApplePayButtonListenerOptions,
|
|
5
|
+
getApplePayButtonInitialHeight,
|
|
6
|
+
getApplePayButtonSrc,
|
|
7
|
+
} from "./apple-pay";
|
|
1
8
|
import {
|
|
2
9
|
attachGooglePayButtonListeners,
|
|
3
10
|
type GooglePayButtonController,
|
|
@@ -301,3 +308,69 @@ export function mountAmosGooglePayButton(
|
|
|
301
308
|
},
|
|
302
309
|
};
|
|
303
310
|
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Options accepted by {@link mountAmosApplePayButton}.
|
|
314
|
+
*/
|
|
315
|
+
export type AmosApplePayButtonOptions = ApplePayButtonListenerOptions & {
|
|
316
|
+
/**
|
|
317
|
+
* The Amos render token for the Apple Pay button.
|
|
318
|
+
*
|
|
319
|
+
* It is safe to pass this to the client. Create this on
|
|
320
|
+
* https://dashboard.amos.com.
|
|
321
|
+
*/
|
|
322
|
+
renderToken: string;
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Controller returned by {@link mountAmosApplePayButton}.
|
|
327
|
+
*/
|
|
328
|
+
export type AmosApplePayButtonMountController = ApplePayButtonController & {
|
|
329
|
+
/**
|
|
330
|
+
* The underlying `<iframe>` element.
|
|
331
|
+
*/
|
|
332
|
+
iframe: HTMLIFrameElement;
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Mount the secure Apple Pay button (express checkout) into a
|
|
337
|
+
* container element. Returns a controller exposing the underlying
|
|
338
|
+
* iframe, an `update()` method, and a `destroy()` method.
|
|
339
|
+
*/
|
|
340
|
+
export function mountAmosApplePayButton(
|
|
341
|
+
container: Container,
|
|
342
|
+
options: AmosApplePayButtonOptions,
|
|
343
|
+
): AmosApplePayButtonMountController {
|
|
344
|
+
const host = resolveContainer(container);
|
|
345
|
+
const { renderToken, ...listenerOptions } = options;
|
|
346
|
+
|
|
347
|
+
const iframe = createIframe({
|
|
348
|
+
src: getApplePayButtonSrc(renderToken),
|
|
349
|
+
title: "Secure Apple Pay button powered by Amos",
|
|
350
|
+
name: "amos-apple-pay-button",
|
|
351
|
+
height: getApplePayButtonInitialHeight(),
|
|
352
|
+
allow: "payment",
|
|
353
|
+
});
|
|
354
|
+
host.appendChild(iframe);
|
|
355
|
+
|
|
356
|
+
const controller = attachApplePayButtonListeners(iframe, {
|
|
357
|
+
...listenerOptions,
|
|
358
|
+
onHeightChange: (height) => {
|
|
359
|
+
iframe.style.height = height;
|
|
360
|
+
listenerOptions.onHeightChange?.(height);
|
|
361
|
+
},
|
|
362
|
+
onAppearanceReady: () => {
|
|
363
|
+
iframe.style.opacity = "1";
|
|
364
|
+
listenerOptions.onAppearanceReady?.();
|
|
365
|
+
},
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
iframe,
|
|
370
|
+
update: controller.update,
|
|
371
|
+
destroy() {
|
|
372
|
+
controller.destroy();
|
|
373
|
+
iframe.remove();
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -191,6 +191,18 @@ export type Message =
|
|
|
191
191
|
}
|
|
192
192
|
| {
|
|
193
193
|
type: "UPDATED_APPEARANCE";
|
|
194
|
+
}
|
|
195
|
+
| {
|
|
196
|
+
/**
|
|
197
|
+
* Iframe → parent: expand the Apple Pay iframe to a full-viewport
|
|
198
|
+
* overlay so Chrome's QR handoff UI is not clipped by the button
|
|
199
|
+
* height. The Apple Pay session stays on the Amos embed origin.
|
|
200
|
+
*/
|
|
201
|
+
type: "EXPAND_IFRAME";
|
|
202
|
+
}
|
|
203
|
+
| {
|
|
204
|
+
/** Iframe → parent: restore the Apple Pay iframe to its button size. */
|
|
205
|
+
type: "COLLAPSE_IFRAME";
|
|
194
206
|
};
|
|
195
207
|
|
|
196
208
|
/**
|