@amos.com/amos-js 0.9.18 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/index.mjs +10 -4
- package/dist/mount.d.ts +10 -6
- package/dist/payment-method-form.d.ts +8 -1
- package/dist/plaid.d.ts +2 -1
- package/dist/types.d.ts +20 -0
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/mount.ts +11 -7
- package/src/payment-method-form.ts +12 -0
- package/src/plaid-bank-ui.ts +5 -2
- package/src/plaid.ts +3 -5
- package/src/types.ts +29 -0
package/README.md
CHANGED
|
@@ -281,6 +281,7 @@ Mount the secure credit-card payment method form into a container element (an `H
|
|
|
281
281
|
- `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.
|
|
282
282
|
|
|
283
283
|
- `onValidityChange` (`(event: { isValid: boolean }) => void`) — called when form validity changes. `isValid` is true when all required fields are present and valid. Does not include PCI data. Use this to enable or disable your checkout button.
|
|
284
|
+
- `onCardBrandChanged` (`(event: { brand: CardBrand | null }) => void`) — called when the detected card brand changes. `brand` is `"visa"`, `"mastercard"`, `"amex"`, `"discover"`, `"diners"`, or `"jcb"`, or `null` when the field is empty or the number does not match a known brand. Does not include PCI data. Credit-card form only.
|
|
284
285
|
- `onHeightChange`, `onAppearanceReady` (advanced — override the default iframe styling logic). The skeleton is removed and the iframe faded in when `onAppearanceReady` fires.
|
|
285
286
|
|
|
286
287
|
**Returns** `AmosPaymentMethodFormMountController`:
|
|
@@ -297,16 +298,16 @@ When the charge meets the merchant’s ACH verification threshold, the SDK hides
|
|
|
297
298
|
|
|
298
299
|
**Additional `options` (ACH verification):**
|
|
299
300
|
|
|
300
|
-
- `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. For setup intents, pass an amount at or above the merchant ACH threshold (the expected future charge) to show Connect.
|
|
301
302
|
|
|
302
|
-
Compare locally once the iframe posts `ACH_THRESHOLD`: Plaid when the amount (converted to cents
|
|
303
|
+
Compare locally once the iframe posts `ACH_THRESHOLD`: Plaid when the amount (converted to cents, default `0`) is `>= achThreshold`. No threshold (or `null`) keeps the manual bank form. If `amount` later drops under the threshold, Plaid credentials are dropped and the iframe form is shown again.
|
|
303
304
|
|
|
304
305
|
```ts
|
|
305
306
|
import { mountAmosBankAccountPaymentMethodForm } from "@amos.com/amos-js";
|
|
306
307
|
|
|
307
308
|
const bank = mountAmosBankAccountPaymentMethodForm("#bank-form", {
|
|
308
309
|
renderToken,
|
|
309
|
-
amount: "50.00", //
|
|
310
|
+
amount: "50.00", // defaults to "0" (manual form until the charge meets the threshold)
|
|
310
311
|
onResult: (result) => {
|
|
311
312
|
/* … */
|
|
312
313
|
},
|
|
@@ -415,7 +416,7 @@ Advanced helpers exposed for integrators that need to construct or inspect the m
|
|
|
415
416
|
|
|
416
417
|
### Exported types
|
|
417
418
|
|
|
418
|
-
`ConfirmationResult`, `ConfirmationIncompleteReason`, `Message`, `Appearance`, `ThemeVariable`, `FormattedGooglePayPaymentData`, `PaymentMethodFormValidityChangeEvent`, plus the per-form `*Options` and `*Controller` types. For OpenAPI schema types, import `components` from `@amos.com/node`.
|
|
419
|
+
`ConfirmationResult`, `ConfirmationIncompleteReason`, `Message`, `Appearance`, `ThemeVariable`, `FormattedGooglePayPaymentData`, `PaymentMethodFormValidityChangeEvent`, `CardBrand`, `PaymentMethodFormCardBrandChangeEvent`, plus the per-form `*Options` and `*Controller` types. For OpenAPI schema types, import `components` from `@amos.com/node`.
|
|
419
420
|
|
|
420
421
|
## Notes and potential gotchas
|
|
421
422
|
|
package/dist/index.d.ts
CHANGED
|
@@ -13,5 +13,5 @@ export type { BillingAddressRequirement, CreditCardAdditionalFields, PaymentMeth
|
|
|
13
13
|
export { attachPaymentMethodFormListeners, getBankAccountFormInitialHeight, getBankAccountFormSrc, getCreditCardFormInitialHeight, getCreditCardFormSrc, } from './payment-method-form';
|
|
14
14
|
export type { OpenPlaidLinkInput, PlaidCredentials, PlaidLinkOnSuccessMetadata, } from './plaid';
|
|
15
15
|
export { linkedBankLabelFromMetadata, loadPlaidScript, openPlaidLink, plaidAccountIdFromMetadata, requiresAchVerification, } from './plaid';
|
|
16
|
-
export type { Appearance, AppearanceLabels, ApplePayButtonElementProps, ConfirmationIncompleteReason, ConfirmationResult, GooglePayButtonElementProps, Message, PaymentMethodFormValidityChangeEvent, ThemeVariable, } from './types';
|
|
16
|
+
export type { Appearance, AppearanceLabels, ApplePayButtonElementProps, CardBrand, ConfirmationIncompleteReason, ConfirmationResult, GooglePayButtonElementProps, Message, PaymentMethodFormCardBrandChangeEvent, PaymentMethodFormValidityChangeEvent, ThemeVariable, } from './types';
|
|
17
17
|
export { createMessage } from './types';
|
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 n=new URLSearchParams({token:e,billingAddressRequirement:t});return`${i(e)}/iframe/bank?${n}`}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`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
|
|
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 n=new URLSearchParams({token:e,billingAddressRequirement:t});return`${i(e)}/iframe/bank?${n}`}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`,...o}=t,s=Q({src:W(r,i),title:`Secure bank account payment method form powered by Amos`,name:`amos-bank-account-payment-method-form`,height:K(i)}),c=Ce({host:n,iframe:s,listenerOptions:o,skeletonOptions:{kind:`bank`,appearance:o.appearance,billingAddressRequirement:i}}),l=ve({host:n,iframe:s,options:{amount:a,appearance:o.appearance,onValidityChange:o.onValidityChange}});return{iframe:s,update(e){c.update(e),l.update(e)},destroy(){l.destroy(),c.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
|
@@ -578,6 +578,9 @@ function q(e, t) {
|
|
|
578
578
|
if (s(e)?.requiresVerification) break;
|
|
579
579
|
n.onValidityChange?.({ isValid: t.data.isValid });
|
|
580
580
|
break;
|
|
581
|
+
case "CARD_BRAND_CHANGE":
|
|
582
|
+
n.onCardBrandChanged?.({ brand: t.data.brand });
|
|
583
|
+
break;
|
|
581
584
|
case "CONFIRMATION_RESULT": n.onResult(t.data.result);
|
|
582
585
|
}
|
|
583
586
|
}
|
|
@@ -601,7 +604,7 @@ function q(e, t) {
|
|
|
601
604
|
//#region src/plaid.ts
|
|
602
605
|
var J = "https://cdn.plaid.com/link/v2/stable/link-initialize.js";
|
|
603
606
|
function Y({ amount: e, achThreshold: t }) {
|
|
604
|
-
return t
|
|
607
|
+
return t != null && (e ?? 0) >= t;
|
|
605
608
|
}
|
|
606
609
|
function ce(e) {
|
|
607
610
|
if (e == null) return;
|
|
@@ -670,7 +673,10 @@ function _e(e, t, n) {
|
|
|
670
673
|
}
|
|
671
674
|
function ve({ host: e, iframe: t, options: n }) {
|
|
672
675
|
ge();
|
|
673
|
-
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");
|
|
674
680
|
g.className = "amos-js-plaid-panel", g.setAttribute("data-amos-plaid-panel", "true"), g.dataset.mode = "hidden", _e(g, r.appearance, i);
|
|
675
681
|
let _ = document.createElement("button");
|
|
676
682
|
_.type = "button", _.className = "amos-js-plaid-connect", _.textContent = "Connect bank account", _.setAttribute("data-testid", "amos-plaid-connect");
|
|
@@ -765,7 +771,7 @@ function ve({ host: e, iframe: t, options: n }) {
|
|
|
765
771
|
})();
|
|
766
772
|
}), {
|
|
767
773
|
update(e) {
|
|
768
|
-
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()) {
|
|
769
775
|
O();
|
|
770
776
|
return;
|
|
771
777
|
}
|
|
@@ -939,7 +945,7 @@ function we(e, t) {
|
|
|
939
945
|
});
|
|
940
946
|
}
|
|
941
947
|
function Te(e, t) {
|
|
942
|
-
let n = Z(e), { renderToken: r, billingAddressRequirement: i = "country", amount: a, ...o } = t, s = Q({
|
|
948
|
+
let n = Z(e), { renderToken: r, billingAddressRequirement: i = "country", amount: a = "0", ...o } = t, s = Q({
|
|
943
949
|
src: W(r, i),
|
|
944
950
|
title: "Secure bank account payment method form powered by Amos",
|
|
945
951
|
name: "amos-bank-account-payment-method-form",
|
package/dist/mount.d.ts
CHANGED
|
@@ -81,9 +81,11 @@ 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
|
+
* @default "0"
|
|
87
89
|
*/
|
|
88
90
|
amount?: string;
|
|
89
91
|
};
|
|
@@ -92,9 +94,11 @@ export type AmosBankAccountPaymentMethodFormOptions = PaymentMethodFormListenerO
|
|
|
92
94
|
* element. Returns a controller exposing the underlying iframe, an
|
|
93
95
|
* `update()` method, and a `destroy()` method.
|
|
94
96
|
*
|
|
95
|
-
* When the iframe reports an ACH threshold and `amount` meets it
|
|
96
|
-
*
|
|
97
|
-
*
|
|
97
|
+
* When the iframe reports an ACH threshold and `amount` meets it, a
|
|
98
|
+
* Connect bank button is rendered in the parent document and Plaid Link
|
|
99
|
+
* is opened on click. `amount` defaults to `"0"`, which is typically
|
|
100
|
+
* under the threshold so Connect stays hidden on open-amount forms
|
|
101
|
+
* until the host passes a real charge. The button uses the same
|
|
98
102
|
* `appearance.themeVariables` as the iframe (and inherits host-page
|
|
99
103
|
* tokens when those variables are unset). Otherwise a field-shaped
|
|
100
104
|
* skeleton is shown and replaced by the iframe once appearance is applied.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Appearance, ConfirmationResult, PaymentMethodFormValidityChangeEvent } from './types';
|
|
1
|
+
import { Appearance, ConfirmationResult, PaymentMethodFormCardBrandChangeEvent, PaymentMethodFormValidityChangeEvent } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* The additional fields beyond the standard card number, expiration
|
|
4
4
|
* date, CVV, and billing address fields that are required to be filled
|
|
@@ -65,6 +65,13 @@ export type PaymentMethodFormListenerOptions = {
|
|
|
65
65
|
* PCI data. Use this to enable or disable a host checkout button.
|
|
66
66
|
*/
|
|
67
67
|
onValidityChange?: (event: PaymentMethodFormValidityChangeEvent) => void;
|
|
68
|
+
/**
|
|
69
|
+
* Called when the detected card brand changes. `brand` is the matched
|
|
70
|
+
* network, or `null` when the field is empty or the digits do not
|
|
71
|
+
* match a known brand. Does not include PCI data. Credit-card form
|
|
72
|
+
* only — never fired for bank account.
|
|
73
|
+
*/
|
|
74
|
+
onCardBrandChanged?: (event: PaymentMethodFormCardBrandChangeEvent) => void;
|
|
68
75
|
/**
|
|
69
76
|
* Called when the interactive confirmation flow finishes (success or
|
|
70
77
|
* terminal failure). Not settlement proof — verify via webhooks.
|
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
|
@@ -7,6 +7,18 @@ import { components } from '@amos.com/node';
|
|
|
7
7
|
export type PaymentMethodFormValidityChangeEvent = {
|
|
8
8
|
isValid: boolean;
|
|
9
9
|
};
|
|
10
|
+
/**
|
|
11
|
+
* Detected card network from the PAN prefix inside the iframe.
|
|
12
|
+
* `null` when the field is empty or the digits do not match a known brand.
|
|
13
|
+
*/
|
|
14
|
+
export type CardBrand = "visa" | "mastercard" | "amex" | "discover" | "diners" | "jcb";
|
|
15
|
+
/**
|
|
16
|
+
* PCI-safe card brand update from the credit-card iframe. Does not
|
|
17
|
+
* include the PAN, last4, or BIN.
|
|
18
|
+
*/
|
|
19
|
+
export type PaymentMethodFormCardBrandChangeEvent = {
|
|
20
|
+
brand: CardBrand | null;
|
|
21
|
+
};
|
|
10
22
|
/**
|
|
11
23
|
* Why an interactive confirmation attempt ended with `status: "incomplete"`.
|
|
12
24
|
*
|
|
@@ -226,6 +238,14 @@ export type Message = {
|
|
|
226
238
|
*/
|
|
227
239
|
type: "FORM_VALIDITY_CHANGE";
|
|
228
240
|
isValid: boolean;
|
|
241
|
+
} | {
|
|
242
|
+
/**
|
|
243
|
+
* Embed → parent: detected card brand changed. `brand` is the
|
|
244
|
+
* matched network, or `null` when the field is empty or the
|
|
245
|
+
* digits do not match a known brand. Does not include PCI data.
|
|
246
|
+
*/
|
|
247
|
+
type: "CARD_BRAND_CHANGE";
|
|
248
|
+
brand: CardBrand | null;
|
|
229
249
|
} | {
|
|
230
250
|
/**
|
|
231
251
|
* Embed → parent: merchant ACH verification threshold for this
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -94,10 +94,12 @@ export type {
|
|
|
94
94
|
Appearance,
|
|
95
95
|
AppearanceLabels,
|
|
96
96
|
ApplePayButtonElementProps,
|
|
97
|
+
CardBrand,
|
|
97
98
|
ConfirmationIncompleteReason,
|
|
98
99
|
ConfirmationResult,
|
|
99
100
|
GooglePayButtonElementProps,
|
|
100
101
|
Message,
|
|
102
|
+
PaymentMethodFormCardBrandChangeEvent,
|
|
101
103
|
PaymentMethodFormValidityChangeEvent,
|
|
102
104
|
ThemeVariable,
|
|
103
105
|
} from "./types";
|
package/src/mount.ts
CHANGED
|
@@ -510,9 +510,11 @@ 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
|
+
* @default "0"
|
|
516
518
|
*/
|
|
517
519
|
amount?: string;
|
|
518
520
|
};
|
|
@@ -522,9 +524,11 @@ export type AmosBankAccountPaymentMethodFormOptions =
|
|
|
522
524
|
* element. Returns a controller exposing the underlying iframe, an
|
|
523
525
|
* `update()` method, and a `destroy()` method.
|
|
524
526
|
*
|
|
525
|
-
* When the iframe reports an ACH threshold and `amount` meets it
|
|
526
|
-
*
|
|
527
|
-
*
|
|
527
|
+
* When the iframe reports an ACH threshold and `amount` meets it, a
|
|
528
|
+
* Connect bank button is rendered in the parent document and Plaid Link
|
|
529
|
+
* is opened on click. `amount` defaults to `"0"`, which is typically
|
|
530
|
+
* under the threshold so Connect stays hidden on open-amount forms
|
|
531
|
+
* until the host passes a real charge. The button uses the same
|
|
528
532
|
* `appearance.themeVariables` as the iframe (and inherits host-page
|
|
529
533
|
* tokens when those variables are unset). Otherwise a field-shaped
|
|
530
534
|
* skeleton is shown and replaced by the iframe once appearance is applied.
|
|
@@ -541,7 +545,7 @@ export function mountAmosBankAccountPaymentMethodForm(
|
|
|
541
545
|
const {
|
|
542
546
|
renderToken,
|
|
543
547
|
billingAddressRequirement = "country",
|
|
544
|
-
amount,
|
|
548
|
+
amount = "0",
|
|
545
549
|
...listenerOptions
|
|
546
550
|
} = options;
|
|
547
551
|
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
Appearance,
|
|
9
9
|
ConfirmationResult,
|
|
10
10
|
Message,
|
|
11
|
+
PaymentMethodFormCardBrandChangeEvent,
|
|
11
12
|
PaymentMethodFormValidityChangeEvent,
|
|
12
13
|
} from "./types";
|
|
13
14
|
|
|
@@ -138,6 +139,13 @@ export type PaymentMethodFormListenerOptions = {
|
|
|
138
139
|
* PCI data. Use this to enable or disable a host checkout button.
|
|
139
140
|
*/
|
|
140
141
|
onValidityChange?: (event: PaymentMethodFormValidityChangeEvent) => void;
|
|
142
|
+
/**
|
|
143
|
+
* Called when the detected card brand changes. `brand` is the matched
|
|
144
|
+
* network, or `null` when the field is empty or the digits do not
|
|
145
|
+
* match a known brand. Does not include PCI data. Credit-card form
|
|
146
|
+
* only — never fired for bank account.
|
|
147
|
+
*/
|
|
148
|
+
onCardBrandChanged?: (event: PaymentMethodFormCardBrandChangeEvent) => void;
|
|
141
149
|
/**
|
|
142
150
|
* Called when the interactive confirmation flow finishes (success or
|
|
143
151
|
* terminal failure). Not settlement proof — verify via webhooks.
|
|
@@ -210,6 +218,10 @@ export function attachPaymentMethodFormListeners(
|
|
|
210
218
|
current.onValidityChange?.({ isValid: event.data.isValid });
|
|
211
219
|
break;
|
|
212
220
|
|
|
221
|
+
case "CARD_BRAND_CHANGE":
|
|
222
|
+
current.onCardBrandChanged?.({ brand: event.data.brand });
|
|
223
|
+
break;
|
|
224
|
+
|
|
213
225
|
case "CONFIRMATION_RESULT":
|
|
214
226
|
current.onResult(event.data.result);
|
|
215
227
|
break;
|
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
|
@@ -11,6 +11,26 @@ export type PaymentMethodFormValidityChangeEvent = {
|
|
|
11
11
|
isValid: boolean;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Detected card network from the PAN prefix inside the iframe.
|
|
16
|
+
* `null` when the field is empty or the digits do not match a known brand.
|
|
17
|
+
*/
|
|
18
|
+
export type CardBrand =
|
|
19
|
+
| "visa"
|
|
20
|
+
| "mastercard"
|
|
21
|
+
| "amex"
|
|
22
|
+
| "discover"
|
|
23
|
+
| "diners"
|
|
24
|
+
| "jcb";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* PCI-safe card brand update from the credit-card iframe. Does not
|
|
28
|
+
* include the PAN, last4, or BIN.
|
|
29
|
+
*/
|
|
30
|
+
export type PaymentMethodFormCardBrandChangeEvent = {
|
|
31
|
+
brand: CardBrand | null;
|
|
32
|
+
};
|
|
33
|
+
|
|
14
34
|
/**
|
|
15
35
|
* Why an interactive confirmation attempt ended with `status: "incomplete"`.
|
|
16
36
|
*
|
|
@@ -505,6 +525,15 @@ export type Message =
|
|
|
505
525
|
type: "FORM_VALIDITY_CHANGE";
|
|
506
526
|
isValid: boolean;
|
|
507
527
|
}
|
|
528
|
+
| {
|
|
529
|
+
/**
|
|
530
|
+
* Embed → parent: detected card brand changed. `brand` is the
|
|
531
|
+
* matched network, or `null` when the field is empty or the
|
|
532
|
+
* digits do not match a known brand. Does not include PCI data.
|
|
533
|
+
*/
|
|
534
|
+
type: "CARD_BRAND_CHANGE";
|
|
535
|
+
brand: CardBrand | null;
|
|
536
|
+
}
|
|
508
537
|
| {
|
|
509
538
|
/**
|
|
510
539
|
* Embed → parent: merchant ACH verification threshold for this
|