@drip-sdk/node 1.0.10 → 1.1.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core.ts"],"names":["DripError","_DripError","message","statusCode","code","Drip","config","path","options","controller","timeoutId","res","data","error","healthBaseUrl","start","response","latencyMs","status","timestamp","params","customerId","query","runId","events","startTime","workflowId","workflowName","existing","w","created","c","run","eventsCreated","eventsDuplicates","batchEvents","event","index","batchResult","endResult","durationMs","eventSummary","summary","core_default"],"mappings":"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","file":"core.js","sourcesContent":["/**\n * Drip SDK Core - Essential API for pilots and new integrations\n *\n * This SDK focuses on two core concepts:\n * - **Usage tracking**: trackUsage() for recording usage without billing\n * - **Execution logging**: recordRun() and related methods for tracking runs/events\n *\n * For billing, webhooks, cost estimation, and advanced features:\n * `import { Drip } from '@drip-sdk/node'`\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// Configuration Types\n// ============================================================================\n\n/**\n * Configuration options for the Drip SDK client.\n */\nexport interface DripConfig {\n /**\n * Your Drip API key. Obtain this from the Drip dashboard.\n * @example \"drip_live_abc123...\"\n */\n apiKey: string;\n\n /**\n * Base URL for the Drip API. Defaults to production API.\n * Override for staging/development environments.\n * @default \"https://api.drip.dev/v1\"\n */\n baseUrl?: string;\n\n /**\n * Request timeout in milliseconds.\n * @default 30000\n */\n timeout?: number;\n}\n\n// ============================================================================\n// Customer Types\n// ============================================================================\n\n/**\n * Parameters for creating a new customer.\n */\nexport interface CreateCustomerParams {\n /**\n * Your internal customer/user ID for reconciliation.\n * @example \"user_12345\"\n */\n externalCustomerId?: string;\n\n /**\n * The customer's Drip Smart Account address (derived from their EOA).\n * @example \"0x1234567890abcdef...\"\n */\n onchainAddress: string;\n\n /**\n * Additional metadata to store with the customer.\n */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * A Drip customer record.\n */\nexport interface Customer {\n /** Unique customer ID in Drip */\n id: string;\n\n /** Your business ID (optional - may not be returned by all endpoints) */\n businessId?: string;\n\n /** Your external customer ID (if provided) */\n externalCustomerId: string | null;\n\n /** Customer's on-chain address */\n onchainAddress: string;\n\n /** Custom metadata */\n metadata: Record<string, unknown> | null;\n\n /** ISO timestamp of creation */\n createdAt: string;\n\n /** ISO timestamp of last update */\n updatedAt: string;\n}\n\n/**\n * Options for listing customers.\n */\nexport interface ListCustomersOptions {\n /**\n * Maximum number of customers to return (1-100).\n * @default 100\n */\n limit?: number;\n\n /**\n * Filter by customer status.\n */\n status?: 'ACTIVE' | 'LOW_BALANCE' | 'PAUSED';\n}\n\n/**\n * Response from listing customers.\n */\nexport interface ListCustomersResponse {\n /** Array of customers */\n data: Customer[];\n\n /** Total count returned */\n count: number;\n}\n\n// ============================================================================\n// Usage Tracking Types\n// ============================================================================\n\n/**\n * Parameters for tracking usage without billing.\n */\nexport interface TrackUsageParams {\n /**\n * The Drip customer ID to track usage for.\n */\n customerId: string;\n\n /**\n * The meter/usage type (e.g., 'api_calls', 'tokens').\n */\n meter: string;\n\n /**\n * The quantity of usage to record.\n */\n quantity: number;\n\n /**\n * Unique key to prevent duplicate records.\n */\n idempotencyKey?: string;\n\n /**\n * Human-readable unit label (e.g., 'tokens', 'requests').\n */\n units?: string;\n\n /**\n * Human-readable description of this usage event.\n */\n description?: string;\n\n /**\n * Additional metadata to attach to this usage event.\n */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Result of tracking usage (no billing).\n */\nexport interface TrackUsageResult {\n /** Whether the usage was recorded */\n success: boolean;\n\n /** The usage event ID */\n usageEventId: string;\n\n /** Customer ID */\n customerId: string;\n\n /** Usage type that was recorded */\n usageType: string;\n\n /** Quantity recorded */\n quantity: number;\n\n /** Whether this customer is internal-only */\n isInternal: boolean;\n\n /** Confirmation message */\n message: string;\n}\n\n// ============================================================================\n// Run & Event Types (Execution Ledger)\n// ============================================================================\n\n/**\n * Parameters for starting a new run.\n */\nexport interface StartRunParams {\n /** Customer ID this run belongs to */\n customerId: string;\n\n /** Workflow ID this run executes */\n workflowId: string;\n\n /** Your external run ID for correlation */\n externalRunId?: string;\n\n /** Correlation ID for distributed tracing */\n correlationId?: string;\n\n /** Parent run ID for nested runs */\n parentRunId?: string;\n\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Possible run statuses.\n */\nexport type RunStatus =\n | 'PENDING'\n | 'RUNNING'\n | 'COMPLETED'\n | 'FAILED'\n | 'CANCELLED'\n | 'TIMEOUT';\n\n/**\n * Result of starting a run.\n */\nexport interface RunResult {\n id: string;\n customerId: string;\n workflowId: string;\n workflowName: string;\n status: RunStatus;\n correlationId: string | null;\n createdAt: string;\n}\n\n/**\n * Parameters for ending/updating a run.\n */\nexport interface EndRunParams {\n /** New status for the run */\n status: 'COMPLETED' | 'FAILED' | 'CANCELLED' | 'TIMEOUT';\n\n /** Error message if failed */\n errorMessage?: string;\n\n /** Error code for categorization */\n errorCode?: string;\n\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Result of ending a run.\n */\nexport interface EndRunResult {\n id: string;\n status: RunStatus;\n endedAt: string | null;\n durationMs: number | null;\n eventCount: number;\n totalCostUnits: string | null;\n}\n\n/**\n * Parameters for emitting an event to a run.\n */\nexport interface EmitEventParams {\n /** Run ID to attach this event to */\n runId: string;\n\n /** Event type (e.g., \"request.start\", \"llm.call\") */\n eventType: string;\n\n /** Quantity of units consumed */\n quantity?: number;\n\n /** Human-readable unit label */\n units?: string;\n\n /** Human-readable description */\n description?: string;\n\n /** Cost in abstract units */\n costUnits?: number;\n\n /** Currency for cost */\n costCurrency?: string;\n\n /** Correlation ID for tracing */\n correlationId?: string;\n\n /** Parent event ID for trace tree */\n parentEventId?: string;\n\n /** OpenTelemetry-style span ID */\n spanId?: string;\n\n /** Idempotency key */\n idempotencyKey?: string;\n\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Result of emitting an event.\n */\nexport interface EventResult {\n id: string;\n runId: string;\n eventType: string;\n quantity: number;\n costUnits: number | null;\n isDuplicate: boolean;\n timestamp: string;\n}\n\n/**\n * A single event to record in a run.\n */\nexport interface RecordRunEvent {\n /** Event type (e.g., \"request.start\", \"llm.call\", \"request.end\") */\n eventType: string;\n\n /** Quantity of units consumed */\n quantity?: number;\n\n /** Human-readable unit label */\n units?: string;\n\n /** Human-readable description */\n description?: string;\n\n /** Cost in abstract units */\n costUnits?: number;\n\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for recording a complete run in one call.\n */\nexport interface RecordRunParams {\n /** Customer ID this run belongs to */\n customerId: string;\n\n /**\n * Workflow/request type identifier. Examples:\n * - \"rpc-request\" for RPC providers\n * - \"api-request\" for API providers\n * - \"agent-run\" for AI agents\n *\n * Auto-creates if it doesn't exist.\n */\n workflow: string;\n\n /** Events that occurred during the run */\n events: RecordRunEvent[];\n\n /** Final status of the run */\n status: 'COMPLETED' | 'FAILED' | 'CANCELLED' | 'TIMEOUT';\n\n /** Error message if status is FAILED */\n errorMessage?: string;\n\n /** Error code if status is FAILED */\n errorCode?: string;\n\n /** Your external run ID for correlation */\n externalRunId?: string;\n\n /** Correlation ID for distributed tracing */\n correlationId?: string;\n\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Result of recording a run.\n */\nexport interface RecordRunResult {\n /** The created run */\n run: {\n id: string;\n workflowId: string;\n workflowName: string;\n status: RunStatus;\n durationMs: number | null;\n };\n\n /** Summary of events created */\n events: {\n created: number;\n duplicates: number;\n };\n\n /** Total cost computed */\n totalCostUnits: string | null;\n\n /** Human-readable summary */\n summary: string;\n}\n\n/**\n * Full run timeline response.\n */\nexport interface RunTimeline {\n run: {\n id: string;\n customerId: string;\n customerName: string | null;\n workflowId: string;\n workflowName: string;\n status: RunStatus;\n startedAt: string | null;\n endedAt: string | null;\n durationMs: number | null;\n errorMessage: string | null;\n errorCode: string | null;\n correlationId: string | null;\n metadata: Record<string, unknown> | null;\n };\n timeline: Array<{\n id: string;\n eventType: string;\n quantity: number;\n units: string | null;\n description: string | null;\n costUnits: number | null;\n timestamp: string;\n correlationId: string | null;\n parentEventId: string | null;\n charge: {\n id: string;\n amountUsdc: string;\n status: string;\n } | null;\n }>;\n totals: {\n eventCount: number;\n totalQuantity: string;\n totalCostUnits: string;\n totalChargedUsdc: string;\n };\n summary: string;\n}\n\n// ============================================================================\n// Internal Types (used by recordRun)\n// ============================================================================\n\ninterface Workflow {\n id: string;\n name: string;\n slug: string;\n productSurface: string;\n description: string | null;\n isActive: boolean;\n createdAt: string;\n}\n\ninterface CreateWorkflowParams {\n name: string;\n slug: string;\n productSurface?: 'RPC' | 'WEBHOOK' | 'AGENT' | 'PIPELINE' | 'CUSTOM';\n description?: string;\n metadata?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * Error thrown by Drip SDK operations.\n */\nexport class DripError extends Error {\n constructor(\n message: string,\n public statusCode: number,\n public code?: string,\n ) {\n super(message);\n this.name = 'DripError';\n Object.setPrototypeOf(this, DripError.prototype);\n }\n}\n\n// ============================================================================\n// Core SDK Class\n// ============================================================================\n\n/**\n * Drip SDK Core - Essential API for pilots and new integrations.\n *\n * Two core concepts:\n * - **Usage tracking**: `trackUsage()` - record usage without billing\n * - **Execution logging**: `recordRun()` - track request/run lifecycle with events\n *\n * For billing (`charge()`), webhooks, and advanced features:\n * ```typescript\n * import { Drip } from '@drip-sdk/node';\n * ```\n *\n * @example\n * ```typescript\n * import { Drip } from '@drip-sdk/node/core';\n *\n * const drip = new Drip({ apiKey: process.env.DRIP_API_KEY! });\n *\n * // Verify connection\n * const health = await drip.ping();\n * console.log(`API healthy: ${health.ok}`);\n *\n * // Track usage (no billing)\n * await drip.trackUsage({\n * customerId: 'cust_123',\n * meter: 'api_calls',\n * quantity: 1,\n * });\n *\n * // Record a complete request/run with events\n * const result = await drip.recordRun({\n * customerId: 'cust_123',\n * workflow: 'rpc-request', // or 'api-request', 'agent-run'\n * events: [\n * { eventType: 'request.start' },\n * { eventType: 'llm.call', quantity: 1500, units: 'tokens' },\n * { eventType: 'request.end' },\n * ],\n * status: 'COMPLETED',\n * });\n *\n * console.log(result.summary);\n * ```\n */\nexport class Drip {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly timeout: number;\n\n /**\n * Creates a new Drip SDK client.\n *\n * @param config - Configuration options\n * @throws {Error} If apiKey is not provided\n */\n constructor(config: DripConfig) {\n if (!config.apiKey) {\n throw new Error('Drip API key is required');\n }\n\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl || 'https://api.drip.dev/v1';\n this.timeout = config.timeout || 30000;\n }\n\n /**\n * Makes an authenticated request to the Drip API.\n * @internal\n */\n private async request<T>(\n path: string,\n options: RequestInit = {},\n ): Promise<T> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n ...options,\n signal: controller.signal,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n ...options.headers,\n },\n });\n\n if (res.status === 204) {\n return { success: true } as T;\n }\n\n const data = await res.json();\n\n if (!res.ok) {\n throw new DripError(\n data.message || data.error || 'Request failed',\n res.status,\n data.code,\n );\n }\n\n return data as T;\n } catch (error) {\n if (error instanceof DripError) {\n throw error;\n }\n if (error instanceof Error && error.name === 'AbortError') {\n throw new DripError('Request timed out', 408, 'TIMEOUT');\n }\n throw new DripError(\n error instanceof Error ? error.message : 'Unknown error',\n 0,\n 'UNKNOWN',\n );\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n // ==========================================================================\n // Health Check\n // ==========================================================================\n\n /**\n * Pings the Drip API to check connectivity and measure latency.\n *\n * Use this to verify:\n * - API key is valid\n * - Base URL is correct\n * - Network connectivity works\n *\n * @returns Health status with latency information\n * @throws {DripError} If the request fails or times out\n *\n * @example\n * ```typescript\n * const health = await drip.ping();\n * if (health.ok) {\n * console.log(`API healthy, latency: ${health.latencyMs}ms`);\n * } else {\n * console.error(`API unhealthy: ${health.status}`);\n * }\n * ```\n */\n async ping(): Promise<{ ok: boolean; status: string; latencyMs: number; timestamp: number }> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n let healthBaseUrl = this.baseUrl;\n if (healthBaseUrl.endsWith('/v1/')) {\n healthBaseUrl = healthBaseUrl.slice(0, -4);\n } else if (healthBaseUrl.endsWith('/v1')) {\n healthBaseUrl = healthBaseUrl.slice(0, -3);\n }\n healthBaseUrl = healthBaseUrl.replace(/\\/+$/, '');\n\n const start = Date.now();\n\n try {\n const response = await fetch(`${healthBaseUrl}/health`, {\n signal: controller.signal,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n },\n });\n const latencyMs = Date.now() - start;\n\n let status = 'unknown';\n let timestamp = Date.now();\n\n try {\n const data = await response.json() as { status?: string; timestamp?: number };\n if (typeof data.status === 'string') {\n status = data.status;\n }\n if (typeof data.timestamp === 'number') {\n timestamp = data.timestamp;\n }\n } catch {\n status = response.ok ? 'healthy' : `error:${response.status}`;\n }\n\n if (!response.ok && status === 'unknown') {\n status = `error:${response.status}`;\n }\n\n return {\n ok: response.ok && status === 'healthy',\n status,\n latencyMs,\n timestamp,\n };\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new DripError('Request timed out', 408, 'TIMEOUT');\n }\n throw new DripError(\n error instanceof Error ? error.message : 'Unknown error',\n 0,\n 'UNKNOWN',\n );\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n // ==========================================================================\n // Customer Methods\n // ==========================================================================\n\n /**\n * Creates a new customer in your Drip account.\n *\n * @param params - Customer creation parameters\n * @returns The created customer\n * @throws {DripError} If creation fails (e.g., duplicate customer)\n *\n * @example\n * ```typescript\n * const customer = await drip.createCustomer({\n * onchainAddress: '0x1234567890abcdef...',\n * externalCustomerId: 'user_123',\n * });\n * ```\n */\n async createCustomer(params: CreateCustomerParams): Promise<Customer> {\n return this.request<Customer>('/customers', {\n method: 'POST',\n body: JSON.stringify(params),\n });\n }\n\n /**\n * Retrieves a customer by their Drip ID.\n *\n * @param customerId - The Drip customer ID\n * @returns The customer details\n * @throws {DripError} If customer not found (404)\n */\n async getCustomer(customerId: string): Promise<Customer> {\n return this.request<Customer>(`/customers/${customerId}`);\n }\n\n /**\n * Lists all customers for your business.\n *\n * @param options - Optional filtering and pagination\n * @returns List of customers\n */\n async listCustomers(\n options?: ListCustomersOptions,\n ): Promise<ListCustomersResponse> {\n const params = new URLSearchParams();\n\n if (options?.limit) {\n params.set('limit', options.limit.toString());\n }\n if (options?.status) {\n params.set('status', options.status);\n }\n\n const query = params.toString();\n const path = query ? `/customers?${query}` : '/customers';\n\n return this.request<ListCustomersResponse>(path);\n }\n\n // ==========================================================================\n // Usage Tracking (No Billing)\n // ==========================================================================\n\n /**\n * Records usage for tracking WITHOUT billing.\n *\n * Use this for:\n * - Pilot programs (track before billing)\n * - Internal team usage\n * - Pre-billing tracking before customer setup\n *\n * For actual billing, use `charge()` from the full SDK.\n *\n * @param params - Usage tracking parameters\n * @returns The tracked usage event\n *\n * @example\n * ```typescript\n * const result = await drip.trackUsage({\n * customerId: 'cust_abc123',\n * meter: 'api_calls',\n * quantity: 100,\n * description: 'API calls during pilot',\n * });\n *\n * console.log(`Tracked: ${result.usageEventId}`);\n * ```\n */\n async trackUsage(params: TrackUsageParams): Promise<TrackUsageResult> {\n return this.request<TrackUsageResult>('/usage/internal', {\n method: 'POST',\n body: JSON.stringify({\n customerId: params.customerId,\n usageType: params.meter,\n quantity: params.quantity,\n idempotencyKey: params.idempotencyKey,\n units: params.units,\n description: params.description,\n metadata: params.metadata,\n }),\n });\n }\n\n // ==========================================================================\n // Private Workflow Methods (used by recordRun)\n // ==========================================================================\n\n private async createWorkflow(params: CreateWorkflowParams): Promise<Workflow> {\n return this.request<Workflow>('/workflows', {\n method: 'POST',\n body: JSON.stringify(params),\n });\n }\n\n private async listWorkflows(): Promise<{ data: Workflow[]; count: number }> {\n return this.request<{ data: Workflow[]; count: number }>('/workflows');\n }\n\n // ==========================================================================\n // Run & Event Methods (Execution Ledger)\n // ==========================================================================\n\n /**\n * Starts a new run for tracking execution.\n *\n * @param params - Run parameters\n * @returns The started run\n *\n * @example\n * ```typescript\n * const run = await drip.startRun({\n * customerId: 'cust_abc123',\n * workflowId: 'wf_xyz789',\n * });\n *\n * // Emit events during execution...\n * await drip.emitEvent({ runId: run.id, eventType: 'llm.call', quantity: 1000 });\n *\n * // End the run\n * await drip.endRun(run.id, { status: 'COMPLETED' });\n * ```\n */\n async startRun(params: StartRunParams): Promise<RunResult> {\n return this.request<RunResult>('/runs', {\n method: 'POST',\n body: JSON.stringify(params),\n });\n }\n\n /**\n * Ends a run with a final status.\n *\n * @param runId - The run ID to end\n * @param params - End parameters including status\n * @returns Updated run info\n */\n async endRun(runId: string, params: EndRunParams): Promise<EndRunResult> {\n return this.request<EndRunResult>(`/runs/${runId}`, {\n method: 'PATCH',\n body: JSON.stringify(params),\n });\n }\n\n /**\n * Gets a run's full timeline with events and computed totals.\n *\n * @param runId - The run ID\n * @returns Full timeline with events and summary\n *\n * @example\n * ```typescript\n * const { run, timeline, totals, summary } = await drip.getRunTimeline('run_abc123');\n *\n * console.log(`Status: ${run.status}`);\n * console.log(`Summary: ${summary}`);\n *\n * for (const event of timeline) {\n * console.log(`${event.eventType}: ${event.quantity} ${event.units}`);\n * }\n * ```\n */\n async getRunTimeline(runId: string): Promise<RunTimeline> {\n return this.request<RunTimeline>(`/runs/${runId}`);\n }\n\n /**\n * Emits an event to a run.\n *\n * @param params - Event parameters\n * @returns The created event\n *\n * @example\n * ```typescript\n * await drip.emitEvent({\n * runId: run.id,\n * eventType: 'llm.call',\n * quantity: 1500,\n * units: 'tokens',\n * description: 'GPT-4 completion',\n * });\n * ```\n */\n async emitEvent(params: EmitEventParams): Promise<EventResult> {\n return this.request<EventResult>('/events', {\n method: 'POST',\n body: JSON.stringify(params),\n });\n }\n\n /**\n * Emits multiple events in a single request.\n *\n * @param events - Array of events to emit\n * @returns Summary of created events\n */\n async emitEventsBatch(\n events: Array<EmitEventParams>,\n ): Promise<{\n success: boolean;\n created: number;\n duplicates: number;\n events: Array<{ id: string; eventType: string; isDuplicate: boolean }>;\n }> {\n return this.request('/run-events/batch', {\n method: 'POST',\n body: JSON.stringify({ events }),\n });\n }\n\n /**\n * Records a complete request/run in a single call.\n *\n * This is the **hero method** for tracking execution. It combines:\n * - Workflow creation (auto-creates if needed)\n * - Run creation\n * - Event emission\n * - Run completion\n *\n * @param params - Run parameters including events\n * @returns The created run with event summary\n *\n * @example\n * ```typescript\n * // RPC provider example\n * const result = await drip.recordRun({\n * customerId: 'cust_123',\n * workflow: 'rpc-request',\n * events: [\n * { eventType: 'request.start' },\n * { eventType: 'eth_call', quantity: 1 },\n * { eventType: 'request.end' },\n * ],\n * status: 'COMPLETED',\n * });\n *\n * // API provider example\n * const result = await drip.recordRun({\n * customerId: 'cust_123',\n * workflow: 'api-request',\n * events: [\n * { eventType: 'request.start' },\n * { eventType: 'llm.call', quantity: 2000, units: 'tokens' },\n * { eventType: 'request.end' },\n * ],\n * status: 'COMPLETED',\n * });\n *\n * console.log(result.summary);\n * // Output: \"✓ Rpc Request: 3 events recorded (152ms)\"\n * ```\n */\n async recordRun(params: RecordRunParams): Promise<RecordRunResult> {\n const startTime = Date.now();\n\n // Step 1: Ensure workflow exists (get or create)\n let workflowId = params.workflow;\n let workflowName = params.workflow;\n\n if (!params.workflow.startsWith('wf_')) {\n try {\n const workflows = await this.listWorkflows();\n const existing = workflows.data.find(\n (w) => w.slug === params.workflow || w.id === params.workflow,\n );\n\n if (existing) {\n workflowId = existing.id;\n workflowName = existing.name;\n } else {\n const created = await this.createWorkflow({\n name: params.workflow.replace(/[_-]/g, ' ').replace(/\\b\\w/g, (c) => c.toUpperCase()),\n slug: params.workflow,\n productSurface: 'CUSTOM',\n });\n workflowId = created.id;\n workflowName = created.name;\n }\n } catch {\n workflowId = params.workflow;\n }\n }\n\n // Step 2: Create the run\n const run = await this.startRun({\n customerId: params.customerId,\n workflowId,\n externalRunId: params.externalRunId,\n correlationId: params.correlationId,\n metadata: params.metadata,\n });\n\n // Step 3: Emit all events in batch\n let eventsCreated = 0;\n let eventsDuplicates = 0;\n\n if (params.events.length > 0) {\n const batchEvents = params.events.map((event, index) => ({\n runId: run.id,\n eventType: event.eventType,\n quantity: event.quantity,\n units: event.units,\n description: event.description,\n costUnits: event.costUnits,\n metadata: event.metadata,\n idempotencyKey: params.externalRunId\n ? `${params.externalRunId}:${event.eventType}:${index}`\n : undefined,\n }));\n\n const batchResult = await this.emitEventsBatch(batchEvents);\n eventsCreated = batchResult.created;\n eventsDuplicates = batchResult.duplicates;\n }\n\n // Step 4: End the run\n const endResult = await this.endRun(run.id, {\n status: params.status,\n errorMessage: params.errorMessage,\n errorCode: params.errorCode,\n });\n\n const durationMs = Date.now() - startTime;\n\n // Build summary\n const eventSummary = params.events.length > 0\n ? `${eventsCreated} events recorded`\n : 'no events';\n const statusEmoji = params.status === 'COMPLETED' ? '✓' : params.status === 'FAILED' ? '✗' : '○';\n const summary = `${statusEmoji} ${workflowName}: ${eventSummary} (${endResult.durationMs ?? durationMs}ms)`;\n\n return {\n run: {\n id: run.id,\n workflowId,\n workflowName,\n status: params.status,\n durationMs: endResult.durationMs,\n },\n events: {\n created: eventsCreated,\n duplicates: eventsDuplicates,\n },\n totalCostUnits: endResult.totalCostUnits,\n summary,\n };\n }\n}\n\n// Default export for convenience\nexport default Drip;\n"]}
package/dist/express.cjs CHANGED
@@ -1,3 +1,3 @@
1
- 'use strict';var crypto=require('crypto');var E=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var w=class{_total=0;_flushed=false;_flushCount=0;_chargeFn;_options;constructor(e,r){this._chargeFn=e,this._options=r;}get total(){return this._total}get isFlushed(){return this._flushed}get flushCount(){return this._flushCount}async add(e){return e<=0?null:(this._total+=e,this._options.onAdd?.(e,this._total),this._options.flushThreshold!==void 0&&this._total>=this._options.flushThreshold?this.flush():null)}addSync(e){e<=0||(this._total+=e,this._options.onAdd?.(e,this._total));}async flush(){let e=this._total;if(this._total=0,e===0)return {success:true,quantity:0,charge:null,isReplay:false};let r=this._options.idempotencyKey?`${this._options.idempotencyKey}_flush_${this._flushCount}`:void 0,s=await this._chargeFn({customerId:this._options.customerId,meter:this._options.meter,quantity:e,idempotencyKey:r,metadata:this._options.metadata});this._flushed=true,this._flushCount++;let i={success:s.success,quantity:e,charge:s.charge,isReplay:s.isReplay};return this._options.onFlush?.(i),i}reset(){this._total=0;}};var I={maxAttempts:3,baseDelayMs:100,maxDelayMs:5e3};function U(t){return t instanceof Error&&(t.message.includes("fetch")||t.message.includes("network"))?true:t instanceof f?t.statusCode>=500||t.statusCode===408||t.statusCode===429:false}async function N(t,e={}){let r=e.maxAttempts??I.maxAttempts,s=e.baseDelayMs??I.baseDelayMs,i=e.maxDelayMs??I.maxDelayMs,n=e.isRetryable??U,o;for(let a=1;a<=r;a++)try{return await t()}catch(c){if(o=c,a===r||!n(c))throw c;let m=Math.min(s*Math.pow(2,a-1)+Math.random()*100,i);await new Promise(d=>setTimeout(d,m));}throw o}var f=class t extends Error{constructor(r,s,i){super(r);this.statusCode=s;this.code=i;this.name="DripError",Object.setPrototypeOf(this,t.prototype);}},P=class{apiKey;baseUrl;timeout;constructor(e){if(!e.apiKey)throw new Error("Drip API key is required");this.apiKey=e.apiKey,this.baseUrl=e.baseUrl||"https://api.drip.dev/v1",this.timeout=e.timeout||3e4;}async request(e,r={}){let s=new AbortController,i=setTimeout(()=>s.abort(),this.timeout);try{let n=await fetch(`${this.baseUrl}${e}`,{...r,signal:s.signal,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,...r.headers}});if(n.status===204)return {success:!0};let o=await n.json();if(!n.ok)throw new f(o.message||o.error||"Request failed",n.status,o.code);return o}catch(n){throw n instanceof f?n:n instanceof Error&&n.name==="AbortError"?new f("Request timed out",408,"TIMEOUT"):new f(n instanceof Error?n.message:"Unknown error",0,"UNKNOWN")}finally{clearTimeout(i);}}async ping(){let e=new AbortController,r=setTimeout(()=>e.abort(),this.timeout),s=this.baseUrl;s.endsWith("/v1/")?s=s.slice(0,-4):s.endsWith("/v1")&&(s=s.slice(0,-3)),s=s.replace(/\/+$/,"");let i=Date.now();try{let n=await fetch(`${s}/health`,{signal:e.signal,headers:{Authorization:`Bearer ${this.apiKey}`}}),o=Date.now()-i,a="unknown",c=Date.now();try{let m=await n.json();typeof m.status=="string"&&(a=m.status),typeof m.timestamp=="number"&&(c=m.timestamp);}catch{a=n.ok?"healthy":`error:${n.status}`;}return !n.ok&&a==="unknown"&&(a=`error:${n.status}`),{ok:n.ok&&a==="healthy",status:a,latencyMs:o,timestamp:c}}catch(n){throw n instanceof Error&&n.name==="AbortError"?new f("Request timed out",408,"TIMEOUT"):new f(n instanceof Error?n.message:"Unknown error",0,"UNKNOWN")}finally{clearTimeout(r);}}async createCustomer(e){return this.request("/customers",{method:"POST",body:JSON.stringify(e)})}async getCustomer(e){return this.request(`/customers/${e}`)}async listCustomers(e){let r=new URLSearchParams;e?.limit&&r.set("limit",e.limit.toString()),e?.status&&r.set("status",e.status);let s=r.toString(),i=s?`/customers?${s}`:"/customers";return this.request(i)}async getBalance(e){return this.request(`/customers/${e}/balance`)}async charge(e){return this.request("/usage",{method:"POST",body:JSON.stringify({customerId:e.customerId,usageType:e.meter,quantity:e.quantity,idempotencyKey:e.idempotencyKey,metadata:e.metadata})})}async wrapApiCall(e){let r=e.idempotencyKey??`wrap_${Date.now()}_${Math.random().toString(36).slice(2,11)}`,s=await e.call(),i=e.extractUsage(s),n=await N(()=>this.charge({customerId:e.customerId,meter:e.meter,quantity:i,idempotencyKey:r,metadata:e.metadata}),e.retryOptions);return {result:s,charge:n,idempotencyKey:r}}async trackUsage(e){return this.request("/usage/internal",{method:"POST",body:JSON.stringify({customerId:e.customerId,usageType:e.meter,quantity:e.quantity,idempotencyKey:e.idempotencyKey,units:e.units,description:e.description,metadata:e.metadata})})}async getCharge(e){return this.request(`/charges/${e}`)}async listCharges(e){let r=new URLSearchParams;e?.customerId&&r.set("customerId",e.customerId),e?.status&&r.set("status",e.status),e?.limit&&r.set("limit",e.limit.toString()),e?.offset&&r.set("offset",e.offset.toString());let s=r.toString(),i=s?`/charges?${s}`:"/charges";return this.request(i)}async getChargeStatus(e){return this.request(`/charges/${e}/status`)}async checkout(e){let r=await this.request("/checkout",{method:"POST",body:JSON.stringify({customer_id:e.customerId,external_customer_id:e.externalCustomerId,amount:e.amount,return_url:e.returnUrl,cancel_url:e.cancelUrl,metadata:e.metadata})});return {id:r.id,url:r.url,expiresAt:r.expires_at,amountUsd:r.amount_usd}}async createWebhook(e){return this.request("/webhooks",{method:"POST",body:JSON.stringify(e)})}async listWebhooks(){return this.request("/webhooks")}async getWebhook(e){return this.request(`/webhooks/${e}`)}async deleteWebhook(e){return this.request(`/webhooks/${e}`,{method:"DELETE"})}async testWebhook(e){return this.request(`/webhooks/${e}/test`,{method:"POST"})}async rotateWebhookSecret(e){return this.request(`/webhooks/${e}/rotate-secret`,{method:"POST"})}async createWorkflow(e){return this.request("/workflows",{method:"POST",body:JSON.stringify(e)})}async listWorkflows(){return this.request("/workflows")}async startRun(e){return this.request("/runs",{method:"POST",body:JSON.stringify(e)})}async endRun(e,r){return this.request(`/runs/${e}`,{method:"PATCH",body:JSON.stringify(r)})}async getRunTimeline(e){return this.request(`/runs/${e}`)}async emitEvent(e){return this.request("/events",{method:"POST",body:JSON.stringify(e)})}async emitEventsBatch(e){return this.request("/run-events/batch",{method:"POST",body:JSON.stringify({events:e})})}async listMeters(){let e=await this.request("/pricing-plans");return {data:e.data.map(r=>({id:r.id,name:r.name,meter:r.unitType,unitPriceUsd:r.unitPriceUsd,isActive:r.isActive})),count:e.count}}async recordRun(e){let r=Date.now(),s=e.workflow,i=e.workflow;if(!e.workflow.startsWith("wf_"))try{let g=(await this.listWorkflows()).data.find(l=>l.slug===e.workflow||l.id===e.workflow);if(g)s=g.id,i=g.name;else {let l=await this.createWorkflow({name:e.workflow.replace(/[_-]/g," ").replace(/\b\w/g,x=>x.toUpperCase()),slug:e.workflow,productSurface:"AGENT"});s=l.id,i=l.name;}}catch{s=e.workflow;}let n=await this.startRun({customerId:e.customerId,workflowId:s,externalRunId:e.externalRunId,correlationId:e.correlationId,metadata:e.metadata}),o=0,a=0;if(e.events.length>0){let p=e.events.map((l,x)=>({runId:n.id,eventType:l.eventType,quantity:l.quantity,units:l.units,description:l.description,costUnits:l.costUnits,metadata:l.metadata,idempotencyKey:e.externalRunId?`${e.externalRunId}:${l.eventType}:${x}`:void 0})),g=await this.emitEventsBatch(p);o=g.created,a=g.duplicates;}let c=await this.endRun(n.id,{status:e.status,errorMessage:e.errorMessage,errorCode:e.errorCode}),m=Date.now()-r,d=e.events.length>0?`${o} events recorded`:"no events",y=`${e.status==="COMPLETED"?"\u2713":e.status==="FAILED"?"\u2717":"\u25CB"} ${i}: ${d} (${c.durationMs??m}ms)`;return {run:{id:n.id,workflowId:s,workflowName:i,status:e.status,durationMs:c.durationMs},events:{created:o,duplicates:a},totalCostUnits:c.totalCostUnits,summary:y}}static generateIdempotencyKey(e){let r=[e.customerId,e.runId??"no_run",e.stepName,String(e.sequence??0)],s=0,i=r.join("|");for(let n=0;n<i.length;n++){let o=i.charCodeAt(n);s=(s<<5)-s+o,s=s&s;}return `drip_${Math.abs(s).toString(36)}_${e.stepName.slice(0,16)}`}static async verifyWebhookSignature(e,r,s,i=300){if(!e||!r||!s)return false;try{let n=r.split(","),o=n.find(b=>b.startsWith("t=")),a=n.find(b=>b.startsWith("v1="));if(!o||!a)return !1;let c=parseInt(o.slice(2),10),m=a.slice(3);if(isNaN(c))return !1;let d=Math.floor(Date.now()/1e3);if(Math.abs(d-c)>i)return !1;let u=`${c}.${e}`,y=new TextEncoder,p=y.encode(s),g=y.encode(u),l=globalThis.crypto?.subtle??E("crypto").webcrypto.subtle,x=await l.importKey("raw",p,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),O=await l.sign("HMAC",x,g),k=Array.from(new Uint8Array(O)).map(b=>b.toString(16).padStart(2,"0")).join("");if(m.length!==k.length)return !1;let q=0;for(let b=0;b<m.length;b++)q|=m.charCodeAt(b)^k.charCodeAt(b);return q===0}catch{return false}}static verifyWebhookSignatureSync(e,r,s,i=300){if(!e||!r||!s)return false;try{let n=r.split(","),o=n.find(x=>x.startsWith("t=")),a=n.find(x=>x.startsWith("v1="));if(!o||!a)return !1;let c=parseInt(o.slice(2),10),m=a.slice(3);if(isNaN(c))return !1;let d=Math.floor(Date.now()/1e3);if(Math.abs(d-c)>i)return !1;let u=E("crypto"),y=`${c}.${e}`,p=u.createHmac("sha256",s).update(y).digest("hex"),g=Buffer.from(m),l=Buffer.from(p);return g.length!==l.length?!1:u.timingSafeEqual(g,l)}catch{return false}}static generateWebhookSignature(e,r,s){let i=E("crypto"),n=s??Math.floor(Date.now()/1e3),o=`${n}.${e}`,a=i.createHmac("sha256",r).update(o).digest("hex");return `t=${n},v1=${a}`}createStreamMeter(e){return new w(this.charge.bind(this),e)}};var h=class t extends Error{constructor(r,s,i,n){super(r);this.code=s;this.statusCode=i;this.details=n;this.name="DripMiddlewareError",Object.setPrototypeOf(this,t.prototype);}};var L=300,K=300,$=["x-payment-signature","x-payment-session-key","x-payment-smart-account","x-payment-timestamp","x-payment-amount","x-payment-recipient","x-payment-usage-id","x-payment-nonce"];function F(t){return t.toLowerCase()}function R(t,e){let r=F(e);if(t[r]!==void 0){let s=t[r];return Array.isArray(s)?s[0]:s}for(let[s,i]of Object.entries(t))if(s.toLowerCase()===r)return Array.isArray(i)?i[0]:i}function D(t){return $.every(e=>R(t,e)!==void 0)}function X(t){let e=R(t,"x-payment-signature"),r=R(t,"x-payment-session-key"),s=R(t,"x-payment-smart-account"),i=R(t,"x-payment-timestamp"),n=R(t,"x-payment-amount"),o=R(t,"x-payment-recipient"),a=R(t,"x-payment-usage-id"),c=R(t,"x-payment-nonce");if(!e||!r||!s||!i||!n||!o||!a||!c)return null;let m=parseInt(i,10);if(isNaN(m)||Math.floor(Date.now()/1e3)-m>K)return null;let u=(y,p)=>{if(!y.startsWith("0x"))return false;let g=y.slice(2);return g.length<p?false:/^[a-fA-F0-9]+$/.test(g)};return !u(e,130)||!u(r,64)||!u(s,40)?null:{signature:e,sessionKeyId:r,smartAccount:s,timestamp:m,amount:n,recipient:o,usageId:a,nonce:c}}function H(t){let e=Math.floor(Date.now()/1e3),r=e+(t.expiresInSec??L),s=`${e}-${crypto.randomBytes(16).toString("hex")}`,i=t.usageId;i.startsWith("0x")||(i=v(i));let n={"X-Payment-Required":"true","X-Payment-Amount":t.amount,"X-Payment-Recipient":t.recipient,"X-Payment-Usage-Id":i,"X-Payment-Description":t.description??"API usage charge","X-Payment-Expires":String(r),"X-Payment-Nonce":s,"X-Payment-Timestamp":String(e)},o={amount:t.amount,recipient:t.recipient,usageId:i,description:t.description??"API usage charge",expiresAt:r,nonce:s,timestamp:e};return {headers:n,paymentRequest:o}}function v(t){let e=5381,r=52711;for(let n=0;n<t.length;n++){let o=t.charCodeAt(n);e=(e<<5)+e^o,r=(r<<5)+r^o;}return `0x${Math.abs(e*31+r).toString(16).padStart(16,"0").slice(0,16).padEnd(64,"0")}`}async function j(t,e){let r=e.customerResolver??"header";if(typeof r=="function")return r(t);if(r==="header"){let s=R(t.headers,"x-drip-customer-id")??R(t.headers,"x-customer-id");if(!s)throw new h("Missing customer ID. Include X-Drip-Customer-Id header.","CUSTOMER_RESOLUTION_FAILED",400);return s}if(r==="query"){let s=t.query??{},i=s.drip_customer_id??s.customer_id,n=Array.isArray(i)?i[0]:i;if(!n)throw new h("Missing customer ID. Include drip_customer_id query parameter.","CUSTOMER_RESOLUTION_FAILED",400);return n}throw new h(`Invalid customer resolver: ${r}`,"CONFIGURATION_ERROR",500)}async function B(t,e){return typeof e.quantity=="function"?e.quantity(t):e.quantity}async function G(t,e,r){if(r.idempotencyKey)return r.idempotencyKey(t);let s=Date.now(),i=[t.method,t.url,e,s];return `drip_${v(i.join("|")).slice(2,18)}`}function T(t){let e=t.apiKey??process.env.DRIP_API_KEY;if(!e)throw new h("Missing Drip API key. Set DRIP_API_KEY environment variable or pass apiKey in config.","CONFIGURATION_ERROR",500);return new P({apiKey:e,baseUrl:t.baseUrl??process.env.DRIP_API_URL})}async function A(t,e){if(e.skipInDevelopment&&process.env.NODE_ENV==="development"){console.warn("[Drip] Skipping billing in development mode. Set skipInDevelopment: false or NODE_ENV to production to enable billing.");let r=T(e),s={success:true,usageEventId:"dev_usage_event",isReplay:false,charge:{id:"dev_charge",amountUsdc:"0.00",amountToken:"0",txHash:"0x0",status:"CONFIRMED"}};return {success:true,state:{customerId:"dev_customer",quantity:typeof e.quantity=="number"?e.quantity:1,idempotencyKey:"dev_idempotency",hasPaymentProof:false},charge:s,drip:r,isReplay:false}}try{let r=T(e),s=await j(t,e),i=await B(t,e),n=await G(t,s,e),o=D(t.headers),a=o?X(t.headers):void 0,c={customerId:s,quantity:i,idempotencyKey:n,hasPaymentProof:o,paymentProof:a??void 0},m=typeof e.metadata=="function"?e.metadata(t):e.metadata;try{let d=await r.charge({customerId:s,meter:e.meter,quantity:i,idempotencyKey:n,metadata:m});return e.onCharge&&await e.onCharge(d,t),{success:!0,state:c,charge:d,drip:r,isReplay:d.isReplay??!1}}catch(d){if(d instanceof f){if(d.statusCode===402){let u=process.env.DRIP_RECIPIENT_ADDRESS;if(!u)throw new h("DRIP_RECIPIENT_ADDRESS environment variable must be configured for x402 payment flow.","CONFIGURATION_ERROR",500);let y="0.01",p=d.message.match(/amount[:\s]+([0-9.]+)/i);p?y=p[1]:y=(i*1e-4).toFixed(6);let{headers:g,paymentRequest:l}=H({amount:y,recipient:u,usageId:n,description:`${e.meter} usage charge`});return {success:!1,error:new h("Insufficient balance. Payment required.","PAYMENT_REQUIRED",402),paymentRequired:{headers:g,paymentRequest:l}}}throw e.onError&&await e.onError(d,t),new h(d.message,"CHARGE_FAILED",d.statusCode,{code:d.code})}throw d}}catch(r){if(r instanceof h)return {success:false,error:r};let s=r instanceof Error?r.message:"Unknown error";return {success:false,error:new h(s,"INTERNAL_ERROR",500)}}}function S(t){let e={};for(let[r,s]of Object.entries(t))e[r.toLowerCase()]=Array.isArray(s)?s[0]:s;return e}function J(t,e,r){t.status(402).set(e).json({error:"Payment required",code:"PAYMENT_REQUIRED",paymentRequest:r,instructions:{step1:"Sign the payment request with your session key using EIP-712",step2:"Retry the request with X-Payment-* headers",documentation:"https://docs.drip.dev/x402"}});}function Y(t,e,r,s,i){t.status(s).json({error:e,code:r,...i&&{details:i}});}function M(t){let e=t.attachToRequest??true;return async(r,s,i)=>{let n={method:r.method,url:r.originalUrl||r.url,headers:S(r.headers),query:r.query},o=typeof t.quantity=="function"?await t.quantity(r):t.quantity,a;if(typeof t.customerResolver=="function"){let p=t.customerResolver;a=async()=>p(r);}else a=t.customerResolver;let c;if(typeof t.idempotencyKey=="function"){let p=t.idempotencyKey;c=async()=>p(r);}let m=typeof t.metadata=="function"?t.metadata(r):t.metadata,d={meter:t.meter,quantity:o,apiKey:t.apiKey,baseUrl:t.baseUrl,customerResolver:a,idempotencyKey:c,metadata:m,skipInDevelopment:t.skipInDevelopment,onCharge:void 0,onError:void 0},u=await A(n,d);if(!u.success){if(t.errorHandler&&await t.errorHandler(u.error,r,s))return;if(u.paymentRequired){J(s,u.paymentRequired.headers,u.paymentRequired.paymentRequest);return}Y(s,u.error.message,u.error.code,u.error.statusCode,u.error.details);return}t.onCharge&&await t.onCharge(u.charge,r);let y={drip:u.drip,customerId:u.state.customerId,charge:u.charge,isReplay:u.isReplay};e&&(r.drip=y),i();}}function Q(t){return e=>M({...t,...e})}function z(t){return D(S(t.headers))}function _(t){return "drip"in t&&typeof t.drip=="object"}function V(t){if(!_(t))throw new Error("Drip context not found on request. Ensure dripMiddleware is applied before this route.");return t.drip}
2
- exports.Drip=P;exports.DripError=f;exports.DripMiddlewareError=h;exports.createDripMiddleware=Q;exports.dripMiddleware=M;exports.getDripContext=V;exports.hasDripContext=_;exports.hasPaymentProofHeaders=z;//# sourceMappingURL=express.cjs.map
1
+ 'use strict';var crypto=require('crypto');var q=(r=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+r+'" is not supported')});var P=class{_total=0;_flushed=false;_flushCount=0;_chargeFn;_options;constructor(e,t){this._chargeFn=e,this._options=t;}get total(){return this._total}get isFlushed(){return this._flushed}get flushCount(){return this._flushCount}async add(e){return e<=0?null:(this._total+=e,this._options.onAdd?.(e,this._total),this._options.flushThreshold!==void 0&&this._total>=this._options.flushThreshold?this.flush():null)}addSync(e){e<=0||(this._total+=e,this._options.onAdd?.(e,this._total));}async flush(){let e=this._total;if(this._total=0,e===0)return {success:true,quantity:0,charge:null,isReplay:false};let t=this._options.idempotencyKey?`${this._options.idempotencyKey}_flush_${this._flushCount}`:void 0,s=await this._chargeFn({customerId:this._options.customerId,meter:this._options.meter,quantity:e,idempotencyKey:t,metadata:this._options.metadata});this._flushed=true,this._flushCount++;let i={success:s.success,quantity:e,charge:s.charge,isReplay:s.isReplay};return this._options.onFlush?.(i),i}reset(){this._total=0;}};var j={requestsPerSecond:100,burstSize:200,enabled:true},T=class{config;tokens;lastRefill;constructor(e){this.config={...j,...e},this.tokens=this.config.burstSize,this.lastRefill=Date.now();}refill(){let e=Date.now(),t=(e-this.lastRefill)/1e3;this.tokens=Math.min(this.config.burstSize,this.tokens+t*this.config.requestsPerSecond),this.lastRefill=e;}async acquire(e){if(!this.config.enabled)return true;let t=e!==void 0?Date.now()+e:void 0;for(;;){if(this.refill(),this.tokens>=1)return this.tokens-=1,true;let s=(1-this.tokens)/this.config.requestsPerSecond*1e3;if(t!==void 0){let i=t-Date.now();if(i<=0)return false;await this.sleep(Math.min(s,i));}else await this.sleep(s);}}tryAcquire(){return this.config.enabled?(this.refill(),this.tokens>=1?(this.tokens-=1,true):false):true}get availableTokens(){return this.refill(),this.tokens}sleep(e){return new Promise(t=>setTimeout(t,e))}};var k=class r extends Error{attempts;lastError;constructor(e,t){super(`Retry exhausted after ${e} attempts: ${t.message}`),this.name="RetryExhaustedError",this.attempts=e,this.lastError=t,Object.setPrototypeOf(this,r.prototype);}};function L(r,e){let t=e.baseDelayMs*Math.pow(e.exponentialBase,r);if(t=Math.min(t,e.maxDelayMs),e.jitter>0){let s=t*e.jitter;t+=Math.random()*2*s-s;}return Math.max(0,t)}function N(r,e){if(r instanceof Error){if(r.message.includes("fetch")||r.message.includes("network")||r.message.includes("ECONNREFUSED")||r.message.includes("ETIMEDOUT"))return true;let t=r.statusCode;if(t!==void 0)return e.retryableStatusCodes.includes(t)}return false}var G={failureThreshold:5,successThreshold:2,timeoutMs:3e4,enabled:true},S=class r extends Error{circuitName;timeUntilRetryMs;constructor(e,t){super(`Circuit '${e}' is open. Retry in ${Math.round(t)}ms`),this.name="CircuitBreakerOpenError",this.circuitName=e,this.timeUntilRetryMs=t,Object.setPrototypeOf(this,r.prototype);}},M=class{name;config;state="closed";failureCount=0;successCount=0;lastFailureTime=null;constructor(e,t){this.name=e,this.config={...G,...t};}getState(){return this.checkStateTransition(),this.state}checkStateTransition(){this.state==="open"&&this.lastFailureTime!==null&&Date.now()-this.lastFailureTime>=this.config.timeoutMs&&(this.state="half_open",this.successCount=0);}recordSuccess(){this.config.enabled&&(this.state==="half_open"?(this.successCount+=1,this.successCount>=this.config.successThreshold&&(this.state="closed",this.failureCount=0)):this.state==="closed"&&(this.failureCount=0));}recordFailure(){this.config.enabled&&(this.failureCount+=1,this.lastFailureTime=Date.now(),this.state==="half_open"?this.state="open":this.state==="closed"&&this.failureCount>=this.config.failureThreshold&&(this.state="open"));}allowRequest(){return !this.config.enabled||(this.checkStateTransition(),this.state==="closed")?true:this.state==="half_open"}getTimeUntilRetry(){if(this.state!=="open"||this.lastFailureTime===null)return 0;let e=Date.now()-this.lastFailureTime;return Math.max(0,this.config.timeoutMs-e)}reset(){this.state="closed",this.failureCount=0,this.successCount=0,this.lastFailureTime=null;}},D=class{windowSize;metrics=[];totalRequests=0;totalSuccesses=0;totalFailures=0;constructor(e=1e3){this.windowSize=e;}record(e){for(this.metrics.push(e),this.totalRequests+=1,e.success?this.totalSuccesses+=1:this.totalFailures+=1;this.metrics.length>this.windowSize;)this.metrics.shift();}getSummary(){if(this.metrics.length===0)return {windowSize:0,totalRequests:0,totalSuccesses:0,totalFailures:0,successRate:0,avgLatencyMs:0,minLatencyMs:0,maxLatencyMs:0,p50LatencyMs:0,p95LatencyMs:0,p99LatencyMs:0,requestsByEndpoint:{},errorsByType:{}};let e=this.metrics.map(o=>o.durationMs).sort((o,a)=>o-a),t=this.metrics.filter(o=>o.success).length,s={};for(let o of this.metrics)s[o.endpoint]=(s[o.endpoint]??0)+1;let i={};for(let o of this.metrics)o.error&&(i[o.error]=(i[o.error]??0)+1);let n=e.reduce((o,a)=>o+a,0);return {windowSize:this.metrics.length,totalRequests:this.totalRequests,totalSuccesses:this.totalSuccesses,totalFailures:this.totalFailures,successRate:t/this.metrics.length*100,avgLatencyMs:n/e.length,minLatencyMs:e[0],maxLatencyMs:e[e.length-1],p50LatencyMs:e[Math.floor(e.length*.5)],p95LatencyMs:e[Math.floor(e.length*.95)],p99LatencyMs:e[Math.floor(e.length*.99)],requestsByEndpoint:s,errorsByType:i}}reset(){this.metrics.length=0,this.totalRequests=0,this.totalSuccesses=0,this.totalFailures=0;}};function x(){return {rateLimiter:{requestsPerSecond:100,burstSize:200,enabled:true},retry:{maxRetries:3,baseDelayMs:100,maxDelayMs:1e4,exponentialBase:2,jitter:.1,retryableStatusCodes:[429,500,502,503,504],enabled:true},circuitBreaker:{failureThreshold:5,successThreshold:2,timeoutMs:3e4,enabled:true},collectMetrics:true}}function v(){return {rateLimiter:{requestsPerSecond:1e3,burstSize:2e3,enabled:true},retry:{maxRetries:2,baseDelayMs:50,maxDelayMs:5e3,exponentialBase:2,jitter:.1,retryableStatusCodes:[429,500,502,503,504],enabled:true},circuitBreaker:{failureThreshold:10,successThreshold:3,timeoutMs:15e3,enabled:true},collectMetrics:true}}var w=class{config;rateLimiter;circuitBreaker;metrics;constructor(e){this.config={...x(),...e,rateLimiter:{...x().rateLimiter,...e?.rateLimiter},retry:{...x().retry,...e?.retry},circuitBreaker:{...x().circuitBreaker,...e?.circuitBreaker}},this.rateLimiter=new T(this.config.rateLimiter),this.circuitBreaker=new M("drip_api",this.config.circuitBreaker),this.metrics=this.config.collectMetrics?new D:null;}async execute(e,t="UNKNOWN",s="unknown"){let i=performance.now(),n=0,o=null;if(!await this.rateLimiter.acquire(3e4))throw new Error("Rate limiter timeout");if(!this.circuitBreaker.allowRequest())throw new S(this.circuitBreaker.name,this.circuitBreaker.getTimeUntilRetry());for(let u=0;u<=this.config.retry.maxRetries;u++)try{let c=await e();if(this.circuitBreaker.recordSuccess(),this.metrics){let d=performance.now()-i;this.metrics.record({method:t,endpoint:s,statusCode:200,durationMs:d,success:!0,timestamp:Date.now(),retryCount:n});}return c}catch(c){if(o=c instanceof Error?c:new Error(String(c)),this.config.retry.enabled&&N(c,this.config.retry)&&u<this.config.retry.maxRetries){n+=1;let l=L(u,this.config.retry);await this.sleep(l);continue}if(this.circuitBreaker.recordFailure(),this.metrics){let l=performance.now()-i,g=c.statusCode??null;this.metrics.record({method:t,endpoint:s,statusCode:g,durationMs:l,success:false,timestamp:Date.now(),error:o.name,retryCount:n});}throw c}throw o?new k(this.config.retry.maxRetries+1,o):new Error("Unexpected execution path")}getMetrics(){return this.metrics?.getSummary()??null}getHealth(){return {circuitBreaker:{state:this.circuitBreaker.getState(),timeUntilRetryMs:this.circuitBreaker.getTimeUntilRetry()},rateLimiter:{availableTokens:this.rateLimiter.availableTokens,requestsPerSecond:this.config.rateLimiter.requestsPerSecond},metrics:this.getMetrics()}}sleep(e){return new Promise(t=>setTimeout(t,e))}};var A={maxAttempts:3,baseDelayMs:100,maxDelayMs:5e3};function z(r){return r instanceof Error&&(r.message.includes("fetch")||r.message.includes("network"))?true:r instanceof y?r.statusCode>=500||r.statusCode===408||r.statusCode===429:false}async function J(r,e={}){let t=e.maxAttempts??A.maxAttempts,s=e.baseDelayMs??A.baseDelayMs,i=e.maxDelayMs??A.maxDelayMs,n=e.isRetryable??z,o;for(let a=1;a<=t;a++)try{return await r()}catch(u){if(o=u,a===t||!n(u))throw u;let c=Math.min(s*Math.pow(2,a-1)+Math.random()*100,i);await new Promise(d=>setTimeout(d,c));}throw o}var y=class r extends Error{constructor(t,s,i){super(t);this.statusCode=s;this.code=i;this.name="DripError",Object.setPrototypeOf(this,r.prototype);}},I=class{apiKey;baseUrl;timeout;resilience;constructor(e){if(!e.apiKey)throw new Error("Drip API key is required");this.apiKey=e.apiKey,this.baseUrl=e.baseUrl||"https://api.drip.dev/v1",this.timeout=e.timeout||3e4,e.resilience===true?this.resilience=new w(x()):e.resilience==="high-throughput"?this.resilience=new w(v()):e.resilience&&typeof e.resilience=="object"?this.resilience=new w(e.resilience):this.resilience=null;}async request(e,t={}){let s=(t.method??"GET").toUpperCase();return this.resilience?this.resilience.execute(()=>this.rawRequest(e,t),s,e):this.rawRequest(e,t)}async rawRequest(e,t={}){let s=new AbortController,i=setTimeout(()=>s.abort(),this.timeout);try{let n=await fetch(`${this.baseUrl}${e}`,{...t,signal:s.signal,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,...t.headers}});if(n.status===204)return {success:!0};let o=await n.json();if(!n.ok)throw new y(o.message||o.error||"Request failed",n.status,o.code);return o}catch(n){throw n instanceof y?n:n instanceof Error&&n.name==="AbortError"?new y("Request timed out",408,"TIMEOUT"):new y(n instanceof Error?n.message:"Unknown error",0,"UNKNOWN")}finally{clearTimeout(i);}}async ping(){let e=new AbortController,t=setTimeout(()=>e.abort(),this.timeout),s=this.baseUrl;s.endsWith("/v1/")?s=s.slice(0,-4):s.endsWith("/v1")&&(s=s.slice(0,-3)),s=s.replace(/\/+$/,"");let i=Date.now();try{let n=await fetch(`${s}/health`,{signal:e.signal,headers:{Authorization:`Bearer ${this.apiKey}`}}),o=Date.now()-i,a="unknown",u=Date.now();try{let c=await n.json();typeof c.status=="string"&&(a=c.status),typeof c.timestamp=="number"&&(u=c.timestamp);}catch{a=n.ok?"healthy":`error:${n.status}`;}return !n.ok&&a==="unknown"&&(a=`error:${n.status}`),{ok:n.ok&&a==="healthy",status:a,latencyMs:o,timestamp:u}}catch(n){throw n instanceof Error&&n.name==="AbortError"?new y("Request timed out",408,"TIMEOUT"):new y(n instanceof Error?n.message:"Unknown error",0,"UNKNOWN")}finally{clearTimeout(t);}}getMetrics(){return this.resilience?.getMetrics()??null}getHealth(){return this.resilience?.getHealth()??null}async createCustomer(e){return this.request("/customers",{method:"POST",body:JSON.stringify(e)})}async getCustomer(e){return this.request(`/customers/${e}`)}async listCustomers(e){let t=new URLSearchParams;e?.limit&&t.set("limit",e.limit.toString()),e?.status&&t.set("status",e.status);let s=t.toString(),i=s?`/customers?${s}`:"/customers";return this.request(i)}async getBalance(e){return this.request(`/customers/${e}/balance`)}async charge(e){return this.request("/usage",{method:"POST",body:JSON.stringify({customerId:e.customerId,usageType:e.meter,quantity:e.quantity,idempotencyKey:e.idempotencyKey,metadata:e.metadata})})}async wrapApiCall(e){let t=e.idempotencyKey??`wrap_${Date.now()}_${Math.random().toString(36).slice(2,11)}`,s=await e.call(),i=e.extractUsage(s),n=await J(()=>this.charge({customerId:e.customerId,meter:e.meter,quantity:i,idempotencyKey:t,metadata:e.metadata}),e.retryOptions);return {result:s,charge:n,idempotencyKey:t}}async trackUsage(e){return this.request("/usage/internal",{method:"POST",body:JSON.stringify({customerId:e.customerId,usageType:e.meter,quantity:e.quantity,idempotencyKey:e.idempotencyKey,units:e.units,description:e.description,metadata:e.metadata})})}async getCharge(e){return this.request(`/charges/${e}`)}async listCharges(e){let t=new URLSearchParams;e?.customerId&&t.set("customerId",e.customerId),e?.status&&t.set("status",e.status),e?.limit&&t.set("limit",e.limit.toString()),e?.offset&&t.set("offset",e.offset.toString());let s=t.toString(),i=s?`/charges?${s}`:"/charges";return this.request(i)}async getChargeStatus(e){return this.request(`/charges/${e}/status`)}async checkout(e){let t=await this.request("/checkout",{method:"POST",body:JSON.stringify({customer_id:e.customerId,external_customer_id:e.externalCustomerId,amount:e.amount,return_url:e.returnUrl,cancel_url:e.cancelUrl,metadata:e.metadata})});return {id:t.id,url:t.url,expiresAt:t.expires_at,amountUsd:t.amount_usd}}async createWebhook(e){return this.request("/webhooks",{method:"POST",body:JSON.stringify(e)})}async listWebhooks(){return this.request("/webhooks")}async getWebhook(e){return this.request(`/webhooks/${e}`)}async deleteWebhook(e){return this.request(`/webhooks/${e}`,{method:"DELETE"})}async testWebhook(e){return this.request(`/webhooks/${e}/test`,{method:"POST"})}async rotateWebhookSecret(e){return this.request(`/webhooks/${e}/rotate-secret`,{method:"POST"})}async createWorkflow(e){return this.request("/workflows",{method:"POST",body:JSON.stringify(e)})}async listWorkflows(){return this.request("/workflows")}async startRun(e){return this.request("/runs",{method:"POST",body:JSON.stringify(e)})}async endRun(e,t){return this.request(`/runs/${e}`,{method:"PATCH",body:JSON.stringify(t)})}async getRunTimeline(e){return this.request(`/runs/${e}`)}async emitEvent(e){return this.request("/events",{method:"POST",body:JSON.stringify(e)})}async emitEventsBatch(e){return this.request("/run-events/batch",{method:"POST",body:JSON.stringify({events:e})})}async listMeters(){let e=await this.request("/pricing-plans");return {data:e.data.map(t=>({id:t.id,name:t.name,meter:t.unitType,unitPriceUsd:t.unitPriceUsd,isActive:t.isActive})),count:e.count}}async estimateFromUsage(e){let t=e.periodStart instanceof Date?e.periodStart.toISOString():e.periodStart,s=e.periodEnd instanceof Date?e.periodEnd.toISOString():e.periodEnd;return this.request("/dashboard/cost-estimate/from-usage",{method:"POST",body:JSON.stringify({customerId:e.customerId,periodStart:t,periodEnd:s,defaultUnitPrice:e.defaultUnitPrice,includeChargedEvents:e.includeChargedEvents,usageTypes:e.usageTypes,customPricing:e.customPricing})})}async estimateFromHypothetical(e){return this.request("/dashboard/cost-estimate/hypothetical",{method:"POST",body:JSON.stringify({items:e.items,defaultUnitPrice:e.defaultUnitPrice,customPricing:e.customPricing})})}async recordRun(e){let t=Date.now(),s=e.workflow,i=e.workflow;if(!e.workflow.startsWith("wf_"))try{let h=(await this.listWorkflows()).data.find(m=>m.slug===e.workflow||m.id===e.workflow);if(h)s=h.id,i=h.name;else {let m=await this.createWorkflow({name:e.workflow.replace(/[_-]/g," ").replace(/\b\w/g,b=>b.toUpperCase()),slug:e.workflow,productSurface:"AGENT"});s=m.id,i=m.name;}}catch{s=e.workflow;}let n=await this.startRun({customerId:e.customerId,workflowId:s,externalRunId:e.externalRunId,correlationId:e.correlationId,metadata:e.metadata}),o=0,a=0;if(e.events.length>0){let p=e.events.map((m,b)=>({runId:n.id,eventType:m.eventType,quantity:m.quantity,units:m.units,description:m.description,costUnits:m.costUnits,metadata:m.metadata,idempotencyKey:e.externalRunId?`${e.externalRunId}:${m.eventType}:${b}`:void 0})),h=await this.emitEventsBatch(p);o=h.created,a=h.duplicates;}let u=await this.endRun(n.id,{status:e.status,errorMessage:e.errorMessage,errorCode:e.errorCode}),c=Date.now()-t,d=e.events.length>0?`${o} events recorded`:"no events",g=`${e.status==="COMPLETED"?"\u2713":e.status==="FAILED"?"\u2717":"\u25CB"} ${i}: ${d} (${u.durationMs??c}ms)`;return {run:{id:n.id,workflowId:s,workflowName:i,status:e.status,durationMs:u.durationMs},events:{created:o,duplicates:a},totalCostUnits:u.totalCostUnits,summary:g}}static generateIdempotencyKey(e){let t=[e.customerId,e.runId??"no_run",e.stepName,String(e.sequence??0)],s=0,i=t.join("|");for(let n=0;n<i.length;n++){let o=i.charCodeAt(n);s=(s<<5)-s+o,s=s&s;}return `drip_${Math.abs(s).toString(36)}_${e.stepName.slice(0,16)}`}static async verifyWebhookSignature(e,t,s,i=300){if(!e||!t||!s)return false;try{let n=t.split(","),o=n.find(C=>C.startsWith("t=")),a=n.find(C=>C.startsWith("v1="));if(!o||!a)return !1;let u=parseInt(o.slice(2),10),c=a.slice(3);if(isNaN(u))return !1;let d=Math.floor(Date.now()/1e3);if(Math.abs(d-u)>i)return !1;let l=`${u}.${e}`,g=new TextEncoder,p=g.encode(s),h=g.encode(l),m=globalThis.crypto?.subtle??q("crypto").webcrypto.subtle,b=await m.importKey("raw",p,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),X=await m.sign("HMAC",b,h),_=Array.from(new Uint8Array(X)).map(C=>C.toString(16).padStart(2,"0")).join("");if(c.length!==_.length)return !1;let O=0;for(let C=0;C<c.length;C++)O|=c.charCodeAt(C)^_.charCodeAt(C);return O===0}catch{return false}}static verifyWebhookSignatureSync(e,t,s,i=300){if(!e||!t||!s)return false;try{let n=t.split(","),o=n.find(b=>b.startsWith("t=")),a=n.find(b=>b.startsWith("v1="));if(!o||!a)return !1;let u=parseInt(o.slice(2),10),c=a.slice(3);if(isNaN(u))return !1;let d=Math.floor(Date.now()/1e3);if(Math.abs(d-u)>i)return !1;let l=q("crypto"),g=`${u}.${e}`,p=l.createHmac("sha256",s).update(g).digest("hex"),h=Buffer.from(c),m=Buffer.from(p);return h.length!==m.length?!1:l.timingSafeEqual(h,m)}catch{return false}}static generateWebhookSignature(e,t,s){let i=q("crypto"),n=s??Math.floor(Date.now()/1e3),o=`${n}.${e}`,a=i.createHmac("sha256",t).update(o).digest("hex");return `t=${n},v1=${a}`}createStreamMeter(e){return new P(this.charge.bind(this),e)}};var f=class r extends Error{constructor(t,s,i,n){super(t);this.code=s;this.statusCode=i;this.details=n;this.name="DripMiddlewareError",Object.setPrototypeOf(this,r.prototype);}};var Q=300,V=300,Z=["x-payment-signature","x-payment-session-key","x-payment-smart-account","x-payment-timestamp","x-payment-amount","x-payment-recipient","x-payment-usage-id","x-payment-nonce"];function ee(r){return r.toLowerCase()}function R(r,e){let t=ee(e);if(r[t]!==void 0){let s=r[t];return Array.isArray(s)?s[0]:s}for(let[s,i]of Object.entries(r))if(s.toLowerCase()===t)return Array.isArray(i)?i[0]:i}function U(r){return Z.every(e=>R(r,e)!==void 0)}function te(r){let e=R(r,"x-payment-signature"),t=R(r,"x-payment-session-key"),s=R(r,"x-payment-smart-account"),i=R(r,"x-payment-timestamp"),n=R(r,"x-payment-amount"),o=R(r,"x-payment-recipient"),a=R(r,"x-payment-usage-id"),u=R(r,"x-payment-nonce");if(!e||!t||!s||!i||!n||!o||!a||!u)return null;let c=parseInt(i,10);if(isNaN(c)||Math.floor(Date.now()/1e3)-c>V)return null;let l=(g,p)=>{if(!g.startsWith("0x"))return false;let h=g.slice(2);return h.length<p?false:/^[a-fA-F0-9]+$/.test(h)};return !l(e,130)||!l(t,64)||!l(s,40)?null:{signature:e,sessionKeyId:t,smartAccount:s,timestamp:c,amount:n,recipient:o,usageId:a,nonce:u}}function re(r){let e=Math.floor(Date.now()/1e3),t=e+(r.expiresInSec??Q),s=`${e}-${crypto.randomBytes(16).toString("hex")}`,i=r.usageId;i.startsWith("0x")||(i=W(i));let n={"X-Payment-Required":"true","X-Payment-Amount":r.amount,"X-Payment-Recipient":r.recipient,"X-Payment-Usage-Id":i,"X-Payment-Description":r.description??"API usage charge","X-Payment-Expires":String(t),"X-Payment-Nonce":s,"X-Payment-Timestamp":String(e)},o={amount:r.amount,recipient:r.recipient,usageId:i,description:r.description??"API usage charge",expiresAt:t,nonce:s,timestamp:e};return {headers:n,paymentRequest:o}}function W(r){let e=5381,t=52711;for(let n=0;n<r.length;n++){let o=r.charCodeAt(n);e=(e<<5)+e^o,t=(t<<5)+t^o;}return `0x${Math.abs(e*31+t).toString(16).padStart(16,"0").slice(0,16).padEnd(64,"0")}`}async function se(r,e){let t=e.customerResolver??"header";if(typeof t=="function")return t(r);if(t==="header"){let s=R(r.headers,"x-drip-customer-id")??R(r.headers,"x-customer-id");if(!s)throw new f("Missing customer ID. Include X-Drip-Customer-Id header.","CUSTOMER_RESOLUTION_FAILED",400);return s}if(t==="query"){let s=r.query??{},i=s.drip_customer_id??s.customer_id,n=Array.isArray(i)?i[0]:i;if(!n)throw new f("Missing customer ID. Include drip_customer_id query parameter.","CUSTOMER_RESOLUTION_FAILED",400);return n}throw new f(`Invalid customer resolver: ${t}`,"CONFIGURATION_ERROR",500)}async function ne(r,e){return typeof e.quantity=="function"?e.quantity(r):e.quantity}async function ie(r,e,t){if(t.idempotencyKey)return t.idempotencyKey(r);let s=Date.now(),i=[r.method,r.url,e,s];return `drip_${W(i.join("|")).slice(2,18)}`}function F(r){let e=r.apiKey??process.env.DRIP_API_KEY;if(!e)throw new f("Missing Drip API key. Set DRIP_API_KEY environment variable or pass apiKey in config.","CONFIGURATION_ERROR",500);return new I({apiKey:e,baseUrl:r.baseUrl??process.env.DRIP_API_URL})}async function B(r,e){if(e.skipInDevelopment&&process.env.NODE_ENV==="development"){console.warn("[Drip] Skipping billing in development mode. Set skipInDevelopment: false or NODE_ENV to production to enable billing.");let t=F(e),s={success:true,usageEventId:"dev_usage_event",isReplay:false,charge:{id:"dev_charge",amountUsdc:"0.00",amountToken:"0",txHash:"0x0",status:"CONFIRMED"}};return {success:true,state:{customerId:"dev_customer",quantity:typeof e.quantity=="number"?e.quantity:1,idempotencyKey:"dev_idempotency",hasPaymentProof:false},charge:s,drip:t,isReplay:false}}try{let t=F(e),s=await se(r,e),i=await ne(r,e),n=await ie(r,s,e),o=U(r.headers),a=o?te(r.headers):void 0,u={customerId:s,quantity:i,idempotencyKey:n,hasPaymentProof:o,paymentProof:a??void 0},c=typeof e.metadata=="function"?e.metadata(r):e.metadata;try{let d=await t.charge({customerId:s,meter:e.meter,quantity:i,idempotencyKey:n,metadata:c});return e.onCharge&&await e.onCharge(d,r),{success:!0,state:u,charge:d,drip:t,isReplay:d.isReplay??!1}}catch(d){if(d instanceof y){if(d.statusCode===402){let l=process.env.DRIP_RECIPIENT_ADDRESS;if(!l)throw new f("DRIP_RECIPIENT_ADDRESS environment variable must be configured for x402 payment flow.","CONFIGURATION_ERROR",500);let g="0.01",p=d.message.match(/amount[:\s]+([0-9.]+)/i);p?g=p[1]:g=(i*1e-4).toFixed(6);let{headers:h,paymentRequest:m}=re({amount:g,recipient:l,usageId:n,description:`${e.meter} usage charge`});return {success:!1,error:new f("Insufficient balance. Payment required.","PAYMENT_REQUIRED",402),paymentRequired:{headers:h,paymentRequest:m}}}throw e.onError&&await e.onError(d,r),new f(d.message,"CHARGE_FAILED",d.statusCode,{code:d.code})}throw d}}catch(t){if(t instanceof f)return {success:false,error:t};let s=t instanceof Error?t.message:"Unknown error";return {success:false,error:new f(s,"INTERNAL_ERROR",500)}}}function K(r){let e={};for(let[t,s]of Object.entries(r))e[t.toLowerCase()]=Array.isArray(s)?s[0]:s;return e}function oe(r,e,t){r.status(402).set(e).json({error:"Payment required",code:"PAYMENT_REQUIRED",paymentRequest:t,instructions:{step1:"Sign the payment request with your session key using EIP-712",step2:"Retry the request with X-Payment-* headers",documentation:"https://docs.drip.dev/x402"}});}function ae(r,e,t,s,i){r.status(s).json({error:e,code:t,...i&&{details:i}});}function $(r){let e=r.attachToRequest??true;return async(t,s,i)=>{let n={method:t.method,url:t.originalUrl||t.url,headers:K(t.headers),query:t.query},o=typeof r.quantity=="function"?await r.quantity(t):r.quantity,a;if(typeof r.customerResolver=="function"){let p=r.customerResolver;a=async()=>p(t);}else a=r.customerResolver;let u;if(typeof r.idempotencyKey=="function"){let p=r.idempotencyKey;u=async()=>p(t);}let c=typeof r.metadata=="function"?r.metadata(t):r.metadata,d={meter:r.meter,quantity:o,apiKey:r.apiKey,baseUrl:r.baseUrl,customerResolver:a,idempotencyKey:u,metadata:c,skipInDevelopment:r.skipInDevelopment,onCharge:void 0,onError:void 0},l=await B(n,d);if(!l.success){if(r.errorHandler&&await r.errorHandler(l.error,t,s))return;if(l.paymentRequired){oe(s,l.paymentRequired.headers,l.paymentRequired.paymentRequest);return}ae(s,l.error.message,l.error.code,l.error.statusCode,l.error.details);return}r.onCharge&&await r.onCharge(l.charge,t);let g={drip:l.drip,customerId:l.state.customerId,charge:l.charge,isReplay:l.isReplay};e&&(t.drip=g),i();}}function ue(r){return e=>$({...r,...e})}function ce(r){return U(K(r.headers))}function H(r){return "drip"in r&&typeof r.drip=="object"}function le(r){if(!H(r))throw new Error("Drip context not found on request. Ensure dripMiddleware is applied before this route.");return r.drip}
2
+ exports.Drip=I;exports.DripError=y;exports.DripMiddlewareError=f;exports.createDripMiddleware=ue;exports.dripMiddleware=$;exports.getDripContext=le;exports.hasDripContext=H;exports.hasPaymentProofHeaders=ce;//# sourceMappingURL=express.cjs.map
3
3
  //# sourceMappingURL=express.cjs.map