Skip to content

Latest commit

 

History

History
357 lines (316 loc) · 20.2 KB

File metadata and controls

357 lines (316 loc) · 20.2 KB

Architecture

Directory Structure

src/
├── index.ts                    # Main entry point (barrel exports)
├── components/                 # React components
│   ├── index.ts
│   ├── AdyenCheckout.tsx       # Main checkout component with context provider
│   ├── ApplePayButton.tsx      # Apple Pay button component
│   ├── GooglePayButton.tsx     # Google Pay button component
│   ├── utils.ts                # Configuration validation utilities
│   └── common/
│       └── Styles.ts           # Shared styles
├── core/                       # Core types, constants, and configurations
│   ├── index.ts
│   ├── types.ts                # Payment types and component interfaces
│   ├── constants.ts            # Event enums, error codes, result codes
│   ├── components.ts           # Payment method component mappings
│   └── configurations/         # Configuration interfaces
│       ├── index.ts
│       ├── Configuration.ts
│       ├── AddressLookup.ts
│       ├── ApplePayConfiguration.ts
│       ├── CardsConfiguration.ts
│       ├── DropInConfiguration.ts
│       ├── GooglePayConfiguration.ts
│       ├── PartialPaymentConfiguration.ts
│       └── ThreeDSConfiguration.ts
├── hooks/                      # React hooks
│   ├── index.ts
│   └── useAdyenCheckout.ts     # Context hook for checkout state
└── modules/                    # Native module wrappers
    ├── index.ts
    ├── base/                   # Base wrapper classes
    │   ├── EventListenerWrapper.ts     # Abstract base for event handling
    │   ├── ModuleWrapper.ts            # Abstract base with hide()
    │   ├── PaymentComponentWrapper.ts  # Abstract base with open()
    │   ├── ActionHandlingComponentWrapper.ts  # Abstract base with handle()
    │   ├── ModuleMock.ts               # Mock for unavailable modules
    │   ├── constants.ts                # Module-specific constants
    │   ├── getWrapper.ts               # Factory to resolve payment method wrappers
    │   └── utils.ts                    # Utility functions
    ├── action/                 # Standalone action handler
    │   ├── AdyenAction.ts
    │   └── ActionModuleWrapper.ts
    ├── applepay/               # Apple Pay module
    │   ├── AdyenApplePay.ts
    │   └── ApplePayWrapper.ts
    ├── cse/                    # Client-side encryption
    │   ├── AdyenCSEModule.ts
    │   ├── AdyenCSEModuleWrapper.ts
    │   └── types.ts                  # Card type definition
    ├── dropin/                 # Drop-in module
    │   ├── AdyenDropIn.ts
    │   └── DropInWrapper.ts
    ├── googlepay/              # Google Pay module
    │   ├── AdyenGooglePay.ts
    │   └── GooglePayWrapper.ts
    ├── instant/                # Instant/redirect payments
    │   ├── AdyenInstant.ts
    │   └── InstantWrapper.ts
    └── session/                # Session management
        ├── SessionHelperModule.ts
        ├── SessionWrapper.ts
        └── types.ts

Class Hierarchy

Wrapper Classes

Events are declared via static events property and automatically inherited through the prototype chain.

NativeModule (react-native)
    │
    ▼
EventListenerWrapper<T>                                      # Abstract - manages event subscriptions
    │                                                          - getRegisteredEvents() traverses prototype chain
    │                                                          - isSupported(event)
    │                                                          - addListener/removeListeners
    ▼
ModuleWrapper<T>                                             # Abstract - adds hide()
    │   static events = [onError, onComplete]
    │   implements AdyenComponent
    │
    ▼
PaymentComponentWrapper<T>                                   # Abstract - adds open()
    │   static events = [onSubmit]
    │
    ├──► ApplePayWrapper                                     # implements ApplePayModule
    │       + isAvailable()
    │
    ▼
ActionHandlingComponentWrapper<T>                            # Abstract - adds handle()
    │   static events = [onAdditionalDetails]
    │   implements AdyenActionComponent
    │
    ├──► GooglePayWrapper                                    # implements GooglePayModule
    │       + isAvailable()
    │
    ├──► InstantWrapper                                      # implements InstantModule
    │
    └──► DropInWrapper                                       # implements DropInModule
            static events = [onBinValue, onBinLookup,
                           onDisableStoredPaymentMethod,
                           onAddressConfirm, onAddressUpdate,
                           onCheckBalance, onRequestOrder, onCancelOrder]
            + getReturnURL(), 
            + removeStored()                       (RemovesStoredPayment)
            + update(), confirm(), reject()        (AddressLookup)
            + provideBalance/Order/PaymentMethods  (PartialPayment)

Standalone Wrappers (outside hierarchy)

These don't inherit from EventListenerWrapper as they don't need event subscription management:

