@drip-sdk/node 1.1.0 → 1.1.2

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.
package/dist/core.cjs.map CHANGED
@@ -1 +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.cjs","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"]}
1
+ {"version":3,"sources":["../src/idempotency.ts","../src/core.ts"],"names":["_callCounter","deterministicIdempotencyKey","prefix","components","seq","parts","c","hash","createHash","DripError","_DripError","message","statusCode","code","Drip","config","apiKey","baseUrl","path","options","controller","timeoutId","res","data","error","healthBaseUrl","start","response","latencyMs","status","timestamp","params","customerId","query","idempotencyKey","runId","events","err","startTime","workflowId","workflowName","workflows","match","w","created","run","eventsCreated","eventsDuplicates","batchEvents","evt","i","batchResult","endResult","durationMs","statusIcon","core_default","_singleton","getSingleton","drip","_target","prop","instance","value"],"mappings":"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","file":"core.cjs","sourcesContent":["/**\n * Deterministic idempotency key generation for SDK calls.\n *\n * Keys are:\n * - **Unique per call** — a monotonic counter ensures two rapid calls with\n * identical parameters produce different keys.\n * - **Stable across retries** — the key is generated once per SDK method\n * invocation and reused for every retry attempt.\n * - **Deterministic** — no randomness; keys are reproducible given the same\n * counter state.\n *\n * @internal\n */\nimport { createHash } from 'crypto';\n\nlet _callCounter = 0;\n\n/**\n * Generate a deterministic, unique idempotency key.\n *\n * @param prefix - Short prefix for the key type (e.g. `chg`, `track`, `evt`, `run`, `stream`)\n * @param components - Call-specific values (customerId, meter, quantity, etc.)\n * @returns A key like `chg_<24-char hex hash>`\n */\nexport function deterministicIdempotencyKey(\n prefix: string,\n ...components: Array<string | number | undefined>\n): string {\n const seq = ++_callCounter;\n const parts = components.filter((c) => c !== undefined).map(String);\n parts.push(String(seq));\n const hash = createHash('sha256').update(parts.join('|')).digest('hex').slice(0, 24);\n return `${prefix}_${hash}`;\n}\n\n/**\n * Reset counter — only for tests.\n * @internal\n */\nexport function _resetCallCounter(): void {\n _callCounter = 0;\n}\n","/**\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\nimport { deterministicIdempotencyKey } from './idempotency.js';\n\n// ============================================================================\n// Configuration Types\n// ============================================================================\n\n/**\n * Configuration options for the Drip SDK client.\n *\n * All fields are optional - the SDK will read from environment variables:\n * - `DRIP_API_KEY` - Your Drip API key\n * - `DRIP_BASE_URL` - Override API base URL (optional)\n */\nexport interface DripConfig {\n /**\n * Your Drip API key. Obtain this from the Drip dashboard.\n * Falls back to `DRIP_API_KEY` environment variable if not provided.\n *\n * Supports both key types:\n * - **Secret keys** (`sk_live_...` / `sk_test_...`): Full access to all endpoints\n * - **Public keys** (`pk_live_...` / `pk_test_...`): Safe for client-side use.\n * Can access usage tracking, customers, runs, and events.\n *\n * @example \"sk_live_abc123...\" or \"pk_live_abc123...\"\n */\n apiKey?: string;\n\n /**\n * Base URL for the Drip API. Defaults to production API.\n * Falls back to `DRIP_BASE_URL` environment variable if not provided.\n * @default \"https://drip-app-hlunj.ondigitalocean.app/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 * At least one of `externalCustomerId` or `onchainAddress` is required.\n * @example \"user_12345\"\n */\n externalCustomerId?: string;\n\n /**\n * The customer's Drip Smart Account address (derived from their EOA).\n * At least one of `externalCustomerId` or `onchainAddress` is required.\n * @example \"0x1234567890abcdef...\"\n */\n onchainAddress?: string;\n\n /**\n * Whether this customer is internal-only (usage tracked but not billed).\n * @default false\n */\n isInternal?: boolean;\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 (null for internal-only customers) */\n onchainAddress: string | null;\n\n /** Whether this customer is internal-only (usage tracked but not billed) */\n isInternal?: boolean;\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 * Auto-generated if not provided, ensuring every call is individually trackable.\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 from GET /runs/:id/timeline.\n */\nexport interface RunTimeline {\n runId: string;\n workflowId: string | null;\n customerId: string;\n status: RunStatus;\n startedAt: string | null;\n endedAt: string | null;\n durationMs: number | null;\n events: Array<{\n id: string;\n eventType: string;\n actionName: string | null;\n outcome: 'SUCCESS' | 'FAILED' | 'PENDING' | 'TIMEOUT' | 'RETRYING';\n explanation: string | null;\n description: string | null;\n timestamp: string;\n durationMs: number | null;\n parentEventId: string | null;\n retryOfEventId: string | null;\n attemptNumber: number;\n retriedByEventId: string | null;\n costUsdc: string | null;\n isRetry: boolean;\n retryChain: {\n totalAttempts: number;\n finalOutcome: string;\n events: string[];\n } | null;\n metadata: {\n usageType: string;\n quantity: number;\n units: string | null;\n } | null;\n }>;\n anomalies: Array<{\n id: string;\n type: string;\n severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';\n title: string;\n explanation: string;\n relatedEventIds: string[];\n detectedAt: string;\n status: 'OPEN' | 'INVESTIGATING' | 'RESOLVED' | 'FALSE_POSITIVE' | 'IGNORED';\n }>;\n summary: {\n totalEvents: number;\n byType: Record<string, number>;\n byOutcome: Record<string, number>;\n retriedEvents: number;\n failedEvents: number;\n totalCostUsdc: string | null;\n };\n hasMore: boolean;\n nextCursor: string | null;\n}\n\n/**\n * Run details response from GET /runs/:id.\n */\nexport interface RunDetails {\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 totals: {\n eventCount: number;\n totalQuantity: string;\n totalCostUnits: string;\n };\n _links: {\n timeline: string;\n };\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?: 'API' | '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 * The type of API key being used.\n *\n * - `'secret'` — Full access (sk_live_... / sk_test_...)\n * - `'public'` — Client-safe, restricted access (pk_live_... / pk_test_...)\n * - `'unknown'` — Key format not recognized (legacy or custom)\n */\n readonly keyType: 'secret' | 'public' | 'unknown';\n\n /**\n * Creates a new Drip SDK client.\n *\n * @param config - Configuration options (all optional, reads from env vars)\n * @throws {Error} If apiKey is not provided and DRIP_API_KEY env var is not set\n *\n * @example\n * ```typescript\n * // Option 1: Explicit config\n * const drip = new Drip({ apiKey: 'your-api-key' });\n *\n * // Option 2: Auto-config from environment (recommended)\n * // Set DRIP_API_KEY env var, then:\n * const drip = new Drip();\n *\n * // Option 3: Use pre-initialized singleton\n * import { drip } from '@drip-sdk/node';\n * ```\n */\n constructor(config: DripConfig = {}) {\n // Read from config or fall back to environment variables\n const apiKey = config.apiKey ?? (typeof process !== 'undefined' ? process.env.DRIP_API_KEY : undefined);\n const baseUrl = config.baseUrl ?? (typeof process !== 'undefined' ? process.env.DRIP_BASE_URL : undefined);\n\n if (!apiKey) {\n throw new Error(\n 'Drip API key is required. Either pass { apiKey } to constructor or set DRIP_API_KEY environment variable.'\n );\n }\n\n this.apiKey = apiKey;\n this.baseUrl = baseUrl || 'https://drip-app-hlunj.ondigitalocean.app/v1';\n this.timeout = config.timeout || 30000;\n\n // Detect key type from prefix\n if (apiKey.startsWith('sk_')) {\n this.keyType = 'secret';\n } else if (apiKey.startsWith('pk_')) {\n this.keyType = 'public';\n } else {\n this.keyType = 'unknown';\n }\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 const idempotencyKey = params.idempotencyKey\n ?? deterministicIdempotencyKey('track', params.customerId, params.meter, params.quantity);\n\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,\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 run details with summary totals.\n *\n * For full event history with retry chains and anomalies, use `getRunTimeline()`.\n *\n * @param runId - The run ID\n * @returns Run details with totals\n *\n * @example\n * ```typescript\n * const run = await drip.getRun('run_abc123');\n * console.log(`Status: ${run.status}, Events: ${run.totals.eventCount}`);\n * ```\n */\n async getRun(runId: string): Promise<RunDetails> {\n return this.request<RunDetails>(`/runs/${runId}`);\n }\n\n /**\n * Gets a run's full timeline with events, anomalies, and analytics.\n *\n * @param runId - The run ID\n * @param options - Pagination and filtering options\n * @returns Full timeline with events, anomalies, and summary\n *\n * @example\n * ```typescript\n * const timeline = await drip.getRunTimeline('run_abc123');\n *\n * console.log(`Status: ${timeline.status}`);\n * console.log(`Events: ${timeline.summary.totalEvents}`);\n *\n * for (const event of timeline.events) {\n * console.log(`${event.eventType}: ${event.outcome}`);\n * }\n * ```\n */\n async getRunTimeline(\n runId: string,\n options?: { limit?: number; cursor?: string; includeAnomalies?: boolean; collapseRetries?: boolean },\n ): Promise<RunTimeline> {\n const params = new URLSearchParams();\n if (options?.limit) params.set('limit', options.limit.toString());\n if (options?.cursor) params.set('cursor', options.cursor);\n if (options?.includeAnomalies !== undefined) params.set('includeAnomalies', String(options.includeAnomalies));\n if (options?.collapseRetries !== undefined) params.set('collapseRetries', String(options.collapseRetries));\n\n const query = params.toString();\n const path = query ? `/runs/${runId}/timeline?${query}` : `/runs/${runId}/timeline`;\n\n return this.request<RunTimeline>(path);\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 const idempotencyKey = params.idempotencyKey\n ?? deterministicIdempotencyKey('evt', params.runId, params.eventType, params.quantity);\n\n return this.request<EventResult>('/run-events', {\n method: 'POST',\n body: JSON.stringify({ ...params, idempotencyKey }),\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 skipped: number;\n events: Array<{ id: string; eventType: string; isDuplicate: boolean; skipped?: boolean; reason?: string }>;\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 // Try single-call endpoint first; fall back to 4-step orchestration\n // if the server doesn't support it yet (404).\n try {\n return await this.request<RecordRunResult>('/runs/record', {\n method: 'POST',\n body: JSON.stringify({\n customerId: params.customerId,\n workflow: params.workflow,\n events: params.events,\n status: params.status,\n errorMessage: params.errorMessage,\n errorCode: params.errorCode,\n externalRunId: params.externalRunId,\n correlationId: params.correlationId,\n metadata: params.metadata,\n }),\n });\n } catch (err) {\n if (err instanceof DripError && err.statusCode === 404) {\n return this._recordRunFallback(params);\n }\n throw err;\n }\n }\n\n /**\n * 4-step orchestration fallback for servers without POST /runs/record.\n * @internal\n */\n private async _recordRunFallback(params: RecordRunParams): Promise<RecordRunResult> {\n const startTime = Date.now();\n\n // Step 1: Resolve workflow\n let workflowId = params.workflow;\n let workflowName = params.workflow;\n const { data: workflows } = await this.listWorkflows();\n const match = workflows.find(\n (w) => w.slug === params.workflow || w.id === params.workflow,\n );\n if (match) {\n workflowId = match.id;\n workflowName = match.name;\n } else {\n const created = await this.request<Workflow>('/workflows', {\n method: 'POST',\n body: JSON.stringify({\n name: params.workflow.replace(/[_-]/g, ' ').replace(/\\b\\w/g, (c) => c.toUpperCase()),\n slug: params.workflow,\n productSurface: 'CUSTOM',\n }),\n });\n workflowId = created.id;\n workflowName = created.name;\n }\n\n // Step 2: Start run\n const run = await this.startRun({\n customerId: params.customerId,\n workflowId,\n correlationId: params.correlationId,\n externalRunId: params.externalRunId,\n metadata: params.metadata,\n });\n\n // Step 3: Emit events\n let eventsCreated = 0;\n let eventsDuplicates = 0;\n if (params.events.length > 0) {\n const batchEvents = params.events.map((evt, i) => ({\n runId: run.id,\n eventType: evt.eventType,\n quantity: evt.quantity ?? 1,\n units: evt.units,\n description: evt.description,\n costUnits: evt.costUnits,\n metadata: evt.metadata,\n idempotencyKey: params.externalRunId\n ? `${params.externalRunId}:${evt.eventType}:${i}`\n : undefined,\n }));\n const batchResult = await this.emitEventsBatch(batchEvents);\n eventsCreated = batchResult.created;\n eventsDuplicates = batchResult.duplicates;\n }\n\n // Step 4: End 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 const statusIcon = params.status === 'COMPLETED' ? '\\u2713' : params.status === 'FAILED' ? '\\u2717' : '\\u25CB';\n\n return {\n run: {\n id: run.id,\n workflowId,\n workflowName,\n status: endResult.status as RunStatus,\n durationMs: endResult.durationMs ?? durationMs,\n },\n events: { created: eventsCreated, duplicates: eventsDuplicates },\n totalCostUnits: endResult.totalCostUnits ?? null,\n summary: `${statusIcon} ${workflowName}: ${eventsCreated} events recorded (${endResult.durationMs ?? durationMs}ms)`,\n };\n }\n}\n\n// Default export for convenience\nexport default Drip;\n\n// ============================================================================\n// Pre-initialized Singleton\n// ============================================================================\n\n/**\n * Pre-initialized Drip client singleton.\n *\n * Reads configuration from environment variables:\n * - `DRIP_API_KEY` (required)\n * - `DRIP_BASE_URL` (optional)\n *\n * @example\n * ```typescript\n * import { drip } from '@drip-sdk/node';\n *\n * // One line to track usage\n * await drip.trackUsage({ customerId: 'cust_123', meter: 'api_calls', quantity: 1 });\n * ```\n *\n * @throws {Error} on first use if DRIP_API_KEY is not set\n */\nlet _singleton: Drip | null = null;\n\nfunction getSingleton(): Drip {\n if (!_singleton) {\n _singleton = new Drip();\n }\n return _singleton;\n}\n\n/**\n * Pre-initialized Drip client singleton.\n *\n * Uses lazy initialization - only creates the client when first accessed.\n * Reads `DRIP_API_KEY` from environment variables.\n *\n * @example\n * ```typescript\n * import { drip } from '@drip-sdk/node';\n *\n * // Track usage with one line\n * await drip.trackUsage({ customerId: 'cust_123', meter: 'api_calls', quantity: 1 });\n *\n * // Record a run\n * await drip.recordRun({\n * customerId: 'cust_123',\n * workflow: 'agent-run',\n * events: [{ eventType: 'llm.call', quantity: 1000, units: 'tokens' }],\n * status: 'COMPLETED',\n * });\n * ```\n */\nexport const drip: Drip = new Proxy({} as Drip, {\n get(_target, prop) {\n const instance = getSingleton();\n const value = instance[prop as keyof Drip];\n if (typeof value === 'function') {\n return value.bind(instance);\n }\n return value;\n },\n});\n"]}
package/dist/core.d.cts CHANGED
@@ -12,17 +12,28 @@
12
12
  */
