@amos.com/amos-js 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/dist/apple-pay.d.ts +78 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +140 -34
- package/dist/mount.d.ts +30 -2
- package/dist/payment-method-form.d.ts +3 -4
- package/package.json +1 -1
- package/src/apple-pay.ts +187 -0
- package/src/index.ts +13 -0
- package/src/mount.ts +77 -4
- package/src/payment-method-form.ts +11 -17
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
|
|
|
@@ -232,7 +232,7 @@ Mount the secure credit-card payment method form into a container element (an `H
|
|
|
232
232
|
|
|
233
233
|
- `appearance` (`{ themeVariables?: Partial<Record<ThemeVariable, string>>; labels?: "above" | "floating" | "placeholder" }`)
|
|
234
234
|
- `additionalFields` (`{ cardholderName: boolean }`, defaults to `{ cardholderName: false }`)
|
|
235
|
-
- `billingAddressRequirement` (`"
|
|
235
|
+
- `billingAddressRequirement` (`"country" | "full"`, defaults to `"country"`) — how much billing address the iframe collects. `country` collects country / region and, for CA / PR / GB / US, a postal code (labeled ZIP for the United States). `full` shows a full street address form with Smarty autocomplete.
|
|
236
236
|
- `onPaymentIntentConfirmationSucceeded` (`(paymentIntent: components["schemas"]["PaymentIntent"]) => void`)
|
|
237
237
|
- `onSetupIntentConfirmationSucceeded` (`(setupIntent: components["schemas"]["SetupIntent"]) => void`)
|
|
238
238
|
- `onHeightChange`, `onAppearanceReady` (advanced — override the default iframe styling logic)
|
|
@@ -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,78 @@
|
|
|
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
|
+
* Uses the same postMessage protocol as Google Pay express checkout.
|
|
77
|
+
*/
|
|
78
|
+
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/
|
|
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,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(e){return`${t(e)}/iframe/google-pay?token=${e}`}function h(){return`40px`}function g(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 _({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 v={country:212,full:452},y=80,b={country:400,full:640};function x(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 S(e,n=`country`){let r=new URLSearchParams({token:e,billingAddressRequirement:n});return`${t(e)}/iframe/bank?${r}`}function C(e={cardholderName:!1},t=`country`){return`${(v[t]??v.country)+(e.cardholderName?y:0)}px`}function w(e=`country`){return`${b[e]??b.country}px`}function T(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 E(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 D={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`};function O({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,D,{height:r}),a}function k(e,t){let n=E(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t,s=O({src:x(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:C(i,a)});n.appendChild(s);let c=T(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 A(e,t){let n=E(e),{renderToken:r,billingAddressRequirement:i=`country`,...a}=t,o=O({src:S(r,i),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:w(i)});n.appendChild(o);let s=T(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 j(e,t){let n=E(e),{renderToken:r,...i}=t,a=O({src:m(r),title:`Secure Google Pay button powered by Amos`,name:`amos-google-pay-button`,height:h(),allow:`payment`});n.appendChild(a);let o=g(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 M(e,t){let n=E(e),{renderToken:r,...i}=t,a=O({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=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.attachApplePayButtonListeners=p,exports.attachGooglePayButtonListeners=g,exports.attachPaymentMethodFormListeners=T,exports.confirmPaymentIntent=c,exports.confirmSetupIntent=l,exports.createMessage=n,exports.decodeJwt=e,exports.formatGooglePayPaymentData=_,exports.getApplePayButtonInitialHeight=f,exports.getApplePayButtonSrc=d,exports.getBankAccountFormInitialHeight=w,exports.getBankAccountFormSrc=S,exports.getCreditCardFormInitialHeight=C,exports.getCreditCardFormSrc=x,exports.getEmbedOrigin=t,exports.getGooglePayButtonInitialHeight=h,exports.getGooglePayButtonSrc=m,exports.mountAmosApplePayButton=M,exports.mountAmosBankAccountPaymentMethodForm=A,exports.mountAmosCreditCardPaymentMethodForm=k,exports.mountAmosGooglePayButton=j,exports.sendConfirmationFailed=u,exports.sendParentReadyMessage=r,exports.updateAmount=a,exports.updateAppearance=i,exports.updateMerchantName=o,exports.validateForm=s;
|
package/dist/index.mjs
CHANGED
|
@@ -82,9 +82,9 @@ 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";
|
|
@@ -163,7 +163,89 @@ function p(e, t) {
|
|
|
163
163
|
}
|
|
164
164
|
};
|
|
165
165
|
}
|
|
166
|
-
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/google-pay.ts
|
|
168
|
+
function m(e) {
|
|
169
|
+
return `${t(e)}/iframe/google-pay?token=${e}`;
|
|
170
|
+
}
|
|
171
|
+
function h() {
|
|
172
|
+
return "40px";
|
|
173
|
+
}
|
|
174
|
+
function g(e, t) {
|
|
175
|
+
let n = { ...t };
|
|
176
|
+
function s() {
|
|
177
|
+
a({
|
|
178
|
+
iframe: e,
|
|
179
|
+
amount: n.amount
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
function l() {
|
|
183
|
+
o({
|
|
184
|
+
iframe: e,
|
|
185
|
+
merchantName: n.merchantName
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
function d(t) {
|
|
189
|
+
switch (t.data.type) {
|
|
190
|
+
case "IFRAME_READY":
|
|
191
|
+
r(e), i({
|
|
192
|
+
iframe: e,
|
|
193
|
+
appearance: n.appearance
|
|
194
|
+
}), s(), l();
|
|
195
|
+
break;
|
|
196
|
+
case "UPDATE_HEIGHT":
|
|
197
|
+
n.onHeightChange?.(t.data.height);
|
|
198
|
+
break;
|
|
199
|
+
case "UPDATE_APPEARANCE":
|
|
200
|
+
i({
|
|
201
|
+
iframe: e,
|
|
202
|
+
appearance: t.data.appearance
|
|
203
|
+
});
|
|
204
|
+
break;
|
|
205
|
+
case "UPDATED_APPEARANCE":
|
|
206
|
+
n.onAppearanceReady?.();
|
|
207
|
+
break;
|
|
208
|
+
case "CREATE_PAYMENT_INTENT":
|
|
209
|
+
n.onInitiatePaymentIntentRequest({
|
|
210
|
+
paymentIntentCreateAttributes: t.data.paymentIntentCreateAttributes,
|
|
211
|
+
customerCreateAttributes: t.data.customerCreateAttributes
|
|
212
|
+
}).then((t) => {
|
|
213
|
+
c({
|
|
214
|
+
iframe: e,
|
|
215
|
+
token: t
|
|
216
|
+
});
|
|
217
|
+
}).catch((t) => {
|
|
218
|
+
u({
|
|
219
|
+
iframe: e,
|
|
220
|
+
errorMessage: t instanceof Error ? t.message : "Unknown error"
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
break;
|
|
224
|
+
case "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED":
|
|
225
|
+
n.onPaymentIntentConfirmationSucceeded(t.data.paymentIntent);
|
|
226
|
+
break;
|
|
227
|
+
case "CONFIRMATION_FAILED":
|
|
228
|
+
n.onConfirmationFailed(t.data.errorMessage);
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return window.addEventListener("message", d), {
|
|
233
|
+
update(t) {
|
|
234
|
+
let r = "appearance" in t, a = "amount" in t, o = "merchantName" in t;
|
|
235
|
+
n = {
|
|
236
|
+
...n,
|
|
237
|
+
...t
|
|
238
|
+
}, r && i({
|
|
239
|
+
iframe: e,
|
|
240
|
+
appearance: n.appearance
|
|
241
|
+
}), a && s(), o && l();
|
|
242
|
+
},
|
|
243
|
+
destroy() {
|
|
244
|
+
window.removeEventListener("message", d);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function _({ paymentData: e }) {
|
|
167
249
|
return { paymentMethod: {
|
|
168
250
|
type: "googlepay",
|
|
169
251
|
billing_address_attributes: {
|
|
@@ -195,16 +277,14 @@ function m({ paymentData: e }) {
|
|
|
195
277
|
}
|
|
196
278
|
//#endregion
|
|
197
279
|
//#region src/payment-method-form.ts
|
|
198
|
-
var
|
|
199
|
-
|
|
200
|
-
postalCodeAndCountry: 212,
|
|
280
|
+
var v = {
|
|
281
|
+
country: 212,
|
|
201
282
|
full: 452
|
|
202
|
-
},
|
|
203
|
-
|
|
204
|
-
postalCodeAndCountry: 400,
|
|
283
|
+
}, y = 80, b = {
|
|
284
|
+
country: 400,
|
|
205
285
|
full: 640
|
|
206
286
|
};
|
|
207
|
-
function
|
|
287
|
+
function x(e, n = { cardholderName: !1 }, r = "country") {
|
|
208
288
|
let i = Object.entries(n).filter(([, e]) => e).map(([e]) => e).join(","), a = new URLSearchParams({
|
|
209
289
|
token: e,
|
|
210
290
|
additionalFields: i,
|
|
@@ -212,20 +292,20 @@ function v(e, n = { cardholderName: !1 }, r = "postalCode") {
|
|
|
212
292
|
});
|
|
213
293
|
return `${t(e)}/iframe/card?${a}`;
|
|
214
294
|
}
|
|
215
|
-
function
|
|
295
|
+
function S(e, n = "country") {
|
|
216
296
|
let r = new URLSearchParams({
|
|
217
297
|
token: e,
|
|
218
298
|
billingAddressRequirement: n
|
|
219
299
|
});
|
|
220
300
|
return `${t(e)}/iframe/bank?${r}`;
|
|
221
301
|
}
|
|
222
|
-
function
|
|
223
|
-
return `${(
|
|
302
|
+
function C(e = { cardholderName: !1 }, t = "country") {
|
|
303
|
+
return `${(v[t] ?? v.country) + (e.cardholderName ? y : 0)}px`;
|
|
224
304
|
}
|
|
225
|
-
function
|
|
226
|
-
return `${
|
|
305
|
+
function w(e = "country") {
|
|
306
|
+
return `${b[e] ?? b.country}px`;
|
|
227
307
|
}
|
|
228
|
-
function
|
|
308
|
+
function T(e, t) {
|
|
229
309
|
let n = { ...t };
|
|
230
310
|
function a(t) {
|
|
231
311
|
switch (t.data.type) {
|
|
@@ -276,7 +356,7 @@ function S(e, t) {
|
|
|
276
356
|
}
|
|
277
357
|
//#endregion
|
|
278
358
|
//#region src/mount.ts
|
|
279
|
-
function
|
|
359
|
+
function E(e) {
|
|
280
360
|
if (typeof e == "string") {
|
|
281
361
|
let t = document.querySelector(e);
|
|
282
362
|
if (!(t instanceof HTMLElement)) throw Error(`[amos-js] Container "${e}" did not match any HTMLElement.`);
|
|
@@ -284,26 +364,26 @@ function C(e) {
|
|
|
284
364
|
}
|
|
285
365
|
return e;
|
|
286
366
|
}
|
|
287
|
-
var
|
|
367
|
+
var D = {
|
|
288
368
|
width: "calc(100% + 8px)",
|
|
289
369
|
transition: "opacity 150ms ease-in, height 200ms ease-in-out",
|
|
290
370
|
margin: "0 -4px",
|
|
291
371
|
opacity: "0",
|
|
292
372
|
border: "0"
|
|
293
373
|
};
|
|
294
|
-
function
|
|
374
|
+
function O({ src: e, title: t, name: n, height: r, allow: i }) {
|
|
295
375
|
let a = document.createElement("iframe");
|
|
296
|
-
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,
|
|
376
|
+
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, D, { height: r }), a;
|
|
297
377
|
}
|
|
298
|
-
function
|
|
299
|
-
let n =
|
|
300
|
-
src:
|
|
378
|
+
function k(e, t) {
|
|
379
|
+
let n = E(e), { renderToken: r, additionalFields: i = { cardholderName: !1 }, billingAddressRequirement: a = "country", ...o } = t, s = O({
|
|
380
|
+
src: x(r, i, a),
|
|
301
381
|
title: "Secure credit card payment method form powered by Amos",
|
|
302
382
|
name: "amos-credit-card-payment-method-form",
|
|
303
|
-
height:
|
|
383
|
+
height: C(i, a)
|
|
304
384
|
});
|
|
305
385
|
n.appendChild(s);
|
|
306
|
-
let c =
|
|
386
|
+
let c = T(s, {
|
|
307
387
|
...o,
|
|
308
388
|
onHeightChange: (e) => {
|
|
309
389
|
s.style.height = e, o.onHeightChange?.(e);
|
|
@@ -320,15 +400,15 @@ function E(e, t) {
|
|
|
320
400
|
}
|
|
321
401
|
};
|
|
322
402
|
}
|
|
323
|
-
function
|
|
324
|
-
let n =
|
|
325
|
-
src:
|
|
403
|
+
function A(e, t) {
|
|
404
|
+
let n = E(e), { renderToken: r, billingAddressRequirement: i = "country", ...a } = t, o = O({
|
|
405
|
+
src: S(r, i),
|
|
326
406
|
title: "Secure bank account payment method form powered by Amos",
|
|
327
407
|
name: "amos-bank-account-payment-method-form",
|
|
328
|
-
height:
|
|
408
|
+
height: w(i)
|
|
329
409
|
});
|
|
330
410
|
n.appendChild(o);
|
|
331
|
-
let s =
|
|
411
|
+
let s = T(o, {
|
|
332
412
|
...a,
|
|
333
413
|
onHeightChange: (e) => {
|
|
334
414
|
o.style.height = e, a.onHeightChange?.(e);
|
|
@@ -345,11 +425,37 @@ function D(e, t) {
|
|
|
345
425
|
}
|
|
346
426
|
};
|
|
347
427
|
}
|
|
348
|
-
function
|
|
349
|
-
let n =
|
|
350
|
-
src:
|
|
428
|
+
function j(e, t) {
|
|
429
|
+
let n = E(e), { renderToken: r, ...i } = t, a = O({
|
|
430
|
+
src: m(r),
|
|
351
431
|
title: "Secure Google Pay button powered by Amos",
|
|
352
432
|
name: "amos-google-pay-button",
|
|
433
|
+
height: h(),
|
|
434
|
+
allow: "payment"
|
|
435
|
+
});
|
|
436
|
+
n.appendChild(a);
|
|
437
|
+
let o = g(a, {
|
|
438
|
+
...i,
|
|
439
|
+
onHeightChange: (e) => {
|
|
440
|
+
a.style.height = e, i.onHeightChange?.(e);
|
|
441
|
+
},
|
|
442
|
+
onAppearanceReady: () => {
|
|
443
|
+
a.style.opacity = "1", i.onAppearanceReady?.();
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
return {
|
|
447
|
+
iframe: a,
|
|
448
|
+
update: o.update,
|
|
449
|
+
destroy() {
|
|
450
|
+
o.destroy(), a.remove();
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
function M(e, t) {
|
|
455
|
+
let n = E(e), { renderToken: r, ...i } = t, a = O({
|
|
456
|
+
src: d(r),
|
|
457
|
+
title: "Secure Apple Pay button powered by Amos",
|
|
458
|
+
name: "amos-apple-pay-button",
|
|
353
459
|
height: f(),
|
|
354
460
|
allow: "payment"
|
|
355
461
|
});
|
|
@@ -372,4 +478,4 @@ function O(e, t) {
|
|
|
372
478
|
};
|
|
373
479
|
}
|
|
374
480
|
//#endregion
|
|
375
|
-
export { p as attachGooglePayButtonListeners,
|
|
481
|
+
export { p as attachApplePayButtonListeners, g as attachGooglePayButtonListeners, T as attachPaymentMethodFormListeners, c as confirmPaymentIntent, l as confirmSetupIntent, n as createMessage, e as decodeJwt, _ as formatGooglePayPaymentData, f as getApplePayButtonInitialHeight, d as getApplePayButtonSrc, w as getBankAccountFormInitialHeight, S as getBankAccountFormSrc, C as getCreditCardFormInitialHeight, x as getCreditCardFormSrc, t as getEmbedOrigin, h as getGooglePayButtonInitialHeight, m as getGooglePayButtonSrc, M as mountAmosApplePayButton, A as mountAmosBankAccountPaymentMethodForm, k as mountAmosCreditCardPaymentMethodForm, j 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;
|
|
@@ -23,7 +24,7 @@ export type AmosCreditCardPaymentMethodFormOptions = PaymentMethodFormListenerOp
|
|
|
23
24
|
/**
|
|
24
25
|
* How much billing address the form collects.
|
|
25
26
|
*
|
|
26
|
-
* @default "
|
|
27
|
+
* @default "country"
|
|
27
28
|
*/
|
|
28
29
|
billingAddressRequirement?: BillingAddressRequirement;
|
|
29
30
|
};
|
|
@@ -63,7 +64,7 @@ export type AmosBankAccountPaymentMethodFormOptions = PaymentMethodFormListenerO
|
|
|
63
64
|
/**
|
|
64
65
|
* How much billing address the form collects.
|
|
65
66
|
*
|
|
66
|
-
* @default "
|
|
67
|
+
* @default "country"
|
|
67
68
|
*/
|
|
68
69
|
billingAddressRequirement?: BillingAddressRequirement;
|
|
69
70
|
};
|
|
@@ -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 {};
|
|
@@ -12,12 +12,11 @@ export type CreditCardAdditionalFields = {
|
|
|
12
12
|
* How much billing address the embedded credit-card or bank-account form
|
|
13
13
|
* collects.
|
|
14
14
|
*
|
|
15
|
-
* - `
|
|
16
|
-
*
|
|
17
|
-
* - `postalCodeAndCountry` — country and postal code, both required.
|
|
15
|
+
* - `country` — country / region, plus postal / ZIP when that selection
|
|
16
|
+
* collects one (CA, PR, GB, US). Default.
|
|
18
17
|
* - `full` — full street address (Smarty autocomplete on line 1).
|
|
19
18
|
*/
|
|
20
|
-
export type BillingAddressRequirement = "
|
|
19
|
+
export type BillingAddressRequirement = "country" | "full";
|
|
21
20
|
/**
|
|
22
21
|
* Build the iframe `src` URL for the embedded credit-card form.
|
|
23
22
|
*/
|
package/package.json
CHANGED
package/src/apple-pay.ts
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
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
|
+
/**
|
|
92
|
+
* Wire up the host-page side of the Apple Pay iframe message protocol
|
|
93
|
+
* on an existing `<iframe>` element. Returns a controller for updating
|
|
94
|
+
* options and tearing down the listener.
|
|
95
|
+
*
|
|
96
|
+
* The iframe is expected to have already been added to the DOM with the
|
|
97
|
+
* correct `src` (see {@link getApplePayButtonSrc}).
|
|
98
|
+
*
|
|
99
|
+
* Uses the same postMessage protocol as Google Pay express checkout.
|
|
100
|
+
*/
|
|
101
|
+
export function attachApplePayButtonListeners(
|
|
102
|
+
iframe: HTMLIFrameElement,
|
|
103
|
+
options: ApplePayButtonListenerOptions,
|
|
104
|
+
): ApplePayButtonController {
|
|
105
|
+
let current = { ...options };
|
|
106
|
+
|
|
107
|
+
function pushAmount() {
|
|
108
|
+
sendUpdateAmount({ iframe, amount: current.amount });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function pushMerchantName() {
|
|
112
|
+
sendUpdateMerchantName({ iframe, merchantName: current.merchantName });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function handleMessage(event: MessageEvent<Message>) {
|
|
116
|
+
switch (event.data.type) {
|
|
117
|
+
case "IFRAME_READY":
|
|
118
|
+
sendParentReadyMessage(iframe);
|
|
119
|
+
sendUpdateAppearance({ iframe, appearance: current.appearance });
|
|
120
|
+
pushAmount();
|
|
121
|
+
pushMerchantName();
|
|
122
|
+
break;
|
|
123
|
+
|
|
124
|
+
case "UPDATE_HEIGHT":
|
|
125
|
+
current.onHeightChange?.(event.data.height);
|
|
126
|
+
break;
|
|
127
|
+
|
|
128
|
+
case "UPDATE_APPEARANCE":
|
|
129
|
+
sendUpdateAppearance({ iframe, appearance: event.data.appearance });
|
|
130
|
+
break;
|
|
131
|
+
|
|
132
|
+
case "UPDATED_APPEARANCE":
|
|
133
|
+
current.onAppearanceReady?.();
|
|
134
|
+
break;
|
|
135
|
+
|
|
136
|
+
case "CREATE_PAYMENT_INTENT":
|
|
137
|
+
current
|
|
138
|
+
.onInitiatePaymentIntentRequest({
|
|
139
|
+
paymentIntentCreateAttributes:
|
|
140
|
+
event.data.paymentIntentCreateAttributes,
|
|
141
|
+
customerCreateAttributes: event.data.customerCreateAttributes,
|
|
142
|
+
})
|
|
143
|
+
.then((token) => {
|
|
144
|
+
confirmPaymentIntent({ iframe, token });
|
|
145
|
+
})
|
|
146
|
+
.catch((error: unknown) => {
|
|
147
|
+
sendConfirmationFailed({
|
|
148
|
+
iframe,
|
|
149
|
+
errorMessage:
|
|
150
|
+
error instanceof Error ? error.message : "Unknown error",
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
break;
|
|
154
|
+
|
|
155
|
+
case "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED":
|
|
156
|
+
current.onPaymentIntentConfirmationSucceeded(event.data.paymentIntent);
|
|
157
|
+
break;
|
|
158
|
+
|
|
159
|
+
case "CONFIRMATION_FAILED":
|
|
160
|
+
current.onConfirmationFailed(event.data.errorMessage);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
window.addEventListener("message", handleMessage);
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
update(patch) {
|
|
169
|
+
const hadAppearance = "appearance" in patch;
|
|
170
|
+
const hadAmount = "amount" in patch;
|
|
171
|
+
const hadMerchantName = "merchantName" in patch;
|
|
172
|
+
current = { ...current, ...patch };
|
|
173
|
+
if (hadAppearance) {
|
|
174
|
+
sendUpdateAppearance({ iframe, appearance: current.appearance });
|
|
175
|
+
}
|
|
176
|
+
if (hadAmount) {
|
|
177
|
+
pushAmount();
|
|
178
|
+
}
|
|
179
|
+
if (hadMerchantName) {
|
|
180
|
+
pushMerchantName();
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
destroy() {
|
|
184
|
+
window.removeEventListener("message", handleMessage);
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
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,
|
|
@@ -89,7 +96,7 @@ export type AmosCreditCardPaymentMethodFormOptions =
|
|
|
89
96
|
/**
|
|
90
97
|
* How much billing address the form collects.
|
|
91
98
|
*
|
|
92
|
-
* @default "
|
|
99
|
+
* @default "country"
|
|
93
100
|
*/
|
|
94
101
|
billingAddressRequirement?: BillingAddressRequirement;
|
|
95
102
|
};
|
|
@@ -125,7 +132,7 @@ export function mountAmosCreditCardPaymentMethodForm(
|
|
|
125
132
|
const {
|
|
126
133
|
renderToken,
|
|
127
134
|
additionalFields = { cardholderName: false },
|
|
128
|
-
billingAddressRequirement = "
|
|
135
|
+
billingAddressRequirement = "country",
|
|
129
136
|
...listenerOptions
|
|
130
137
|
} = options;
|
|
131
138
|
|
|
@@ -181,7 +188,7 @@ export type AmosBankAccountPaymentMethodFormOptions =
|
|
|
181
188
|
/**
|
|
182
189
|
* How much billing address the form collects.
|
|
183
190
|
*
|
|
184
|
-
* @default "
|
|
191
|
+
* @default "country"
|
|
185
192
|
*/
|
|
186
193
|
billingAddressRequirement?: BillingAddressRequirement;
|
|
187
194
|
};
|
|
@@ -202,7 +209,7 @@ export function mountAmosBankAccountPaymentMethodForm(
|
|
|
202
209
|
const host = resolveContainer(container);
|
|
203
210
|
const {
|
|
204
211
|
renderToken,
|
|
205
|
-
billingAddressRequirement = "
|
|
212
|
+
billingAddressRequirement = "country",
|
|
206
213
|
...listenerOptions
|
|
207
214
|
} = options;
|
|
208
215
|
|
|
@@ -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
|
+
}
|
|
@@ -19,28 +19,22 @@ export type CreditCardAdditionalFields = {
|
|
|
19
19
|
* How much billing address the embedded credit-card or bank-account form
|
|
20
20
|
* collects.
|
|
21
21
|
*
|
|
22
|
-
* - `
|
|
23
|
-
*
|
|
24
|
-
* - `postalCodeAndCountry` — country and postal code, both required.
|
|
22
|
+
* - `country` — country / region, plus postal / ZIP when that selection
|
|
23
|
+
* collects one (CA, PR, GB, US). Default.
|
|
25
24
|
* - `full` — full street address (Smarty autocomplete on line 1).
|
|
26
25
|
*/
|
|
27
|
-
export type BillingAddressRequirement =
|
|
28
|
-
| "postalCode"
|
|
29
|
-
| "postalCodeAndCountry"
|
|
30
|
-
| "full";
|
|
26
|
+
export type BillingAddressRequirement = "country" | "full";
|
|
31
27
|
|
|
32
28
|
const CREDIT_CARD_ADDRESS_HEIGHT_PX: Record<BillingAddressRequirement, number> =
|
|
33
29
|
{
|
|
34
|
-
|
|
35
|
-
postalCodeAndCountry: 212,
|
|
30
|
+
country: 212,
|
|
36
31
|
full: 452,
|
|
37
32
|
};
|
|
38
33
|
|
|
39
34
|
const CREDIT_CARD_CARDHOLDER_NAME_HEIGHT_PX = 80;
|
|
40
35
|
|
|
41
36
|
const BANK_ACCOUNT_HEIGHT_PX: Record<BillingAddressRequirement, number> = {
|
|
42
|
-
|
|
43
|
-
postalCodeAndCountry: 400,
|
|
37
|
+
country: 400,
|
|
44
38
|
full: 640,
|
|
45
39
|
};
|
|
46
40
|
|
|
@@ -50,7 +44,7 @@ const BANK_ACCOUNT_HEIGHT_PX: Record<BillingAddressRequirement, number> = {
|
|
|
50
44
|
export function getCreditCardFormSrc(
|
|
51
45
|
renderToken: string,
|
|
52
46
|
additionalFields: CreditCardAdditionalFields = { cardholderName: false },
|
|
53
|
-
billingAddressRequirement: BillingAddressRequirement = "
|
|
47
|
+
billingAddressRequirement: BillingAddressRequirement = "country",
|
|
54
48
|
): string {
|
|
55
49
|
const enabled = Object.entries(additionalFields)
|
|
56
50
|
.filter(([, value]) => value)
|
|
@@ -71,7 +65,7 @@ export function getCreditCardFormSrc(
|
|
|
71
65
|
*/
|
|
72
66
|
export function getBankAccountFormSrc(
|
|
73
67
|
renderToken: string,
|
|
74
|
-
billingAddressRequirement: BillingAddressRequirement = "
|
|
68
|
+
billingAddressRequirement: BillingAddressRequirement = "country",
|
|
75
69
|
): string {
|
|
76
70
|
const params = new URLSearchParams({
|
|
77
71
|
token: renderToken,
|
|
@@ -88,11 +82,11 @@ export function getBankAccountFormSrc(
|
|
|
88
82
|
*/
|
|
89
83
|
export function getCreditCardFormInitialHeight(
|
|
90
84
|
additionalFields: CreditCardAdditionalFields = { cardholderName: false },
|
|
91
|
-
billingAddressRequirement: BillingAddressRequirement = "
|
|
85
|
+
billingAddressRequirement: BillingAddressRequirement = "country",
|
|
92
86
|
): string {
|
|
93
87
|
const addressHeight =
|
|
94
88
|
CREDIT_CARD_ADDRESS_HEIGHT_PX[billingAddressRequirement] ??
|
|
95
|
-
CREDIT_CARD_ADDRESS_HEIGHT_PX.
|
|
89
|
+
CREDIT_CARD_ADDRESS_HEIGHT_PX.country;
|
|
96
90
|
const cardholderExtra = additionalFields.cardholderName
|
|
97
91
|
? CREDIT_CARD_CARDHOLDER_NAME_HEIGHT_PX
|
|
98
92
|
: 0;
|
|
@@ -104,9 +98,9 @@ export function getCreditCardFormInitialHeight(
|
|
|
104
98
|
* `billingAddressRequirement` into account.
|
|
105
99
|
*/
|
|
106
100
|
export function getBankAccountFormInitialHeight(
|
|
107
|
-
billingAddressRequirement: BillingAddressRequirement = "
|
|
101
|
+
billingAddressRequirement: BillingAddressRequirement = "country",
|
|
108
102
|
): string {
|
|
109
|
-
return `${BANK_ACCOUNT_HEIGHT_PX[billingAddressRequirement] ?? BANK_ACCOUNT_HEIGHT_PX.
|
|
103
|
+
return `${BANK_ACCOUNT_HEIGHT_PX[billingAddressRequirement] ?? BANK_ACCOUNT_HEIGHT_PX.country}px`;
|
|
110
104
|
}
|
|
111
105
|
|
|
112
106
|
/**
|