@amos.com/amos-js 0.7.2 → 0.9.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 CHANGED
@@ -51,11 +51,14 @@ const form = mountAmosCreditCardPaymentMethodForm(
51
51
  "--radius": "0.5rem",
52
52
  },
53
53
  },
54
- onPaymentIntentConfirmationSucceeded: (paymentIntent) => {
55
- console.log("Payment succeeded:", paymentIntent.id);
56
- },
57
- onConfirmationFailed: (errorMessage) => {
58
- console.error("Payment failed:", errorMessage);
54
+ onResult: (result) => {
55
+ // Unlock UI. Verify settlement on your backend via webhooks.
56
+ if (result.status === "succeeded") {
57
+ console.log("Confirm returned:", result);
58
+ } else if (result.status === "failed") {
59
+ console.error("Confirm failed:", result.errorMessage);
60
+ }
61
+ // status === "incomplete": field errors shown in the iframe; customer can retry
59
62
  },
60
63
  },
61
64
  );
@@ -87,12 +90,12 @@ form.destroy();
87
90
  The following flow is for credit card and bank account payment method types only.
88
91
 
89
92
  1. **Set up prerequisites**: create a `renderToken` (safe for client), and keep `apiKey` and `accountId` server-side only.
90
- 2. **Render your checkout UI** by calling `mountAmosCreditCardPaymentMethodForm(container, options)` (or `mountAmosBankAccountPaymentMethodForm(...)`) along with the required option (`onConfirmationFailed`) and optional callbacks (`onPaymentIntentConfirmationSucceeded`, `onSetupIntentConfirmationSucceeded`). The iframe height is auto-managed by the SDK.
93
+ 2. **Render your checkout UI** by calling `mountAmosCreditCardPaymentMethodForm(container, options)` (or `mountAmosBankAccountPaymentMethodForm(...)`) along with the required `onResult` callback. The iframe height is auto-managed by the SDK.
91
94
  3. **User clicks "Pay now" button**: call `validateForm({ iframe: form.iframe })`, which returns `Promise<true>` if the embedded form is valid, and `Promise<false>` otherwise.
92
95
  4. **Create payment intent on your server**: use your server-side Amos client to call `POST /payment_intents`. You may also associate this payment intent with a new or existing customer via `POST /customers`. This must be server-side because it uses your private API key.
93
96
  5. **Return the payment intent token to the browser**: your backend responds with the embed token (`components["schemas"]["EmbedToken"]`) needed for confirmation.
94
97
  6. **Confirm the payment intent from the client**: call `confirmPaymentIntent({ iframe: form.iframe, token })` in the browser to continue the payment flow.
95
- 7. **Handle UX**: show the user a "processing" state when the "Pay now" button is clicked, and show a success or error message via `onPaymentIntentConfirmationSucceeded` and `onConfirmationFailed`.
98
+ 7. **Handle UX**: show the user a "processing" state when the "Pay now" button is clicked, and handle `onResult`. Do not treat `onResult` as settlement proof — verify payment success on your backend via webhooks. Recoverable field errors are shown in the iframe (`status: "incomplete"`).
96
99
 
97
100
  ### Google Pay
98
101
 
@@ -128,11 +131,12 @@ const button = mountAmosGooglePayButton(
128
131
  const { token } = await response.json();
129
132
  return token;
130
133
  },
131
- onPaymentIntentConfirmationSucceeded: (paymentIntent) => {
132
- console.log("Google Pay succeeded:", paymentIntent.id);
133
- },
134
- onConfirmationFailed: (errorMessage) => {
135
- console.error("Google Pay failed:", errorMessage);
134
+ onResult: (result) => {
135
+ if (result.status === "succeeded") {
136
+ console.log("Google Pay confirm returned:", result);
137
+ } else if (result.status === "failed") {
138
+ console.error("Google Pay failed:", result.errorMessage);
139
+ }
136
140
  },
137
141
  },
138
142
  );
@@ -147,7 +151,7 @@ Setup intents are used to save payment methods for future use (e.g. recurring pa
147
151
 
148
152
  - On the server, call `POST /setup_intents` instead of `POST /payment_intents`.
149
153
  - On the client, call `confirmSetupIntent({ iframe, token })` instead of `confirmPaymentIntent({ iframe, token })`.
150
- - Use `onSetupIntentConfirmationSucceeded` instead of `onPaymentIntentConfirmationSucceeded`.
154
+ - The same `onResult` callback is used; succeeded setup intents arrive as `{ status: "succeeded", intent: "setup", setupIntent }`.
151
155
 
152
156
  The same `mountAmosCreditCardPaymentMethodForm` / `mountAmosBankAccountPaymentMethodForm` controllers support both payment intents and setup intents — they are differentiated by which confirmation function you call.
153
157
 
@@ -226,15 +230,15 @@ Mount the secure credit-card payment method form into a container element (an `H
226
230
  **Required `options`:**
227
231
 
228
232
  - `renderToken` (`string`)
229
- - `onConfirmationFailed` (`(errorMessage: string) => void`)
233
+ - `onResult` (`(result: ConfirmationResult) => void`) — required. Called when the interactive confirmation attempt finishes (`succeeded`, `failed`, or `incomplete`). Not settlement proof; verify via webhooks.
230
234
 
231
235
  **Optional `options`:**
232
236
 
233
237
  - `appearance` (`{ themeVariables?: Partial<Record<ThemeVariable, string>>; labels?: "above" | "floating" | "placeholder" }`)
234
238
  - `additionalFields` (`{ cardholderName: boolean }`, defaults to `{ cardholderName: false }`)
235
239
  - `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
- - `onPaymentIntentConfirmationSucceeded` (`(paymentIntent: components["schemas"]["PaymentIntent"]) => void`)
237
- - `onSetupIntentConfirmationSucceeded` (`(setupIntent: components["schemas"]["SetupIntent"]) => void`)
240
+
241
+
238
242
  - `onHeightChange`, `onAppearanceReady` (advanced — override the default iframe styling logic)
239
243
 
240
244
  **Returns** `AmosPaymentMethodFormMountController`:
@@ -257,8 +261,8 @@ Mount the secure Google Pay button (express checkout) into a container element.
257
261
  - `amount` (`string`)
258
262
  - `merchantName` (`string`)
259
263
  - `onInitiatePaymentIntentRequest` (`({ paymentIntentCreateAttributes, customerCreateAttributes }) => Promise<components["schemas"]["EmbedToken"]["token"]>`)
260
- - `onPaymentIntentConfirmationSucceeded` (`(paymentIntent: components["schemas"]["PaymentIntent"]) => void`)
261
- - `onConfirmationFailed` (`(errorMessage: string) => void`)
264
+
265
+ - `onResult` (`(result: ConfirmationResult) => void`) — required. Called when the interactive confirmation attempt finishes (`succeeded`, `failed`, or `incomplete`). Not settlement proof; verify via webhooks.
262
266
 
263
267
  **Optional `options`:** `appearance`, `onHeightChange`, `onAppearanceReady`.
264
268
 
@@ -307,7 +311,7 @@ Advanced helpers exposed for integrators that need to construct or inspect the m
307
311
  ## Notes and potential gotchas
308
312
 
309
313
  - **`iframe` argument**: every messaging helper (`validateForm`, `confirmPaymentIntent`, `confirmSetupIntent`) accepts the `iframe` element directly. With the mount helpers, use `controller.iframe`.
310
- - **Same components for payment vs setup intents**: `mountAmosCreditCardPaymentMethodForm` and `mountAmosBankAccountPaymentMethodForm` support both payment intents and setup intents. The flow differs only by which server call you make and which confirmation function you use. You may optionally provide `onPaymentIntentConfirmationSucceeded` and/or `onSetupIntentConfirmationSucceeded`; the appropriate one is invoked based on the flow.
314
+ - **Same components for payment vs setup intents**: `mountAmosCreditCardPaymentMethodForm` and `mountAmosBankAccountPaymentMethodForm` support both payment intents and setup intents. The flow differs only by which server call you make and which confirmation function you use. Handle both outcomes via `onResult`.
311
315
  - **Amount format**: for `mountAmosGooglePayButton`, `amount` is a string (e.g. `"5000"` for $50.00). For `components["schemas"]["CreatePaymentIntentInput"]` on the server, `amount` is a number in cents (e.g. `5000`).
312
316
  - **Browser-only**: the mount and messaging helpers require `window` and the DOM. They are not safe to call during server-side rendering — call them from client-side code only (for example, inside a `useEffect`-like hook in your framework of choice).
313
317
 
@@ -1,5 +1,5 @@
1
1
  import { components } from '@amos.com/node';
2
- import { Appearance } from './types';
2
+ import { Appearance, ConfirmationResult } from './types';
3
3
  /**
4
4
  * Build the iframe `src` URL for the embedded Apple Pay button.
5
5
  */
@@ -41,13 +41,10 @@ export type ApplePayButtonListenerOptions = {
41
41
  customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
42
42
  }) => Promise<components["schemas"]["EmbedToken"]["token"]>;
43
43
  /**
44
- * Called when payment intent confirmation succeeds.
44
+ * Called when the interactive confirmation flow finishes (success or
45
+ * terminal failure). Not settlement proof — verify via webhooks.
45
46
  */
46
- onPaymentIntentConfirmationSucceeded: (paymentIntent: components["schemas"]["PaymentIntent"]) => void;
47
- /**
48
- * Called when payment intent confirmation fails.
49
- */
50
- onConfirmationFailed: (errorMessage: string) => void;
47
+ onResult: (result: ConfirmationResult) => void;
51
48
  };