13
13
  /**
14
14
  * Configuration options for the Drip SDK client.
15
+ *
16
+ * All fields are optional - the SDK will read from environment variables:
17
+ * - `DRIP_API_KEY` - Your Drip API key
18
+ * - `DRIP_BASE_URL` - Override API base URL (optional)
15
19
  */
16
20
  interface DripConfig {
17
21
  /**
18
22
  * Your Drip API key. Obtain this from the Drip dashboard.
19
- * @example "drip_live_abc123..."
23
+ * Falls back to `DRIP_API_KEY` environment variable if not provided.
24
+ *
25
+ * Supports both key types:
26
+ * - **Secret keys** (`sk_live_...` / `sk_test_...`): Full access to all endpoints
27
+ * - **Public keys** (`pk_live_...` / `pk_test_...`): Safe for client-side use.
28
+ * Can access usage tracking, customers, runs, and events.
29
+ *
30
+ * @example "sk_live_abc123..." or "pk_live_abc123..."
20
31
  */
21
- apiKey: string;
32
+ apiKey?: string;
22
33
  /**
23
34
  * Base URL for the Drip API. Defaults to production API.
24
- * Override for staging/development environments.
25
- * @default "https://api.drip.dev/v1"
35
+ * Falls back to `DRIP_BASE_URL` environment variable if not provided.
36
+ * @default "https://drip-app-hlunj.ondigitalocean.app/v1"
26
37
  */
27
38
  baseUrl?: string;
28
39
  /**
@@ -37,14 +48,21 @@ interface DripConfig {
37
48
  interface CreateCustomerParams {
38
49
  /**
39
50
  * Your internal customer/user ID for reconciliation.
51
+ * At least one of `externalCustomerId` or `onchainAddress` is required.
40
52
  * @example "user_12345"
41
53
  */
42
54
  externalCustomerId?: string;
43
55
  /**
44
56
  * The customer's Drip Smart Account address (derived from their EOA).
57
+ * At least one of `externalCustomerId` or `onchainAddress` is required.
45
58
  * @example "0x1234567890abcdef..."
46
59
  */
47
- onchainAddress: string;
60
+ onchainAddress?: string;
61
+ /**
62
+ * Whether this customer is internal-only (usage tracked but not billed).
63
+ * @default false
64
+ */
65
+ isInternal?: boolean;
48
66
  /**
49
67
  * Additional metadata to store with the customer.
50
68
  */
@@ -60,8 +78,10 @@ interface Customer {
60
78
  businessId?: string;
61
79
  /** Your external customer ID (if provided) */
62
80
  externalCustomerId: string | null;
63
- /** Customer's on-chain address */
64
- onchainAddress: string;
81
+ /** Customer's on-chain address (null for internal-only customers) */
82
+ onchainAddress: string | null;
83
+ /** Whether this customer is internal-only (usage tracked but not billed) */
84
+ isInternal?: boolean;
65
85
  /** Custom metadata */
66
86
  metadata: Record<string, unknown> | null;
67
87
  /** ISO timestamp of creation */
@@ -110,6 +130,7 @@ interface TrackUsageParams {
110
130
  quantity: number;
111
131
  /**
112
132
  * Unique key to prevent duplicate records.
133
+ * Auto-generated if not provided, ensuring every call is individually trackable.
113
134
  */
114
135
  idempotencyKey?: string;
115
136
  /**
@@ -312,47 +333,88 @@ interface RecordRunResult {
312
333
  summary: string;
313
334
  }
314
335
  /**
315
- * Full run timeline response.
336
+ * Full run timeline response from GET /runs/:id/timeline.
316
337
  */
317
338
  interface RunTimeline {
318
- run: {
319
- id: string;
320
- customerId: string;
321
- customerName: string | null;
322
- workflowId: string;
323
- workflowName: string;
324
- status: RunStatus;
325
- startedAt: string | null;
326
- endedAt: string | null;
327
- durationMs: number | null;
328
- errorMessage: string | null;
329
- errorCode: string | null;
330
- correlationId: string | null;
331
- metadata: Record<string, unknown> | null;
332
- };
333
- timeline: Array<{
339
+ runId: string;
340
+ workflowId: string | null;
341
+ customerId: string;
342
+ status: RunStatus;
343
+ startedAt: string | null;
344
+ endedAt: string | null;
345
+ durationMs: number | null;
346
+ events: Array<{
334
347
  id: string;
335
348
  eventType: string;
336
- quantity: number;
337
- units: string | null;
349
+ actionName: string | null;
350
+ outcome: 'SUCCESS' | 'FAILED' | 'PENDING' | 'TIMEOUT' | 'RETRYING';
351
+ explanation: string | null;
338
352
  description: string | null;
339
- costUnits: number | null;
340
353
  timestamp: string;
341
- correlationId: string | null;
354
+ durationMs: number | null;
342
355
  parentEventId: string | null;
343
- charge: {
344
- id: string;
345
- amountUsdc: string;
346
- status: string;
356
+ retryOfEventId: string | null;
357
+ attemptNumber: number;
358
+ retriedByEventId: string | null;
359
+ costUsdc: string | null;
360
+ isRetry: boolean;
361
+ retryChain: {
362
+ totalAttempts: number;
363
+ finalOutcome: string;
364
+ events: string[];
365
+ } | null;
366
+ metadata: {
367
+ usageType: string;
368
+ quantity: number;
369
+ units: string | null;
347
370
  } | null;
348
371
  }>;
372
+ anomalies: Array<{
373
+ id: string;
374
+ type: string;
375
+ severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
376
+ title: string;
377
+ explanation: string;
378
+ relatedEventIds: string[];
379
+ detectedAt: string;
380
+ status: 'OPEN' | 'INVESTIGATING' | 'RESOLVED' | 'FALSE_POSITIVE' | 'IGNORED';
381
+ }>;
382
+ summary: {
383
+ totalEvents: number;
384
+ byType: Record<string, number>;
385
+ byOutcome: Record<string, number>;
386
+ retriedEvents: number;
387
+ failedEvents: number;
388
+ totalCostUsdc: string | null;
389
+ };
390
+ hasMore: boolean;
391
+ nextCursor: string | null;
392
+ }
393
+ /**
394
+ * Run details response from GET /runs/:id.
395
+ */
396
+ interface RunDetails {
397
+ id: string;
398
+ customerId: string;
399
+ customerName: string | null;
400
+ workflowId: string;
401
+ workflowName: string;
402
+ status: RunStatus;
403
+ startedAt: string | null;
404
+ endedAt: string | null;
405
+ durationMs: number | null;
406
+ errorMessage: string | null;
407
+ errorCode: string | null;
408
+ correlationId: string | null;
409
+ metadata: Record<string, unknown> | null;
349
410
  totals: {
350
411
  eventCount: number;
351
412
  totalQuantity: string;
352
413
  totalCostUnits: string;
353
- totalChargedUsdc: string;
354
414
  };
355
- summary: string;
415
+ _links: {
416
+ timeline: string;
417
+ };
356
418
  }
357
419
  /**
358
420
  * Error thrown by Drip SDK operations.
@@ -410,13 +472,34 @@ declare class Drip {
410
472
  private readonly apiKey;
411
473
  private readonly baseUrl;
412
474
  private readonly timeout;
475
+ /**
476
+ * The type of API key being used.
477
+ *
478
+ * - `'secret'` — Full access (sk_live_... / sk_test_...)
479
+ * - `'public'` — Client-safe, restricted access (pk_live_... / pk_test_...)
480
+ * - `'unknown'` — Key format not recognized (legacy or custom)
481
+ */
482
+ readonly keyType: 'secret' | 'public' | 'unknown';
413
483
  /**
414
484
  * Creates a new Drip SDK client.
415
485
  *
416
- * @param config - Configuration options
417
- * @throws {Error} If apiKey is not provided
486
+ * @param config - Configuration options (all optional, reads from env vars)
487
+ * @throws {Error} If apiKey is not provided and DRIP_API_KEY env var is not set
488
+ *
489
+ * @example
490
+ * ```typescript
491
+ * // Option 1: Explicit config
492
+ * const drip = new Drip({ apiKey: 'your-api-key' });
493
+ *
494
+ * // Option 2: Auto-config from environment (recommended)
495
+ * // Set DRIP_API_KEY env var, then:
496
+ * const drip = new Drip();
497
+ *
498
+ * // Option 3: Use pre-initialized singleton
499
+ * import { drip } from '@drip-sdk/node';
500
+ * ```
418
501
  */
419
- constructor(config: DripConfig);
502
+ constructor(config?: DripConfig);
420
503
  /**
421
504
  * Makes an authenticated request to the Drip API.
422
505
  * @internal
@@ -538,24 +621,45 @@ declare class Drip {
538
621
  */
539
622
  endRun(runId: string, params: EndRunParams): Promise<EndRunResult>;
540
623
  /**
541
- * Gets a run's full timeline with events and computed totals.
624
+ * Gets run details with summary totals.
625
+ *
626
+ * For full event history with retry chains and anomalies, use `getRunTimeline()`.
542
627
  *
543
628
  * @param runId - The run ID
544
- * @returns Full timeline with events and summary
629
+ * @returns Run details with totals
545
630
  *
546
631
  * @example
547
632
  * ```typescript
548
- * const { run, timeline, totals, summary } = await drip.getRunTimeline('run_abc123');
633
+ * const run = await drip.getRun('run_abc123');
634
+ * console.log(`Status: ${run.status}, Events: ${run.totals.eventCount}`);
635
+ * ```
636
+ */
637
+ getRun(runId: string): Promise<RunDetails>;
638
+ /**
639
+ * Gets a run's full timeline with events, anomalies, and analytics.
549
640
  *
550
- * console.log(`Status: ${run.status}`);
551
- * console.log(`Summary: ${summary}`);
641
+ * @param runId - The run ID
642
+ * @param options - Pagination and filtering options
643
+ * @returns Full timeline with events, anomalies, and summary
644
+ *
645
+ * @example
646
+ * ```typescript
647
+ * const timeline = await drip.getRunTimeline('run_abc123');
552
648
  *
553
- * for (const event of timeline) {
554
- * console.log(`${event.eventType}: ${event.quantity} ${event.units}`);
649
+ * console.log(`Status: ${timeline.status}`);
650
+ * console.log(`Events: ${timeline.summary.totalEvents}`);
651
+ *
652
+ * for (const event of timeline.events) {
653
+ * console.log(`${event.eventType}: ${event.outcome}`);
555
654
  * }
556
655
  * ```
557
656
  */
558
- getRunTimeline(runId: string): Promise<RunTimeline>;
657
+ getRunTimeline(runId: string, options?: {
658
+ limit?: number;
659
+ cursor?: string;
660
+ includeAnomalies?: boolean;
661
+ collapseRetries?: boolean;
662
+ }): Promise<RunTimeline>;
559
663
  /**
560
664
  * Emits an event to a run.
561
665
  *
@@ -584,10 +688,13 @@ declare class Drip {
584
688
  success: boolean;
585
689
  created: number;
586
690
  duplicates: number;
691
+ skipped: number;
587
692
  events: Array<{
588
693
  id: string;
589
694
  eventType: string;
590
695
  isDuplicate: boolean;
696
+ skipped?: boolean;
697
+ reason?: string;
591
698
  }>;
592
699
  }>;
593
700
  /**
@@ -633,8 +740,37 @@ declare class Drip {
633
740
  * ```
634
741
  */
635
742
  recordRun(params: RecordRunParams): Promise<RecordRunResult>;
743
+ /**
744
+ * 4-step orchestration fallback for servers without POST /runs/record.
745
+ * @internal
746
+ */
747
+ private _recordRunFallback;
636
748
  }
637
749
 
750
+ /**
751
+ * Pre-initialized Drip client singleton.
752
+ *
753
+ * Uses lazy initialization - only creates the client when first accessed.
754
+ * Reads `DRIP_API_KEY` from environment variables.
755
+ *
756
+ * @example
757
+ * ```typescript
758
+ * import { drip } from '@drip-sdk/node';
759
+ *
760
+ * // Track usage with one line
761
+ * await drip.trackUsage({ customerId: 'cust_123', meter: 'api_calls', quantity: 1 });
762
+ *
763
+ * // Record a run
764
+ * await drip.recordRun({
765
+ * customerId: 'cust_123',
766
+ * workflow: 'agent-run',
767
+ * events: [{ eventType: 'llm.call', quantity: 1000, units: 'tokens' }],
768
+ * status: 'COMPLETED',
769
+ * });
770
+ * ```
771
+ */
772
+ declare const drip: Drip;
773
+
638
774
  // @ts-ignore
639
775
  export = Drip;
640
- export { type CreateCustomerParams, type Customer, Drip, type DripConfig, DripError, type EmitEventParams, type EndRunParams, type EndRunResult, type EventResult, type ListCustomersOptions, type ListCustomersResponse, type RecordRunEvent, type RecordRunParams, type RecordRunResult, type RunResult, type RunStatus, type RunTimeline, type StartRunParams, type TrackUsageParams, type TrackUsageResult };
776
+ export { type CreateCustomerParams, type Customer, Drip, type DripConfig, DripError, type EmitEventParams, type EndRunParams, type EndRunResult, type EventResult, type ListCustomersOptions, type ListCustomersResponse, type RecordRunEvent, type RecordRunParams, type RecordRunResult, type RunDetails, type RunResult, type RunStatus, type RunTimeline, type StartRunParams, type TrackUsageParams, type TrackUsageResult, drip };