ActionModuleWrapper                                          # implements ActionModule
    - handle(action, config) → Promise<PaymentDetailsData>
    - hide(success)
    - threeDS2SdkVersion

SessionWrapper                                               # implements SessionHelperModule
    - createSession(session, config) → Promise<SessionContext>
    - hide(success, option?)

AdyenCSEModuleWrapper                                        # implements AdyenCSEModule
    - encryptCard(card, publicKey)
    - encryptBin(bin, publicKey)

Interface Dependencies

Core Component Interfaces (core/types.ts)

AdyenComponent                    # Base interface
    │   hide(success, option?)
    │
    └──► AdyenActionComponent     # Extends AdyenComponent
            handle(action)

ConditionalPaymentComponent       # Standalone interface
    isAvailable(paymentMethod, configuration) → Promise<boolean>

Native Module Interface Hierarchy

Native module interfaces extend their public module interfaces for type alignment:

NativeModule (react-native)
    │
    ├──► BaseNativeModule                                                  # modules/base/ModuleWrapper.ts
    │       - hide(success, option?)
    │       │
    │       └──► PaymentModule                                             # modules/base/PaymentComponentWrapper.ts
    │               - hide(success, option?)                                 [inherited]
    │               - open(paymentMethods, configuration)
    │               │
    │               ├──► ActionHandlingNativeModule                        # modules/base/ActionHandlingComponentWrapper.ts
    │               │       - hide(success, option?)                         [inherited]
    │               │       - open(paymentMethods, config)                   [inherited]
    │               │       - handle(action)
    │               │       │
    │               │       ├──► GooglePayNativeModule                     # modules/googlepay/GooglePayWrapper.ts
    │               │       │       - hide(success, option?)                 [inherited]
    │               │       │       - open(paymentMethods, config)           [inherited]
    │               │       │       - handle(action)                         [inherited]
    │               │       │       - isAvailable(paymentMethod, config) → Promise<boolean>
    │               │       │
    │               │       └──► DropInNativeModule                        # modules/dropin/DropInWrapper.ts
    │               │               - hide(success, option?)                 [inherited]
    │               │               - open(paymentMethods, config)           [inherited]
    │               │               - handle(action)                         [inherited]
    │               │               - getReturnURL() → Promise<string>
    │               │               - providePaymentMethods(paymentMethods, order)
    │               │               - provideBalance(success, balance?, error?)
    │               │               - provideOrder(success, order?, error?)
    │               │               - removeStored(success)
    │               │               - update(results)
    │               │               - confirm(success, addressOrError?)
    │               │
    │               └──► ApplePayNativeModule                              # modules/applepay/ApplePayWrapper.ts
    │                       - hide(success, option?)                         [inherited]
    │                       - open(paymentMethods, config)                   [inherited]
    │                       - isAvailable(paymentMethod, config) → Promise<boolean>
    │
    ├──► ActionNativeModule                                                # modules/action/ActionModuleWrapper.ts
    │       - handle(action, config) → Promise<PaymentDetailsData>
    │       - hide(success)
    │       - getConstants() → { threeDS2SdkVersion }
    │
    ├──► SessionNativeModule                                               # modules/session/SessionWrapper.ts
    │       - hide(success, option?)
    │       - createSession(session, config) → Promise<SessionContext>
    │
    └──► CSENativeModule                                                   # modules/cse/AdyenCSEModuleWrapper.ts
            - encryptCard(payload, publicKey) → Promise<Card>
            - encryptBin(payload, publicKey) → Promise<string>

Public Module Interfaces

ApplePayModule                                               # extends AdyenComponent, ConditionalPaymentComponent
    - hide(success, option?)                                   [from AdyenComponent]
    - isAvailable(paymentMethod, config) → Promise<boolean>    [from ConditionalPaymentComponent]

GooglePayModule                                              # extends ConditionalPaymentComponent, AdyenActionComponent
    - hide(success, option?)                                   [from AdyenComponent]
    - handle(action)                                           [from AdyenActionComponent]
    - isAvailable(paymentMethod, config) → Promise<boolean>    [from ConditionalPaymentComponent]

InstantModule                                                # extends AdyenActionComponent
    - hide(success, option?)                                   [from AdyenComponent]
    - handle(action)                                           [from AdyenActionComponent]

DropInModule                                                 # extends AdyenActionComponent
    - hide(success, option?)                                   [from AdyenComponent]
    - handle(action)                                           [from AdyenActionComponent]
    - getReturnURL() → Promise<string>
    - providePaymentMethods(paymentMethods, order)

ActionModule                                                 # standalone
    - threeDS2SdkVersion: string
    - handle(action, config) → Promise<PaymentDetailsData>
    - hide(success)