52
49
  /**
53
50
  * Controller returned by {@link attachApplePayButtonListeners} and
@@ -1,5 +1,5 @@
1
1
  import { components } from '@amos.com/node';
2
- import { Appearance } from './types';
2
+ import { Appearance, ConfirmationResult } from './types';
3
3
  /**
4
4
  * Build the iframe `src` URL for the embedded Google Pay button.
5
5
  */
@@ -41,13 +41,10 @@ export type GooglePayButtonListenerOptions = {
41
41
  customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
42
42
  }) => Promise<components["schemas"]["EmbedToken"]["token"]>;
43
43
  /**
44
- * Called when payment intent confirmation succeeds.
44
+ * Called when the interactive confirmation flow finishes (success or
45
+ * terminal failure). Not settlement proof — verify via webhooks.
45
46
  */
46
- onPaymentIntentConfirmationSucceeded: (paymentIntent: components["schemas"]["PaymentIntent"]) => void;
47
- /**
48
- * Called when payment intent confirmation fails.
49
- */
50
- onConfirmationFailed: (errorMessage: string) => void;
47
+ onResult: (result: ConfirmationResult) => void;
51
48
  };
52
49
  /**
53
50
  * Controller returned by {@link attachGooglePayButtonListeners} and
package/dist/index.d.ts CHANGED
@@ -4,10 +4,10 @@ export { attachApplePayButtonListeners, getApplePayButtonInitialHeight, getApple
4
4
  export type { FormattedGooglePayPaymentData, GooglePayButtonController, GooglePayButtonListenerOptions, } from './google-pay';
5
5
  export { attachGooglePayButtonListeners, formatGooglePayPaymentData, getGooglePayButtonInitialHeight, getGooglePayButtonSrc, } from './google-pay';
6
6
  export { decodeJwt, getEmbedOrigin } from './jwt';
7
- export { confirmPaymentIntent, confirmSetupIntent, sendConfirmationFailed, sendParentReadyMessage, updateAmount, updateAppearance, updateMerchantName, validateForm, } from './messaging';
7
+ export { confirmPaymentIntent, confirmSetupIntent, sendConfirmationResult, sendParentReadyMessage, updateAmount, updateAppearance, updateMerchantName, validateForm, } from './messaging';
8
8
  export type { AmosApplePayButtonMountController, AmosApplePayButtonOptions, AmosBankAccountPaymentMethodFormOptions, AmosCreditCardPaymentMethodFormOptions, AmosGooglePayButtonMountController, AmosGooglePayButtonOptions, AmosPaymentMethodFormMountController, } from './mount';
9
9
  export { mountAmosApplePayButton, mountAmosBankAccountPaymentMethodForm, mountAmosCreditCardPaymentMethodForm, mountAmosGooglePayButton, } from './mount';
10
10
  export type { BillingAddressRequirement, CreditCardAdditionalFields, PaymentMethodFormController, PaymentMethodFormListenerOptions, } from './payment-method-form';
11
11
  export { attachPaymentMethodFormListeners, getBankAccountFormInitialHeight, getBankAccountFormSrc, getCreditCardFormInitialHeight, getCreditCardFormSrc, } from './payment-method-form';
12
- export type { Appearance, AppearanceLabels, Message, ThemeVariable, } from './types';
12
+ export type { Appearance, AppearanceLabels, ConfirmationResult, Message, ThemeVariable, } from './types';
13
13
  export { createMessage } from './types';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`data-amos-apple-pay-waiting`;function t({onCancel:t}){let n=document.querySelector(`[${e}]`);if(n)return n;let r=document.createElement(`div`);r.setAttribute(e,`true`),r.setAttribute(`role`,`dialog`),r.setAttribute(`aria-modal`,`true`),r.setAttribute(`aria-labelledby`,`amos-apple-pay-waiting-title`),Object.assign(r.style,{position:`fixed`,inset:`0`,zIndex:`2147483646`,display:`flex`,alignItems:`center`,justifyContent:`center`,padding:`24px`,boxSizing:`border-box`,background:`rgba(0, 0, 0, 0.55)`,fontFamily:`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif`});let i=document.createElement(`div`);Object.assign(i.style,{width:`100%`,maxWidth:`360px`,borderRadius:`12px`,background:`#fff`,padding:`28px 24px 20px`,boxSizing:`border-box`,textAlign:`center`,boxShadow:`0 12px 40px rgba(0, 0, 0, 0.25)`});let a=document.createElement(`div`);a.setAttribute(`aria-hidden`,`true`),Object.assign(a.style,{display:`inline-flex`,alignItems:`center`,justifyContent:`center`,gap:`6px`,marginBottom:`16px`,fontSize:`28px`,fontWeight:`600`,letterSpacing:`-0.02em`,color:`#000`,lineHeight:`1`}),a.innerHTML=`<svg width="22" height="26" viewBox="0 0 14 17" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M13.072 5.846c-.1.08-1.873 1.09-1.873 3.34 0 2.61 2.29 3.53 2.36 3.55-.04.1-.368 1.27-.766 2.52-.35 1.09-.72 2.18-1.28 2.18-.55 0-.73-.36-1.43-.36-.71 0-.93.37-1.48.37-.55 0-.93-.99-1.35-2.01-.5-1.2-.88-2.43-.88-3.85 0-2.26 1.47-3.46 2.91-3.46.57 0 1.11.38 1.49.38.37 0 .98-.45 1.7-.45.28 0 1.27.03 1.97 1.01ZM9.52 3.37c.3-.36.52-.86.52-1.36 0-.07 0-.14-.01-.2-.5.02-1.1.33-1.46.75-.28.32-.55.84-.55 1.35 0 .07.01.15.02.17.04.01.1.02.16.02.45 0 1.02-.3 1.32-.73Z"/></svg><span>Pay</span>`;let o=document.createElement(`p`);o.id=`amos-apple-pay-waiting-title`,Object.assign(o.style,{margin:`0 0 20px`,fontSize:`15px`,lineHeight:`1.45`,color:`#1a1a1a`}),o.textContent=`Complete your payment in the open Apple Pay window, or close Apple Pay to continue paying another way.`;let s=document.createElement(`button`);return s.type=`button`,s.textContent=`Cancel payment`,Object.assign(s.style,{display:`block`,width:`100%`,border:`none`,borderRadius:`8px`,padding:`12px 16px`,background:`#2c2c2e`,color:`#fff`,fontSize:`15px`,fontWeight:`500`,cursor:`pointer`}),s.addEventListener(`click`,t),i.append(a,o,s),r.append(i),document.body.append(r),r}function n(){document.querySelector(`[${e}]`)?.remove()}function r(e){let[t=``,n=``,r=``]=e?.split(`.`)??[],i=typeof atob==`function`?atob:e=>Buffer.from(e,`base64`).toString(`utf8`);return{header:JSON.parse(i(t)),payload:JSON.parse(i(n)),signature:r}}function i(e){let{env:t=`sandbox`}=r(e).payload;switch(t){case`production`:return`https://embed.amos.com`;case`sandbox`:return`https://embed-sandbox.amos.com`;default:return`https://embed-sandbox.amos.com`}}function a(e){return e}function o(e){e?.contentWindow?.postMessage(a({type:`PARENT_ACKNOWLEDGED_IFRAME_READY`}),`*`)}function s({iframe:e,appearance:t={}}){e?.contentWindow?.postMessage(a({type:`UPDATE_APPEARANCE`,appearance:t}),`*`)}function c({iframe:e,amount:t}){e?.contentWindow?.postMessage(a({type:`UPDATE_AMOUNT`,amount:t}),`*`)}function l({iframe:e,merchantName:t}){e?.contentWindow?.postMessage(a({type:`UPDATE_MERCHANT_NAME`,merchantName:t}),`*`)}function u({iframe:e}){let t=crypto.randomUUID();return new Promise(n=>{e?.contentWindow?.postMessage(a({type:`VALIDATE_FORM`,requestId:t}),`*`);let r=setTimeout(()=>{window.removeEventListener(`message`,i),n(!1)},5e3);function i(e){e.data.type===`VALIDATE_FORM`&&e.data.requestId===t&&(window.removeEventListener(`message`,i),clearTimeout(r),n(e.data.isValid??!1))}window.addEventListener(`message`,i)})}function d({iframe:e,token:t}){let{payment_intent_id:n}=r(t).payload;e?.contentWindow?.postMessage(a({type:`CONFIRM_PAYMENT_INTENT`,token:t,id:n??void 0}),`*`)}function f({iframe:e,token:t}){let{setup_intent_id:n}=r(t).payload;e?.contentWindow?.postMessage(a({type:`CONFIRM_SETUP_INTENT`,token:t,id:n??void 0}),`*`)}function p({iframe:e,errorMessage:t}){e?.contentWindow?.postMessage(a({type:`CONFIRMATION_FAILED`,errorMessage:t}),`*`)}function m(e){return`${i(e)}/iframe/apple-pay?token=${e}`}function h(){return`40px`}function g(e){e.contentWindow?.postMessage(a({type:`APPLE_PAY_CANCEL`}),`*`)}function _(e,r){let i={...r};function a(){c({iframe:e,amount:i.amount})}function u(){l({iframe:e,merchantName:i.merchantName})}function f(r){if(r.source===e.contentWindow)switch(r.data.type){case`IFRAME_READY`:o(e),s({iframe:e,appearance:i.appearance}),a(),u();break;case`UPDATE_HEIGHT`:i.onHeightChange?.(r.data.height);break;case`UPDATE_APPEARANCE`:s({iframe:e,appearance:r.data.appearance});break;case`UPDATED_APPEARANCE`:i.onAppearanceReady?.();break;case`APPLE_PAY_WINDOW_OPEN`:t({onCancel:()=>{g(e),n()}});break;case`APPLE_PAY_WINDOW_CLOSE`:n();break;case`CREATE_PAYMENT_INTENT`:i.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:r.data.paymentIntentCreateAttributes,customerCreateAttributes:r.data.customerCreateAttributes}).then(t=>{d({iframe:e,token:t})}).catch(t=>{p({iframe:e,errorMessage:t instanceof Error?t.message:`Unknown error`})});break;case`PAYMENT_INTENT_CONFIRMATION_SUCCEEDED`:n(),i.onPaymentIntentConfirmationSucceeded(r.data.paymentIntent);break;case`CONFIRMATION_FAILED`:n(),i.onConfirmationFailed(r.data.errorMessage);break}}return window.addEventListener(`message`,f),{update(t){let n=`appearance`in t,r=`amount`in t,o=`merchantName`in t;i={...i,...t},n&&s({iframe:e,appearance:i.appearance}),r&&a(),o&&u()},destroy(){window.removeEventListener(`message`,f),n()}}}function v(e){return`${i(e)}/iframe/google-pay?token=${e}`}function y(){return`40px`}function b(e,t){let n={...t};function r(){c({iframe:e,amount:n.amount})}function i(){l({iframe:e,merchantName:n.merchantName})}function a(t){switch(t.data.type){case`IFRAME_READY`:o(e),s({iframe:e,appearance:n.appearance}),r(),i();break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:s({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`CREATE_PAYMENT_INTENT`:n.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:t.data.paymentIntentCreateAttributes,customerCreateAttributes:t.data.customerCreateAttributes}).then(t=>{d({iframe:e,token:t})}).catch(t=>{p({iframe:e,errorMessage:t instanceof Error?t.message:`Unknown error`})});break;case`PAYMENT_INTENT_CONFIRMATION_SUCCEEDED`:n.onPaymentIntentConfirmationSucceeded(t.data.paymentIntent);break;case`CONFIRMATION_FAILED`:n.onConfirmationFailed(t.data.errorMessage);break}}return window.addEventListener(`message`,a),{update(t){let a=`appearance`in t,o=`amount`in t,c=`merchantName`in t;n={...n,...t},a&&s({iframe:e,appearance:n.appearance}),o&&r(),c&&i()},destroy(){window.removeEventListener(`message`,a)}}}function x({paymentData:e}){return{paymentMethod:{type:`googlepay`,billing_address_attributes:{name:e.shippingAddress?.name,address_line1:e.shippingAddress?.address1,address_line2:e.shippingAddress?.address2,city:e.shippingAddress?.locality,state:e.shippingAddress?.administrativeArea,postal_code:e.shippingAddress?.postalCode,country:e.shippingAddress?.countryCode,email:e.email,phone:e.shippingAddress?.phoneNumber},card_profile_attributes:{wallet_provider:`googlepay`,wallet_payload:e.paymentMethodData.tokenizationData.token,wallet_last4:e.paymentMethodData.info?.cardDetails,wallet_brand:(()=>{switch(e.paymentMethodData.info?.cardNetwork){case`AMEX`:return`american_express`;case`VISA`:return`visa`;case`MASTERCARD`:return`master`;case`DISCOVER`:return`discover`;default:return}})()}}}}var S={country:212,full:452},C=80,w={country:400,full:640};function T(e,t={cardholderName:!1},n=`country`){let r=Object.entries(t).filter(([,e])=>e).map(([e])=>e).join(`,`),a=new URLSearchParams({token:e,additionalFields:r,billingAddressRequirement:n});return`${i(e)}/iframe/card?${a}`}function E(e,t=`country`){let n=new URLSearchParams({token:e,billingAddressRequirement:t});return`${i(e)}/iframe/bank?${n}`}function D(e={cardholderName:!1},t=`country`){return`${(S[t]??S.country)+(e.cardholderName?C:0)}px`}function O(e=`country`){return`${w[e]??w.country}px`}function k(e,t){let n={...t};function r(t){switch(t.data.type){case`IFRAME_READY`:o(e),s({iframe:e,appearance:n.appearance});break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:s({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`PAYMENT_INTENT_CONFIRMATION_SUCCEEDED`:n.onPaymentIntentConfirmationSucceeded?.(t.data.paymentIntent);break;case`SETUP_INTENT_CONFIRMATION_SUCCEEDED`:n.onSetupIntentConfirmationSucceeded?.(t.data.setupIntent);break;case`CONFIRMATION_FAILED`:n.onConfirmationFailed(t.data.errorMessage);break}}return window.addEventListener(`message`,r),{update(t){let r=`appearance`in t;n={...n,...t},r&&s({iframe:e,appearance:n.appearance})},destroy(){window.removeEventListener(`message`,r)}}}function A(e){if(typeof e==`string`){let t=document.querySelector(e);if(!(t instanceof HTMLElement))throw Error(`[amos-js] Container "${e}" did not match any HTMLElement.`);return t}return e}var j={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`};function M({src:e,title:t,name:n,height:r,allow:i}){let a=document.createElement(`iframe`);return a.src=e,a.title=t,a.name=n,a.setAttribute(`role`,`presentation`),a.scrolling=`no`,i&&(a.allow=i),Object.assign(a.style,j,{height:r}),a}function N(e,t){let n=A(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t,s=M({src:T(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:D(i,a)});n.appendChild(s);let c=k(s,{...o,onHeightChange:e=>{s.style.height=e,o.onHeightChange?.(e)},onAppearanceReady:()=>{s.style.opacity=`1`,o.onAppearanceReady?.()}});return{iframe:s,update:c.update,destroy(){c.destroy(),s.remove()}}}function P(e,t){let n=A(e),{renderToken:r,billingAddressRequirement:i=`country`,...a}=t,o=M({src:E(r,i),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:O(i)});n.appendChild(o);let s=k(o,{...a,onHeightChange:e=>{o.style.height=e,a.onHeightChange?.(e)},onAppearanceReady:()=>{o.style.opacity=`1`,a.onAppearanceReady?.()}});return{iframe:o,update:s.update,destroy(){s.destroy(),o.remove()}}}function F(e,t){let n=A(e),{renderToken:r,...i}=t,a=M({src:v(r),title:`Secure Google Pay button powered by Amos`,name:`amos-google-pay-button`,height:y(),allow:`payment`});n.appendChild(a);let o=b(a,{...i,onHeightChange:e=>{a.style.height=e,i.onHeightChange?.(e)},onAppearanceReady:()=>{a.style.opacity=`1`,i.onAppearanceReady?.()}});return{iframe:a,update:o.update,destroy(){o.destroy(),a.remove()}}}function I(e,t){let n=A(e),{renderToken:r,...i}=t,a=M({src:m(r),title:`Secure Apple Pay button powered by Amos`,name:`amos-apple-pay-button`,height:h(),allow:`payment`});n.appendChild(a);let o=_(a,{...i,onHeightChange:e=>{a.style.height=e,i.onHeightChange?.(e)},onAppearanceReady:()=>{a.style.opacity=`1`,i.onAppearanceReady?.()}});return{iframe:a,update:o.update,destroy(){o.destroy(),a.remove()}}}exports.attachApplePayButtonListeners=_,exports.attachGooglePayButtonListeners=b,exports.attachPaymentMethodFormListeners=k,exports.confirmPaymentIntent=d,exports.confirmSetupIntent=f,exports.createMessage=a,exports.decodeJwt=r,exports.formatGooglePayPaymentData=x,exports.getApplePayButtonInitialHeight=h,exports.getApplePayButtonSrc=m,exports.getBankAccountFormInitialHeight=O,exports.getBankAccountFormSrc=E,exports.getCreditCardFormInitialHeight=D,exports.getCreditCardFormSrc=T,exports.getEmbedOrigin=i,exports.getGooglePayButtonInitialHeight=y,exports.getGooglePayButtonSrc=v,exports.mountAmosApplePayButton=I,exports.mountAmosBankAccountPaymentMethodForm=P,exports.mountAmosCreditCardPaymentMethodForm=N,exports.mountAmosGooglePayButton=F,exports.sendConfirmationFailed=p,exports.sendParentReadyMessage=o,exports.updateAmount=c,exports.updateAppearance=s,exports.updateMerchantName=l,exports.validateForm=u;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`data-amos-apple-pay-waiting`;function t({onCancel:t}){let n=document.querySelector(`[${e}]`);if(n)return n;let r=document.createElement(`div`);r.setAttribute(e,`true`),r.setAttribute(`role`,`dialog`),r.setAttribute(`aria-modal`,`true`),r.setAttribute(`aria-labelledby`,`amos-apple-pay-waiting-title`),Object.assign(r.style,{position:`fixed`,inset:`0`,zIndex:`2147483646`,display:`flex`,alignItems:`center`,justifyContent:`center`,padding:`24px`,boxSizing:`border-box`,background:`rgba(0, 0, 0, 0.55)`,fontFamily:`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif`});let i=document.createElement(`div`);Object.assign(i.style,{width:`100%`,maxWidth:`360px`,borderRadius:`12px`,background:`#fff`,padding:`28px 24px 20px`,boxSizing:`border-box`,textAlign:`center`,boxShadow:`0 12px 40px rgba(0, 0, 0, 0.25)`});let a=document.createElement(`div`);a.setAttribute(`aria-hidden`,`true`),Object.assign(a.style,{display:`inline-flex`,alignItems:`center`,justifyContent:`center`,gap:`6px`,marginBottom:`16px`,fontSize:`28px`,fontWeight:`600`,letterSpacing:`-0.02em`,color:`#000`,lineHeight:`1`}),a.innerHTML=`<svg width="22" height="26" viewBox="0 0 14 17" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M13.072 5.846c-.1.08-1.873 1.09-1.873 3.34 0 2.61 2.29 3.53 2.36 3.55-.04.1-.368 1.27-.766 2.52-.35 1.09-.72 2.18-1.28 2.18-.55 0-.73-.36-1.43-.36-.71 0-.93.37-1.48.37-.55 0-.93-.99-1.35-2.01-.5-1.2-.88-2.43-.88-3.85 0-2.26 1.47-3.46 2.91-3.46.57 0 1.11.38 1.49.38.37 0 .98-.45 1.7-.45.28 0 1.27.03 1.97 1.01ZM9.52 3.37c.3-.36.52-.86.52-1.36 0-.07 0-.14-.01-.2-.5.02-1.1.33-1.46.75-.28.32-.55.84-.55 1.35 0 .07.01.15.02.17.04.01.1.02.16.02.45 0 1.02-.3 1.32-.73Z"/></svg><span>Pay</span>`;let o=document.createElement(`p`);o.id=`amos-apple-pay-waiting-title`,Object.assign(o.style,{margin:`0 0 20px`,fontSize:`15px`,lineHeight:`1.45`,color:`#1a1a1a`}),o.textContent=`Complete your payment in the open Apple Pay window, or close Apple Pay to continue paying another way.`;let s=document.createElement(`button`);return s.type=`button`,s.textContent=`Cancel payment`,Object.assign(s.style,{display:`block`,width:`100%`,border:`none`,borderRadius:`8px`,padding:`12px 16px`,background:`#2c2c2e`,color:`#fff`,fontSize:`15px`,fontWeight:`500`,cursor:`pointer`}),s.addEventListener(`click`,t),i.append(a,o,s),r.append(i),document.body.append(r),r}function n(){document.querySelector(`[${e}]`)?.remove()}function r(e){let[t=``,n=``,r=``]=e?.split(`.`)??[],i=typeof atob==`function`?atob:e=>Buffer.from(e,`base64`).toString(`utf8`);return{header:JSON.parse(i(t)),payload:JSON.parse(i(n)),signature:r}}function i(e){let{env:t=`sandbox`}=r(e).payload;switch(t){case`production`:return`https://embed.amos.com`;case`sandbox`:return`https://embed-sandbox.amos.com`;default:return`https://embed-sandbox.amos.com`}}function a(e){return e}function o(e){e?.contentWindow?.postMessage(a({type:`PARENT_ACKNOWLEDGED_IFRAME_READY`}),`*`)}function s({iframe:e,appearance:t={}}){e?.contentWindow?.postMessage(a({type:`UPDATE_APPEARANCE`,appearance:t}),`*`)}function c({iframe:e,amount:t}){e?.contentWindow?.postMessage(a({type:`UPDATE_AMOUNT`,amount:t}),`*`)}function l({iframe:e,merchantName:t}){e?.contentWindow?.postMessage(a({type:`UPDATE_MERCHANT_NAME`,merchantName:t}),`*`)}function u({iframe:e}){let t=crypto.randomUUID();return new Promise(n=>{e?.contentWindow?.postMessage(a({type:`VALIDATE_FORM`,requestId:t}),`*`);let r=setTimeout(()=>{window.removeEventListener(`message`,i),n(!1)},5e3);function i(e){e.data.type===`VALIDATE_FORM`&&e.data.requestId===t&&(window.removeEventListener(`message`,i),clearTimeout(r),n(e.data.isValid??!1))}window.addEventListener(`message`,i)})}function d({iframe:e,token:t}){let{payment_intent_id:n}=r(t).payload;e?.contentWindow?.postMessage(a({type:`CONFIRM_PAYMENT_INTENT`,token:t,id:n??void 0}),`*`)}function f({iframe:e,token:t}){let{setup_intent_id:n}=r(t).payload;e?.contentWindow?.postMessage(a({type:`CONFIRM_SETUP_INTENT`,token:t,id:n??void 0}),`*`)}function p({iframe:e,result:t}){e?.contentWindow?.postMessage(a({type:`CONFIRMATION_RESULT`,result:t}),`*`)}function m(e){return`${i(e)}/iframe/apple-pay?token=${e}`}function h(){return`40px`}function g(e){e.contentWindow?.postMessage(a({type:`APPLE_PAY_CANCEL`}),`*`)}function _(e,r){let i={...r};function a(){c({iframe:e,amount:i.amount})}function u(){l({iframe:e,merchantName:i.merchantName})}function f(r){if(r.source===e.contentWindow)switch(r.data.type){case`IFRAME_READY`:o(e),s({iframe:e,appearance:i.appearance}),a(),u();break;case`UPDATE_HEIGHT`:i.onHeightChange?.(r.data.height);break;case`UPDATE_APPEARANCE`:s({iframe:e,appearance:r.data.appearance});break;case`UPDATED_APPEARANCE`:i.onAppearanceReady?.();break;case`APPLE_PAY_WINDOW_OPEN`:t({onCancel:()=>{g(e),n()}});break;case`APPLE_PAY_WINDOW_CLOSE`:n();break;case`CREATE_PAYMENT_INTENT`:i.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:r.data.paymentIntentCreateAttributes,customerCreateAttributes:r.data.customerCreateAttributes}).then(t=>{d({iframe:e,token:t})}).catch(e=>{n(),i.onResult({status:`failed`,errorMessage:e instanceof Error?e.message:`Unknown error`})});break;case`CONFIRMATION_RESULT`:n(),i.onResult(r.data.result);break}}return window.addEventListener(`message`,f),{update(t){let n=`appearance`in t,r=`amount`in t,o=`merchantName`in t;i={...i,...t},n&&s({iframe:e,appearance:i.appearance}),r&&a(),o&&u()},destroy(){window.removeEventListener(`message`,f),n()}}}function v(e){return`${i(e)}/iframe/google-pay?token=${e}`}function y(){return`40px`}function b(e,t){let n={...t};function r(){c({iframe:e,amount:n.amount})}function i(){l({iframe:e,merchantName:n.merchantName})}function a(t){switch(t.data.type){case`IFRAME_READY`:o(e),s({iframe:e,appearance:n.appearance}),r(),i();break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:s({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`CREATE_PAYMENT_INTENT`:n.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:t.data.paymentIntentCreateAttributes,customerCreateAttributes:t.data.customerCreateAttributes}).then(t=>{d({iframe:e,token:t})}).catch(e=>{n.onResult({status:`failed`,errorMessage:e instanceof Error?e.message:`Unknown error`})});break;case`CONFIRMATION_RESULT`:n.onResult(t.data.result);break}}return window.addEventListener(`message`,a),{update(t){let a=`appearance`in t,o=`amount`in t,c=`merchantName`in t;n={...n,...t},a&&s({iframe:e,appearance:n.appearance}),o&&r(),c&&i()},destroy(){window.removeEventListener(`message`,a)}}}function x({paymentData:e}){return{paymentMethod:{type:`googlepay`,billing_address_attributes:{name:e.shippingAddress?.name,address_line1:e.shippingAddress?.address1,address_line2:e.shippingAddress?.address2,city:e.shippingAddress?.locality,state:e.shippingAddress?.administrativeArea,postal_code:e.shippingAddress?.postalCode,country:e.shippingAddress?.countryCode,email:e.email,phone:e.shippingAddress?.phoneNumber},card_profile_attributes:{wallet_provider:`googlepay`,wallet_payload:e.paymentMethodData.tokenizationData.token,wallet_last4:e.paymentMethodData.info?.cardDetails,wallet_brand:(()=>{switch(e.paymentMethodData.info?.cardNetwork){case`AMEX`:return`american_express`;case`VISA`:return`visa`;case`MASTERCARD`:return`master`;case`DISCOVER`:return`discover`;default:return}})()}}}}var S={country:212,full:452},C=80,w={country:400,full:640};function T(e,t={cardholderName:!1},n=`country`){let r=Object.entries(t).filter(([,e])=>e).map(([e])=>e).join(`,`),a=new URLSearchParams({token:e,additionalFields:r,billingAddressRequirement:n});return`${i(e)}/iframe/card?${a}`}function E(e,t=`country`){let n=new URLSearchParams({token:e,billingAddressRequirement:t});return`${i(e)}/iframe/bank?${n}`}function D(e={cardholderName:!1},t=`country`){return`${(S[t]??S.country)+(e.cardholderName?C:0)}px`}function O(e=`country`){return`${w[e]??w.country}px`}function k(e,t){let n={...t};function r(t){switch(t.data.type){case`IFRAME_READY`:o(e),s({iframe:e,appearance:n.appearance});break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:s({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`CONFIRMATION_RESULT`:n.onResult(t.data.result);break}}return window.addEventListener(`message`,r),{update(t){let r=`appearance`in t;n={...n,...t},r&&s({iframe:e,appearance:n.appearance})},destroy(){window.removeEventListener(`message`,r)}}}function A(e){if(typeof e==`string`){let t=document.querySelector(e);if(!(t instanceof HTMLElement))throw Error(`[amos-js] Container "${e}" did not match any HTMLElement.`);return t}return e}var j={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`};function M({src:e,title:t,name:n,height:r,allow:i}){let a=document.createElement(`iframe`);return a.src=e,a.title=t,a.name=n,a.setAttribute(`role`,`presentation`),a.scrolling=`no`,i&&(a.allow=i),Object.assign(a.style,j,{height:r}),a}function N(e,t){let n=A(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t,s=M({src:T(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:D(i,a)});n.appendChild(s);let c=k(s,{...o,onHeightChange:e=>{s.style.height=e,o.onHeightChange?.(e)},onAppearanceReady:()=>{s.style.opacity=`1`,o.onAppearanceReady?.()}});return{iframe:s,update:c.update,destroy(){c.destroy(),s.remove()}}}function P(e,t){let n=A(e),{renderToken:r,billingAddressRequirement:i=`country`,...a}=t,o=M({src:E(r,i),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:O(i)});n.appendChild(o);let s=k(o,{...a,onHeightChange:e=>{o.style.height=e,a.onHeightChange?.(e)},onAppearanceReady:()=>{o.style.opacity=`1`,a.onAppearanceReady?.()}});return{iframe:o,update:s.update,destroy(){s.destroy(),o.remove()}}}function F(e,t){let n=A(e),{renderToken:r,...i}=t,a=M({src:v(r),title:`Secure Google Pay button powered by Amos`,name:`amos-google-pay-button`,height:y(),allow:`payment`});n.appendChild(a);let o=b(a,{...i,onHeightChange:e=>{a.style.height=e,i.onHeightChange?.(e)},onAppearanceReady:()=>{a.style.opacity=`1`,i.onAppearanceReady?.()}});return{iframe:a,update:o.update,destroy(){o.destroy(),a.remove()}}}function I(e,t){let n=A(e),{renderToken:r,...i}=t,a=M({src:m(r),title:`Secure Apple Pay button powered by Amos`,name:`amos-apple-pay-button`,height:h(),allow:`payment`});n.appendChild(a);let o=_(a,{...i,onHeightChange:e=>{a.style.height=e,i.onHeightChange?.(e)},onAppearanceReady:()=>{a.style.opacity=`1`,i.onAppearanceReady?.()}});return{iframe:a,update:o.update,destroy(){o.destroy(),a.remove()}}}exports.attachApplePayButtonListeners=_,exports.attachGooglePayButtonListeners=b,exports.attachPaymentMethodFormListeners=k,exports.confirmPaymentIntent=d,exports.confirmSetupIntent=f,exports.createMessage=a,exports.decodeJwt=r,exports.formatGooglePayPaymentData=x,exports.getApplePayButtonInitialHeight=h,exports.getApplePayButtonSrc=m,exports.getBankAccountFormInitialHeight=O,exports.getBankAccountFormSrc=E,exports.getCreditCardFormInitialHeight=D,exports.getCreditCardFormSrc=T,exports.getEmbedOrigin=i,exports.getGooglePayButtonInitialHeight=y,exports.getGooglePayButtonSrc=v,exports.mountAmosApplePayButton=I,exports.mountAmosBankAccountPaymentMethodForm=P,exports.mountAmosCreditCardPaymentMethodForm=N,exports.mountAmosGooglePayButton=F,exports.sendConfirmationResult=p,exports.sendParentReadyMessage=o,exports.updateAmount=c,exports.updateAppearance=s,exports.updateMerchantName=l,exports.validateForm=u;
package/dist/index.mjs CHANGED
@@ -142,10 +142,10 @@ function f({ iframe: e, token: t }) {
142
142
  id: n ?? void 0
143
143
  }), "*");
144
144
  }
145
- function p({ iframe: e, errorMessage: t }) {
145
+ function p({ iframe: e, result: t }) {
146
146
  e?.contentWindow?.postMessage(a({
147
- type: "CONFIRMATION_FAILED",
148
- errorMessage: t
147
+ type: "CONFIRMATION_RESULT",
148
+ result: t
149
149
  }), "*");
150
150
  }
151
151
  //#endregion
@@ -210,18 +210,15 @@ function _(e, r) {
210
210
  iframe: e,
211
211
  token: t
212
212
  });
213
- }).catch((t) => {
214
- p({
215
- iframe: e,
216
- errorMessage: t instanceof Error ? t.message : "Unknown error"
213
+ }).catch((e) => {
214
+ n(), i.onResult({
215
+ status: "failed",
216
+ errorMessage: e instanceof Error ? e.message : "Unknown error"
217
217
  });
218
218
  });
219
219
  break;
220
- case "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED":
221
- n(), i.onPaymentIntentConfirmationSucceeded(r.data.paymentIntent);
222
- break;
223
- case "CONFIRMATION_FAILED":
224
- n(), i.onConfirmationFailed(r.data.errorMessage);
220
+ case "CONFIRMATION_RESULT":
221
+ n(), i.onResult(r.data.result);
225
222
  break;
226
223
  }
227
224
  }
@@ -292,18 +289,15 @@ function b(e, t) {
292
289
  iframe: e,
293
290
  token: t
294
291
  });
295
- }).catch((t) => {
296
- p({
297
- iframe: e,
298
- errorMessage: t instanceof Error ? t.message : "Unknown error"
292
+ }).catch((e) => {
293
+ n.onResult({
294
+ status: "failed",
295
+ errorMessage: e instanceof Error ? e.message : "Unknown error"
299
296
  });
300
297
  });
301
298
  break;
302
- case "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED":
303
- n.onPaymentIntentConfirmationSucceeded(t.data.paymentIntent);
304
- break;
305
- case "CONFIRMATION_FAILED":
306
- n.onConfirmationFailed(t.data.errorMessage);
299
+ case "CONFIRMATION_RESULT":
300
+ n.onResult(t.data.result);
307
301
  break;
308
302
  }
309
303
  }
@@ -405,14 +399,8 @@ function k(e, t) {
405
399
  case "UPDATED_APPEARANCE":
406
400
  n.onAppearanceReady?.();
407
401
  break;
408
- case "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED":
409
- n.onPaymentIntentConfirmationSucceeded?.(t.data.paymentIntent);
410
- break;
411
- case "SETUP_INTENT_CONFIRMATION_SUCCEEDED":
412
- n.onSetupIntentConfirmationSucceeded?.(t.data.setupIntent);
413
- break;
414
- case "CONFIRMATION_FAILED":
415
- n.onConfirmationFailed(t.data.errorMessage);
402
+ case "CONFIRMATION_RESULT":
403
+ n.onResult(t.data.result);
416
404
  break;
417
405
  }
418
406
  }
@@ -556,4 +544,4 @@ function I(e, t) {
556
544
  };
557
545
  }
558
546
  //#endregion
559
- export { _ as attachApplePayButtonListeners, b as attachGooglePayButtonListeners, k as attachPaymentMethodFormListeners, d as confirmPaymentIntent, f as confirmSetupIntent, a as createMessage, r as decodeJwt, x as formatGooglePayPaymentData, h as getApplePayButtonInitialHeight, m as getApplePayButtonSrc, O as getBankAccountFormInitialHeight, E as getBankAccountFormSrc, D as getCreditCardFormInitialHeight, T as getCreditCardFormSrc, i as getEmbedOrigin, y as getGooglePayButtonInitialHeight, v as getGooglePayButtonSrc, I as mountAmosApplePayButton, P as mountAmosBankAccountPaymentMethodForm, N as mountAmosCreditCardPaymentMethodForm, F as mountAmosGooglePayButton, p as sendConfirmationFailed, o as sendParentReadyMessage, c as updateAmount, s as updateAppearance, l as updateMerchantName, u as validateForm };
547
+ export { _ as attachApplePayButtonListeners, b as attachGooglePayButtonListeners, k as attachPaymentMethodFormListeners, d as confirmPaymentIntent, f as confirmSetupIntent, a as createMessage, r as decodeJwt, x as formatGooglePayPaymentData, h as getApplePayButtonInitialHeight, m as getApplePayButtonSrc, O as getBankAccountFormInitialHeight, E as getBankAccountFormSrc, D as getCreditCardFormInitialHeight, T as getCreditCardFormSrc, i as getEmbedOrigin, y as getGooglePayButtonInitialHeight, v as getGooglePayButtonSrc, I as mountAmosApplePayButton, P as mountAmosBankAccountPaymentMethodForm, N as mountAmosCreditCardPaymentMethodForm, F as mountAmosGooglePayButton, p as sendConfirmationResult, o as sendParentReadyMessage, c as updateAmount, s as updateAppearance, l as updateMerchantName, u as validateForm };
@@ -1,5 +1,5 @@
1
1
  import { components } from '@amos.com/node';
2
- import { Appearance } from './types';
2
+ import { Appearance, Message } from './types';
3
3
  type Iframe = HTMLIFrameElement | null | undefined;
4
4
  /**
5
5
  * Notify the embedded iframe that the host page is ready to receive
@@ -65,11 +65,13 @@ export declare function confirmSetupIntent({ iframe, token, }: {
65
65
  iframe: Iframe;
66
66
  } & Pick<components["schemas"]["EmbedToken"], "token">): void;
67
67
  /**
68
- * Notify the iframe that confirmation failed (used by express-checkout
69
- * flows after `onInitiatePaymentIntentRequest` rejects).
68
+ * Notify the iframe that confirmation finished with a failure (used by
69
+ * express-checkout flows after `onInitiatePaymentIntentRequest` rejects).
70
70
  */
