export interface DataFastTracking { visitorId?: string; sessionId?: string; } export interface HeadersLike { get?(name: string): string | null | undefined; [key: string]: any; } export interface CreemSdkClientLike { checkouts: { create(params: any): Promise; }; transactions: { getById(id: string): Promise; }; } export interface InternalCreateCheckoutRequest { productId: string; successUrl: string; requestId?: string; units?: number; discountCode?: string; customer?: string | Record; customFields?: Record; metadata?: Record | null; } export interface InternalCreemClient { createCheckout(request: InternalCreateCheckoutRequest): Promise; getTransactionById(transactionId: string): Promise; } export interface DataFastPaymentPayload { amount: number; currency: string; transaction_id: string; renewal: boolean; customer_id?: string; datafast_visitor_id?: string; email?: string; name?: string; timestamp?: string; refunded?: boolean; } export interface RetryConfig { retries?: number; baseDelayMs?: number; maxDelayMs?: number; } export interface DeadLetterContext { eventType: string; eventId: string; transactionId: string; payment?: DataFastPaymentPayload; error: Error; attempts: number; } export interface DataFastApiResponse { status: number; body: unknown; } export interface HealthCheckResult { ok: boolean; /** * @deprecated Use `ok` instead. Kept for backwards compatibility. */ healthy: boolean; checks: { creemApiKey: { ok: boolean; message: string; latencyMs?: number }; webhookSecret: { ok: boolean; message: string; latencyMs?: number }; datafastApi: { ok: boolean; message: string; latencyMs?: number }; }; timestamp: string; } export type MetadataMergeStrategy = 'preserve' | 'overwrite' | 'error'; export interface CreemDataFastOptions { creemApiKey?: string; creemWebhookSecret: string; datafastApiKey: string; datafastApiBaseUrl?: string; testMode?: boolean; creemClient?: CreemSdkClientLike; fetch?: typeof globalThis.fetch; logger?: LoggerLike; timeoutMs?: number; retry?: RetryConfig; strictTracking?: boolean; captureSessionId?: boolean; cookieName?: string; sessionCookieName?: string; webhookDryRun?: boolean; /** * @deprecated Use `webhookDryRun` instead. Kept for backwards compatibility. */ dryRun?: boolean; eventFilter?: SupportedWebhookEvent[]; onDeadLetter?: (context: DeadLetterContext) => void | Promise; hydrateTransactionOnSubscriptionPaid?: boolean; idempotencyStore?: IdempotencyStore; idempotencyInFlightTtlSeconds?: number; idempotencyProcessedTtlSeconds?: number; } export interface LoggerLike { debug(message: string, ...args: any[]): void; info(message: string, ...args: any[]): void; warn(message: string, ...args: any[]): void; error(message: string, ...args: any[]): void; } export interface IdempotencyStore { claim(key: string, ttlSeconds?: number): Promise; complete(key: string, ttlSeconds?: number): Promise; release(key: string): Promise; } export interface BrowserTrackingResult { visitorId?: string; sessionId?: string; } export interface CreateCheckoutParams { productId: string; successUrl: string; requestId?: string; units?: number; discountCode?: string; customer?: string | Record; customFields?: Record; metadata?: Record | null; tracking?: DataFastTracking; mergeStrategy?: MetadataMergeStrategy; } export interface CreateCheckoutContext { request?: { headers: HeadersLike; url?: string; }; cookieHeader?: string; strictTracking?: boolean; } export interface CreateCheckoutResult { checkoutId: string; checkoutUrl: string; injectedTracking: DataFastTracking; finalMetadata: Record | null; raw: any; } export interface HandleWebhookParams { rawBody: string; headers: HeadersLike; } export interface HandleWebhookResult { ok: boolean; ignored: boolean; eventId?: string; eventType?: string; reason?: 'unsupported_event' | 'duplicate_event' | 'delegated_to_subscription_paid'; deduplicated?: boolean; payload?: DataFastPaymentPayload; datafastResponse?: DataFastApiResponse | unknown; } export interface CheckoutDependencies { creem: InternalCreemClient; logger: LoggerLike; captureSessionId: boolean; strictTracking: boolean; } export type SupportedWebhookEvent = 'checkout.completed' | 'subscription.paid' | 'refund.created'; export interface WebhookHandlerDependencies { creemWebhookSecret: string; datafast: InternalDataFastClient; creem: InternalCreemClient; idempotencyStore: IdempotencyStore; idempotencyInFlightTtlSeconds: number; idempotencyProcessedTtlSeconds: number; eventFilter?: SupportedWebhookEvent[]; webhookDryRun?: boolean; /** * @deprecated Use `webhookDryRun` instead. Kept for backwards compatibility. */ dryRun?: boolean; onDeadLetter?: (context: DeadLetterContext) => void | Promise; retry?: RetryConfig; hydrateTransactionOnSubscriptionPaid: boolean; logger: LoggerLike; } export interface InternalDataFastClient { sendPayment(payload: DataFastPaymentPayload): Promise; sendPayments?( payloads: DataFastPaymentPayload[] ): Promise<{ results: Array<{ ok: boolean; response?: DataFastApiResponse; error?: Error }> }>; getPayments?(visitorId: string): Promise; } export interface CheckoutCompletedEvent { id: string; eventType?: string; event_type?: string; object?: { order?: { id: string; amount: number; currency: string; type?: string; metadata?: Record; }; customer?: | string | { id?: string; email?: string; name?: string; }; metadata?: Record; subscription?: string | { id?: string }; }; } export interface SubscriptionPaidEvent { id: string; eventType?: string; event_type?: string; object?: { customer?: | string | { id?: string; email?: string; name?: string; }; metadata?: Record; product?: { price?: number; currency?: string; }; last_transaction_id?: string; lastTransactionId?: string; last_transaction_date?: string; lastTransactionDate?: string; }; } export interface RefundCreatedEvent { id: string; eventType?: string; event_type?: string; created_at?: number | string; createdAt?: number | string; object?: { id?: string; refund_amount?: number; refundAmount?: number; refund_currency?: string; refundCurrency?: string; customer?: | string | { id?: string; email?: string; name?: string; }; metadata?: Record; created_at?: number | string; createdAt?: number | string; transaction?: { id?: string; subscription?: string | null; type?: string; metadata?: Record; created_at?: number | string; createdAt?: number | string; customer?: | string | { id?: string; email?: string; name?: string; }; }; }; } export interface NormalizedTransaction { id: string; amount: number; currency: string; timestamp?: string; } export interface CheckoutMetadata { datafast_visitor_id?: string; datafast_session_id?: string; [key: string]: any; } export interface CheckoutCompletedCustomer { id?: string; email?: string; name?: string; } export interface SubscriptionPaidCustomer { id?: string; email?: string; name?: string; } export interface RefundCreatedCustomer { id?: string; email?: string; name?: string; } export interface CreemDataFastClient { createCheckout( params: CreateCheckoutParams, context?: CreateCheckoutContext ): Promise; handleWebhook(params: HandleWebhookParams): Promise; replayWebhook(params: HandleWebhookParams): Promise; verifyWebhookSignature(rawBody: string, headers: HeadersLike): Promise; buildCheckoutUrl(params: { checkoutUrl: string; visitorId?: string; sessionId?: string; mergeStrategy?: MetadataMergeStrategy; }): string; healthCheck(): Promise; sendPayments( payloads: DataFastPaymentPayload[] ): Promise<{ results: Array<{ ok: boolean; response?: DataFastApiResponse; error?: Error }> }>; getPayments(visitorId: string): Promise; creem: InternalCreemClient; } export interface NextWebhookHandlerOptions { onError?(error: unknown): void | Promise; } export interface ExpressLikeRequest { body: string | Buffer; headers: Record; } export interface ExpressLikeResponse { status(code: number): ExpressLikeResponse; send(body: any): ExpressLikeResponse; } export interface ExpressWebhookHandlerOptions { onError?(error: unknown): void | Promise; }