@amos.com/amos-js 0.10.0 → 0.10.2
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 +18 -5
- package/dist/index.js +2 -2
- package/dist/index.mjs +22 -19
- package/dist/mount.d.ts +24 -6
- package/dist/payment-method-form.d.ts +4 -1
- package/dist/plaid.d.ts +2 -1
- package/dist/types.d.ts +5 -4
- package/package.json +5 -5
- package/src/mount.ts +27 -8
- package/src/payment-method-form.ts +7 -0
- package/src/plaid-bank-ui.ts +5 -2
- package/src/plaid.ts +3 -5
- package/src/types.ts +5 -4
package/README.md
CHANGED
|
@@ -173,7 +173,7 @@ Setup intents are used to save payment methods for future use (e.g. recurring pa
|
|
|
173
173
|
- On the client, call `confirmSetupIntent({ iframe, token })` instead of `confirmPaymentIntent({ iframe, token })`.
|
|
174
174
|
- The same `onResult` callback is used; succeeded setup intents arrive as `{ status: "succeeded", intent: "setup", setupIntent }`.
|
|
175
175
|
|
|
176
|
-
The same `mountAmosCreditCardPaymentMethodForm` / `mountAmosBankAccountPaymentMethodForm` controllers support both payment intents and setup intents — they are differentiated by which confirmation function you call.
|
|
176
|
+
The same `mountAmosCreditCardPaymentMethodForm` / `mountAmosBankAccountPaymentMethodForm` controllers support both payment intents and setup intents — they are differentiated by which confirmation function you call. For bank setup, pass `intent: "setup"` so Connect / Plaid is always shown (no merchant ACH threshold lookup).
|
|
177
177
|
|
|
178
178
|
## Understanding PCI DSS compliance requirements
|
|
179
179
|
|
|
@@ -298,16 +298,17 @@ When the charge meets the merchant’s ACH verification threshold, the SDK hides
|
|
|
298
298
|
|
|
299
299
|
**Additional `options` (ACH verification):**
|
|
300
300
|
|
|
301
|
-
- `amount` (`string`, major-currency decimal, e.g. `"50.00"`) — same format as Google Pay / Apple Pay. Compared to the threshold the iframe fetches (cents).
|
|
301
|
+
- `amount` (`string`, major-currency decimal, e.g. `"50.00"`, **required**, defaults to `"0"`) — same format as Google Pay / Apple Pay. Compared to the threshold the iframe fetches (cents). Pass `"0"` (the default) on open-amount forms until the customer enters a charge — 0 is typically under the threshold, so Connect stays hidden. Pass `amount` and `update({ amount })` when it changes.
|
|
302
|
+
- `intent` (`"payment" | "setup"`, defaults to `"payment"`) — `"setup"` always shows Connect / Plaid (no merchant ACH threshold lookup), unless the render token disables verification. Use this when saving a bank account for later charges.
|
|
302
303
|
|
|
303
|
-
Compare locally once the iframe posts `ACH_THRESHOLD`: Plaid when
|
|
304
|
+
Compare locally once the iframe posts `ACH_THRESHOLD`: Plaid when `requireVerification` is true (setup intents), or when the amount (converted to cents, default `0`) is `>= achThreshold`. No threshold (or `null`) keeps the manual bank form. Render tokens with Plaid verification disabled never require Connect. If `amount` later drops under the threshold, Plaid credentials are dropped and the iframe form is shown again.
|
|
304
305
|
|
|
305
306
|
```ts
|
|
306
307
|
import { mountAmosBankAccountPaymentMethodForm } from "@amos.com/amos-js";
|
|
307
308
|
|
|
308
309
|
const bank = mountAmosBankAccountPaymentMethodForm("#bank-form", {
|
|
309
310
|
renderToken,
|
|
310
|
-
amount: "50.00", //
|
|
311
|
+
amount: "50.00", // defaults to "0" (manual form until the charge meets the threshold)
|
|
311
312
|
onResult: (result) => {
|
|
312
313
|
/* … */
|
|
313
314
|
},
|
|
@@ -316,6 +317,18 @@ const bank = mountAmosBankAccountPaymentMethodForm("#bank-form", {
|
|
|
316
317
|
bank.update({ amount: "25.00" });
|
|
317
318
|
```
|
|
318
319
|
|
|
320
|
+
Setup (always Connect, no merchant lookup):
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
mountAmosBankAccountPaymentMethodForm("#bank-form", {
|
|
324
|
+
renderToken,
|
|
325
|
+
intent: "setup",
|
|
326
|
+
onResult: (result) => {
|
|
327
|
+
/* … */
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
319
332
|
`validateForm` / `confirmPaymentIntent` / `confirmSetupIntent` stay iframe-based. When Plaid succeeded, confirm sends `payment_method.plaid` (`public_token`, `account_id`) and does not require typed account numbers.
|
|
320
333
|
|
|
321
334
|
**CSP:** the parent page must allow Plaid’s script and frames, for example `script-src https://cdn.plaid.com` and `frame-src https://cdn.plaid.com https://*.plaid.com`. Amos never loads `PLAID_SECRET` / `PLAID_CLIENT_ID` in the SDK or embed iframe.
|
|
@@ -424,7 +437,7 @@ Advanced helpers exposed for integrators that need to construct or inspect the m
|
|
|
424
437
|
- **`onResult` is not settlement proof**: `onResult` tells you when to stop waiting (e.g. dismiss a spinner). Verify payment or setup success on your backend via webhooks. On `status: "incomplete"`, unlock your UI — the customer can fix fields in the iframe and retry. Use `result.reason` (`"field_errors"` or `"validation_failed"`) to distinguish recoverable states.
|
|
425
438
|
- **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`.
|
|
426
439
|
- **Amount format**: for `mountAmosGooglePayButton`, `mountAmosApplePayButton`, and `mountAmosBankAccountPaymentMethodForm`, `amount` is a major-currency decimal string (e.g. `"50.00"` for $50.00). For `components["schemas"]["CreatePaymentIntentInput"]` on the server (card/bank create, and the object the wallet iframe sends to `onInitiatePaymentIntentRequest`), `amount` is a number in cents (e.g. `5000`).
|
|
427
|
-
- **Plaid Link (ACH verification)**: load `cdn.plaid.com` from the **parent** document (see CSP above). Merchants do not proxy Pay API; the bank iframe fetches the ACH threshold and mints link tokens. Confirm still goes through the bank iframe so Amos can attach `plaid` to the payment method.
|
|
440
|
+
- **Plaid Link (ACH verification)**: load `cdn.plaid.com` from the **parent** document (see CSP above). Merchants do not proxy Pay API; the bank iframe fetches the ACH threshold for payment intents and mints link tokens. Setup intents skip the merchant lookup and always require Plaid unless the render token disables verification. Confirm still goes through the bank iframe so Amos can attach `plaid` to the payment method.
|
|
428
441
|
- **Apple Pay waiting overlay**: on browsers where Apple's QR handoff opens in a popup (non-Safari), `mountAmosApplePayButton` shows a fixed full-viewport overlay on the host page until payment completes, the popup closes, or the user clicks **Cancel payment**. Avoid stacking other fixed UI above it.
|
|
429
442
|
- **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).
|
|
430
443
|
|
package/dist/index.js
CHANGED
|
@@ -65,7 +65,7 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`data-a
|
|
|
65
65
|
animation: none;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
`;function A(){if(document.getElementById(k))return;let e=document.createElement(`style`);e.id=k,e.textContent=ne,document.head.appendChild(e)}function j(e,t){for(let[t,n]of Object.entries(te))e.style.setProperty(t,n);let n=t?.themeVariables;if(n)for(let[t,r]of Object.entries(n))typeof r==`string`&&r.trim()!==``&&e.style.setProperty(t,r.trim())}function M(e,t){let n=document.createElement(`div`);if(n.className=e,t)for(let e of t)n.appendChild(e);return n}function N(e,t){let n=M(`amos-js-form-skeleton-field`);t!==void 0&&(n.style.flexGrow=String(t)),e===`above`&&n.appendChild(M(`amos-js-form-skeleton-label`));let r=M(`amos-js-form-skeleton-input`);return e===`floating`&&r.classList.add(`amos-js-form-skeleton-input-floating`),n.appendChild(r),n}function P(e,t){return M(t?`amos-js-form-skeleton-row-stack`:`amos-js-form-skeleton-row`,e)}function re({labels:e,requirement:t,wrapCountryZip:n}){return t===`full`?[N(e),N(e),P([N(e,1.4),N(e,.7),N(e,.8)],!1),N(e)]:[P([N(e),N(e)],n)]}function ie(e){let t=e.appearance?.labels??`above`,n=e.billingAddressRequirement??`country`;if(e.kind===`card`){let r=[N(t),P([N(t),N(t)],!1)];return e.additionalFields?.cardholderName&&r.push(N(t)),r.push(...re({labels:t,requirement:n,wrapCountryZip:!1})),r}return[N(t),P([N(t),N(t)],!0),N(t),P([N(`above`),N(`above`)],!0),...re({labels:t,requirement:n,wrapCountryZip:!0})]}function ae(e){A();let t=M(`amos-js-form-skeleton`);t.setAttribute(`aria-hidden`,`true`);function n(e){j(t,e.appearance),t.replaceChildren(...ie(e))}return n(e),{element:t,update:n}}function F(e){A();let t=M(`amos-js-form-skeleton-input amos-js-wallet-skeleton`);t.setAttribute(`aria-hidden`,`true`);function n(e){j(t,void 0),t.style.height=e.height,t.style.borderRadius=e.borderRadius??`4px`}return n(e),{element:t,update:n}}function I(e){if(typeof e==`number`&&Number.isFinite(e))return`${e}px`;if(typeof e==`string`&&e.trim()!==``)return e.trim()}function L({iframeStyle:e,buttonProps:t}){return I(e?.borderRadius)??I(t?.buttonRadius)??I(t?.style?.borderRadius)??I(t?.style?.[`--apple-pay-button-border-radius`])??`4px`}function R(e){return`${i(e)}/iframe/google-pay?token=${e}`}function z(){return`48px`}function B(e,{height:t=`48px`,...n}){let r={...n,height:t};function i(){h({iframe:e,amount:r.amount})}function a(){g({iframe:e,merchantName:r.merchantName})}function o(){m({iframe:e,height:r.height??`48px`,props:r.buttonProps??{}})}function s(t){if(t.source===e.contentWindow)switch(t.data.type){case`IFRAME_READY`:d(e),f({iframe:e,appearance:{}}),i(),a(),o();break;case`UPDATE_HEIGHT`:r.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:f({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:r.onAppearanceReady?.();break;case`CREATE_PAYMENT_INTENT`:r.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:t.data.paymentIntentCreateAttributes,customerCreateAttributes:t.data.customerCreateAttributes}).then(t=>{S({iframe:e,token:t})}).catch(e=>{r.onResult({status:`failed`,errorMessage:e instanceof Error?e.message:`Unknown error`})});break;case`CONFIRMATION_RESULT`:r.onResult(t.data.result)}}return window.addEventListener(`message`,s),{update(e){let t=`amount`in e,n=`merchantName`in e,s=`height`in e||`buttonProps`in e;r={...r,...e},t&&i(),n&&a(),s&&o()},destroy(){window.removeEventListener(`message`,s)}}}function oe({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_payload:e.paymentMethodData.tokenizationData.token}}}}var V={country:212,full:452},se=80,H={country:400,full:640};function U(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 W(e,t=`country`){let
|
|
68
|
+
`;function A(){if(document.getElementById(k))return;let e=document.createElement(`style`);e.id=k,e.textContent=ne,document.head.appendChild(e)}function j(e,t){for(let[t,n]of Object.entries(te))e.style.setProperty(t,n);let n=t?.themeVariables;if(n)for(let[t,r]of Object.entries(n))typeof r==`string`&&r.trim()!==``&&e.style.setProperty(t,r.trim())}function M(e,t){let n=document.createElement(`div`);if(n.className=e,t)for(let e of t)n.appendChild(e);return n}function N(e,t){let n=M(`amos-js-form-skeleton-field`);t!==void 0&&(n.style.flexGrow=String(t)),e===`above`&&n.appendChild(M(`amos-js-form-skeleton-label`));let r=M(`amos-js-form-skeleton-input`);return e===`floating`&&r.classList.add(`amos-js-form-skeleton-input-floating`),n.appendChild(r),n}function P(e,t){return M(t?`amos-js-form-skeleton-row-stack`:`amos-js-form-skeleton-row`,e)}function re({labels:e,requirement:t,wrapCountryZip:n}){return t===`full`?[N(e),N(e),P([N(e,1.4),N(e,.7),N(e,.8)],!1),N(e)]:[P([N(e),N(e)],n)]}function ie(e){let t=e.appearance?.labels??`above`,n=e.billingAddressRequirement??`country`;if(e.kind===`card`){let r=[N(t),P([N(t),N(t)],!1)];return e.additionalFields?.cardholderName&&r.push(N(t)),r.push(...re({labels:t,requirement:n,wrapCountryZip:!1})),r}return[N(t),P([N(t),N(t)],!0),N(t),P([N(`above`),N(`above`)],!0),...re({labels:t,requirement:n,wrapCountryZip:!0})]}function ae(e){A();let t=M(`amos-js-form-skeleton`);t.setAttribute(`aria-hidden`,`true`);function n(e){j(t,e.appearance),t.replaceChildren(...ie(e))}return n(e),{element:t,update:n}}function F(e){A();let t=M(`amos-js-form-skeleton-input amos-js-wallet-skeleton`);t.setAttribute(`aria-hidden`,`true`);function n(e){j(t,void 0),t.style.height=e.height,t.style.borderRadius=e.borderRadius??`4px`}return n(e),{element:t,update:n}}function I(e){if(typeof e==`number`&&Number.isFinite(e))return`${e}px`;if(typeof e==`string`&&e.trim()!==``)return e.trim()}function L({iframeStyle:e,buttonProps:t}){return I(e?.borderRadius)??I(t?.buttonRadius)??I(t?.style?.borderRadius)??I(t?.style?.[`--apple-pay-button-border-radius`])??`4px`}function R(e){return`${i(e)}/iframe/google-pay?token=${e}`}function z(){return`48px`}function B(e,{height:t=`48px`,...n}){let r={...n,height:t};function i(){h({iframe:e,amount:r.amount})}function a(){g({iframe:e,merchantName:r.merchantName})}function o(){m({iframe:e,height:r.height??`48px`,props:r.buttonProps??{}})}function s(t){if(t.source===e.contentWindow)switch(t.data.type){case`IFRAME_READY`:d(e),f({iframe:e,appearance:{}}),i(),a(),o();break;case`UPDATE_HEIGHT`:r.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:f({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:r.onAppearanceReady?.();break;case`CREATE_PAYMENT_INTENT`:r.onInitiatePaymentIntentRequest({paymentIntentCreateAttributes:t.data.paymentIntentCreateAttributes,customerCreateAttributes:t.data.customerCreateAttributes}).then(t=>{S({iframe:e,token:t})}).catch(e=>{r.onResult({status:`failed`,errorMessage:e instanceof Error?e.message:`Unknown error`})});break;case`CONFIRMATION_RESULT`:r.onResult(t.data.result)}}return window.addEventListener(`message`,s),{update(e){let t=`amount`in e,n=`merchantName`in e,s=`height`in e||`buttonProps`in e;r={...r,...e},t&&i(),n&&a(),s&&o()},destroy(){window.removeEventListener(`message`,s)}}}function oe({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_payload:e.paymentMethodData.tokenizationData.token}}}}var V={country:212,full:452},se=80,H={country:400,full:640};function U(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 W(e,t=`country`,n=`payment`){let r=new URLSearchParams({token:e,billingAddressRequirement:t});return n===`setup`&&r.set(`intent`,`setup`),`${i(e)}/iframe/bank?${r}`}function G(e={cardholderName:!1},t=`country`){return`${(V[t]??V.country)+(e.cardholderName?se:0)}px`}function K(e=`country`){return`${H[e]??H.country}px`}function q(e,t){let n={...t};function r(t){if(t.source===e.contentWindow)switch(t.data.type){case`IFRAME_READY`:d(e),f({iframe:e,appearance:n.appearance});break;case`UPDATE_HEIGHT`:n.onHeightChange?.(t.data.height);break;case`UPDATE_APPEARANCE`:f({iframe:e,appearance:t.data.appearance});break;case`UPDATED_APPEARANCE`:n.onAppearanceReady?.();break;case`FORM_VALIDITY_CHANGE`:if(s(e)?.requiresVerification)break;n.onValidityChange?.({isValid:t.data.isValid});break;case`CARD_BRAND_CHANGE`:n.onCardBrandChanged?.({brand:t.data.brand});break;case`CONFIRMATION_RESULT`:n.onResult(t.data.result)}}return window.addEventListener(`message`,r),{update(t){let r=`appearance`in t;n={...n,...t},r&&f({iframe:e,appearance:n.appearance})},destroy(){window.removeEventListener(`message`,r)}}}var J=`https://cdn.plaid.com/link/v2/stable/link-initialize.js`;function Y({amount:e,achThreshold:t}){return t!=null&&(e??0)>=t}function ce(e){if(e==null)return;let t=e.trim();if(t===``)return;let n=Number(t.replace(/[^\d.]/g,``));if(Number.isFinite(n))return Math.round(n*100)}function le(e){return e.account_id??e.account?.id??e.accounts?.[0]?.id}function ue(e){let t=e.account??e.accounts?.[0];return{bankName:e.institution?.name??`Bank account`,last4:t?.mask??``}}var X;function de(){for(let e of document.querySelectorAll(`script[src="${J}"]`))e.remove()}function fe(){return typeof window>`u`?Promise.reject(Error(`Plaid Link requires a browser`)):window.Plaid?Promise.resolve():X||(de(),X=new Promise((e,t)=>{let n=document.createElement(`script`);n.src=J,n.async=!0;let r=e=>{n.remove(),X=void 0,t(Error(e))};n.addEventListener(`load`,()=>{if(window.Plaid){e();return}r(`Plaid Link failed to initialize`)},{once:!0}),n.addEventListener(`error`,()=>r(`Failed to load Plaid Link`),{once:!0}),document.head.append(n)}),X)}async function pe({token:e,onSuccess:t,onExit:n,signal:r}){if(await fe(),r?.aborted)return()=>{};if(!window.Plaid)throw Error(`Plaid Link failed to initialize`);let i=window.Plaid.create({token:e,onSuccess:t,onExit:e=>{n?.(e)}});return r?.aborted?(i.destroy(),()=>{}):(i.open(),()=>{i.destroy()})}var me=`amos-js-plaid-bank-ui-styles`,he=`
|
|
69
69
|
.amos-js-plaid-panel {
|
|
70
70
|
box-sizing: border-box;
|
|
71
71
|
color: var(--foreground, oklch(0.145 0 0));
|
|
@@ -171,4 +171,4 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`data-a
|
|
|
171
171
|
transition: none;
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
|
-
`;function ge(){if(document.getElementById(me))return;let e=document.createElement(`style`);e.id=me,e.textContent=he,document.head.append(e)}function _e(e,t,n){for(let t of n)e.style.removeProperty(t);n.length=0;let r=t?.themeVariables;if(r)for(let[t,i]of Object.entries(r))typeof i==`string`&&i.trim()!==``&&(e.style.setProperty(t,i.trim()),n.push(t))}function ve({host:e,iframe:t,options:n}){ge();let r={...n},i=[],a=!1,s,l=!1,u,d=!1,f,p,m=new AbortController,h,g=document.createElement(`div`);g.className=`amos-js-plaid-panel`,g.setAttribute(`data-amos-plaid-panel`,`true`),g.dataset.mode=`hidden`,_e(g,r.appearance,i);let _=document.createElement(`button`);_.type=`button`,_.className=`amos-js-plaid-connect`,_.textContent=`Connect bank account`,_.setAttribute(`data-testid`,`amos-plaid-connect`);let v=document.createElement(`div`);v.className=`amos-js-plaid-linked`;let y=document.createElement(`span`);y.className=`amos-js-plaid-linked-name`;let b=document.createElement(`span`);b.className=`amos-js-plaid-linked-meta`;let x=document.createElement(`button`);x.type=`button`,x.className=`amos-js-plaid-disconnect`,x.textContent=`Disconnect`,x.setAttribute(`aria-label`,`Disconnect bank account`);let S=document.createElement(`p`);S.className=`amos-js-plaid-error`,S.setAttribute(`role`,`alert`),v.append(y,b,x),g.append(_,v,S),e.append(g);let C=t.parentElement;function w(e){S.textContent=e??``}function T(){return a?l?!0:Y({amount:ce(r.amount),achThreshold:s}):!1}function E(){let e=!!h;f!==e&&(f=e,r.onValidityChange?.({isValid:e}))}function D(){let e=T();if(o(t,{requiresVerification:e,plaid:e?h?.credentials:void 0,clearLinked:O}),!e){g.dataset.mode=`hidden`,C&&(C.style.display=``),f=void 0;return}g.dataset.mode=h?`linked`:`connect`,C&&(C.style.display=`none`),h&&(y.textContent=h.bankName,b.textContent=h.last4?`****${h.last4}`:`Connected`),E()}function O(){h=void 0,u=void 0,p?.(),p=void 0,w(void 0),D()}function k(e){if(e.source===t.contentWindow&&e.data.type===`ACH_THRESHOLD`){if(a=!0,s=e.data.achThreshold??void 0,l=e.data.requireVerification===!0,h&&!T()){O();return}D()}}return window.addEventListener(`message`,k),D(),x.addEventListener(`click`,()=>{O()}),_.addEventListener(`click`,()=>{(async()=>{if(!(m.signal.aborted||d)){d=!0,_.disabled=!0,w(void 0);try{if(u||=await ee({iframe:t}),m.signal.aborted)return;let e=u;p?.(),p=await pe({token:e,signal:m.signal,onSuccess:(e,t)=>{if(m.signal.aborted)return;let n=le(t);if(!n){w(`Select a bank account to continue.`);return}let r=ue(t);h={credentials:{public_token:e,account_id:n},bankName:r.bankName,last4:r.last4},u=void 0,D()},onExit:e=>{m.signal.aborted||e?.error_code===`INVALID_LINK_TOKEN`&&(u=void 0)}}),m.signal.aborted&&(p(),p=void 0)}catch(e){if(u=void 0,m.signal.aborted)return;w(e instanceof Error?e.message:`Could not connect bank.`)}finally{d=!1,m.signal.aborted||(_.disabled=!1)}}})()}),{update(e){if(`amount`in e&&(r.amount=e.amount),`onValidityChange`in e&&(r.onValidityChange=e.onValidityChange),`appearance`in e&&(r.appearance=e.appearance,_e(g,r.appearance,i)),h&&!T()){O();return}D()},destroy(){m.abort(),window.removeEventListener(`message`,k),p?.(),p=void 0,c(t),g.remove()}}}function Z(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 ye={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`},be={width:`100%`,transition:`height 200ms ease-in-out`,margin:`0`,opacity:`0`,border:`0`},xe={position:`absolute`,top:`0`,left:`0`,width:`100%`,height:`100%`,margin:`0`,opacity:`0`,transition:`none`,pointerEvents:`none`},Se={position:`absolute`,top:`0`,left:`-4px`,width:`calc(100% + 8px)`,height:`100%`,margin:`0`,transition:`none`,pointerEvents:`none`};function Q({src:e,title:t,name:n,height:r,allow:i,className:a,style:o=ye}){let s=document.createElement(`iframe`);return s.src=e,s.title=t,s.name=n,s.setAttribute(`role`,`presentation`),s.scrolling=`no`,i&&(s.allow=i),a!=null&&(s.className=a),Object.assign(s.style,o,{height:r}),s}function Ce({host:e,iframe:t,listenerOptions:n,skeletonOptions:r}){let i=document.createElement(`div`);i.style.position=`relative`,i.style.width=`100%`,i.setAttribute(`aria-busy`,`true`);let a=ae(r);Object.assign(t.style,Se),i.append(a.element,t),e.appendChild(i);let o=!1,s=!1,c,l=r.appearance,u,d;function f(){return i.getBoundingClientRect().height}function p(){return c?Number.parseFloat(c):NaN}function m(){if(o)return;o=!0,d!==void 0&&(clearTimeout(d),d=void 0);let e=f(),n=p(),r=Number.isFinite(n)?Math.max(n,e):e;t.style.transition=`none`,t.style.position=``,t.style.top=``,t.style.left=``,t.style.margin=ye.margin??``,t.style.height=`${r}px`,t.style.opacity=`1`,t.style.pointerEvents=``,a.element.remove(),i.removeAttribute(`aria-busy`),u=setTimeout(()=>{t.style.transition=`height 200ms ease-in-out`},400)}function h(){if(o||!s)return;let e=p(),t=f();Number.isFinite(e)&&e>=t-2&&m()}let g=q(t,{...n,onHeightChange:e=>{c=e,o?t.style.height=e:h(),n.onHeightChange?.(e)},onAppearanceReady:()=>{s=!0,h(),!o&&d===void 0&&(d=setTimeout(()=>{m()},1500)),n.onAppearanceReady?.()}});return{iframe:t,update(e){g.update(e),!o&&`appearance`in e&&(l=e.appearance,a.update({...r,appearance:l}))},destroy(){u!==void 0&&clearTimeout(u),d!==void 0&&clearTimeout(d),g.destroy(),i.remove()}}}function $({host:e,iframe:t,listenerOptions:n,iframeStyle:r,attachListeners:i}){let a={height:n.height??`48px`,borderRadius:L({iframeStyle:r,buttonProps:n.buttonProps})},o=F(a),s=document.createElement(`div`);s.style.position=`relative`,s.style.width=`100%`,s.style.height=a.height,s.style.overflow=`hidden`,s.setAttribute(`aria-busy`,`true`),Object.assign(t.style,xe),t.style.height=`100%`,s.append(o.element,t),e.appendChild(s);let c=!1,l=!1,u,d=n;function f(){c||(c=!0,u!==void 0&&(clearTimeout(u),u=void 0),t.style.opacity=`1`,t.style.pointerEvents=``,o.element.remove(),s.removeAttribute(`aria-busy`))}function p(){c||!l||f()}let m=i(t,{...n,onHeightChange:e=>{d.onHeightChange?.(e)},onAppearanceReady:()=>{l=!0,p(),d.onAppearanceReady?.()}});return u=setTimeout(()=>{f()},1500),{iframe:t,update(e){d={...d,...e};let t={...e};delete t.onAppearanceReady,delete t.onHeightChange,m.update(t),a={height:d.height??a.height,borderRadius:L({iframeStyle:r,buttonProps:d.buttonProps})},s.style.height=a.height,c||o.update(a)},destroy(){u!==void 0&&clearTimeout(u),m.destroy(),s.remove()}}}function we(e,t){let n=Z(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t;return Ce({host:n,iframe:Q({src:U(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:G(i,a)}),listenerOptions:o,skeletonOptions:{kind:`card`,appearance:o.appearance,additionalFields:i,billingAddressRequirement:a}})}function Te(e,t){let n=Z(e),{renderToken:r,billingAddressRequirement:i=`country`,amount:a
|
|
174
|
+
`;function ge(){if(document.getElementById(me))return;let e=document.createElement(`style`);e.id=me,e.textContent=he,document.head.append(e)}function _e(e,t,n){for(let t of n)e.style.removeProperty(t);n.length=0;let r=t?.themeVariables;if(r)for(let[t,i]of Object.entries(r))typeof i==`string`&&i.trim()!==``&&(e.style.setProperty(t,i.trim()),n.push(t))}function ve({host:e,iframe:t,options:n}){ge();let r={...n,amount:n.amount??`0`},i=[],a=!1,s,l=!1,u,d=!1,f,p,m=new AbortController,h,g=document.createElement(`div`);g.className=`amos-js-plaid-panel`,g.setAttribute(`data-amos-plaid-panel`,`true`),g.dataset.mode=`hidden`,_e(g,r.appearance,i);let _=document.createElement(`button`);_.type=`button`,_.className=`amos-js-plaid-connect`,_.textContent=`Connect bank account`,_.setAttribute(`data-testid`,`amos-plaid-connect`);let v=document.createElement(`div`);v.className=`amos-js-plaid-linked`;let y=document.createElement(`span`);y.className=`amos-js-plaid-linked-name`;let b=document.createElement(`span`);b.className=`amos-js-plaid-linked-meta`;let x=document.createElement(`button`);x.type=`button`,x.className=`amos-js-plaid-disconnect`,x.textContent=`Disconnect`,x.setAttribute(`aria-label`,`Disconnect bank account`);let S=document.createElement(`p`);S.className=`amos-js-plaid-error`,S.setAttribute(`role`,`alert`),v.append(y,b,x),g.append(_,v,S),e.append(g);let C=t.parentElement;function w(e){S.textContent=e??``}function T(){return a?l?!0:Y({amount:ce(r.amount),achThreshold:s}):!1}function E(){let e=!!h;f!==e&&(f=e,r.onValidityChange?.({isValid:e}))}function D(){let e=T();if(o(t,{requiresVerification:e,plaid:e?h?.credentials:void 0,clearLinked:O}),!e){g.dataset.mode=`hidden`,C&&(C.style.display=``),f=void 0;return}g.dataset.mode=h?`linked`:`connect`,C&&(C.style.display=`none`),h&&(y.textContent=h.bankName,b.textContent=h.last4?`****${h.last4}`:`Connected`),E()}function O(){h=void 0,u=void 0,p?.(),p=void 0,w(void 0),D()}function k(e){if(e.source===t.contentWindow&&e.data.type===`ACH_THRESHOLD`){if(a=!0,s=e.data.achThreshold??void 0,l=e.data.requireVerification===!0,h&&!T()){O();return}D()}}return window.addEventListener(`message`,k),D(),x.addEventListener(`click`,()=>{O()}),_.addEventListener(`click`,()=>{(async()=>{if(!(m.signal.aborted||d)){d=!0,_.disabled=!0,w(void 0);try{if(u||=await ee({iframe:t}),m.signal.aborted)return;let e=u;p?.(),p=await pe({token:e,signal:m.signal,onSuccess:(e,t)=>{if(m.signal.aborted)return;let n=le(t);if(!n){w(`Select a bank account to continue.`);return}let r=ue(t);h={credentials:{public_token:e,account_id:n},bankName:r.bankName,last4:r.last4},u=void 0,D()},onExit:e=>{m.signal.aborted||e?.error_code===`INVALID_LINK_TOKEN`&&(u=void 0)}}),m.signal.aborted&&(p(),p=void 0)}catch(e){if(u=void 0,m.signal.aborted)return;w(e instanceof Error?e.message:`Could not connect bank.`)}finally{d=!1,m.signal.aborted||(_.disabled=!1)}}})()}),{update(e){if(`amount`in e&&(r.amount=e.amount??`0`),`onValidityChange`in e&&(r.onValidityChange=e.onValidityChange),`appearance`in e&&(r.appearance=e.appearance,_e(g,r.appearance,i)),h&&!T()){O();return}D()},destroy(){m.abort(),window.removeEventListener(`message`,k),p?.(),p=void 0,c(t),g.remove()}}}function Z(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 ye={width:`calc(100% + 8px)`,transition:`opacity 150ms ease-in, height 200ms ease-in-out`,margin:`0 -4px`,opacity:`0`,border:`0`},be={width:`100%`,transition:`height 200ms ease-in-out`,margin:`0`,opacity:`0`,border:`0`},xe={position:`absolute`,top:`0`,left:`0`,width:`100%`,height:`100%`,margin:`0`,opacity:`0`,transition:`none`,pointerEvents:`none`},Se={position:`absolute`,top:`0`,left:`-4px`,width:`calc(100% + 8px)`,height:`100%`,margin:`0`,transition:`none`,pointerEvents:`none`};function Q({src:e,title:t,name:n,height:r,allow:i,className:a,style:o=ye}){let s=document.createElement(`iframe`);return s.src=e,s.title=t,s.name=n,s.setAttribute(`role`,`presentation`),s.scrolling=`no`,i&&(s.allow=i),a!=null&&(s.className=a),Object.assign(s.style,o,{height:r}),s}function Ce({host:e,iframe:t,listenerOptions:n,skeletonOptions:r}){let i=document.createElement(`div`);i.style.position=`relative`,i.style.width=`100%`,i.setAttribute(`aria-busy`,`true`);let a=ae(r);Object.assign(t.style,Se),i.append(a.element,t),e.appendChild(i);let o=!1,s=!1,c,l=r.appearance,u,d;function f(){return i.getBoundingClientRect().height}function p(){return c?Number.parseFloat(c):NaN}function m(){if(o)return;o=!0,d!==void 0&&(clearTimeout(d),d=void 0);let e=f(),n=p(),r=Number.isFinite(n)?Math.max(n,e):e;t.style.transition=`none`,t.style.position=``,t.style.top=``,t.style.left=``,t.style.margin=ye.margin??``,t.style.height=`${r}px`,t.style.opacity=`1`,t.style.pointerEvents=``,a.element.remove(),i.removeAttribute(`aria-busy`),u=setTimeout(()=>{t.style.transition=`height 200ms ease-in-out`},400)}function h(){if(o||!s)return;let e=p(),t=f();Number.isFinite(e)&&e>=t-2&&m()}let g=q(t,{...n,onHeightChange:e=>{c=e,o?t.style.height=e:h(),n.onHeightChange?.(e)},onAppearanceReady:()=>{s=!0,h(),!o&&d===void 0&&(d=setTimeout(()=>{m()},1500)),n.onAppearanceReady?.()}});return{iframe:t,update(e){g.update(e),!o&&`appearance`in e&&(l=e.appearance,a.update({...r,appearance:l}))},destroy(){u!==void 0&&clearTimeout(u),d!==void 0&&clearTimeout(d),g.destroy(),i.remove()}}}function $({host:e,iframe:t,listenerOptions:n,iframeStyle:r,attachListeners:i}){let a={height:n.height??`48px`,borderRadius:L({iframeStyle:r,buttonProps:n.buttonProps})},o=F(a),s=document.createElement(`div`);s.style.position=`relative`,s.style.width=`100%`,s.style.height=a.height,s.style.overflow=`hidden`,s.setAttribute(`aria-busy`,`true`),Object.assign(t.style,xe),t.style.height=`100%`,s.append(o.element,t),e.appendChild(s);let c=!1,l=!1,u,d=n;function f(){c||(c=!0,u!==void 0&&(clearTimeout(u),u=void 0),t.style.opacity=`1`,t.style.pointerEvents=``,o.element.remove(),s.removeAttribute(`aria-busy`))}function p(){c||!l||f()}let m=i(t,{...n,onHeightChange:e=>{d.onHeightChange?.(e)},onAppearanceReady:()=>{l=!0,p(),d.onAppearanceReady?.()}});return u=setTimeout(()=>{f()},1500),{iframe:t,update(e){d={...d,...e};let t={...e};delete t.onAppearanceReady,delete t.onHeightChange,m.update(t),a={height:d.height??a.height,borderRadius:L({iframeStyle:r,buttonProps:d.buttonProps})},s.style.height=a.height,c||o.update(a)},destroy(){u!==void 0&&clearTimeout(u),m.destroy(),s.remove()}}}function we(e,t){let n=Z(e),{renderToken:r,additionalFields:i={cardholderName:!1},billingAddressRequirement:a=`country`,...o}=t;return Ce({host:n,iframe:Q({src:U(r,i,a),title:`Secure credit card payment method form powered by Amos`,name:`amos-credit-card-payment-method-form`,height:G(i,a)}),listenerOptions:o,skeletonOptions:{kind:`card`,appearance:o.appearance,additionalFields:i,billingAddressRequirement:a}})}function Te(e,t){let n=Z(e),{renderToken:r,billingAddressRequirement:i=`country`,amount:a=`0`,intent:o=`payment`,...s}=t,c=Q({src:W(r,i,o),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:K(i)}),l=Ce({host:n,iframe:c,listenerOptions:s,skeletonOptions:{kind:`bank`,appearance:s.appearance,billingAddressRequirement:i}}),u=ve({host:n,iframe:c,options:{amount:a,appearance:s.appearance,onValidityChange:s.onValidityChange}});return{iframe:c,update(e){l.update(e),u.update(e)},destroy(){u.destroy(),l.destroy()}}}function Ee(e,t){let n=Z(e),{renderToken:r,iframeClassName:i,iframeStyle:a,...o}=t,s=Q({src:R(r),title:`Secure Google Pay button powered by Amos`,name:`amos-google-pay-button`,height:o.height??z(),allow:`payment`,className:i,style:be});return Object.assign(s.style,a),$({host:n,iframe:s,listenerOptions:o,iframeStyle:a,attachListeners:B})}function De(e,t){let n=Z(e),{renderToken:r,iframeClassName:i,iframeStyle:a,...o}=t,s=Q({src:T(r),title:`Secure Apple Pay button powered by Amos`,name:`amos-apple-pay-button`,height:o.height??E(),allow:`payment`,className:i,style:be});return Object.assign(s.style,a),$({host:n,iframe:s,listenerOptions:o,iframeStyle:a,attachListeners:O})}exports.SKELETON_STYLES=ne,exports.attachApplePayButtonListeners=O,exports.attachGooglePayButtonListeners=B,exports.attachPaymentMethodFormListeners=q,exports.confirmPaymentIntent=S,exports.confirmSetupIntent=C,exports.createMessage=l,exports.createPaymentMethodFormSkeleton=ae,exports.createWalletButtonSkeleton=F,exports.decodeJwt=r,exports.ensureSkeletonStyles=A,exports.formatGooglePayPaymentData=oe,exports.getApplePayButtonInitialHeight=E,exports.getApplePayButtonSrc=T,exports.getBankAccountFormInitialHeight=K,exports.getBankAccountFormSrc=W,exports.getCreditCardFormInitialHeight=G,exports.getCreditCardFormSrc=U,exports.getEmbedOrigin=i,exports.getGooglePayButtonInitialHeight=z,exports.getGooglePayButtonSrc=R,exports.linkedBankLabelFromMetadata=ue,exports.loadPlaidScript=fe,exports.mountAmosApplePayButton=De,exports.mountAmosBankAccountPaymentMethodForm=Te,exports.mountAmosCreditCardPaymentMethodForm=we,exports.mountAmosGooglePayButton=Ee,exports.openPlaidLink=pe,exports.plaidAccountIdFromMetadata=le,exports.requiresAchVerification=Y,exports.resetForm=y,exports.resolveWalletButtonSkeletonBorderRadius=L,exports.sendConfirmationResult=w,exports.sendParentReadyMessage=d,exports.updateAmount=h,exports.updateAppearance=f,exports.updateApplePayButton=p,exports.updateGooglePayButton=m,exports.updateMerchantName=g,exports.validateForm=_;
|
package/dist/index.mjs
CHANGED
|
@@ -539,12 +539,12 @@ function U(e, t = { cardholderName: !1 }, n = "country") {
|
|
|
539
539
|
});
|
|
540
540
|
return `${i(e)}/iframe/card?${a}`;
|
|
541
541
|
}
|
|
542
|
-
function W(e, t = "country") {
|
|
543
|
-
let
|
|
542
|
+
function W(e, t = "country", n = "payment") {
|
|
543
|
+
let r = new URLSearchParams({
|
|
544
544
|
token: e,
|
|
545
545
|
billingAddressRequirement: t
|
|
546
546
|
});
|
|
547
|
-
return `${i(e)}/iframe/bank?${
|
|
547
|
+
return n === "setup" && r.set("intent", "setup"), `${i(e)}/iframe/bank?${r}`;
|
|
548
548
|
}
|
|
549
549
|
function G(e = { cardholderName: !1 }, t = "country") {
|
|
550
550
|
return `${(V[t] ?? V.country) + (e.cardholderName ? se : 0)}px`;
|
|
@@ -604,7 +604,7 @@ function q(e, t) {
|
|
|
604
604
|
//#region src/plaid.ts
|
|
605
605
|
var J = "https://cdn.plaid.com/link/v2/stable/link-initialize.js";
|
|
606
606
|
function Y({ amount: e, achThreshold: t }) {
|
|
607
|
-
return t
|
|
607
|
+
return t != null && (e ?? 0) >= t;
|
|
608
608
|
}
|
|
609
609
|
function ce(e) {
|
|
610
610
|
if (e == null) return;
|
|
@@ -673,7 +673,10 @@ function _e(e, t, n) {
|
|
|
673
673
|
}
|
|
674
674
|
function ve({ host: e, iframe: t, options: n }) {
|
|
675
675
|
ge();
|
|
676
|
-
let r = {
|
|
676
|
+
let r = {
|
|
677
|
+
...n,
|
|
678
|
+
amount: n.amount ?? "0"
|
|
679
|
+
}, i = [], a = !1, s, l = !1, u, d = !1, f, p, m = new AbortController(), h, g = document.createElement("div");
|
|
677
680
|
g.className = "amos-js-plaid-panel", g.setAttribute("data-amos-plaid-panel", "true"), g.dataset.mode = "hidden", _e(g, r.appearance, i);
|
|
678
681
|
let _ = document.createElement("button");
|
|
679
682
|
_.type = "button", _.className = "amos-js-plaid-connect", _.textContent = "Connect bank account", _.setAttribute("data-testid", "amos-plaid-connect");
|
|
@@ -768,7 +771,7 @@ function ve({ host: e, iframe: t, options: n }) {
|
|
|
768
771
|
})();
|
|
769
772
|
}), {
|
|
770
773
|
update(e) {
|
|
771
|
-
if ("amount" in e && (r.amount = e.amount), "onValidityChange" in e && (r.onValidityChange = e.onValidityChange), "appearance" in e && (r.appearance = e.appearance, _e(g, r.appearance, i)), h && !T()) {
|
|
774
|
+
if ("amount" in e && (r.amount = e.amount ?? "0"), "onValidityChange" in e && (r.onValidityChange = e.onValidityChange), "appearance" in e && (r.appearance = e.appearance, _e(g, r.appearance, i)), h && !T()) {
|
|
772
775
|
O();
|
|
773
776
|
return;
|
|
774
777
|
}
|
|
@@ -942,36 +945,36 @@ function we(e, t) {
|
|
|
942
945
|
});
|
|
943
946
|
}
|
|
944
947
|
function Te(e, t) {
|
|
945
|
-
let n = Z(e), { renderToken: r, billingAddressRequirement: i = "country", amount: a,
|
|
946
|
-
src: W(r, i),
|
|
948
|
+
let n = Z(e), { renderToken: r, billingAddressRequirement: i = "country", amount: a = "0", intent: o = "payment", ...s } = t, c = Q({
|
|
949
|
+
src: W(r, i, o),
|
|
947
950
|
title: "Secure bank account payment method form powered by Amos",
|
|
948
951
|
name: "amos-bank-account-payment-method-form",
|
|
949
952
|
height: K(i)
|
|
950
|
-
}),
|
|
953
|
+
}), l = Ce({
|
|
951
954
|
host: n,
|
|
952
|
-
iframe:
|
|
953
|
-
listenerOptions:
|
|
955
|
+
iframe: c,
|
|
956
|
+
listenerOptions: s,
|
|
954
957
|
skeletonOptions: {
|
|
955
958
|
kind: "bank",
|
|
956
|
-
appearance:
|
|
959
|
+
appearance: s.appearance,
|
|
957
960
|
billingAddressRequirement: i
|
|
958
961
|
}
|
|
959
|
-
}),
|
|
962
|
+
}), u = ve({
|
|
960
963
|
host: n,
|
|
961
|
-
iframe:
|
|
964
|
+
iframe: c,
|
|
962
965
|
options: {
|
|
963
966
|
amount: a,
|
|
964
|
-
appearance:
|
|
965
|
-
onValidityChange:
|
|
967
|
+
appearance: s.appearance,
|
|
968
|
+
onValidityChange: s.onValidityChange
|
|
966
969
|
}
|
|
967
970
|
});
|
|
968
971
|
return {
|
|
969
|
-
iframe:
|
|
972
|
+
iframe: c,
|
|
970
973
|
update(e) {
|
|
971
|
-
|
|
974
|
+
l.update(e), u.update(e);
|
|
972
975
|
},
|
|
973
976
|
destroy() {
|
|
974
|
-
|
|
977
|
+
u.destroy(), l.destroy();
|
|
975
978
|
}
|
|
976
979
|
};
|
|
977
980
|
}
|
package/dist/mount.d.ts
CHANGED
|
@@ -81,20 +81,38 @@ export type AmosBankAccountPaymentMethodFormOptions = PaymentMethodFormListenerO
|
|
|
81
81
|
/**
|
|
82
82
|
* Charge amount as a major-currency decimal string (e.g. `"50.00"`
|
|
83
83
|
* for $50.00), the same format as Google Pay / Apple Pay. Compared
|
|
84
|
-
* to the merchant ACH threshold fetched by the iframe.
|
|
85
|
-
*
|
|
86
|
-
*
|
|
84
|
+
* to the merchant ACH threshold fetched by the iframe. Defaults to
|
|
85
|
+
* `"0"`, which is typically under the threshold so Connect / Plaid
|
|
86
|
+
* stays hidden until the host passes a real charge.
|
|
87
|
+
*
|
|
88
|
+
* Ignored when {@link AmosBankAccountPaymentMethodFormOptions.intent}
|
|
89
|
+
* is `"setup"` — setup intents always show Connect (unless the render
|
|
90
|
+
* token disables Plaid verification).
|
|
91
|
+
*
|
|
92
|
+
* @default "0"
|
|
87
93
|
*/
|
|
88
94
|
amount?: string;
|
|
95
|
+
/**
|
|
96
|
+
* `"setup"` saves a bank account for later charges and always shows
|
|
97
|
+
* Connect / Plaid (no merchant threshold lookup). `"payment"`
|
|
98
|
+
* compares {@link AmosBankAccountPaymentMethodFormOptions.amount} to
|
|
99
|
+
* the merchant ACH threshold.
|
|
100
|
+
*
|
|
101
|
+
* @default "payment"
|
|
102
|
+
*/
|
|
103
|
+
intent?: "payment" | "setup";
|
|
89
104
|
};
|
|
90
105
|
/**
|
|
91
106
|
* Mount the secure bank-account payment method form into a container
|
|
92
107
|
* element. Returns a controller exposing the underlying iframe, an
|
|
93
108
|
* `update()` method, and a `destroy()` method.
|
|
94
109
|
*
|
|
95
|
-
* When the iframe reports an ACH threshold and `amount` meets it
|
|
96
|
-
*
|
|
97
|
-
*
|
|
110
|
+
* When the iframe reports an ACH threshold and `amount` meets it, a
|
|
111
|
+
* Connect bank button is rendered in the parent document and Plaid Link
|
|
112
|
+
* is opened on click. `amount` defaults to `"0"`, which is typically
|
|
113
|
+
* under the threshold so Connect stays hidden on open-amount forms
|
|
114
|
+
* until the host passes a real charge. Pass `intent: "setup"` to always
|
|
115
|
+
* show Connect without a merchant lookup. The button uses the same
|
|
98
116
|
* `appearance.themeVariables` as the iframe (and inherits host-page
|
|
99
117
|
* tokens when those variables are unset). Otherwise a field-shaped
|
|
100
118
|
* skeleton is shown and replaced by the iframe once appearance is applied.
|
|
@@ -22,8 +22,11 @@ export type BillingAddressRequirement = "country" | "full";
|
|
|
22
22
|
export declare function getCreditCardFormSrc(renderToken: string, additionalFields?: CreditCardAdditionalFields, billingAddressRequirement?: BillingAddressRequirement): string;
|
|
23
23
|
/**
|
|
24
24
|
* Build the iframe `src` URL for the embedded bank-account form.
|
|
25
|
+
*
|
|
26
|
+
* Pass `intent: "setup"` so the iframe always requires Plaid (when the
|
|
27
|
+
* render token allows it) and does not `GET /merchants` for a threshold.
|
|
25
28
|
*/
|
|
26
|
-
export declare function getBankAccountFormSrc(renderToken: string, billingAddressRequirement?: BillingAddressRequirement): string;
|
|
29
|
+
export declare function getBankAccountFormSrc(renderToken: string, billingAddressRequirement?: BillingAddressRequirement, intent?: "payment" | "setup"): string;
|
|
27
30
|
/**
|
|
28
31
|
* Default iframe pixel height for the credit-card form, taking the
|
|
29
32
|
* configured `additionalFields` and `billingAddressRequirement` into
|
package/dist/plaid.d.ts
CHANGED
|
@@ -42,8 +42,9 @@ declare global {
|
|
|
42
42
|
* fields.
|
|
43
43
|
*
|
|
44
44
|
* - No `achThreshold`: always manual ACH (backward compatible).
|
|
45
|
-
* - `amount` omitted: Plaid (setup / unknown future charge).
|
|
46
45
|
* - Otherwise: Plaid when `amount >= achThreshold`.
|
|
46
|
+
* - Omitted `amount` is treated as `0` (typically under the threshold, so
|
|
47
|
+
* Connect stays hidden until the host passes a charge).
|
|
47
48
|
*
|
|
48
49
|
* `amount` and `achThreshold` are integer minor units (cents).
|
|
49
50
|
*/
|
package/dist/types.d.ts
CHANGED
|
@@ -248,10 +248,11 @@ export type Message = {
|
|
|
248
248
|
brand: CardBrand | null;
|
|
249
249
|
} | {
|
|
250
250
|
/**
|
|
251
|
-
* Embed → parent:
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
251
|
+
* Embed → parent: ACH verification policy for this bank iframe.
|
|
252
|
+
* `achThreshold` is cents, or `null` when the merchant has no
|
|
253
|
+
* threshold (manual ACH). `requireVerification` is true for setup
|
|
254
|
+
* intents (always Plaid, no merchant lookup), and when a payment
|
|
255
|
+
* threshold fetch failed in production (fail closed).
|
|
255
256
|
*/
|
|
256
257
|
type: "ACH_THRESHOLD";
|
|
257
258
|
achThreshold?: number | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amos.com/amos-js",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,11 +35,8 @@
|
|
|
35
35
|
"author": "Amos",
|
|
36
36
|
"license": "MIT",
|
|
37
37
|
"description": "Amos JavaScript SDK for embedding payment methods via iframes.",
|
|
38
|
-
"peerDependencies": {
|
|
39
|
-
"@amos.com/node": ">=0.1.39"
|
|
40
|
-
},
|
|
41
38
|
"devDependencies": {
|
|
42
|
-
"@amos.com/node": "0.1.
|
|
39
|
+
"@amos.com/node": "0.1.50",
|
|
43
40
|
"@biomejs/biome": "2.5.7",
|
|
44
41
|
"@changesets/cli": "2.31.1",
|
|
45
42
|
"@types/node": "26.1.2",
|
|
@@ -50,5 +47,8 @@
|
|
|
50
47
|
},
|
|
51
48
|
"dependencies": {
|
|
52
49
|
"@types/googlepay": "0.7.11"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@amos.com/node": ">=0.1.50"
|
|
53
53
|
}
|
|
54
54
|
}
|
package/src/mount.ts
CHANGED
|
@@ -510,11 +510,26 @@ export type AmosBankAccountPaymentMethodFormOptions =
|
|
|
510
510
|
/**
|
|
511
511
|
* Charge amount as a major-currency decimal string (e.g. `"50.00"`
|
|
512
512
|
* for $50.00), the same format as Google Pay / Apple Pay. Compared
|
|
513
|
-
* to the merchant ACH threshold fetched by the iframe.
|
|
514
|
-
*
|
|
515
|
-
*
|
|
513
|
+
* to the merchant ACH threshold fetched by the iframe. Defaults to
|
|
514
|
+
* `"0"`, which is typically under the threshold so Connect / Plaid
|
|
515
|
+
* stays hidden until the host passes a real charge.
|
|
516
|
+
*
|
|
517
|
+
* Ignored when {@link AmosBankAccountPaymentMethodFormOptions.intent}
|
|
518
|
+
* is `"setup"` — setup intents always show Connect (unless the render
|
|
519
|
+
* token disables Plaid verification).
|
|
520
|
+
*
|
|
521
|
+
* @default "0"
|
|
516
522
|
*/
|
|
517
523
|
amount?: string;
|
|
524
|
+
/**
|
|
525
|
+
* `"setup"` saves a bank account for later charges and always shows
|
|
526
|
+
* Connect / Plaid (no merchant threshold lookup). `"payment"`
|
|
527
|
+
* compares {@link AmosBankAccountPaymentMethodFormOptions.amount} to
|
|
528
|
+
* the merchant ACH threshold.
|
|
529
|
+
*
|
|
530
|
+
* @default "payment"
|
|
531
|
+
*/
|
|
532
|
+
intent?: "payment" | "setup";
|
|
518
533
|
};
|
|
519
534
|
|
|
520
535
|
/**
|
|
@@ -522,9 +537,12 @@ export type AmosBankAccountPaymentMethodFormOptions =
|
|
|
522
537
|
* element. Returns a controller exposing the underlying iframe, an
|
|
523
538
|
* `update()` method, and a `destroy()` method.
|
|
524
539
|
*
|
|
525
|
-
* When the iframe reports an ACH threshold and `amount` meets it
|
|
526
|
-
*
|
|
527
|
-
*
|
|
540
|
+
* When the iframe reports an ACH threshold and `amount` meets it, a
|
|
541
|
+
* Connect bank button is rendered in the parent document and Plaid Link
|
|
542
|
+
* is opened on click. `amount` defaults to `"0"`, which is typically
|
|
543
|
+
* under the threshold so Connect stays hidden on open-amount forms
|
|
544
|
+
* until the host passes a real charge. Pass `intent: "setup"` to always
|
|
545
|
+
* show Connect without a merchant lookup. The button uses the same
|
|
528
546
|
* `appearance.themeVariables` as the iframe (and inherits host-page
|
|
529
547
|
* tokens when those variables are unset). Otherwise a field-shaped
|
|
530
548
|
* skeleton is shown and replaced by the iframe once appearance is applied.
|
|
@@ -541,12 +559,13 @@ export function mountAmosBankAccountPaymentMethodForm(
|
|
|
541
559
|
const {
|
|
542
560
|
renderToken,
|
|
543
561
|
billingAddressRequirement = "country",
|
|
544
|
-
amount,
|
|
562
|
+
amount = "0",
|
|
563
|
+
intent = "payment",
|
|
545
564
|
...listenerOptions
|
|
546
565
|
} = options;
|
|
547
566
|
|
|
548
567
|
const iframe = createIframe({
|
|
549
|
-
src: getBankAccountFormSrc(renderToken, billingAddressRequirement),
|
|
568
|
+
src: getBankAccountFormSrc(renderToken, billingAddressRequirement, intent),
|
|
550
569
|
title: "Secure bank account payment method form powered by Amos",
|
|
551
570
|
name: "amos-bank-account-payment-method-form",
|
|
552
571
|
height: getBankAccountFormInitialHeight(billingAddressRequirement),
|
|
@@ -68,15 +68,22 @@ export function getCreditCardFormSrc(
|
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* Build the iframe `src` URL for the embedded bank-account form.
|
|
71
|
+
*
|
|
72
|
+
* Pass `intent: "setup"` so the iframe always requires Plaid (when the
|
|
73
|
+
* render token allows it) and does not `GET /merchants` for a threshold.
|
|
71
74
|
*/
|
|
72
75
|
export function getBankAccountFormSrc(
|
|
73
76
|
renderToken: string,
|
|
74
77
|
billingAddressRequirement: BillingAddressRequirement = "country",
|
|
78
|
+
intent: "payment" | "setup" = "payment",
|
|
75
79
|
): string {
|
|
76
80
|
const params = new URLSearchParams({
|
|
77
81
|
token: renderToken,
|
|
78
82
|
billingAddressRequirement,
|
|
79
83
|
});
|
|
84
|
+
if (intent === "setup") {
|
|
85
|
+
params.set("intent", "setup");
|
|
86
|
+
}
|
|
80
87
|
|
|
81
88
|
return `${getEmbedOrigin(renderToken)}/iframe/bank?${params}`;
|
|
82
89
|
}
|
package/src/plaid-bank-ui.ts
CHANGED
|
@@ -181,7 +181,10 @@ export function attachPlaidBankUi({
|
|
|
181
181
|
} {
|
|
182
182
|
ensurePlaidBankUiStyles();
|
|
183
183
|
|
|
184
|
-
const current: PlaidBankUiOptions = {
|
|
184
|
+
const current: PlaidBankUiOptions = {
|
|
185
|
+
...options,
|
|
186
|
+
amount: options.amount ?? "0",
|
|
187
|
+
};
|
|
185
188
|
const appliedThemeKeys: Array<string> = [];
|
|
186
189
|
let thresholdKnown = false;
|
|
187
190
|
let achThreshold: number | undefined;
|
|
@@ -394,7 +397,7 @@ export function attachPlaidBankUi({
|
|
|
394
397
|
return {
|
|
395
398
|
update(patch) {
|
|
396
399
|
if ("amount" in patch) {
|
|
397
|
-
current.amount = patch.amount;
|
|
400
|
+
current.amount = patch.amount ?? "0";
|
|
398
401
|
}
|
|
399
402
|
if ("onValidityChange" in patch) {
|
|
400
403
|
current.onValidityChange = patch.onValidityChange;
|
package/src/plaid.ts
CHANGED
|
@@ -51,8 +51,9 @@ declare global {
|
|
|
51
51
|
* fields.
|
|
52
52
|
*
|
|
53
53
|
* - No `achThreshold`: always manual ACH (backward compatible).
|
|
54
|
-
* - `amount` omitted: Plaid (setup / unknown future charge).
|
|
55
54
|
* - Otherwise: Plaid when `amount >= achThreshold`.
|
|
55
|
+
* - Omitted `amount` is treated as `0` (typically under the threshold, so
|
|
56
|
+
* Connect stays hidden until the host passes a charge).
|
|
56
57
|
*
|
|
57
58
|
* `amount` and `achThreshold` are integer minor units (cents).
|
|
58
59
|
*/
|
|
@@ -66,10 +67,7 @@ export function requiresAchVerification({
|
|
|
66
67
|
if (achThreshold == null) {
|
|
67
68
|
return false;
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
return amount >= achThreshold;
|
|
70
|
+
return (amount ?? 0) >= achThreshold;
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
/**
|
package/src/types.ts
CHANGED
|
@@ -536,10 +536,11 @@ export type Message =
|
|
|
536
536
|
}
|
|
537
537
|
| {
|
|
538
538
|
/**
|
|
539
|
-
* Embed → parent:
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
539
|
+
* Embed → parent: ACH verification policy for this bank iframe.
|
|
540
|
+
* `achThreshold` is cents, or `null` when the merchant has no
|
|
541
|
+
* threshold (manual ACH). `requireVerification` is true for setup
|
|
542
|
+
* intents (always Plaid, no merchant lookup), and when a payment
|
|
543
|
+
* threshold fetch failed in production (fail closed).
|
|
543
544
|
*/
|
|
544
545
|
type: "ACH_THRESHOLD";
|
|
545
546
|
achThreshold?: number | null;
|