71
- export declare function sendConfirmationFailed({ iframe, errorMessage, }: {
71
+ export declare function sendConfirmationResult({ iframe, result, }: {
72
72
  iframe: Iframe;
73
- errorMessage: string;
73
+ result: Extract<Message, {
74
+ type: "CONFIRMATION_RESULT";
75
+ }>["result"];
74
76
  }): void;
75
77
  export {};
@@ -1,5 +1,4 @@
1
- import { components } from '@amos.com/node';
2
- import { Appearance } from './types';
1
+ import { Appearance, ConfirmationResult } from './types';
3
2
  /**
4
3
  * The additional fields beyond the standard card number, expiration
5
4
  * date, CVV, and billing address fields that are required to be filled
@@ -61,17 +60,11 @@ export type PaymentMethodFormListenerOptions = {
61
60
  */
62
61
  onAppearanceReady?: () => void;
63
62
  /**
64
- * Called when payment intent confirmation succeeds.
63
+ * Called when the interactive confirmation flow finishes (success or
64
+ * terminal failure). Not settlement proof — verify via webhooks.
65
+ * Recoverable field errors stay in the iframe and do not invoke this.
65
66
  */
66
- onPaymentIntentConfirmationSucceeded?: (paymentIntent: components["schemas"]["PaymentIntent"]) => void;
67
- /**
68
- * Called when setup intent confirmation succeeds.
69
- */
70
- onSetupIntentConfirmationSucceeded?: (setupIntent: components["schemas"]["SetupIntent"]) => void;
71
- /**
72
- * Called when payment or setup intent confirmation fails.
73
- */
74
- onConfirmationFailed: (errorMessage: string) => void;
67
+ onResult: (result: ConfirmationResult) => void;
75
68
  };
76
69
  /**
77
70
  * Controller returned by {@link attachPaymentMethodFormListeners} and
package/dist/types.d.ts CHANGED
@@ -1,4 +1,35 @@
1
1
  import { components } from '@amos.com/node';
2
+ /**
3
+ * Outcome of an interactive confirmation flow inside the Amos iframe.
4
+ *
5
+ * `onResult` / `CONFIRMATION_RESULT` means the host should stop waiting
6
+ * (e.g. dismiss a spinner). It is **not** proof that funds were
7
+ * received — verify settlement on your backend via webhooks (or by
8
+ * retrieving the PaymentIntent / SetupIntent with your secret key),
9
+ * the same way Stripe recommends.
10
+ *
11
+ * Recoverable field validation errors (e.g. bad expiration year) are
12
+ * shown inside the iframe and do **not** produce a result; the customer
13
+ * can fix the form and retry.
14
+ */
15
+ export type ConfirmationResult = {
16
+ status: "succeeded";
17
+ intent: "payment";
18
+ paymentIntent: components["schemas"]["PaymentIntent"];
19
+ } | {
20
+ status: "succeeded";
21
+ intent: "setup";
22
+ setupIntent: components["schemas"]["SetupIntent"];
23
+ } | {
24
+ /**
25
+ * Recoverable validation was shown in the iframe. Unlock the host UI;
26
+ * the customer can fix fields and retry. Do not treat as settlement.
27
+ */
28
+ status: "incomplete";
29
+ } | {
30
+ status: "failed";
31
+ errorMessage: string;
32
+ };
2
33
  /**
3
34
  * CSS custom properties that control the appearance of the embedded
4
35
  * Amos iframe UI. Only the variables you provide are sent; omitted
@@ -58,14 +89,13 @@ export type Message = {
58
89
  } & Pick<components["schemas"]["PaymentIntent"], "id"> & Pick<components["schemas"]["EmbedToken"], "token">) | ({
59
90
  type: "CONFIRM_SETUP_INTENT";
60
91
  } & Pick<components["schemas"]["SetupIntent"], "id"> & Pick<components["schemas"]["EmbedToken"], "token">) | {
61
- type: "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED";
62
- paymentIntent: components["schemas"]["PaymentIntent"];
63
- } | {
64
- type: "SETUP_INTENT_CONFIRMATION_SUCCEEDED";
65
- setupIntent: components["schemas"]["SetupIntent"];
66
- } | {
67
- type: "CONFIRMATION_FAILED";
68
- errorMessage: string;
92
+ /**
93
+ * Embed → parent: the interactive confirmation flow finished.
94
+ * Not settlement proof — verify payment/setup success on your
95
+ * backend via webhooks (or by retrieving the intent).
96
+ */
97
+ type: "CONFIRMATION_RESULT";
98
+ result: ConfirmationResult;
69
99
  } | {
70
100
  type: "UPDATED_APPEARANCE";
71
101
  } | {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amos.com/amos-js",
3
- "version": "0.7.2",
3
+ "version": "0.9.0",
4
4
  "main": "dist/index.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -44,7 +44,7 @@
44
44
  "vite-plugin-dts": "5.0.3"
45
45
  },
