diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..2368fb2 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,435 @@ +// TypeScript declarations for @juspay-tech/react-hyper-js +// Auto-generated from ReScript source files — do not edit manually. + +import type { ReactNode, ComponentType as ReactComponentType } from "react"; +import type { + HyperInstance, + ElementsOptions, + Element, + EventData, + ConfirmPaymentResponse, + ConfirmPaymentErrorResponse, + RetrievePaymentIntentResponse, + ElementsAppearanceOptions, +} from "@juspay-tech/hyper-js"; + +// --------------------------------------------------------------------------- +// Session types (from src/types/HyperSession.res) +// --------------------------------------------------------------------------- + +/** Status of a HyperSession lifecycle */ +export type SessionStatus = "loading" | "ready" | "error"; + +/** Options for creating a HyperSession */ +export interface SessionOptions { + appearance?: Record; + layout?: any; + fonts?: any[]; + locale?: string; + loader?: string; + clientSecret?: string; +} + +/** Parameters passed to confirmPayment via HyperSession */ +export interface SessionConfirmPaymentParams { + confirmParams: Record; + redirect?: string; +} + +/** Result returned by HyperSession.confirmPayment */ +export interface SessionConfirmPaymentResult { + error?: any; + status?: string; + paymentIntent?: any; +} + +/** + * The HyperSession object returned by `useHyperSession`. + * + * Provides a self-contained session that holds its own widgets instance + * and SDK methods, without requiring a `` provider. + */ +export interface HyperSession { + /** The widgets instance (available when status is "ready") */ + widgets: Element | null; + /** Current session status */ + status: SessionStatus; + /** Error message if status is "error" */ + error: string | null; + /** Confirm the payment using the session's internal widgets */ + confirmPayment( + params: SessionConfirmPaymentParams + ): Promise; + /** Confirm a card payment by client secret */ + confirmCardPayment( + clientSecret: string, + data?: any, + options?: any + ): Promise; + /** Retrieve a payment intent by its ID */ + retrievePaymentIntent(paymentIntentId: string): Promise; + /** Create a payment request object */ + paymentRequest(options: any): any; + /** Complete an update intent flow */ + completeUpdateIntent(clientSecret: string): Promise; + /** Initiate an update intent flow */ + initiateUpdateIntent(): Promise; + /** Confirm tokenization */ + confirmTokenization(params: any): Promise; +} + +// --------------------------------------------------------------------------- +// Context types (from src/Context.res) +// --------------------------------------------------------------------------- + +/** + * Return type of `useHyper()` — the switch context. + * + * Provides SDK payment methods scoped to the current `` provider. + */ +export interface UseHyperReturn { + /** The client secret for the current payment intent */ + clientSecret: string; + /** Confirm the payment */ + confirmPayment(params: any): Promise; + /** Confirm a card payment by client secret */ + confirmCardPayment( + clientSecret: string, + data?: any, + options?: any + ): Promise; + /** Retrieve a payment intent by its ID */ + retrievePaymentIntent(paymentIntentId: string): Promise; + /** Create a payment request object */ + paymentRequest(options: any): any; + /** Complete an update intent flow */ + completeUpdateIntent(clientSecret: string): Promise; + /** Initiate an update intent flow */ + initiateUpdateIntent(): Promise; + /** Confirm tokenization */ + confirmTokenization(params: any): Promise; +} + +/** + * Return type of `useWidgets()` — the elements context. + * + * Provides access to the current elements options. + */ +export interface UseWidgetsReturn { + options: Record; + update(options: any): void; + getElement(componentName: string): any | null; + fetchUpdates(): Promise; + create(componentType: string, options: any): any; +} + +// --------------------------------------------------------------------------- +// Hooks +// --------------------------------------------------------------------------- + +/** + * Returns the Hyper SDK context (switch context). + * + * Must be called inside a `` or `` provider. + * + * @example + * ```tsx + * const hyper = useHyper(); + * const result = await hyper.confirmPayment({ elements, confirmParams: { return_url } }); + * ``` + */ +export function useHyper(): UseHyperReturn; + +/** + * @deprecated Use `useHyper()` instead. + */ +export function useStripe(): UseHyperReturn; + +/** + * Returns the widgets (elements) context. + * + * Must be called inside a `` or `` provider. + * + * @example + * ```tsx + * const widgets = useWidgets(); + * ``` + */ +export function useWidgets(): UseWidgetsReturn; + +/** + * @deprecated Use `useWidgets()` instead. + */ +export function useElements(): UseWidgetsReturn; + +/** + * Standalone session hook — creates a HyperSession without a provider. + * + * Reads `window.__HYPER_SDK_INSTANCE__` to obtain the SDK instance. + * + * @param sdkAuthorization - The client secret / payment authorization token. + * @param options - Optional session configuration. + * @returns A `HyperSession` object when authorization is provided, or `null`. + * + * @example + * ```tsx + * const session = useHyperSession(clientSecret, { appearance }); + * if (session?.status === "ready") { + * const result = await session.confirmPayment({ confirmParams: { return_url } }); + * } + * ``` + */ +export function useHyperSession( + sdkAuthorization?: string, + options?: SessionOptions +): HyperSession | null; + +// --------------------------------------------------------------------------- +// Common element callback types +// --------------------------------------------------------------------------- + +/** Callback invoked when an element event fires with optional JSON data */ +export type ElementEventHandler = ((data?: any) => void) | undefined; + +/** Callback invoked when the SDK pay button is clicked (return a Promise) */ +export type PaymentButtonClickHandler = + | (() => Promise) + | undefined; + +// --------------------------------------------------------------------------- +// Provider component props +// --------------------------------------------------------------------------- + +/** Props for the `` provider */ +export interface HyperElementsProps { + /** A Promise resolving to a HyperInstance (from `loadHyper()`) */ + hyper: Promise; + /** Elements options including clientSecret, appearance, locale, etc. */ + options: ElementsOptions | Record; + children: ReactNode; +} + +/** + * Props for the `` provider (Stripe-compatible naming). + * + * Identical to `HyperElementsProps` except the instance prop is named `stripe`. + */ +export interface ElementsProps { + /** A Promise resolving to a HyperInstance (Stripe-compat prop name) */ + stripe: Promise; + /** Elements options including clientSecret, appearance, locale, etc. */ + options: ElementsOptions | Record; + children: ReactNode; +} + +/** Props for the `` provider */ +export interface HyperManagementElementsProps { + /** A Promise resolving to a HyperInstance (from `loadHyper()`) */ + hyper: Promise; + /** Management elements options (ephemeralKey, appearance, etc.) */ + options: Record; + children: ReactNode; +} + +// --------------------------------------------------------------------------- +// Standard element component props +// --------------------------------------------------------------------------- + +/** + * Common props shared by all standard payment element components. + * + * All props are optional — the component will render with defaults. + */ +export interface PaymentElementComponentProps { + /** A unique identifier for the element container */ + id?: string; + /** Element-specific configuration options */ + options?: Record; + /** Fires when the element value changes */ + onChange?: ElementEventHandler; + /** Fires when the element is ready */ + onReady?: ElementEventHandler; + /** Fires when the element gains focus */ + onFocus?: ElementEventHandler; + /** Fires when the element loses focus */ + onBlur?: ElementEventHandler; + /** Fires when the element is clicked */ + onClick?: ElementEventHandler; + /** Fires when payment completes */ + onPaymentComplete?: ElementEventHandler; + /** Intercept SDK pay button click for custom validation before confirm */ + onPaymentButtonClick?: PaymentButtonClickHandler; +} + +// --------------------------------------------------------------------------- +// Payment Methods Management element props +// --------------------------------------------------------------------------- + +/** Props for the `` component */ +export interface PaymentMethodsManagementElementProps { + /** A unique identifier for the element container (default: "payment-management") */ + id?: string; + /** Element-specific configuration options */ + options?: Record; + /** Fires when the element value changes */ + onChange?: ElementEventHandler; + /** Fires when the element is ready */ + onReady?: ElementEventHandler; + /** Fires when the element gains focus */ + onFocus?: ElementEventHandler; + /** Fires when the element loses focus */ + onBlur?: ElementEventHandler; + /** Fires when the element is clicked */ + onClick?: ElementEventHandler; + /** The component type (default: "paymentMethodsManagement") */ + componentType?: string; +} + +// --------------------------------------------------------------------------- +// PaymentElementSession props +// --------------------------------------------------------------------------- + +/** Props for the `` component */ +export interface PaymentElementSessionProps { + /** A HyperSession object (from `useHyperSession`) */ + session: HyperSession; + /** Element-specific configuration options */ + options?: Record; + /** Fires when the element value changes */ + onChange?: (data: any) => void; + /** Fires when the element is ready */ + onReady?: () => void; + /** Fires when the element gains focus */ + onFocus?: () => void; + /** Fires when the element loses focus */ + onBlur?: () => void; + /** Fires when the element is clicked */ + onClick?: () => void; + /** Fires when payment completes */ + onPaymentComplete?: (data: any) => void; + /** Intercept SDK pay button click */ + onPaymentButtonClick?: () => Promise; + /** A unique identifier for the element container (default: "payment-element") */ + id?: string; +} + +// --------------------------------------------------------------------------- +// Provider components +// --------------------------------------------------------------------------- + +/** + * Provider that initializes the Hyper SDK context. + * + * Wrap your checkout form with this component to give child elements and + * hooks access to the SDK instance. + * + * @example + * ```tsx + * + * + * + * ``` + */ +export const HyperElements: ReactComponentType; + +/** + * Stripe-compatible alias for ``. + * + * Uses `stripe` prop instead of `hyper` for drop-in migration. + */ +export const Elements: ReactComponentType; + +/** + * Provider for payment methods management flows. + * + * Used with `` for saved payment method management. + */ +export const HyperManagementElements: ReactComponentType; + +// --------------------------------------------------------------------------- +// Standard element components +// --------------------------------------------------------------------------- + +/** + * Renders the unified payment form (all payment methods). + * + * @example + * ```tsx + * console.log(event)} + * /> + * ``` + */ +export const PaymentElement: ReactComponentType; + +/** Alias for `` */ +export const UnifiedCheckout: ReactComponentType; + +/** Renders a combined card input (number + expiry + CVC) */ +export const CardElement: ReactComponentType; + +/** Alias for `` */ +export const CardWidget: ReactComponentType; + +/** Renders a standalone card number input */ +export const CardNumberElement: ReactComponentType; + +/** Alias for `` */ +export const CardNumberWidget: ReactComponentType; + +/** Renders a standalone card expiry input */ +export const CardExpiryElement: ReactComponentType; + +/** Alias for `` */ +export const CardExpiryWidget: ReactComponentType; + +/** Renders a standalone card CVC input */ +export const CardCVCElement: ReactComponentType; + +/** Alias for `` */ +export const CardCVCWidget: ReactComponentType; + +/** Renders a Google Pay button */ +export const GooglePayElement: ReactComponentType; + +/** Renders an Apple Pay button */ +export const ApplePayElement: ReactComponentType; + +/** Renders a PayPal button */ +export const PayPalElement: ReactComponentType; + +/** Renders a Paze button */ +export const PazeElement: ReactComponentType; + +/** Renders an express checkout strip (GPay + Apple Pay + PayPal etc.) */ +export const ExpressCheckoutElement: ReactComponentType; + +// --------------------------------------------------------------------------- +// Management components +// --------------------------------------------------------------------------- + +/** + * Renders the saved payment methods management UI. + * + * Must be wrapped in ``. + */ +export const PaymentMethodsManagementElement: ReactComponentType; + +// --------------------------------------------------------------------------- +// Session components +// --------------------------------------------------------------------------- + +/** + * Renders a payment element using a `HyperSession` instead of a provider. + * + * @example + * ```tsx + * const session = useHyperSession(clientSecret); + * if (session) { + * return ; + * } + * ``` + */ +export const PaymentElementSession: ReactComponentType; diff --git a/package-lock.json b/package-lock.json index eddd5b5..baf1364 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,8 +17,10 @@ "@babel/core": "^7.27.4", "@babel/preset-env": "^7.27.2", "@babel/preset-react": "^7.27.1", + "@types/react": "^19.2.14", "babel-loader": "^10.0.0", "rescript": "^11.1.0", + "typescript": "^6.0.2", "webpack": "^5.99.9", "webpack-cli": "^6.0.1" }, @@ -1789,6 +1791,15 @@ "undici-types": "~7.16.0" } }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -2291,6 +2302,12 @@ "node": ">= 8" } }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -3331,6 +3348,19 @@ } } }, + "node_modules/typescript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", + "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", diff --git a/package.json b/package.json index aa4a42e..211f3bd 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,15 @@ "name": "@juspay-tech/react-hyper-js", "version": "2.0.0", "main": "dist/bundle.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/bundle.js", + "require": "./dist/bundle.js", + "default": "./dist/bundle.js" + } + }, "files": [ "dist/", "README.md", @@ -24,7 +33,7 @@ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "scripts": { - "build": "webpack --mode production", + "build": "webpack --mode production && cp src/index.d.ts dist/index.d.ts", "re:build": "rescript", "re:start": "rescript build -w", "re:format": "rescript format -all", @@ -35,8 +44,10 @@ "@babel/core": "^7.27.4", "@babel/preset-env": "^7.27.2", "@babel/preset-react": "^7.27.1", + "@types/react": "^19.2.14", "babel-loader": "^10.0.0", "rescript": "^11.1.0", + "typescript": "^6.0.2", "webpack": "^5.99.9", "webpack-cli": "^6.0.1" }, diff --git a/src/index.d.ts b/src/index.d.ts new file mode 100644 index 0000000..2368fb2 --- /dev/null +++ b/src/index.d.ts @@ -0,0 +1,435 @@ +// TypeScript declarations for @juspay-tech/react-hyper-js +// Auto-generated from ReScript source files — do not edit manually. + +import type { ReactNode, ComponentType as ReactComponentType } from "react"; +import type { + HyperInstance, + ElementsOptions, + Element, + EventData, + ConfirmPaymentResponse, + ConfirmPaymentErrorResponse, + RetrievePaymentIntentResponse, + ElementsAppearanceOptions, +} from "@juspay-tech/hyper-js"; + +// --------------------------------------------------------------------------- +// Session types (from src/types/HyperSession.res) +// --------------------------------------------------------------------------- + +/** Status of a HyperSession lifecycle */ +export type SessionStatus = "loading" | "ready" | "error"; + +/** Options for creating a HyperSession */ +export interface SessionOptions { + appearance?: Record; + layout?: any; + fonts?: any[]; + locale?: string; + loader?: string; + clientSecret?: string; +} + +/** Parameters passed to confirmPayment via HyperSession */ +export interface SessionConfirmPaymentParams { + confirmParams: Record; + redirect?: string; +} + +/** Result returned by HyperSession.confirmPayment */ +export interface SessionConfirmPaymentResult { + error?: any; + status?: string; + paymentIntent?: any; +} + +/** + * The HyperSession object returned by `useHyperSession`. + * + * Provides a self-contained session that holds its own widgets instance + * and SDK methods, without requiring a `` provider. + */ +export interface HyperSession { + /** The widgets instance (available when status is "ready") */ + widgets: Element | null; + /** Current session status */ + status: SessionStatus; + /** Error message if status is "error" */ + error: string | null; + /** Confirm the payment using the session's internal widgets */ + confirmPayment( + params: SessionConfirmPaymentParams + ): Promise; + /** Confirm a card payment by client secret */ + confirmCardPayment( + clientSecret: string, + data?: any, + options?: any + ): Promise; + /** Retrieve a payment intent by its ID */ + retrievePaymentIntent(paymentIntentId: string): Promise; + /** Create a payment request object */ + paymentRequest(options: any): any; + /** Complete an update intent flow */ + completeUpdateIntent(clientSecret: string): Promise; + /** Initiate an update intent flow */ + initiateUpdateIntent(): Promise; + /** Confirm tokenization */ + confirmTokenization(params: any): Promise; +} + +// --------------------------------------------------------------------------- +// Context types (from src/Context.res) +// --------------------------------------------------------------------------- + +/** + * Return type of `useHyper()` — the switch context. + * + * Provides SDK payment methods scoped to the current `` provider. + */ +export interface UseHyperReturn { + /** The client secret for the current payment intent */ + clientSecret: string; + /** Confirm the payment */ + confirmPayment(params: any): Promise; + /** Confirm a card payment by client secret */ + confirmCardPayment( + clientSecret: string, + data?: any, + options?: any + ): Promise; + /** Retrieve a payment intent by its ID */ + retrievePaymentIntent(paymentIntentId: string): Promise; + /** Create a payment request object */ + paymentRequest(options: any): any; + /** Complete an update intent flow */ + completeUpdateIntent(clientSecret: string): Promise; + /** Initiate an update intent flow */ + initiateUpdateIntent(): Promise; + /** Confirm tokenization */ + confirmTokenization(params: any): Promise; +} + +/** + * Return type of `useWidgets()` — the elements context. + * + * Provides access to the current elements options. + */ +export interface UseWidgetsReturn { + options: Record; + update(options: any): void; + getElement(componentName: string): any | null; + fetchUpdates(): Promise; + create(componentType: string, options: any): any; +} + +// --------------------------------------------------------------------------- +// Hooks +// --------------------------------------------------------------------------- + +/** + * Returns the Hyper SDK context (switch context). + * + * Must be called inside a `` or `` provider. + * + * @example + * ```tsx + * const hyper = useHyper(); + * const result = await hyper.confirmPayment({ elements, confirmParams: { return_url } }); + * ``` + */ +export function useHyper(): UseHyperReturn; + +/** + * @deprecated Use `useHyper()` instead. + */ +export function useStripe(): UseHyperReturn; + +/** + * Returns the widgets (elements) context. + * + * Must be called inside a `` or `` provider. + * + * @example + * ```tsx + * const widgets = useWidgets(); + * ``` + */ +export function useWidgets(): UseWidgetsReturn; + +/** + * @deprecated Use `useWidgets()` instead. + */ +export function useElements(): UseWidgetsReturn; + +/** + * Standalone session hook — creates a HyperSession without a provider. + * + * Reads `window.__HYPER_SDK_INSTANCE__` to obtain the SDK instance. + * + * @param sdkAuthorization - The client secret / payment authorization token. + * @param options - Optional session configuration. + * @returns A `HyperSession` object when authorization is provided, or `null`. + * + * @example + * ```tsx + * const session = useHyperSession(clientSecret, { appearance }); + * if (session?.status === "ready") { + * const result = await session.confirmPayment({ confirmParams: { return_url } }); + * } + * ``` + */ +export function useHyperSession( + sdkAuthorization?: string, + options?: SessionOptions +): HyperSession | null; + +// --------------------------------------------------------------------------- +// Common element callback types +// --------------------------------------------------------------------------- + +/** Callback invoked when an element event fires with optional JSON data */ +export type ElementEventHandler = ((data?: any) => void) | undefined; + +/** Callback invoked when the SDK pay button is clicked (return a Promise) */ +export type PaymentButtonClickHandler = + | (() => Promise) + | undefined; + +// --------------------------------------------------------------------------- +// Provider component props +// --------------------------------------------------------------------------- + +/** Props for the `` provider */ +export interface HyperElementsProps { + /** A Promise resolving to a HyperInstance (from `loadHyper()`) */ + hyper: Promise; + /** Elements options including clientSecret, appearance, locale, etc. */ + options: ElementsOptions | Record; + children: ReactNode; +} + +/** + * Props for the `` provider (Stripe-compatible naming). + * + * Identical to `HyperElementsProps` except the instance prop is named `stripe`. + */ +export interface ElementsProps { + /** A Promise resolving to a HyperInstance (Stripe-compat prop name) */ + stripe: Promise; + /** Elements options including clientSecret, appearance, locale, etc. */ + options: ElementsOptions | Record; + children: ReactNode; +} + +/** Props for the `` provider */ +export interface HyperManagementElementsProps { + /** A Promise resolving to a HyperInstance (from `loadHyper()`) */ + hyper: Promise; + /** Management elements options (ephemeralKey, appearance, etc.) */ + options: Record; + children: ReactNode; +} + +// --------------------------------------------------------------------------- +// Standard element component props +// --------------------------------------------------------------------------- + +/** + * Common props shared by all standard payment element components. + * + * All props are optional — the component will render with defaults. + */ +export interface PaymentElementComponentProps { + /** A unique identifier for the element container */ + id?: string; + /** Element-specific configuration options */ + options?: Record; + /** Fires when the element value changes */ + onChange?: ElementEventHandler; + /** Fires when the element is ready */ + onReady?: ElementEventHandler; + /** Fires when the element gains focus */ + onFocus?: ElementEventHandler; + /** Fires when the element loses focus */ + onBlur?: ElementEventHandler; + /** Fires when the element is clicked */ + onClick?: ElementEventHandler; + /** Fires when payment completes */ + onPaymentComplete?: ElementEventHandler; + /** Intercept SDK pay button click for custom validation before confirm */ + onPaymentButtonClick?: PaymentButtonClickHandler; +} + +// --------------------------------------------------------------------------- +// Payment Methods Management element props +// --------------------------------------------------------------------------- + +/** Props for the `` component */ +export interface PaymentMethodsManagementElementProps { + /** A unique identifier for the element container (default: "payment-management") */ + id?: string; + /** Element-specific configuration options */ + options?: Record; + /** Fires when the element value changes */ + onChange?: ElementEventHandler; + /** Fires when the element is ready */ + onReady?: ElementEventHandler; + /** Fires when the element gains focus */ + onFocus?: ElementEventHandler; + /** Fires when the element loses focus */ + onBlur?: ElementEventHandler; + /** Fires when the element is clicked */ + onClick?: ElementEventHandler; + /** The component type (default: "paymentMethodsManagement") */ + componentType?: string; +} + +// --------------------------------------------------------------------------- +// PaymentElementSession props +// --------------------------------------------------------------------------- + +/** Props for the `` component */ +export interface PaymentElementSessionProps { + /** A HyperSession object (from `useHyperSession`) */ + session: HyperSession; + /** Element-specific configuration options */ + options?: Record; + /** Fires when the element value changes */ + onChange?: (data: any) => void; + /** Fires when the element is ready */ + onReady?: () => void; + /** Fires when the element gains focus */ + onFocus?: () => void; + /** Fires when the element loses focus */ + onBlur?: () => void; + /** Fires when the element is clicked */ + onClick?: () => void; + /** Fires when payment completes */ + onPaymentComplete?: (data: any) => void; + /** Intercept SDK pay button click */ + onPaymentButtonClick?: () => Promise; + /** A unique identifier for the element container (default: "payment-element") */ + id?: string; +} + +// --------------------------------------------------------------------------- +// Provider components +// --------------------------------------------------------------------------- + +/** + * Provider that initializes the Hyper SDK context. + * + * Wrap your checkout form with this component to give child elements and + * hooks access to the SDK instance. + * + * @example + * ```tsx + * + * + * + * ``` + */ +export const HyperElements: ReactComponentType; + +/** + * Stripe-compatible alias for ``. + * + * Uses `stripe` prop instead of `hyper` for drop-in migration. + */ +export const Elements: ReactComponentType; + +/** + * Provider for payment methods management flows. + * + * Used with `` for saved payment method management. + */ +export const HyperManagementElements: ReactComponentType; + +// --------------------------------------------------------------------------- +// Standard element components +// --------------------------------------------------------------------------- + +/** + * Renders the unified payment form (all payment methods). + * + * @example + * ```tsx + * console.log(event)} + * /> + * ``` + */ +export const PaymentElement: ReactComponentType; + +/** Alias for `` */ +export const UnifiedCheckout: ReactComponentType; + +/** Renders a combined card input (number + expiry + CVC) */ +export const CardElement: ReactComponentType; + +/** Alias for `` */ +export const CardWidget: ReactComponentType; + +/** Renders a standalone card number input */ +export const CardNumberElement: ReactComponentType; + +/** Alias for `` */ +export const CardNumberWidget: ReactComponentType; + +/** Renders a standalone card expiry input */ +export const CardExpiryElement: ReactComponentType; + +/** Alias for `` */ +export const CardExpiryWidget: ReactComponentType; + +/** Renders a standalone card CVC input */ +export const CardCVCElement: ReactComponentType; + +/** Alias for `` */ +export const CardCVCWidget: ReactComponentType; + +/** Renders a Google Pay button */ +export const GooglePayElement: ReactComponentType; + +/** Renders an Apple Pay button */ +export const ApplePayElement: ReactComponentType; + +/** Renders a PayPal button */ +export const PayPalElement: ReactComponentType; + +/** Renders a Paze button */ +export const PazeElement: ReactComponentType; + +/** Renders an express checkout strip (GPay + Apple Pay + PayPal etc.) */ +export const ExpressCheckoutElement: ReactComponentType; + +// --------------------------------------------------------------------------- +// Management components +// --------------------------------------------------------------------------- + +/** + * Renders the saved payment methods management UI. + * + * Must be wrapped in ``. + */ +export const PaymentMethodsManagementElement: ReactComponentType; + +// --------------------------------------------------------------------------- +// Session components +// --------------------------------------------------------------------------- + +/** + * Renders a payment element using a `HyperSession` instead of a provider. + * + * @example + * ```tsx + * const session = useHyperSession(clientSecret); + * if (session) { + * return ; + * } + * ``` + */ +export const PaymentElementSession: ReactComponentType; diff --git a/src/index.test-d.ts b/src/index.test-d.ts new file mode 100644 index 0000000..8a3eecf --- /dev/null +++ b/src/index.test-d.ts @@ -0,0 +1,602 @@ +/** + * Type tests for @juspay-tech/react-hyper-js + * + * These tests exercise every exported type, component, and hook to ensure the + * declarations in index.d.ts are correct and complete. Run with: + * + * npx tsc --project tsconfig.test.json --noEmit + * + * Expected result: 0 errors. + */ + +import * as React from "react"; + +// --------------------------------------------------------------------------- +// 1. Import all exports from @juspay-tech/react-hyper-js +// --------------------------------------------------------------------------- +import { + // Types + type SessionStatus, + type SessionOptions, + type SessionConfirmPaymentParams, + type SessionConfirmPaymentResult, + type HyperSession, + type UseHyperReturn, + type UseWidgetsReturn, + type ElementEventHandler, + type PaymentButtonClickHandler, + type HyperElementsProps, + type ElementsProps, + type HyperManagementElementsProps, + type PaymentElementComponentProps, + type PaymentMethodsManagementElementProps, + type PaymentElementSessionProps, + + // Hooks + useHyper, + useStripe, + useWidgets, + useElements, + useHyperSession, + + // Provider components + HyperElements, + Elements, + HyperManagementElements, + + // Standard element components + PaymentElement, + CardElement, + CardNumberElement, + CardExpiryElement, + CardCVCElement, + GooglePayElement, + ApplePayElement, + PayPalElement, + PazeElement, + ExpressCheckoutElement, + + // Deprecated aliases + UnifiedCheckout, + CardWidget, + CardNumberWidget, + CardExpiryWidget, + CardCVCWidget, + + // Management + PaymentMethodsManagementElement, + + // Session + PaymentElementSession, +} from "@juspay-tech/react-hyper-js"; + +// --------------------------------------------------------------------------- +// 2. Import shared types from @juspay-tech/hyper-js +// --------------------------------------------------------------------------- +import { + type HyperInstance, + type ElementsOptions, + type Element, + type EventData, + type ConfirmPaymentResponse, + type ConfirmPaymentErrorResponse, + type RetrievePaymentIntentResponse, + type ElementsAppearanceOptions, + loadHyper, +} from "@juspay-tech/hyper-js"; + +// --------------------------------------------------------------------------- +// Helper: compile-time assertion that a value has an expected type +// --------------------------------------------------------------------------- +function expectType(_value: T): void {} + +// --------------------------------------------------------------------------- +// 3. SessionStatus type +// --------------------------------------------------------------------------- +{ + const loading: SessionStatus = "loading"; + const ready: SessionStatus = "ready"; + const error: SessionStatus = "error"; + expectType(loading); + expectType(ready); + expectType(error); +} + +// --------------------------------------------------------------------------- +// 4. SessionOptions +// --------------------------------------------------------------------------- +{ + const opts: SessionOptions = {}; + const optsFull: SessionOptions = { + appearance: { theme: "midnight" }, + layout: "tabs", + fonts: [{ cssSrc: "https://fonts.googleapis.com/css2?family=Roboto" }], + locale: "en", + loader: "auto", + clientSecret: "pi_xxx_secret_yyy", + }; + expectType(opts); + expectType(optsFull); +} + +// --------------------------------------------------------------------------- +// 5. SessionConfirmPaymentParams / SessionConfirmPaymentResult +// --------------------------------------------------------------------------- +{ + const params: SessionConfirmPaymentParams = { + confirmParams: { return_url: "https://example.com" }, + redirect: "if_required", + }; + expectType(params); + + const result: SessionConfirmPaymentResult = { + error: undefined, + status: "succeeded", + paymentIntent: { id: "pi_123" }, + }; + expectType(result); +} + +// --------------------------------------------------------------------------- +// 6. HyperSession +// --------------------------------------------------------------------------- +{ + // We can only construct a HyperSession in tests by asserting — it's + // returned by the useHyperSession hook at runtime. + const session = {} as HyperSession; + + expectType(session.widgets); + expectType(session.status); + expectType(session.error); + + // Methods + const confirmPromise = session.confirmPayment({ + confirmParams: { return_url: "https://example.com" }, + }); + expectType>(confirmPromise); + + const cardPromise = session.confirmCardPayment("cs_secret"); + expectType>(cardPromise); + + const retrievePromise = session.retrievePaymentIntent("pi_123"); + expectType>(retrievePromise); + + const pr = session.paymentRequest({ country: "US", currency: "usd" }); + expectType(pr); + + const completePromise = session.completeUpdateIntent("cs_123"); + expectType>(completePromise); + + const initiatePromise = session.initiateUpdateIntent(); + expectType>(initiatePromise); + + const tokenPromise = session.confirmTokenization({ token: "tok_123" }); + expectType>(tokenPromise); +} + +// --------------------------------------------------------------------------- +// 7. UseHyperReturn +// --------------------------------------------------------------------------- +{ + const hyper = {} as UseHyperReturn; + + expectType(hyper.clientSecret); + + const confirmPromise = hyper.confirmPayment({ elements: {} }); + expectType>(confirmPromise); + + const cardPromise = hyper.confirmCardPayment("cs_secret", {}, {}); + expectType>(cardPromise); + + const retrievePromise = hyper.retrievePaymentIntent("pi_123"); + expectType>(retrievePromise); + + const pr = hyper.paymentRequest({ country: "US" }); + expectType(pr); + + const completePromise = hyper.completeUpdateIntent("cs_123"); + expectType>(completePromise); + + const initiatePromise = hyper.initiateUpdateIntent(); + expectType>(initiatePromise); + + const tokenPromise = hyper.confirmTokenization({ token: "tok_123" }); + expectType>(tokenPromise); +} + +// --------------------------------------------------------------------------- +// 8. UseWidgetsReturn +// --------------------------------------------------------------------------- +{ + const widgets = {} as UseWidgetsReturn; + + expectType>(widgets.options); + widgets.update({ locale: "fr" }); + const el = widgets.getElement("payment"); + expectType(el); + const updatesPromise = widgets.fetchUpdates(); + expectType>(updatesPromise); + const created = widgets.create("card", {}); + expectType(created); +} + +// --------------------------------------------------------------------------- +// 9. ElementEventHandler / PaymentButtonClickHandler +// --------------------------------------------------------------------------- +{ + const handler1: ElementEventHandler = (data) => { + console.log(data); + }; + const handler2: ElementEventHandler = undefined; + expectType(handler1); + expectType(handler2); + + const clickHandler1: PaymentButtonClickHandler = async () => {}; + const clickHandler2: PaymentButtonClickHandler = undefined; + expectType(clickHandler1); + expectType(clickHandler2); +} + +// --------------------------------------------------------------------------- +// 10. Provider components — HyperElements +// --------------------------------------------------------------------------- +{ + const hyperPromise: Promise = loadHyper("pk_test_123"); + const options: ElementsOptions = { clientSecret: "pi_xxx_secret_yyy" }; + + // HyperElements with `hyper` prop + const hyperEl = React.createElement(HyperElements, { + hyper: hyperPromise, + options, + children: React.createElement("div"), + }); + expectType(hyperEl); +} + +// --------------------------------------------------------------------------- +// 11. Provider components — Elements (Stripe-compat) +// --------------------------------------------------------------------------- +{ + const hyperPromise: Promise = loadHyper("pk_test_123"); + const options: ElementsOptions = { clientSecret: "pi_xxx_secret_yyy" }; + + const elementsEl = React.createElement(Elements, { + stripe: hyperPromise, + options, + children: React.createElement("div"), + }); + expectType(elementsEl); +} + +// --------------------------------------------------------------------------- +// 12. Provider components — HyperManagementElements +// --------------------------------------------------------------------------- +{ + const hyperPromise: Promise = loadHyper("pk_test_123"); + + const mgmtEl = React.createElement(HyperManagementElements, { + hyper: hyperPromise, + options: { ephemeralKey: "ek_test_123" }, + children: React.createElement("div"), + }); + expectType(mgmtEl); +} + +// --------------------------------------------------------------------------- +// 13. Standard element components — all with PaymentElementComponentProps +// --------------------------------------------------------------------------- +{ + const sharedProps: PaymentElementComponentProps = { + id: "payment", + options: { layout: "tabs" }, + onChange: (data) => console.log(data), + onReady: () => {}, + onFocus: () => {}, + onBlur: () => {}, + onClick: () => {}, + onPaymentComplete: (data) => console.log(data), + onPaymentButtonClick: async () => {}, + }; + + // PaymentElement + expectType( + React.createElement(PaymentElement, sharedProps) + ); + + // CardElement + expectType(React.createElement(CardElement, sharedProps)); + + // CardNumberElement + expectType( + React.createElement(CardNumberElement, sharedProps) + ); + + // CardExpiryElement + expectType( + React.createElement(CardExpiryElement, sharedProps) + ); + + // CardCVCElement + expectType( + React.createElement(CardCVCElement, sharedProps) + ); + + // GooglePayElement + expectType( + React.createElement(GooglePayElement, sharedProps) + ); + + // ApplePayElement + expectType( + React.createElement(ApplePayElement, sharedProps) + ); + + // PayPalElement + expectType( + React.createElement(PayPalElement, sharedProps) + ); + + // PazeElement + expectType(React.createElement(PazeElement, sharedProps)); + + // ExpressCheckoutElement + expectType( + React.createElement(ExpressCheckoutElement, sharedProps) + ); +} + +// --------------------------------------------------------------------------- +// 14. Deprecated aliases +// --------------------------------------------------------------------------- +{ + const props: PaymentElementComponentProps = {}; + + expectType( + React.createElement(UnifiedCheckout, props) + ); + expectType(React.createElement(CardWidget, props)); + expectType( + React.createElement(CardNumberWidget, props) + ); + expectType( + React.createElement(CardExpiryWidget, props) + ); + expectType(React.createElement(CardCVCWidget, props)); +} + +// --------------------------------------------------------------------------- +// 15. PaymentMethodsManagementElement +// --------------------------------------------------------------------------- +{ + const mgmtProps: PaymentMethodsManagementElementProps = { + id: "payment-management", + options: {}, + onChange: (data) => console.log(data), + onReady: () => {}, + onFocus: () => {}, + onBlur: () => {}, + onClick: () => {}, + componentType: "paymentMethodsManagement", + }; + + expectType( + React.createElement(PaymentMethodsManagementElement, mgmtProps) + ); +} + +// --------------------------------------------------------------------------- +// 16. PaymentElementSession +// --------------------------------------------------------------------------- +{ + const session = {} as HyperSession; + + const sessionProps: PaymentElementSessionProps = { + session, + options: { layout: "tabs" }, + onChange: (data: any) => console.log(data), + onReady: () => {}, + onFocus: () => {}, + onBlur: () => {}, + onClick: () => {}, + onPaymentComplete: (data: any) => console.log(data), + onPaymentButtonClick: async () => {}, + id: "payment-element", + }; + + expectType( + React.createElement(PaymentElementSession, sessionProps) + ); +} + +// --------------------------------------------------------------------------- +// 17. useHyper() hook +// --------------------------------------------------------------------------- +{ + // Type-level test: useHyper returns UseHyperReturn + expectType<() => UseHyperReturn>(useHyper); + + // Simulated usage + const hyper: UseHyperReturn = {} as ReturnType; + + expectType(hyper.clientSecret); + expectType>(hyper.confirmPayment({})); + expectType>(hyper.confirmCardPayment("cs_secret")); + expectType>(hyper.retrievePaymentIntent("pi_123")); + expectType(hyper.paymentRequest({})); + expectType>(hyper.completeUpdateIntent("cs_123")); + expectType>(hyper.initiateUpdateIntent()); + expectType>(hyper.confirmTokenization({})); +} + +// --------------------------------------------------------------------------- +// 18. useStripe() deprecated alias +// --------------------------------------------------------------------------- +{ + expectType<() => UseHyperReturn>(useStripe); +} + +// --------------------------------------------------------------------------- +// 19. useWidgets() hook +// --------------------------------------------------------------------------- +{ + expectType<() => UseWidgetsReturn>(useWidgets); + + const widgets: UseWidgetsReturn = {} as ReturnType; + expectType>(widgets.options); +} + +// --------------------------------------------------------------------------- +// 20. useElements() deprecated alias +// --------------------------------------------------------------------------- +{ + expectType<() => UseWidgetsReturn>(useElements); +} + +// --------------------------------------------------------------------------- +// 21. useHyperSession() hook +// --------------------------------------------------------------------------- +{ + // Return type: HyperSession | null + expectType< + ( + sdkAuthorization?: string, + options?: SessionOptions + ) => HyperSession | null + >(useHyperSession); + + // Simulated usage + const session: HyperSession | null = {} as ReturnType; + + if (session !== null) { + expectType(session.status); + expectType(session.widgets); + expectType(session.error); + + // All methods + expectType>( + session.confirmPayment({ + confirmParams: { return_url: "https://example.com" }, + }) + ); + expectType>(session.confirmCardPayment("cs_secret")); + expectType>(session.retrievePaymentIntent("pi_123")); + expectType(session.paymentRequest({})); + expectType>(session.completeUpdateIntent("cs_123")); + expectType>(session.initiateUpdateIntent()); + expectType>(session.confirmTokenization({})); + } +} + +// --------------------------------------------------------------------------- +// 22. Cross-package type compatibility +// --------------------------------------------------------------------------- +{ + // HyperElementsProps.hyper accepts Promise from hyper-js + const hyperPromise: Promise = loadHyper("pk_test_123"); + const props: HyperElementsProps = { + hyper: hyperPromise, + options: { clientSecret: "pi_xxx_secret_yyy" }, + children: null, + }; + expectType(props); + + // ElementsOptions from hyper-js is accepted in provider options + const elementsOpts: ElementsOptions = { + clientSecret: "pi_xxx_secret_yyy", + appearance: { + theme: "midnight", + variables: { colorPrimary: "#0570de" }, + }, + locale: "en", + loader: "auto", + }; + const props2: HyperElementsProps = { + hyper: hyperPromise, + options: elementsOpts, + children: null, + }; + expectType(props2); +} + +// --------------------------------------------------------------------------- +// 23. Shared hyper-js types used in react-hyper-js context +// --------------------------------------------------------------------------- +{ + // EventData is used in element callbacks + const eventData: EventData = { + iframeMounted: true, + focus: false, + blur: false, + ready: true, + clickTriggered: false, + completeDoThis: false, + elementType: "card", + classChange: false, + newClassType: "", + confirmTriggered: false, + oneClickConfirmTriggered: false, + }; + expectType(eventData); + + // ConfirmPaymentResponse + const confirmResp: ConfirmPaymentResponse = { + payment_id: "pi_123", + merchant_id: "m_123", + status: "succeeded", + amount: 1000, + net_amount: 1000, + amount_capturable: 0, + currency: "USD", + payment_method: "card", + attempt_count: 1, + }; + expectType(confirmResp); + + // ConfirmPaymentErrorResponse + const errorResp: ConfirmPaymentErrorResponse = { + submitSuccessful: false, + error: { + type: "validation_error", + message: "Card number is invalid", + }, + }; + expectType(errorResp); + + // RetrievePaymentIntentResponse + const retrieveResp: RetrievePaymentIntentResponse = { + paymentIntent: confirmResp, + }; + expectType(retrieveResp); + + // ElementsAppearanceOptions + const appearance: ElementsAppearanceOptions = { + theme: "midnight", + variables: { + colorPrimary: "#0570de", + fontFamily: "Roboto, sans-serif", + }, + rules: { + ".Input": { borderColor: "#000" }, + }, + labels: "Floating", + }; + expectType(appearance); +} + +// --------------------------------------------------------------------------- +// 24. Components accept minimal props (all optional) +// --------------------------------------------------------------------------- +{ + // PaymentElement with no props + React.createElement(PaymentElement, {}); + + // CardElement with only id + React.createElement(CardElement, { id: "card" }); + + // PaymentMethodsManagementElement with no props + React.createElement(PaymentMethodsManagementElement, {}); + + // PaymentElementSession requires session (mandatory) + const session = {} as HyperSession; + React.createElement(PaymentElementSession, { session }); +} diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 0000000..d0e5f8d --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "strict": true, + "noEmit": true, + "moduleResolution": "bundler", + "esModuleInterop": true, + "jsx": "react-jsx", + "target": "ES2020", + "module": "ESNext", + "paths": { + "@juspay-tech/react-hyper-js": ["./src/index.d.ts"], + "@juspay-tech/hyper-js": ["../hyper-js/src/index.d.ts"] + } + }, + "include": ["src/index.test-d.ts"] +}