diff --git a/types/stripe-v3/index.d.ts b/types/stripe-v3/index.d.ts index 76666e747a..c2a6f8a550 100644 --- a/types/stripe-v3/index.d.ts +++ b/types/stripe-v3/index.d.ts @@ -12,18 +12,23 @@ declare var Stripe: stripe.StripeStatic; declare namespace stripe { interface StripeStatic { - (publicKey: string): Stripe; + (publicKey: string, options?: StripeOptions): Stripe; version: number; } interface Stripe { elements(options?: elements.ElementsCreateOptions): elements.Elements; createToken(element: elements.Element, options?: TokenOptions): Promise; + createToken(name: 'bank_account', options: BankAccountTokenOptions): Promise; + createToken(name: 'pii', options: PiiTokenOptions): Promise; + createSource(element: elements.Element, options?: {owner?: OwnerInfo}): Promise; createSource(options: SourceOptions): Promise; + retrieveSource(options: RetrieveSourceOptions): Promise; + paymentRequest(options: paymentRequest.StripePaymentRequestOptions): paymentRequest.StripePaymentRequest; } interface StripeOptions { - stripeAccount: string; + stripeAccount?: string; } interface TokenOptions { @@ -37,6 +42,33 @@ declare namespace stripe { currency?: string; } + interface BankAccountTokenOptions { + country: string; + currency: string; + routing_number: string; + account_number: string; + account_holder_name: string; + account_holder_type: string; + } + + interface PiiTokenOptions { + personal_id_number: string; + } + + interface OwnerInfo { + address?: { + city?: string; + country?: string; + line1?: string; + line2?: string; + postal_code?: string; + state?: string; + }; + name?: string; + email?: string; + phone?: string; + } + interface SourceOptions { type: string; flow?: 'redirect' | 'receiver' | 'code_verification' | 'none'; @@ -45,19 +77,7 @@ declare namespace stripe { }; currency?: string; amount?: number; - owner?: { - address?: { - city?: string; - country?: string; - line1?: string; - line2?: string; - postal_code?: string; - state?: string; - }; - name?: string; - email?: string; - phone?: string; - }; + owner?: OwnerInfo; metadata?: {}; statement_descriptor?: string; redirect?: { @@ -65,6 +85,9 @@ declare namespace stripe { }; token?: string; usage?: 'reusable' | 'single_use'; + three_d_secure?: { + card: string; + }; } interface Token { @@ -106,6 +129,15 @@ declare namespace stripe { last4: string; mandate_reference: string; }; + card?: Card; + status?: string; + redirect?: { + status: string; + url: string; + }; + three_d_secure?: { + authenticated: boolean; + }; } interface SourceResponse { @@ -165,6 +197,94 @@ declare namespace stripe { metadata: any; name?: string; tokenization_method?: tokenizationType; + three_d_secure?: 'required' | 'recommended' | 'optional' | 'not_supported'; + } + + interface RetrieveSourceOptions { + id: string; + client_secret: string; + } + + // Container for all payment request related types + namespace paymentRequest { + interface StripePaymentRequestUpdateOptions { + currency: string; + total: { + amount: number; + label: string; + pending?: boolean; + }; + displayItems?: Array<{ + amount: number; + label: string; + pending?: boolean; + }>; + shippingOptions?: ShippingOption[]; + } + + interface StripePaymentRequestOptions extends StripePaymentRequestUpdateOptions { + country: string; + requestPayerName?: boolean; + requestPayerEmail?: boolean; + requestPayerPhone?: boolean; + requestShipping?: boolean; + } + + interface UpdateDetails { + status: 'success' | 'fail' | 'invalid_shipping_address'; + total?: { + amount: number; + label: string; + pending?: boolean; + }; + displayItems?: Array<{ + amount: number; + label: string; + pending?: boolean; + }>; + shippingOptions?: ShippingOption[]; + } + + interface ShippingOption { + id: string; + label: string; + detail?: string; + amount: number; + } + + interface ShippingAddress { + country: string; + addressLine: string[]; + region: string; + city: string; + postalCode: string; + recipient: string; + phone: string; + sortingCode?: string; + dependentLocality?: string; + } + + interface StripePaymentResponse { + token?: Token; + source?: Source; + complete: (status: string) => void; + payerName?: string; + payerEmail?: string; + payerPhone?: string; + shippingAddress?: ShippingAddress; + shippingOption?: ShippingOption; + methodName: string; + } + + interface StripePaymentRequest { + canMakePayment(): Promise<{applePay?: boolean} | null>; + show(): void; + update(options: StripePaymentRequestUpdateOptions): void; + on(event: 'token' | 'source', handler: (response: StripePaymentResponse) => void): void; + on(event: 'cancel', handler: () => void): void; + on(event: 'shippingaddresschange', handler: (response: {updateWith: (options: UpdateDetails) => void, shippingAddress: ShippingAddress}) => void): void; + on(event: 'shippingoptionchange', handler: (response: {updateWith: (options: UpdateDetails) => void, shippingOption: ShippingOption}) => void): void; + } } // Container for all elements related types @@ -181,6 +301,7 @@ declare namespace stripe { // Cannot find name 'HTMLElement' mount(domElement: any): void; on(event: eventTypes, handler: handler): void; + on(event: 'click', handler: (response: {preventDefault: () => void}) => void): void; focus(): void; blur(): void; clear(): void; @@ -202,9 +323,9 @@ declare namespace stripe { locale?: string; } - type elementsType = 'card' | 'cardNumber' | 'cardExpiry' | 'cardCvc' | 'postalCode'; + type elementsType = 'card' | 'cardNumber' | 'cardExpiry' | 'cardCvc' | 'postalCode' | 'paymentRequestButton'; interface Elements { - create(type: elementsType, options: ElementsOptions): Element; + create(type: elementsType, options?: ElementsOptions): Element; } interface ElementsOptions { @@ -219,13 +340,16 @@ declare namespace stripe { hidePostalCode?: boolean; hideIcon?: boolean; iconStyle?: 'solid' | 'default'; + placeholder?: string; style?: { base?: Style; complete?: Style; empty?: Style; invalid?: Style; + paymentRequestButton?: PaymentRequestButtonStyleOptions; }; value?: string | { [objectKey: string]: string; }; + paymentRequest?: paymentRequest.StripePaymentRequest; } interface Style extends StyleOptions { @@ -234,11 +358,13 @@ declare namespace stripe { '::placeholder'?: StyleOptions; '::selection'?: StyleOptions; ':-webkit-autofill'?: StyleOptions; + '::-ms-clear'?: StyleOptions; } interface Font { family?: string; src?: string; + display?: string; style?: string; unicodeRange?: string; weight?: string; @@ -255,9 +381,16 @@ declare namespace stripe { iconColor?: string; lineHeight?: string; letterSpacing?: string; + textAlign?: string; textDecoration?: string; textShadow?: string; textTransform?: string; } + + interface PaymentRequestButtonStyleOptions { + type?: 'default' | 'donate' | 'buy'; + theme: 'dark' | 'light' | 'light-outline'; + height: string; + } } } diff --git a/types/stripe-v3/stripe-v3-tests.ts b/types/stripe-v3/stripe-v3-tests.ts index ccf86e5215..6e8740c5b2 100644 --- a/types/stripe-v3/stripe-v3-tests.ts +++ b/types/stripe-v3/stripe-v3-tests.ts @@ -42,7 +42,93 @@ describe("Stripe", () => { (error: stripe.Error) => { console.error(error); }); + // test 3D secure + const threeDSecureFrame = document.getElementById('3d-secure-frame'); + const ownerInfo = { + name: 'Jimmy', + address: { + line1: '1 High Street', + postal_code: 'XYZ' + } + }; + stripe.createSource(card, { owner: ownerInfo }).then(result => { + if (result.error) { + console.log(result.error.message); + return Promise.resolve(null); + } + if (!result.source) { + console.log('error'); + return Promise.resolve(null); + } + if (!result.source.card || result.source.card.three_d_secure === 'not_supported') { + // make regular payment... + return Promise.resolve(null); + } + return stripe.createSource({ + type: 'three_d_secure', + amount: 100, + currency: 'usd', + three_d_secure: { + card: result.source.id + }, + redirect: { + return_url: location.origin + '/3d-secure-processing-page' + } + }); + }).then(threeDSource => { + if (!threeDSource) { + return Promise.resolve(null); + } + if (threeDSource.error) { + if (threeDSource.error.code === 'payment_method_not_available') { + // make regular payment... + return Promise.resolve(null); + } + console.log('error'); + return Promise.resolve(null); + } + if (!threeDSource.source || threeDSource.source.status === 'failed' || !threeDSource.source.redirect) { + // make regular payment... + return Promise.resolve(null); + } + if (threeDSource.source.redirect.status === 'succeeded') { + // make charge... + return Promise.resolve(null); + } + threeDSecureFrame.setAttribute('src', threeDSource.source.redirect.url); + // now wait until chargeable then make the charge + return Promise.resolve(null); + }); card.destroy(); + // test payment request + const paymentRequest = stripe.paymentRequest({ + country: 'US', + currency: 'usd', + total: { + label: 'Demo total', + amount: 1000, + } + }); + const prButton = elements.create('paymentRequestButton', { paymentRequest }); + paymentRequest.canMakePayment().then(result => { + if (result) { + prButton.mount('#payment-request-button'); + } else { + document.getElementById('payment-request-button')!.style.display = 'none'; + } + }); + paymentRequest.on('token', ev => { + const body = JSON.stringify({token: ev.token!.id}); + // post to server... + Promise.resolve({ok: true}) + .then(response => { + if (response.ok) { + ev.complete('success'); + } else { + ev.complete('fail'); + } + }); + }); }); });