46
46
  "dependencies": {
47
- "@amos.com/node": "0.1.33",
47
+ "@amos.com/node": "0.1.34",
48
48
  "@types/googlepay": "0.7.11"
49
49
  }
50
50
  }
package/src/apple-pay.ts CHANGED
@@ -6,13 +6,17 @@ import {
6
6
  import { getEmbedOrigin } from "./jwt";
7
7
  import {
8
8
  confirmPaymentIntent,
9
- sendConfirmationFailed,
10
9
  sendParentReadyMessage,
11
10
  updateAmount as sendUpdateAmount,
12
11
  updateAppearance as sendUpdateAppearance,
13
12
  updateMerchantName as sendUpdateMerchantName,
14
13
  } from "./messaging";
15
- import { type Appearance, createMessage, type Message } from "./types";
14
+ import {
15
+ type Appearance,
16
+ type ConfirmationResult,
17
+ createMessage,
18
+ type Message,
19
+ } from "./types";
16
20
 
17
21
  /**
18
22
  * Build the iframe `src` URL for the embedded Apple Pay button.
@@ -64,15 +68,10 @@ export type ApplePayButtonListenerOptions = {
64
68
  customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
65
69
  }) => Promise<components["schemas"]["EmbedToken"]["token"]>;
66
70
  /**
67
- * Called when payment intent confirmation succeeds.
68
- */
69
- onPaymentIntentConfirmationSucceeded: (
70
- paymentIntent: components["schemas"]["PaymentIntent"],
71
- ) => void;
72
- /**
73
- * Called when payment intent confirmation fails.
71
+ * Called when the interactive confirmation flow finishes (success or
72
+ * terminal failure). Not settlement proof — verify via webhooks.
74
73
  */
75
- onConfirmationFailed: (errorMessage: string) => void;
74
+ onResult: (result: ConfirmationResult) => void;
76
75
  };