AdyenCSEModule                                               # standalone
    - encryptCard(payload, publicKey) → Promise<Card>
    - encryptBin(payload, publicKey) → Promise<string>

SessionHelperModule                                          # extends AdyenComponent
    - hide(success, option?)                                   [from AdyenComponent]
    - createSession(session, config) → Promise<SessionContext>

Configuration Hierarchy

BaseConfiguration
    │   environment, clientKey, countryCode, locale?
    │
    └──► EnvironmentConfiguration
            │   + amount
            │
            └──► Configuration
                    + analytics?, 
                    + dropin?, 
                    + card?, 
                    + applepay?, 
                    + googlepay?, 
                    + threeDS2?, 
                    + partialPayment?

Event System

Events are declared as static properties on wrapper classes and automatically inherited:

// Base events from ModuleWrapper
static readonly events = [Event.onError, Event.onComplete];

// Additional events from PaymentComponentWrapper
static readonly events = [Event.onSubmit];

// DropInWrapper adds many more
static readonly events = [
  Event.onBinValue, Event.onBinLookup,
  Event.onDisableStoredPaymentMethod,
  Event.onAddressConfirm, Event.onAddressUpdate,
  Event.onCheckBalance, Event.onRequestOrder, Event.onCancelOrder,
];

getRegisteredEvents() in EventListenerWrapper traverses the prototype chain to collect all events.

Event Reference

Event Native Callback Description
onSubmit didSubmitCallback Payment details submitted
onAdditionalDetails didProvideCallback Additional action details needed
onComplete didCompleteCallback Payment completed (vouchers)
onError didFailCallback Error occurred
onDisableStoredPaymentMethod didDisableStoredPaymentMethodCallback Stored payment removal requested
onAddressUpdate didUpdateAddressCallback Address lookup update
onAddressConfirm didConfirmAddressCallback Address confirmed
onCheckBalance didCheckBalanceCallback Balance check requested
onRequestOrder didRequestOrderCallback New order requested
onCancelOrder didCancelOrderCallback Order cancelled
onBinValue didChangeBinValueCallback BIN value changed
onBinLookup didBinLookupCallback BIN lookup completed

Data Flow

┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                               AdyenCheckout                                                    │
│                                            (React Component)                                                   │
│                                                                                                                │
│    ┌─────────────────────────────┐                  ┌────────────────────────────────────────────────────────┐ │
│    │ AdyenCheckout               │                  │ Event Handlers (props)                                 │ │
│    │ Context                     │                  │ - onSubmit(data, component, extra)                     │ │
│    │ - start(name)               │                  │ - onComplete(result, component)                        │ │
│    │ - config                    │                  │ - onError(error, component)                            │ │
│    │ - paymentMethods            │                  │ - onAdditionalDetails(data, component)                 │ │
│    │ - session?                  │                  │ - Address/Partial Payment callbacks                    │ │
│    └─────────────────────────────┘                  └────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
                                                        │
                                                        ▼
                                          ┌───────────────────────────┐
                                          │       getWrapper()        │
                                          │     (module resolver)     │
                                          │     maps type name →      │
                                          │     wrapper instance      │
                                          └───────────────────────────┘
                                                        │
          ┌─────────────────────────────┬───────────────┼───────────────┬─────────────────────────────┐
          ▼                             ▼               ▼               ▼                             ▼
┌───────────────────────┐   ┌───────────────────────┐   ┌───────────────────────┐   ┌───────────────────────┐
│     DropInWrapper     │   │    ApplePayWrapper    │   │   GooglePayWrapper    │   │    InstantWrapper     │
│                       │   │                       │   │                       │   │                       │
│   - open()            │   │   - open()            │   │   - open()            │   │   - open()            │
│   - handle()          │   │   - isAvailable()     │   │   - handle()          │   │   - handle()          │
│   - hide()            │   │   - hide()            │   │   - isAvailable()     │   │   - hide()            │
│   - ...               │   │                       │   │   - hide()            │   │                       │
└───────────────────────┘   └───────────────────────┘   └───────────────────────┘   └───────────────────────┘
          │                             │               │               │                             │
          └─────────────────────────────┴───────────────┼───────────────┴─────────────────────────────┘
                                                        ▼
                                          ┌───────────────────────────┐
                                          │    Native iOS/Android     │
                                          │        Adyen SDK          │
                                          └───────────────────────────┘

Session Flow vs Advanced Flow

Session Flow

  1. Pass session prop to AdyenCheckout
  2. SessionHelper.createSession() initializes session with Adyen
  3. Returns SessionContext with paymentMethods
  4. Events return SessionsResult on completion

Advanced Flow

  1. Pass paymentMethods prop directly to AdyenCheckout
  2. Handle onSubmit → call your server → /payments
  3. Handle onAdditionalDetails → call your server → /payments/details
  4. Call component.handle(action) for any actions