77
76
 
78
77
  /**
@@ -176,22 +175,18 @@ export function attachApplePayButtonListeners(
176
175
  confirmPaymentIntent({ iframe, token });
177
176
  })
178
177
  .catch((error: unknown) => {
179
- sendConfirmationFailed({
180
- iframe,
178
+ hideApplePayWaitingOverlay();
179
+ current.onResult({
180
+ status: "failed",
181
181
  errorMessage:
182
182
  error instanceof Error ? error.message : "Unknown error",
183
183
  });
184
184
  });
185
185
  break;
186
186
 
187
- case "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED":
188
- hideApplePayWaitingOverlay();
189
- current.onPaymentIntentConfirmationSucceeded(event.data.paymentIntent);
190
- break;
191
-
192
- case "CONFIRMATION_FAILED":
187
+ case "CONFIRMATION_RESULT":
193
188
  hideApplePayWaitingOverlay();
194
- current.onConfirmationFailed(event.data.errorMessage);
189
+ current.onResult(event.data.result);
195
190
  break;
196
191
  }
197
192
  }
package/src/google-pay.ts CHANGED
@@ -4,13 +4,12 @@ import type { components } from "@amos.com/node";
4
4
  import { getEmbedOrigin } from "./jwt";
5
5
  import {
6
6
  confirmPaymentIntent,
7
- sendConfirmationFailed,
8
7
  sendParentReadyMessage,
9
8
  updateAmount as sendUpdateAmount,
10
9
  updateAppearance as sendUpdateAppearance,
11
10
  updateMerchantName as sendUpdateMerchantName,
12
11
  } from "./messaging";
13
- import type { Appearance, Message } from "./types";
12
+ import type { Appearance, ConfirmationResult, Message } from "./types";
14
13
 
15
14
  /**
16
15
  * Build the iframe `src` URL for the embedded Google Pay button.
@@ -62,15 +61,10 @@ export type GooglePayButtonListenerOptions = {
62
61
  customerCreateAttributes: components["schemas"]["CreateCustomerInput"];
63
62
  }) => Promise<components["schemas"]["EmbedToken"]["token"]>;
64
63
  /**
65
- * Called when payment intent confirmation succeeds.
64
+ * Called when the interactive confirmation flow finishes (success or
65
+ * terminal failure). Not settlement proof — verify via webhooks.
66
66
  */
67
- onPaymentIntentConfirmationSucceeded: (
68
- paymentIntent: components["schemas"]["PaymentIntent"],
69
- ) => void;
70
- /**
71
- * Called when payment intent confirmation fails.
72
- */
73
- onConfirmationFailed: (errorMessage: string) => void;
67
+ onResult: (result: ConfirmationResult) => void;
74
68
  };
75
69
 
76
70
  /**
@@ -144,20 +138,16 @@ export function attachGooglePayButtonListeners(
144
138
  confirmPaymentIntent({ iframe, token });
145
139
  })
146
140
  .catch((error: unknown) => {
147
- sendConfirmationFailed({
148
- iframe,
141
+ current.onResult({
142
+ status: "failed",
149
143
  errorMessage:
150
144
  error instanceof Error ? error.message : "Unknown error",
151
145
  });
152
146
  });
153
147
  break;
154
148
 
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);
149
+ case "CONFIRMATION_RESULT":
150
+ current.onResult(event.data.result);
161
151
  break;
162
152
  }
163
153
  }
package/src/index.ts CHANGED
@@ -27,7 +27,7 @@ export { decodeJwt, getEmbedOrigin } from "./jwt";
27
27
  export {
28
28
  confirmPaymentIntent,
29
29
  confirmSetupIntent,
30
- sendConfirmationFailed,
30
+ sendConfirmationResult,
31
31
  sendParentReadyMessage,
32
32
  updateAmount,
33
33
  updateAppearance,
@@ -65,6 +65,7 @@ export {
65
65
  export type {
66
66
  Appearance,
67
67
  AppearanceLabels,
68
+ ConfirmationResult,
68
69
  Message,
69
70
  ThemeVariable,
70
71
  } from "./types";
package/src/messaging.ts CHANGED
@@ -157,20 +157,20 @@ export function confirmSetupIntent({
157
157
  }
158
158
 
159
159
  /**
160
- * Notify the iframe that confirmation failed (used by express-checkout
161
- * flows after `onInitiatePaymentIntentRequest` rejects).
160
+ * Notify the iframe that confirmation finished with a failure (used by
161
+ * express-checkout flows after `onInitiatePaymentIntentRequest` rejects).
162
162
  */
163
- export function sendConfirmationFailed({
163
+ export function sendConfirmationResult({
164
164
  iframe,
165
- errorMessage,
165
+ result,
166
166
  }: {
167
167
  iframe: Iframe;
168
- errorMessage: string;
168
+ result: Extract<Message, { type: "CONFIRMATION_RESULT" }>["result"];
169
169
  }): void {
170
170
  iframe?.contentWindow?.postMessage(
171
171
  createMessage({
172
- type: "CONFIRMATION_FAILED",
173
- errorMessage,
172
+ type: "CONFIRMATION_RESULT",
173
+ result,
174
174
  }),
175
175
  "*",
176
176
  );
@@ -1,10 +1,9 @@
1
- import type { components } from "@amos.com/node";
2
1
  import { getEmbedOrigin } from "./jwt";
3
2
  import {
4
3
  sendParentReadyMessage,
5
4
  updateAppearance as sendUpdateAppearance,
6
5
  } from "./messaging";
7
- import type { Appearance, Message } from "./types";
6
+ import type { Appearance, ConfirmationResult, Message } from "./types";
8
7
 
9
8
  /**
10
9
  * The additional fields beyond the standard card number, expiration
@@ -128,21 +127,11 @@ export type PaymentMethodFormListenerOptions = {
128
127
  */
129
128
  onAppearanceReady?: () => void;
130
129
  /**
131
- * Called when payment intent confirmation succeeds.
130
+ * Called when the interactive confirmation flow finishes (success or
131
+ * terminal failure). Not settlement proof — verify via webhooks.
132
+ * Recoverable field errors stay in the iframe and do not invoke this.
132
133
  */
133
- onPaymentIntentConfirmationSucceeded?: (
134
- paymentIntent: components["schemas"]["PaymentIntent"],
135
- ) => void;
136
- /**
137
- * Called when setup intent confirmation succeeds.
138
- */
139
- onSetupIntentConfirmationSucceeded?: (
140
- setupIntent: components["schemas"]["SetupIntent"],
141
- ) => void;
142
- /**
143
- * Called when payment or setup intent confirmation fails.
144
- */
145
- onConfirmationFailed: (errorMessage: string) => void;
134
+ onResult: (result: ConfirmationResult) => void;
146
135
  };
147
136
 
148
137
  /**
@@ -196,18 +185,8 @@ export function attachPaymentMethodFormListeners(
196
185
  current.onAppearanceReady?.();
197
186
  break;
198
187
 
199
- case "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED":
200
- current.onPaymentIntentConfirmationSucceeded?.(
201
- event.data.paymentIntent,
202
- );
203
- break;
204
-
205
- case "SETUP_INTENT_CONFIRMATION_SUCCEEDED":
206
- current.onSetupIntentConfirmationSucceeded?.(event.data.setupIntent);
207
- break;
208
-
209
- case "CONFIRMATION_FAILED":
210
- current.onConfirmationFailed(event.data.errorMessage);
188
+ case "CONFIRMATION_RESULT":
189
+ current.onResult(event.data.result);
211
190
  break;
212
191
  }
213
192
  }
package/src/types.ts CHANGED
@@ -1,5 +1,41 @@
1
1
  import type { components } from "@amos.com/node";
2
2
 
3
+ /**
4
+ * Outcome of an interactive confirmation flow inside the Amos iframe.
5
+ *
6
+ * `onResult` / `CONFIRMATION_RESULT` means the host should stop waiting
7
+ * (e.g. dismiss a spinner). It is **not** proof that funds were
8
+ * received — verify settlement on your backend via webhooks (or by
9
+ * retrieving the PaymentIntent / SetupIntent with your secret key),
10
+ * the same way Stripe recommends.
11
+ *
12
+ * Recoverable field validation errors (e.g. bad expiration year) are
13
+ * shown inside the iframe and do **not** produce a result; the customer
14
+ * can fix the form and retry.
15
+ */
16
+ export type ConfirmationResult =
17
+ | {
18
+ status: "succeeded";
19
+ intent: "payment";
20
+ paymentIntent: components["schemas"]["PaymentIntent"];
21
+ }
22
+ | {
23
+ status: "succeeded";
24
+ intent: "setup";
25
+ setupIntent: components["schemas"]["SetupIntent"];
26
+ }
27
+ | {
28
+ /**
29
+ * Recoverable validation was shown in the iframe. Unlock the host UI;
30
+ * the customer can fix fields and retry. Do not treat as settlement.
31
+ */
32
+ status: "incomplete";
33
+ }
34
+ | {
35
+ status: "failed";
36
+ errorMessage: string;
37
+ };
38
+
3
39
  /**
4
40
  * CSS custom properties that control the appearance of the embedded
5
41
  * Amos iframe UI. Only the variables you provide are sent; omitted
@@ -178,16 +214,13 @@ export type Message =
178
214
  } & Pick<components["schemas"]["SetupIntent"], "id"> &
179
215
  Pick<components["schemas"]["EmbedToken"], "token">)
180
216
  | {
181
- type: "PAYMENT_INTENT_CONFIRMATION_SUCCEEDED";
182
- paymentIntent: components["schemas"]["PaymentIntent"];
183
- }
184
- | {
185
- type: "SETUP_INTENT_CONFIRMATION_SUCCEEDED";
186
- setupIntent: components["schemas"]["SetupIntent"];
187
- }
188
- | {
189
- type: "CONFIRMATION_FAILED";
190
- errorMessage: string;
217
+ /**
218
+ * Embed → parent: the interactive confirmation flow finished.
219
+ * Not settlement proof — verify payment/setup success on your
220
+ * backend via webhooks (or by retrieving the intent).
221
+ */
222
+ type: "CONFIRMATION_RESULT";
223
+ result: ConfirmationResult;
191
224
  }
192
225
  | {
193
226
  type: "UPDATED_APPEARANCE";