@lelemondev/sdk 0.9.0 → 0.9.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.
Files changed (46) hide show
  1. package/dist/anthropic.js +2 -2
  2. package/dist/anthropic.js.map +1 -1
  3. package/dist/anthropic.mjs +2 -2
  4. package/dist/anthropic.mjs.map +1 -1
  5. package/dist/bedrock.js +2 -2
  6. package/dist/bedrock.js.map +1 -1
  7. package/dist/bedrock.mjs +2 -2
  8. package/dist/bedrock.mjs.map +1 -1
  9. package/dist/express.js +1 -1
  10. package/dist/express.js.map +1 -1
  11. package/dist/express.mjs +1 -1
  12. package/dist/express.mjs.map +1 -1
  13. package/dist/gemini.js +2 -2
  14. package/dist/gemini.js.map +1 -1
  15. package/dist/gemini.mjs +2 -2
  16. package/dist/gemini.mjs.map +1 -1
  17. package/dist/hono.js +1 -1
  18. package/dist/hono.js.map +1 -1
  19. package/dist/hono.mjs +1 -1
  20. package/dist/hono.mjs.map +1 -1
  21. package/dist/index.d.mts +31 -1
  22. package/dist/index.d.ts +31 -1
  23. package/dist/index.js +2 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.mjs +2 -2
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/integrations.js +1 -1
  28. package/dist/integrations.js.map +1 -1
  29. package/dist/integrations.mjs +1 -1
  30. package/dist/integrations.mjs.map +1 -1
  31. package/dist/lambda.js.map +1 -1
  32. package/dist/lambda.mjs +1 -1
  33. package/dist/lambda.mjs.map +1 -1
  34. package/dist/next.js +1 -1
  35. package/dist/next.js.map +1 -1
  36. package/dist/next.mjs +1 -1
  37. package/dist/next.mjs.map +1 -1
  38. package/dist/openai.js +2 -2
  39. package/dist/openai.js.map +1 -1
  40. package/dist/openai.mjs +2 -2
  41. package/dist/openai.mjs.map +1 -1
  42. package/dist/openrouter.js +2 -2
  43. package/dist/openrouter.js.map +1 -1
  44. package/dist/openrouter.mjs +2 -2
  45. package/dist/openrouter.mjs.map +1 -1
  46. package/package.json +1 -1
package/dist/lambda.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  /* @lelemondev/sdk - LLM Observability */
2
- async function n(){}function s(t){return async(i,r)=>{try{return await t(i,r)}finally{await n();}}}export{s as withObserve};//# sourceMappingURL=lambda.mjs.map
2
+ async function n(){}function a(t){return async(i,r)=>{try{return await t(i,r)}finally{await n();}}}export{a as withObserve};//# sourceMappingURL=lambda.mjs.map
3
3
  //# sourceMappingURL=lambda.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/config.ts","../src/integrations/lambda.ts"],"names":["flush","withObserve","handler","event","context"],"mappings":";AA2FA,eAAsBA,CAAAA,EAAuB,CAI7C,CCVO,SAASC,CAAAA,CACdC,CAAAA,CACgC,CAChC,OAAO,MAAOC,CAAAA,CAAeC,CAAAA,GAA6C,CACxE,GAAI,CACF,OAAO,MAAMF,CAAAA,CAAQC,CAAAA,CAAOC,CAAO,CACrC,QAAE,CAEA,MAAMJ,CAAAA,GACR,CACF,CACF","file":"lambda.mjs","sourcesContent":["/**\n * Global Configuration\n *\n * Manages SDK configuration and transport instance.\n */\n\nimport type { LelemonConfig } from './types';\nimport { Transport } from './transport';\nimport { setDebug, info, warn, debug } from './logger';\n\n// ─────────────────────────────────────────────────────────────\n// Global State\n// ─────────────────────────────────────────────────────────────\n\nlet globalConfig: LelemonConfig = {};\nlet globalTransport: Transport | null = null;\nlet initialized = false;\n\n// ─────────────────────────────────────────────────────────────\n// Configuration\n// ─────────────────────────────────────────────────────────────\n\nconst DEFAULT_ENDPOINT = 'https://www.lelemon.dev';\n\n/**\n * Initialize the SDK\n * Call once at app startup\n */\nexport function init(config: LelemonConfig = {}): void {\n globalConfig = config;\n\n // Configure debug mode\n if (config.debug) {\n setDebug(true);\n }\n\n info('Initializing SDK', {\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n debug: config.debug ?? false,\n disabled: config.disabled ?? false,\n });\n\n globalTransport = createTransport(config);\n initialized = true;\n\n // Log status after transport is created\n if (globalTransport.isEnabled()) {\n info('SDK initialized - tracing enabled');\n } else {\n debug('SDK initialized - tracing disabled (no API key or explicitly disabled)');\n }\n}\n\n/**\n * Get current config\n */\nexport function getConfig(): LelemonConfig {\n return globalConfig;\n}\n\n/**\n * Check if SDK is initialized\n */\nexport function isInitialized(): boolean {\n return initialized;\n}\n\n/**\n * Check if SDK is enabled\n */\nexport function isEnabled(): boolean {\n return getTransport().isEnabled();\n}\n\n// ─────────────────────────────────────────────────────────────\n// Transport\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Get or create transport instance\n */\nexport function getTransport(): Transport {\n if (!globalTransport) {\n globalTransport = createTransport(globalConfig);\n }\n return globalTransport;\n}\n\n/**\n * Flush all pending traces\n */\nexport async function flush(): Promise<void> {\n if (globalTransport) {\n await globalTransport.flush();\n }\n}\n\n/**\n * Create transport instance\n */\nfunction createTransport(config: LelemonConfig): Transport {\n const apiKey = config.apiKey ?? getEnvVar('LELEMON_API_KEY');\n\n if (!apiKey && !config.disabled) {\n warn('No API key provided. Set apiKey in init() or LELEMON_API_KEY env var. Tracing disabled.');\n }\n\n return new Transport({\n apiKey: apiKey ?? '',\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n debug: config.debug ?? false,\n disabled: config.disabled ?? !apiKey,\n batchSize: config.batchSize,\n flushIntervalMs: config.flushIntervalMs,\n requestTimeoutMs: config.requestTimeoutMs,\n });\n}\n\n/**\n * Get environment variable (works in Node and edge)\n */\nfunction getEnvVar(name: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n","/**\n * AWS Lambda Integration\n *\n * Wraps Lambda handlers to automatically flush traces before the function exits.\n *\n * @example\n * import { withObserve } from '@lelemondev/sdk/lambda';\n *\n * export const handler = withObserve(async (event) => {\n * const openai = observe(new OpenAI());\n * const result = await openai.chat.completions.create({...});\n * return { statusCode: 200, body: JSON.stringify(result) };\n * });\n */\n\nimport { flush } from '../core/config';\n\n// ─────────────────────────────────────────────────────────────\n// Types (minimal to avoid requiring @types/aws-lambda)\n// ─────────────────────────────────────────────────────────────\n\n/**\n * AWS Lambda Context object\n */\nexport interface LambdaContext {\n functionName: string;\n functionVersion: string;\n invokedFunctionArn: string;\n memoryLimitInMB: string;\n awsRequestId: string;\n logGroupName: string;\n logStreamName: string;\n getRemainingTimeInMillis(): number;\n [key: string]: unknown;\n}\n\n/**\n * Generic AWS Lambda handler type\n *\n * @typeParam TEvent - The event type (e.g., APIGatewayProxyEvent)\n * @typeParam TResult - The result type (e.g., APIGatewayProxyResult)\n */\nexport type LambdaHandler<TEvent = unknown, TResult = unknown> = (\n event: TEvent,\n context: LambdaContext\n) => Promise<TResult>;\n\n// ─────────────────────────────────────────────────────────────\n// Wrapper\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Wrap an AWS Lambda handler with automatic trace flushing\n *\n * Always flushes before returning - Lambda freezes the container\n * immediately after the handler returns, so this is required.\n *\n * @param handler - Your Lambda handler function\n * @returns Wrapped handler that auto-flushes traces\n *\n * @example\n * // API Gateway event\n * export const handler = withObserve(async (event) => {\n * const body = JSON.parse(event.body);\n * const openai = observe(new OpenAI());\n * const result = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: body.message }],\n * });\n * return {\n * statusCode: 200,\n * body: JSON.stringify(result.choices[0].message),\n * };\n * });\n *\n * @example\n * // With typed events\n * import type { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';\n *\n * export const handler = withObserve<APIGatewayProxyEvent, APIGatewayProxyResult>(\n * async (event, context) => {\n * return { statusCode: 200, body: 'OK' };\n * }\n * );\n */\nexport function withObserve<TEvent = unknown, TResult = unknown>(\n handler: LambdaHandler<TEvent, TResult>\n): LambdaHandler<TEvent, TResult> {\n return async (event: TEvent, context: LambdaContext): Promise<TResult> => {\n try {\n return await handler(event, context);\n } finally {\n // Always flush - Lambda freezes immediately after return\n await flush();\n }\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/core/config.ts","../src/integrations/lambda.ts"],"names":["flush","withObserve","handler","event","context"],"mappings":";AAwGA,eAAsBA,CAAAA,EAAuB,CAI7C,CCvBO,SAASC,CAAAA,CACdC,CAAAA,CACgC,CAChC,OAAO,MAAOC,CAAAA,CAAeC,CAAAA,GAA6C,CACxE,GAAI,CACF,OAAO,MAAMF,CAAAA,CAAQC,CAAAA,CAAOC,CAAO,CACrC,QAAE,CAEA,MAAMJ,CAAAA,GACR,CACF,CACF","file":"lambda.mjs","sourcesContent":["/**\n * Global Configuration\n *\n * Manages SDK configuration and transport instance.\n */\n\nimport type { LelemonConfig, SDKTelemetry } from './types';\nimport { Transport } from './transport';\nimport { setDebug, info, warn, debug } from './logger';\nimport { buildTelemetry } from './telemetry';\n\n// ─────────────────────────────────────────────────────────────\n// Global State\n// ─────────────────────────────────────────────────────────────\n\nlet globalConfig: LelemonConfig = {};\nlet globalTransport: Transport | null = null;\nlet globalTelemetry: SDKTelemetry | null = null;\nlet initialized = false;\n\n// ─────────────────────────────────────────────────────────────\n// Configuration\n// ─────────────────────────────────────────────────────────────\n\nconst DEFAULT_ENDPOINT = 'https://www.lelemon.dev';\n\n/**\n * Initialize the SDK\n * Call once at app startup\n */\nexport function init(config: LelemonConfig = {}): void {\n globalConfig = config;\n\n // Configure debug mode\n if (config.debug) {\n setDebug(true);\n }\n\n // Build telemetry with service config\n globalTelemetry = buildTelemetry(config.service);\n\n info('Initializing SDK', {\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n debug: config.debug ?? false,\n disabled: config.disabled ?? false,\n telemetry: globalTelemetry,\n });\n\n globalTransport = createTransport(config);\n initialized = true;\n\n // Log status after transport is created\n if (globalTransport.isEnabled()) {\n info('SDK initialized - tracing enabled');\n } else {\n debug('SDK initialized - tracing disabled (no API key or explicitly disabled)');\n }\n}\n\n/**\n * Get current config\n */\nexport function getConfig(): LelemonConfig {\n return globalConfig;\n}\n\n/**\n * Get SDK telemetry\n */\nexport function getTelemetry(): SDKTelemetry | null {\n return globalTelemetry;\n}\n\n/**\n * Check if SDK is initialized\n */\nexport function isInitialized(): boolean {\n return initialized;\n}\n\n/**\n * Check if SDK is enabled\n */\nexport function isEnabled(): boolean {\n return getTransport().isEnabled();\n}\n\n// ─────────────────────────────────────────────────────────────\n// Transport\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Get or create transport instance\n */\nexport function getTransport(): Transport {\n if (!globalTransport) {\n globalTransport = createTransport(globalConfig);\n }\n return globalTransport;\n}\n\n/**\n * Flush all pending traces\n */\nexport async function flush(): Promise<void> {\n if (globalTransport) {\n await globalTransport.flush();\n }\n}\n\n/**\n * Create transport instance\n */\nfunction createTransport(config: LelemonConfig): Transport {\n const apiKey = config.apiKey ?? getEnvVar('LELEMON_API_KEY');\n\n if (!apiKey && !config.disabled) {\n warn('No API key provided. Set apiKey in init() or LELEMON_API_KEY env var. Tracing disabled.');\n }\n\n return new Transport({\n apiKey: apiKey ?? '',\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n debug: config.debug ?? false,\n disabled: config.disabled ?? !apiKey,\n batchSize: config.batchSize,\n flushIntervalMs: config.flushIntervalMs,\n requestTimeoutMs: config.requestTimeoutMs,\n });\n}\n\n/**\n * Get environment variable (works in Node and edge)\n */\nfunction getEnvVar(name: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n","/**\n * AWS Lambda Integration\n *\n * Wraps Lambda handlers to automatically flush traces before the function exits.\n *\n * @example\n * import { withObserve } from '@lelemondev/sdk/lambda';\n *\n * export const handler = withObserve(async (event) => {\n * const openai = observe(new OpenAI());\n * const result = await openai.chat.completions.create({...});\n * return { statusCode: 200, body: JSON.stringify(result) };\n * });\n */\n\nimport { flush } from '../core/config';\n\n// ─────────────────────────────────────────────────────────────\n// Types (minimal to avoid requiring @types/aws-lambda)\n// ─────────────────────────────────────────────────────────────\n\n/**\n * AWS Lambda Context object\n */\nexport interface LambdaContext {\n functionName: string;\n functionVersion: string;\n invokedFunctionArn: string;\n memoryLimitInMB: string;\n awsRequestId: string;\n logGroupName: string;\n logStreamName: string;\n getRemainingTimeInMillis(): number;\n [key: string]: unknown;\n}\n\n/**\n * Generic AWS Lambda handler type\n *\n * @typeParam TEvent - The event type (e.g., APIGatewayProxyEvent)\n * @typeParam TResult - The result type (e.g., APIGatewayProxyResult)\n */\nexport type LambdaHandler<TEvent = unknown, TResult = unknown> = (\n event: TEvent,\n context: LambdaContext\n) => Promise<TResult>;\n\n// ─────────────────────────────────────────────────────────────\n// Wrapper\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Wrap an AWS Lambda handler with automatic trace flushing\n *\n * Always flushes before returning - Lambda freezes the container\n * immediately after the handler returns, so this is required.\n *\n * @param handler - Your Lambda handler function\n * @returns Wrapped handler that auto-flushes traces\n *\n * @example\n * // API Gateway event\n * export const handler = withObserve(async (event) => {\n * const body = JSON.parse(event.body);\n * const openai = observe(new OpenAI());\n * const result = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: body.message }],\n * });\n * return {\n * statusCode: 200,\n * body: JSON.stringify(result.choices[0].message),\n * };\n * });\n *\n * @example\n * // With typed events\n * import type { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';\n *\n * export const handler = withObserve<APIGatewayProxyEvent, APIGatewayProxyResult>(\n * async (event, context) => {\n * return { statusCode: 200, body: 'OK' };\n * }\n * );\n */\nexport function withObserve<TEvent = unknown, TResult = unknown>(\n handler: LambdaHandler<TEvent, TResult>\n): LambdaHandler<TEvent, TResult> {\n return async (event: TEvent, context: LambdaContext): Promise<TResult> => {\n try {\n return await handler(event, context);\n } finally {\n // Always flush - Lambda freezes immediately after return\n await flush();\n }\n };\n}\n"]}
package/dist/next.js CHANGED
@@ -1,3 +1,3 @@
1
1
  'use strict';/* @lelemondev/sdk - LLM Observability */
2
- async function t(){}function a(n,e){return async(i,o)=>{try{return await n(i,o)}finally{e?.after?e.after(()=>t()):e?.waitUntil?e.waitUntil(t()):await t();}}}function p(n){return function(e,i){return a(e,{...n,...i})}}exports.createWrapper=p;exports.withObserve=a;//# sourceMappingURL=next.js.map
2
+ async function t(){}function s(n,e){return async(r,o)=>{try{return await n(r,o)}finally{e?.after?e.after(()=>t()):e?.waitUntil?e.waitUntil(t()):await t();}}}function p(n){return function(e,r){return s(e,{...n,...r})}}exports.createWrapper=p;exports.withObserve=s;//# sourceMappingURL=next.js.map
3
3
  //# sourceMappingURL=next.js.map
package/dist/next.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/config.ts","../src/integrations/next.ts"],"names":["flush","withObserve","handler","options","request","context","createWrapper","defaultOptions"],"mappings":";AA2FA,eAAsBA,CAAAA,EAAuB,CAI7C,CCHO,SAASC,CAAAA,CACdC,EACAC,CAAAA,CAC4B,CAC5B,OAAO,MAAOC,CAAAA,CAAkBC,CAAAA,GAA0C,CACxE,GAAI,CACF,OAAO,MAAMH,CAAAA,CAAQE,CAAAA,CAASC,CAAO,CACvC,CAAA,OAAE,CAEIF,CAAAA,EAAS,MAEXA,CAAAA,CAAQ,KAAA,CAAM,IAAMH,CAAAA,EAAO,CAAA,CAClBG,CAAAA,EAAS,SAAA,CAElBA,EAAQ,SAAA,CAAUH,CAAAA,EAAO,CAAA,CAGzB,MAAMA,CAAAA,GAEV,CACF,CACF,CAeO,SAASM,CAAAA,CAAcC,CAAAA,CAAoC,CAChE,OAAO,SACLL,CAAAA,CACAC,CAAAA,CAC4B,CAC5B,OAAOF,CAAAA,CAAYC,CAAAA,CAAS,CAAE,GAAGK,CAAAA,CAAgB,GAAGJ,CAAQ,CAAC,CAC/D,CACF","file":"next.js","sourcesContent":["/**\n * Global Configuration\n *\n * Manages SDK configuration and transport instance.\n */\n\nimport type { LelemonConfig } from './types';\nimport { Transport } from './transport';\nimport { setDebug, info, warn, debug } from './logger';\n\n// ─────────────────────────────────────────────────────────────\n// Global State\n// ─────────────────────────────────────────────────────────────\n\nlet globalConfig: LelemonConfig = {};\nlet globalTransport: Transport | null = null;\nlet initialized = false;\n\n// ─────────────────────────────────────────────────────────────\n// Configuration\n// ─────────────────────────────────────────────────────────────\n\nconst DEFAULT_ENDPOINT = 'https://www.lelemon.dev';\n\n/**\n * Initialize the SDK\n * Call once at app startup\n */\nexport function init(config: LelemonConfig = {}): void {\n globalConfig = config;\n\n // Configure debug mode\n if (config.debug) {\n setDebug(true);\n }\n\n info('Initializing SDK', {\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n debug: config.debug ?? false,\n disabled: config.disabled ?? false,\n });\n\n globalTransport = createTransport(config);\n initialized = true;\n\n // Log status after transport is created\n if (globalTransport.isEnabled()) {\n info('SDK initialized - tracing enabled');\n } else {\n debug('SDK initialized - tracing disabled (no API key or explicitly disabled)');\n }\n}\n\n/**\n * Get current config\n */\nexport function getConfig(): LelemonConfig {\n return globalConfig;\n}\n\n/**\n * Check if SDK is initialized\n */\nexport function isInitialized(): boolean {\n return initialized;\n}\n\n/**\n * Check if SDK is enabled\n */\nexport function isEnabled(): boolean {\n return getTransport().isEnabled();\n}\n\n// ─────────────────────────────────────────────────────────────\n// Transport\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Get or create transport instance\n */\nexport function getTransport(): Transport {\n if (!globalTransport) {\n globalTransport = createTransport(globalConfig);\n }\n return globalTransport;\n}\n\n/**\n * Flush all pending traces\n */\nexport async function flush(): Promise<void> {\n if (globalTransport) {\n await globalTransport.flush();\n }\n}\n\n/**\n * Create transport instance\n */\nfunction createTransport(config: LelemonConfig): Transport {\n const apiKey = config.apiKey ?? getEnvVar('LELEMON_API_KEY');\n\n if (!apiKey && !config.disabled) {\n warn('No API key provided. Set apiKey in init() or LELEMON_API_KEY env var. Tracing disabled.');\n }\n\n return new Transport({\n apiKey: apiKey ?? '',\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n debug: config.debug ?? false,\n disabled: config.disabled ?? !apiKey,\n batchSize: config.batchSize,\n flushIntervalMs: config.flushIntervalMs,\n requestTimeoutMs: config.requestTimeoutMs,\n });\n}\n\n/**\n * Get environment variable (works in Node and edge)\n */\nfunction getEnvVar(name: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n","/**\n * Next.js App Router Integration\n *\n * Wraps route handlers to automatically flush traces.\n * Supports Next.js 15+ `after()` and Vercel's `waitUntil()`.\n *\n * @example\n * import { withObserve } from '@lelemondev/sdk/next';\n *\n * export const POST = withObserve(async (req) => {\n * const openai = observe(new OpenAI());\n * const result = await openai.chat.completions.create({...});\n * return Response.json(result);\n * });\n */\n\nimport { flush } from '../core/config';\n\n// ─────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Next.js App Router handler type\n *\n * @typeParam TContext - Optional context type for dynamic route parameters\n */\nexport type NextRouteHandler<TContext = unknown> = (\n request: Request,\n context?: TContext\n) => Response | Promise<Response>;\n\n/**\n * Options for the Next.js wrapper\n */\nexport interface NextObserveOptions {\n /**\n * Next.js 15+ after() function from 'next/server'\n * Preferred method - runs after response without blocking\n *\n * @example\n * import { after } from 'next/server';\n * export const POST = withObserve(handler, { after });\n */\n after?: (callback: () => void | Promise<void>) => void;\n\n /**\n * Vercel's waitUntil() from '@vercel/functions'\n * Alternative for Vercel deployments\n *\n * @example\n * import { waitUntil } from '@vercel/functions';\n * export const POST = withObserve(handler, { waitUntil });\n */\n waitUntil?: (promise: Promise<unknown>) => void;\n}\n\n// ─────────────────────────────────────────────────────────────\n// Wrapper\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Wrap a Next.js App Router handler with automatic trace flushing\n *\n * @param handler - Your route handler function\n * @param options - Optional: pass `after` (Next.js 15+) or `waitUntil` (Vercel)\n * @returns Wrapped handler that auto-flushes traces\n *\n * @example\n * // Basic usage (blocking flush)\n * export const POST = withObserve(async (req) => {\n * return Response.json({ ok: true });\n * });\n *\n * @example\n * // Next.js 15+ with after() - non-blocking (recommended)\n * import { after } from 'next/server';\n *\n * export const POST = withObserve(\n * async (req) => Response.json({ ok: true }),\n * { after }\n * );\n *\n * @example\n * // Vercel with waitUntil() - non-blocking\n * import { waitUntil } from '@vercel/functions';\n *\n * export const POST = withObserve(\n * async (req) => Response.json({ ok: true }),\n * { waitUntil }\n * );\n */\nexport function withObserve<TContext = unknown>(\n handler: NextRouteHandler<TContext>,\n options?: NextObserveOptions\n): NextRouteHandler<TContext> {\n return async (request: Request, context?: TContext): Promise<Response> => {\n try {\n return await handler(request, context);\n } finally {\n // Priority: after() > waitUntil() > blocking flush\n if (options?.after) {\n // Next.js 15+ native - best option\n options.after(() => flush());\n } else if (options?.waitUntil) {\n // Vercel platform\n options.waitUntil(flush());\n } else {\n // Fallback: blocking flush\n await flush();\n }\n }\n };\n}\n\n/**\n * Create a pre-configured wrapper with default options\n *\n * @example\n * import { after } from 'next/server';\n * import { createWrapper } from '@lelemondev/sdk/next';\n *\n * const withObserve = createWrapper({ after });\n *\n * export const POST = withObserve(async (req) => {\n * return Response.json({ ok: true });\n * });\n */\nexport function createWrapper(defaultOptions: NextObserveOptions) {\n return function <TContext = unknown>(\n handler: NextRouteHandler<TContext>,\n options?: NextObserveOptions\n ): NextRouteHandler<TContext> {\n return withObserve(handler, { ...defaultOptions, ...options });\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/core/config.ts","../src/integrations/next.ts"],"names":["flush","withObserve","handler","options","request","context","createWrapper","defaultOptions"],"mappings":";AAwGA,eAAsBA,CAAAA,EAAuB,CAI7C,CChBO,SAASC,CAAAA,CACdC,EACAC,CAAAA,CAC4B,CAC5B,OAAO,MAAOC,CAAAA,CAAkBC,CAAAA,GAA0C,CACxE,GAAI,CACF,OAAO,MAAMH,CAAAA,CAAQE,CAAAA,CAASC,CAAO,CACvC,CAAA,OAAE,CAEIF,CAAAA,EAAS,MAEXA,CAAAA,CAAQ,KAAA,CAAM,IAAMH,CAAAA,EAAO,CAAA,CAClBG,CAAAA,EAAS,SAAA,CAElBA,EAAQ,SAAA,CAAUH,CAAAA,EAAO,CAAA,CAGzB,MAAMA,CAAAA,GAEV,CACF,CACF,CAeO,SAASM,CAAAA,CAAcC,CAAAA,CAAoC,CAChE,OAAO,SACLL,CAAAA,CACAC,CAAAA,CAC4B,CAC5B,OAAOF,CAAAA,CAAYC,CAAAA,CAAS,CAAE,GAAGK,CAAAA,CAAgB,GAAGJ,CAAQ,CAAC,CAC/D,CACF","file":"next.js","sourcesContent":["/**\n * Global Configuration\n *\n * Manages SDK configuration and transport instance.\n */\n\nimport type { LelemonConfig, SDKTelemetry } from './types';\nimport { Transport } from './transport';\nimport { setDebug, info, warn, debug } from './logger';\nimport { buildTelemetry } from './telemetry';\n\n// ─────────────────────────────────────────────────────────────\n// Global State\n// ─────────────────────────────────────────────────────────────\n\nlet globalConfig: LelemonConfig = {};\nlet globalTransport: Transport | null = null;\nlet globalTelemetry: SDKTelemetry | null = null;\nlet initialized = false;\n\n// ─────────────────────────────────────────────────────────────\n// Configuration\n// ─────────────────────────────────────────────────────────────\n\nconst DEFAULT_ENDPOINT = 'https://www.lelemon.dev';\n\n/**\n * Initialize the SDK\n * Call once at app startup\n */\nexport function init(config: LelemonConfig = {}): void {\n globalConfig = config;\n\n // Configure debug mode\n if (config.debug) {\n setDebug(true);\n }\n\n // Build telemetry with service config\n globalTelemetry = buildTelemetry(config.service);\n\n info('Initializing SDK', {\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n debug: config.debug ?? false,\n disabled: config.disabled ?? false,\n telemetry: globalTelemetry,\n });\n\n globalTransport = createTransport(config);\n initialized = true;\n\n // Log status after transport is created\n if (globalTransport.isEnabled()) {\n info('SDK initialized - tracing enabled');\n } else {\n debug('SDK initialized - tracing disabled (no API key or explicitly disabled)');\n }\n}\n\n/**\n * Get current config\n */\nexport function getConfig(): LelemonConfig {\n return globalConfig;\n}\n\n/**\n * Get SDK telemetry\n */\nexport function getTelemetry(): SDKTelemetry | null {\n return globalTelemetry;\n}\n\n/**\n * Check if SDK is initialized\n */\nexport function isInitialized(): boolean {\n return initialized;\n}\n\n/**\n * Check if SDK is enabled\n */\nexport function isEnabled(): boolean {\n return getTransport().isEnabled();\n}\n\n// ─────────────────────────────────────────────────────────────\n// Transport\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Get or create transport instance\n */\nexport function getTransport(): Transport {\n if (!globalTransport) {\n globalTransport = createTransport(globalConfig);\n }\n return globalTransport;\n}\n\n/**\n * Flush all pending traces\n */\nexport async function flush(): Promise<void> {\n if (globalTransport) {\n await globalTransport.flush();\n }\n}\n\n/**\n * Create transport instance\n */\nfunction createTransport(config: LelemonConfig): Transport {\n const apiKey = config.apiKey ?? getEnvVar('LELEMON_API_KEY');\n\n if (!apiKey && !config.disabled) {\n warn('No API key provided. Set apiKey in init() or LELEMON_API_KEY env var. Tracing disabled.');\n }\n\n return new Transport({\n apiKey: apiKey ?? '',\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n debug: config.debug ?? false,\n disabled: config.disabled ?? !apiKey,\n batchSize: config.batchSize,\n flushIntervalMs: config.flushIntervalMs,\n requestTimeoutMs: config.requestTimeoutMs,\n });\n}\n\n/**\n * Get environment variable (works in Node and edge)\n */\nfunction getEnvVar(name: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n","/**\n * Next.js App Router Integration\n *\n * Wraps route handlers to automatically flush traces.\n * Supports Next.js 15+ `after()` and Vercel's `waitUntil()`.\n *\n * @example\n * import { withObserve } from '@lelemondev/sdk/next';\n *\n * export const POST = withObserve(async (req) => {\n * const openai = observe(new OpenAI());\n * const result = await openai.chat.completions.create({...});\n * return Response.json(result);\n * });\n */\n\nimport { flush } from '../core/config';\n\n// ─────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Next.js App Router handler type\n *\n * @typeParam TContext - Optional context type for dynamic route parameters\n */\nexport type NextRouteHandler<TContext = unknown> = (\n request: Request,\n context?: TContext\n) => Response | Promise<Response>;\n\n/**\n * Options for the Next.js wrapper\n */\nexport interface NextObserveOptions {\n /**\n * Next.js 15+ after() function from 'next/server'\n * Preferred method - runs after response without blocking\n *\n * @example\n * import { after } from 'next/server';\n * export const POST = withObserve(handler, { after });\n */\n after?: (callback: () => void | Promise<void>) => void;\n\n /**\n * Vercel's waitUntil() from '@vercel/functions'\n * Alternative for Vercel deployments\n *\n * @example\n * import { waitUntil } from '@vercel/functions';\n * export const POST = withObserve(handler, { waitUntil });\n */\n waitUntil?: (promise: Promise<unknown>) => void;\n}\n\n// ─────────────────────────────────────────────────────────────\n// Wrapper\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Wrap a Next.js App Router handler with automatic trace flushing\n *\n * @param handler - Your route handler function\n * @param options - Optional: pass `after` (Next.js 15+) or `waitUntil` (Vercel)\n * @returns Wrapped handler that auto-flushes traces\n *\n * @example\n * // Basic usage (blocking flush)\n * export const POST = withObserve(async (req) => {\n * return Response.json({ ok: true });\n * });\n *\n * @example\n * // Next.js 15+ with after() - non-blocking (recommended)\n * import { after } from 'next/server';\n *\n * export const POST = withObserve(\n * async (req) => Response.json({ ok: true }),\n * { after }\n * );\n *\n * @example\n * // Vercel with waitUntil() - non-blocking\n * import { waitUntil } from '@vercel/functions';\n *\n * export const POST = withObserve(\n * async (req) => Response.json({ ok: true }),\n * { waitUntil }\n * );\n */\nexport function withObserve<TContext = unknown>(\n handler: NextRouteHandler<TContext>,\n options?: NextObserveOptions\n): NextRouteHandler<TContext> {\n return async (request: Request, context?: TContext): Promise<Response> => {\n try {\n return await handler(request, context);\n } finally {\n // Priority: after() > waitUntil() > blocking flush\n if (options?.after) {\n // Next.js 15+ native - best option\n options.after(() => flush());\n } else if (options?.waitUntil) {\n // Vercel platform\n options.waitUntil(flush());\n } else {\n // Fallback: blocking flush\n await flush();\n }\n }\n };\n}\n\n/**\n * Create a pre-configured wrapper with default options\n *\n * @example\n * import { after } from 'next/server';\n * import { createWrapper } from '@lelemondev/sdk/next';\n *\n * const withObserve = createWrapper({ after });\n *\n * export const POST = withObserve(async (req) => {\n * return Response.json({ ok: true });\n * });\n */\nexport function createWrapper(defaultOptions: NextObserveOptions) {\n return function <TContext = unknown>(\n handler: NextRouteHandler<TContext>,\n options?: NextObserveOptions\n ): NextRouteHandler<TContext> {\n return withObserve(handler, { ...defaultOptions, ...options });\n };\n}\n"]}
package/dist/next.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  /* @lelemondev/sdk - LLM Observability */
2
- async function t(){}function s(n,e){return async(i,o)=>{try{return await n(i,o)}finally{e?.after?e.after(()=>t()):e?.waitUntil?e.waitUntil(t()):await t();}}}function u(n){return function(e,i){return s(e,{...n,...i})}}export{u as createWrapper,s as withObserve};//# sourceMappingURL=next.mjs.map
2
+ async function t(){}function l(n,e){return async(r,o)=>{try{return await n(r,o)}finally{e?.after?e.after(()=>t()):e?.waitUntil?e.waitUntil(t()):await t();}}}function u(n){return function(e,r){return l(e,{...n,...r})}}export{u as createWrapper,l as withObserve};//# sourceMappingURL=next.mjs.map
3
3
  //# sourceMappingURL=next.mjs.map
package/dist/next.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/config.ts","../src/integrations/next.ts"],"names":["flush","withObserve","handler","options","request","context","createWrapper","defaultOptions"],"mappings":";AA2FA,eAAsBA,CAAAA,EAAuB,CAI7C,CCHO,SAASC,CAAAA,CACdC,EACAC,CAAAA,CAC4B,CAC5B,OAAO,MAAOC,CAAAA,CAAkBC,CAAAA,GAA0C,CACxE,GAAI,CACF,OAAO,MAAMH,CAAAA,CAAQE,CAAAA,CAASC,CAAO,CACvC,CAAA,OAAE,CAEIF,CAAAA,EAAS,MAEXA,CAAAA,CAAQ,KAAA,CAAM,IAAMH,CAAAA,EAAO,CAAA,CAClBG,CAAAA,EAAS,SAAA,CAElBA,EAAQ,SAAA,CAAUH,CAAAA,EAAO,CAAA,CAGzB,MAAMA,CAAAA,GAEV,CACF,CACF,CAeO,SAASM,CAAAA,CAAcC,CAAAA,CAAoC,CAChE,OAAO,SACLL,CAAAA,CACAC,CAAAA,CAC4B,CAC5B,OAAOF,CAAAA,CAAYC,CAAAA,CAAS,CAAE,GAAGK,CAAAA,CAAgB,GAAGJ,CAAQ,CAAC,CAC/D,CACF","file":"next.mjs","sourcesContent":["/**\n * Global Configuration\n *\n * Manages SDK configuration and transport instance.\n */\n\nimport type { LelemonConfig } from './types';\nimport { Transport } from './transport';\nimport { setDebug, info, warn, debug } from './logger';\n\n// ─────────────────────────────────────────────────────────────\n// Global State\n// ─────────────────────────────────────────────────────────────\n\nlet globalConfig: LelemonConfig = {};\nlet globalTransport: Transport | null = null;\nlet initialized = false;\n\n// ─────────────────────────────────────────────────────────────\n// Configuration\n// ─────────────────────────────────────────────────────────────\n\nconst DEFAULT_ENDPOINT = 'https://www.lelemon.dev';\n\n/**\n * Initialize the SDK\n * Call once at app startup\n */\nexport function init(config: LelemonConfig = {}): void {\n globalConfig = config;\n\n // Configure debug mode\n if (config.debug) {\n setDebug(true);\n }\n\n info('Initializing SDK', {\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n debug: config.debug ?? false,\n disabled: config.disabled ?? false,\n });\n\n globalTransport = createTransport(config);\n initialized = true;\n\n // Log status after transport is created\n if (globalTransport.isEnabled()) {\n info('SDK initialized - tracing enabled');\n } else {\n debug('SDK initialized - tracing disabled (no API key or explicitly disabled)');\n }\n}\n\n/**\n * Get current config\n */\nexport function getConfig(): LelemonConfig {\n return globalConfig;\n}\n\n/**\n * Check if SDK is initialized\n */\nexport function isInitialized(): boolean {\n return initialized;\n}\n\n/**\n * Check if SDK is enabled\n */\nexport function isEnabled(): boolean {\n return getTransport().isEnabled();\n}\n\n// ─────────────────────────────────────────────────────────────\n// Transport\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Get or create transport instance\n */\nexport function getTransport(): Transport {\n if (!globalTransport) {\n globalTransport = createTransport(globalConfig);\n }\n return globalTransport;\n}\n\n/**\n * Flush all pending traces\n */\nexport async function flush(): Promise<void> {\n if (globalTransport) {\n await globalTransport.flush();\n }\n}\n\n/**\n * Create transport instance\n */\nfunction createTransport(config: LelemonConfig): Transport {\n const apiKey = config.apiKey ?? getEnvVar('LELEMON_API_KEY');\n\n if (!apiKey && !config.disabled) {\n warn('No API key provided. Set apiKey in init() or LELEMON_API_KEY env var. Tracing disabled.');\n }\n\n return new Transport({\n apiKey: apiKey ?? '',\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n debug: config.debug ?? false,\n disabled: config.disabled ?? !apiKey,\n batchSize: config.batchSize,\n flushIntervalMs: config.flushIntervalMs,\n requestTimeoutMs: config.requestTimeoutMs,\n });\n}\n\n/**\n * Get environment variable (works in Node and edge)\n */\nfunction getEnvVar(name: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n","/**\n * Next.js App Router Integration\n *\n * Wraps route handlers to automatically flush traces.\n * Supports Next.js 15+ `after()` and Vercel's `waitUntil()`.\n *\n * @example\n * import { withObserve } from '@lelemondev/sdk/next';\n *\n * export const POST = withObserve(async (req) => {\n * const openai = observe(new OpenAI());\n * const result = await openai.chat.completions.create({...});\n * return Response.json(result);\n * });\n */\n\nimport { flush } from '../core/config';\n\n// ─────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Next.js App Router handler type\n *\n * @typeParam TContext - Optional context type for dynamic route parameters\n */\nexport type NextRouteHandler<TContext = unknown> = (\n request: Request,\n context?: TContext\n) => Response | Promise<Response>;\n\n/**\n * Options for the Next.js wrapper\n */\nexport interface NextObserveOptions {\n /**\n * Next.js 15+ after() function from 'next/server'\n * Preferred method - runs after response without blocking\n *\n * @example\n * import { after } from 'next/server';\n * export const POST = withObserve(handler, { after });\n */\n after?: (callback: () => void | Promise<void>) => void;\n\n /**\n * Vercel's waitUntil() from '@vercel/functions'\n * Alternative for Vercel deployments\n *\n * @example\n * import { waitUntil } from '@vercel/functions';\n * export const POST = withObserve(handler, { waitUntil });\n */\n waitUntil?: (promise: Promise<unknown>) => void;\n}\n\n// ─────────────────────────────────────────────────────────────\n// Wrapper\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Wrap a Next.js App Router handler with automatic trace flushing\n *\n * @param handler - Your route handler function\n * @param options - Optional: pass `after` (Next.js 15+) or `waitUntil` (Vercel)\n * @returns Wrapped handler that auto-flushes traces\n *\n * @example\n * // Basic usage (blocking flush)\n * export const POST = withObserve(async (req) => {\n * return Response.json({ ok: true });\n * });\n *\n * @example\n * // Next.js 15+ with after() - non-blocking (recommended)\n * import { after } from 'next/server';\n *\n * export const POST = withObserve(\n * async (req) => Response.json({ ok: true }),\n * { after }\n * );\n *\n * @example\n * // Vercel with waitUntil() - non-blocking\n * import { waitUntil } from '@vercel/functions';\n *\n * export const POST = withObserve(\n * async (req) => Response.json({ ok: true }),\n * { waitUntil }\n * );\n */\nexport function withObserve<TContext = unknown>(\n handler: NextRouteHandler<TContext>,\n options?: NextObserveOptions\n): NextRouteHandler<TContext> {\n return async (request: Request, context?: TContext): Promise<Response> => {\n try {\n return await handler(request, context);\n } finally {\n // Priority: after() > waitUntil() > blocking flush\n if (options?.after) {\n // Next.js 15+ native - best option\n options.after(() => flush());\n } else if (options?.waitUntil) {\n // Vercel platform\n options.waitUntil(flush());\n } else {\n // Fallback: blocking flush\n await flush();\n }\n }\n };\n}\n\n/**\n * Create a pre-configured wrapper with default options\n *\n * @example\n * import { after } from 'next/server';\n * import { createWrapper } from '@lelemondev/sdk/next';\n *\n * const withObserve = createWrapper({ after });\n *\n * export const POST = withObserve(async (req) => {\n * return Response.json({ ok: true });\n * });\n */\nexport function createWrapper(defaultOptions: NextObserveOptions) {\n return function <TContext = unknown>(\n handler: NextRouteHandler<TContext>,\n options?: NextObserveOptions\n ): NextRouteHandler<TContext> {\n return withObserve(handler, { ...defaultOptions, ...options });\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/core/config.ts","../src/integrations/next.ts"],"names":["flush","withObserve","handler","options","request","context","createWrapper","defaultOptions"],"mappings":";AAwGA,eAAsBA,CAAAA,EAAuB,CAI7C,CChBO,SAASC,CAAAA,CACdC,EACAC,CAAAA,CAC4B,CAC5B,OAAO,MAAOC,CAAAA,CAAkBC,CAAAA,GAA0C,CACxE,GAAI,CACF,OAAO,MAAMH,CAAAA,CAAQE,CAAAA,CAASC,CAAO,CACvC,CAAA,OAAE,CAEIF,CAAAA,EAAS,MAEXA,CAAAA,CAAQ,KAAA,CAAM,IAAMH,CAAAA,EAAO,CAAA,CAClBG,CAAAA,EAAS,SAAA,CAElBA,EAAQ,SAAA,CAAUH,CAAAA,EAAO,CAAA,CAGzB,MAAMA,CAAAA,GAEV,CACF,CACF,CAeO,SAASM,CAAAA,CAAcC,CAAAA,CAAoC,CAChE,OAAO,SACLL,CAAAA,CACAC,CAAAA,CAC4B,CAC5B,OAAOF,CAAAA,CAAYC,CAAAA,CAAS,CAAE,GAAGK,CAAAA,CAAgB,GAAGJ,CAAQ,CAAC,CAC/D,CACF","file":"next.mjs","sourcesContent":["/**\n * Global Configuration\n *\n * Manages SDK configuration and transport instance.\n */\n\nimport type { LelemonConfig, SDKTelemetry } from './types';\nimport { Transport } from './transport';\nimport { setDebug, info, warn, debug } from './logger';\nimport { buildTelemetry } from './telemetry';\n\n// ─────────────────────────────────────────────────────────────\n// Global State\n// ─────────────────────────────────────────────────────────────\n\nlet globalConfig: LelemonConfig = {};\nlet globalTransport: Transport | null = null;\nlet globalTelemetry: SDKTelemetry | null = null;\nlet initialized = false;\n\n// ─────────────────────────────────────────────────────────────\n// Configuration\n// ─────────────────────────────────────────────────────────────\n\nconst DEFAULT_ENDPOINT = 'https://www.lelemon.dev';\n\n/**\n * Initialize the SDK\n * Call once at app startup\n */\nexport function init(config: LelemonConfig = {}): void {\n globalConfig = config;\n\n // Configure debug mode\n if (config.debug) {\n setDebug(true);\n }\n\n // Build telemetry with service config\n globalTelemetry = buildTelemetry(config.service);\n\n info('Initializing SDK', {\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n debug: config.debug ?? false,\n disabled: config.disabled ?? false,\n telemetry: globalTelemetry,\n });\n\n globalTransport = createTransport(config);\n initialized = true;\n\n // Log status after transport is created\n if (globalTransport.isEnabled()) {\n info('SDK initialized - tracing enabled');\n } else {\n debug('SDK initialized - tracing disabled (no API key or explicitly disabled)');\n }\n}\n\n/**\n * Get current config\n */\nexport function getConfig(): LelemonConfig {\n return globalConfig;\n}\n\n/**\n * Get SDK telemetry\n */\nexport function getTelemetry(): SDKTelemetry | null {\n return globalTelemetry;\n}\n\n/**\n * Check if SDK is initialized\n */\nexport function isInitialized(): boolean {\n return initialized;\n}\n\n/**\n * Check if SDK is enabled\n */\nexport function isEnabled(): boolean {\n return getTransport().isEnabled();\n}\n\n// ─────────────────────────────────────────────────────────────\n// Transport\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Get or create transport instance\n */\nexport function getTransport(): Transport {\n if (!globalTransport) {\n globalTransport = createTransport(globalConfig);\n }\n return globalTransport;\n}\n\n/**\n * Flush all pending traces\n */\nexport async function flush(): Promise<void> {\n if (globalTransport) {\n await globalTransport.flush();\n }\n}\n\n/**\n * Create transport instance\n */\nfunction createTransport(config: LelemonConfig): Transport {\n const apiKey = config.apiKey ?? getEnvVar('LELEMON_API_KEY');\n\n if (!apiKey && !config.disabled) {\n warn('No API key provided. Set apiKey in init() or LELEMON_API_KEY env var. Tracing disabled.');\n }\n\n return new Transport({\n apiKey: apiKey ?? '',\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n debug: config.debug ?? false,\n disabled: config.disabled ?? !apiKey,\n batchSize: config.batchSize,\n flushIntervalMs: config.flushIntervalMs,\n requestTimeoutMs: config.requestTimeoutMs,\n });\n}\n\n/**\n * Get environment variable (works in Node and edge)\n */\nfunction getEnvVar(name: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n","/**\n * Next.js App Router Integration\n *\n * Wraps route handlers to automatically flush traces.\n * Supports Next.js 15+ `after()` and Vercel's `waitUntil()`.\n *\n * @example\n * import { withObserve } from '@lelemondev/sdk/next';\n *\n * export const POST = withObserve(async (req) => {\n * const openai = observe(new OpenAI());\n * const result = await openai.chat.completions.create({...});\n * return Response.json(result);\n * });\n */\n\nimport { flush } from '../core/config';\n\n// ─────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Next.js App Router handler type\n *\n * @typeParam TContext - Optional context type for dynamic route parameters\n */\nexport type NextRouteHandler<TContext = unknown> = (\n request: Request,\n context?: TContext\n) => Response | Promise<Response>;\n\n/**\n * Options for the Next.js wrapper\n */\nexport interface NextObserveOptions {\n /**\n * Next.js 15+ after() function from 'next/server'\n * Preferred method - runs after response without blocking\n *\n * @example\n * import { after } from 'next/server';\n * export const POST = withObserve(handler, { after });\n */\n after?: (callback: () => void | Promise<void>) => void;\n\n /**\n * Vercel's waitUntil() from '@vercel/functions'\n * Alternative for Vercel deployments\n *\n * @example\n * import { waitUntil } from '@vercel/functions';\n * export const POST = withObserve(handler, { waitUntil });\n */\n waitUntil?: (promise: Promise<unknown>) => void;\n}\n\n// ─────────────────────────────────────────────────────────────\n// Wrapper\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Wrap a Next.js App Router handler with automatic trace flushing\n *\n * @param handler - Your route handler function\n * @param options - Optional: pass `after` (Next.js 15+) or `waitUntil` (Vercel)\n * @returns Wrapped handler that auto-flushes traces\n *\n * @example\n * // Basic usage (blocking flush)\n * export const POST = withObserve(async (req) => {\n * return Response.json({ ok: true });\n * });\n *\n * @example\n * // Next.js 15+ with after() - non-blocking (recommended)\n * import { after } from 'next/server';\n *\n * export const POST = withObserve(\n * async (req) => Response.json({ ok: true }),\n * { after }\n * );\n *\n * @example\n * // Vercel with waitUntil() - non-blocking\n * import { waitUntil } from '@vercel/functions';\n *\n * export const POST = withObserve(\n * async (req) => Response.json({ ok: true }),\n * { waitUntil }\n * );\n */\nexport function withObserve<TContext = unknown>(\n handler: NextRouteHandler<TContext>,\n options?: NextObserveOptions\n): NextRouteHandler<TContext> {\n return async (request: Request, context?: TContext): Promise<Response> => {\n try {\n return await handler(request, context);\n } finally {\n // Priority: after() > waitUntil() > blocking flush\n if (options?.after) {\n // Next.js 15+ native - best option\n options.after(() => flush());\n } else if (options?.waitUntil) {\n // Vercel platform\n options.waitUntil(flush());\n } else {\n // Fallback: blocking flush\n await flush();\n }\n }\n };\n}\n\n/**\n * Create a pre-configured wrapper with default options\n *\n * @example\n * import { after } from 'next/server';\n * import { createWrapper } from '@lelemondev/sdk/next';\n *\n * const withObserve = createWrapper({ after });\n *\n * export const POST = withObserve(async (req) => {\n * return Response.json({ ok: true });\n * });\n */\nexport function createWrapper(defaultOptions: NextObserveOptions) {\n return function <TContext = unknown>(\n handler: NextRouteHandler<TContext>,\n options?: NextObserveOptions\n ): NextRouteHandler<TContext> {\n return withObserve(handler, { ...defaultOptions, ...options });\n };\n}\n"]}
package/dist/openai.js CHANGED
@@ -1,4 +1,4 @@
1
1
  'use strict';var async_hooks=require('async_hooks');/* @lelemondev/sdk - LLM Observability */
2
- var ue=Object.defineProperty;var ce=(e,n,t)=>n in e?ue(e,n,{enumerable:true,configurable:true,writable:true,value:t}):e[n]=t;var I=(e,n,t)=>ce(e,typeof n!="symbol"?n+"":n,t);var z=false;function F(e){z=e;}function w(){return z?true:pe("LELEMON_DEBUG")==="true"}var f="[Lelemon]";function p(e,n){w()&&_("debug",e,n);}function O(e,n){w()&&_("info",e,n);}function x(e,n){_("warn",e,n);}function P(e,n,t,r){w()&&console.log(`${f} Captured trace: provider=${e} model=${n} duration=${t}ms status=${r}`);}function E(e,n){console.error(`${f} Failed to capture trace: provider=${e} error=${n.message}`);}function K(e){w()&&console.log(`${f} Wrapped client: provider=${e}`);}function j(e,n){w()&&console.log(`${f} Sending batch: count=${e} endpoint=${n}`);}function U(e,n){w()&&console.log(`${f} Batch sent successfully: count=${e} duration=${n}ms`);}function G(e,n){let t=n instanceof Error?n.message:String(n);console.error(`${f} Batch send failed: count=${e} error=${t}`);}function W(e,n,t){w()&&console.log(`${f} Request: ${e} ${n} (${t} bytes)`);}function B(e,n){w()&&console.log(`${f} Response: status=${e} duration=${n}ms`);}function _(e,n,t){let r=e==="error"?console.error:e==="warn"?console.warn:console.log;t!==void 0?r(`${f} ${n}`,t):r(`${f} ${n}`);}function pe(e){if(typeof process<"u"&&process.env)return process.env[e]}var le=10,de=1e3,fe=1e4,R=class{constructor(n){I(this,"config");I(this,"queue",[]);I(this,"flushPromise",null);I(this,"flushTimer",null);this.config={apiKey:n.apiKey,endpoint:n.endpoint,debug:n.debug,disabled:n.disabled,batchSize:n.batchSize??le,flushIntervalMs:n.flushIntervalMs??de,requestTimeoutMs:n.requestTimeoutMs??fe};}isEnabled(){return !this.config.disabled&&!!this.config.apiKey}enqueue(n){this.config.disabled||(this.queue.push(n),this.queue.length>=this.config.batchSize?this.flush():this.scheduleFlush());}async flush(){if(this.flushPromise)return this.flushPromise;if(this.queue.length===0)return;this.cancelScheduledFlush();let n=this.queue;return this.queue=[],this.flushPromise=this.sendBatch(n).finally(()=>{this.flushPromise=null;}),this.flushPromise}getPendingCount(){return this.queue.length}scheduleFlush(){this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush();},this.config.flushIntervalMs));}cancelScheduledFlush(){this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null);}async sendBatch(n){if(n.length===0)return;let t=Date.now();j(n.length,`${this.config.endpoint}/api/v1/ingest`);try{await this.request("POST","/api/v1/ingest",{events:n}),U(n.length,Date.now()-t);}catch(r){G(n.length,r);}}async request(n,t,r){let o=`${this.config.endpoint}${t}`,s=new AbortController,i=r?JSON.stringify(r):void 0;W(n,o,i?.length??0);let u=setTimeout(()=>{s.abort();},this.config.requestTimeoutMs),c=Date.now();try{let a=await fetch(o,{method:n,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:i,signal:s.signal});if(clearTimeout(u),B(a.status,Date.now()-c),!a.ok){let v=await a.text().catch(()=>"Unknown error");throw new Error(`HTTP ${a.status}: ${v}`)}let l=await a.text();return l?JSON.parse(l):{}}catch(a){throw clearTimeout(u),a instanceof Error&&a.name==="AbortError"?new Error(`Request timeout after ${this.config.requestTimeoutMs}ms`):a}}};var $={},h=null,H="https://www.lelemon.dev";function ge(e={}){$=e,e.debug&&F(true),O("Initializing SDK",{endpoint:e.endpoint??H,debug:e.debug??false,disabled:e.disabled??false}),h=Y(e),h.isEnabled()?O("SDK initialized - tracing enabled"):p("SDK initialized - tracing disabled (no API key or explicitly disabled)");}function V(){return $}function we(){return b().isEnabled()}function b(){return h||(h=Y($)),h}async function he(){h&&await h.flush();}function Y(e){let n=e.apiKey??be("LELEMON_API_KEY");return !n&&!e.disabled&&x("No API key provided. Set apiKey in init() or LELEMON_API_KEY env var. Tracing disabled."),new R({apiKey:n??"",endpoint:e.endpoint??H,debug:e.debug??false,disabled:e.disabled??!n,batchSize:e.batchSize,flushIntervalMs:e.flushIntervalMs,requestTimeoutMs:e.requestTimeoutMs})}function be(e){if(typeof process<"u"&&process.env)return process.env[e]}var X={};function Q(e){X=e,p("Global context updated",e);}function S(){return X}function k(e){try{let n=b();if(!n.isEnabled()){p("Transport disabled, skipping trace capture");return}let t=S(),r=m(),o=y(),s={provider:e.provider,model:e.model,input:q(e.input),output:Z(e.output),inputTokens:e.inputTokens,outputTokens:e.outputTokens,durationMs:e.durationMs,status:e.status,streaming:e.streaming,sessionId:t.sessionId,userId:t.userId,traceId:r?.traceId,spanId:o,parentSpanId:r?.currentSpanId,metadata:{...t.metadata,...e.metadata,...r?{_traceName:r.name}:{}},tags:t.tags,stopReason:e.stopReason,cacheReadTokens:e.cacheReadTokens,cacheWriteTokens:e.cacheWriteTokens,reasoningTokens:e.reasoningTokens,firstTokenMs:e.firstTokenMs,thinking:e.thinking};return P(e.provider,e.model,e.durationMs,e.status),n.enqueue(s),o}catch(n){E(e.provider,n instanceof Error?n:new Error(String(n)));return}}function T(e){try{let n=b();if(!n.isEnabled()){p("Transport disabled, skipping error capture");return}let t=S(),r=m(),o={provider:e.provider,model:e.model,input:q(e.input),output:null,inputTokens:0,outputTokens:0,durationMs:e.durationMs,status:"error",errorMessage:e.error.message,errorStack:e.error.stack,streaming:e.streaming,sessionId:t.sessionId,userId:t.userId,traceId:r?.traceId,spanId:y(),parentSpanId:r?.currentSpanId,metadata:{...t.metadata,...e.metadata,...r?{_traceName:r.name}:{}},tags:t.tags};P(e.provider,e.model,e.durationMs,"error"),p("Error details",{message:e.error.message,stack:e.error.stack}),n.enqueue(o);}catch(n){E(e.provider,n instanceof Error?n:new Error(String(n)));}}function D(e){try{let n=b();if(!n.isEnabled()){p("Transport disabled, skipping span capture");return}let t=S(),r=m(),o=e.metadata?._traceId,s=e.metadata?._parentSpanId,i={...t.metadata,...e.metadata};delete i._traceId,delete i._parentSpanId;let u={spanType:e.type,name:e.name,provider:"unknown",model:e.name,input:q(e.input),output:Z(e.output),inputTokens:0,outputTokens:0,durationMs:e.durationMs,status:e.status||"success",errorMessage:e.errorMessage,streaming:!1,sessionId:t.sessionId,userId:t.userId,traceId:o??r?.traceId,spanId:y(),parentSpanId:s??r?.currentSpanId,toolCallId:e.toolCallId,metadata:i,tags:t.tags};p(`Span captured: ${e.type}/${e.name}`,{durationMs:e.durationMs}),n.enqueue(u);}catch(n){E("unknown",n instanceof Error?n:new Error(String(n)));}}var J=1e5,ke=["api_key","apikey","password","secret","token","authorization"];function q(e){return M(e,0)}function Z(e){return M(e,0)}function M(e,n){if(n>10)return "[max depth exceeded]";if(e==null)return e;if(typeof e=="string")return e.length>J?e.slice(0,J)+"...[truncated]":e;if(typeof e=="number"||typeof e=="boolean")return e;if(Array.isArray(e))return e.map(t=>M(t,n+1));if(typeof e=="object"){let t={};for(let[r,o]of Object.entries(e))ke.some(s=>r.toLowerCase().includes(s))?t[r]="[REDACTED]":t[r]=M(o,n+1);return t}return String(e)}var ee=new async_hooks.AsyncLocalStorage;function y(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,11)}`}function m(){return ee.getStore()}function N(e,n){let t=m();if(t)for(let r of e)t.pendingToolCalls.set(r,n),p(`Registered tool call ${r} \u2192 LLM span ${n}`);}function Ce(e){let n=m();if(n)return e&&n.pendingToolCalls.has(e)?n.pendingToolCalls.get(e):n.currentSpanId}function ye(e){let n=m();n&&n.pendingToolCalls.delete(e);}async function Ie(e,n){let t=typeof e=="string"?{name:e}:e,r=m(),o=r?.traceId??y(),s=y(),i={traceId:o,rootSpanId:s,currentSpanId:s,parentSpanId:r?.currentSpanId,name:t.name,startTime:Date.now(),input:t.input,metadata:t.metadata,tags:t.tags,pendingToolCalls:new Map};return ee.run(i,async()=>{let u,c;try{return u=await n(),u}catch(a){throw c=a instanceof Error?a:new Error(String(a)),a}finally{Se(i,c?void 0:u,c);}})}function Se(e,n,t){let r=b();if(!r.isEnabled()){p("Transport disabled, skipping root span");return}let o=S(),s=Date.now()-e.startTime,i=t?null:n,u={spanType:"agent",name:e.name,provider:"agent",model:e.name,traceId:e.traceId,spanId:e.rootSpanId,parentSpanId:e.parentSpanId,input:e.input,output:i,inputTokens:0,outputTokens:0,durationMs:s,status:t?"error":"success",errorMessage:t?.message,streaming:false,sessionId:o.sessionId,userId:o.userId,metadata:{...o.metadata,...e.metadata},tags:e.tags??o.tags};p(`Sending root span: ${e.name}`,{durationMs:s,hasError:!!t}),r.enqueue(u);}function ve(e){let n=m();if(!n){process.env.NODE_ENV!=="production"&&console.warn("[Lelemon] span() called outside of trace() - span will not be captured");return}let t=Ce(e.toolCallId);D({type:e.type,name:e.name,input:e.input,output:e.output,durationMs:e.durationMs??0,status:e.status??"success",errorMessage:e.errorMessage,toolCallId:e.toolCallId,metadata:{...e.metadata,_traceId:n.traceId,_parentSpanId:t}}),e.toolCallId&&ye(e.toolCallId);}var d="openai";function ne(e){if(!e||typeof e!="object")return false;if(e.constructor?.name==="OpenAI")return true;let t=e;return !!(t.chat&&t.completions)||!!t.responses}function te(e){return async function(...t){let r=Date.now(),o=t[0]||{},s=o.stream===true;try{let i=await e(...t);if(s&&re(i))return xe(i,o,r);let u=Date.now()-r,c=i,a=k({provider:d,model:o.model||c.model||"unknown",input:o.messages,rawResponse:i,durationMs:u,status:"success",streaming:!1});if(a){let l=ae(c);l.length>0&&N(l,a);}return i}catch(i){let u=Date.now()-r;throw T({provider:d,model:o.model||"unknown",input:o.messages,error:i instanceof Error?i:new Error(String(i)),durationMs:u,streaming:s}),i}}}function re(e){return e!=null&&typeof e[Symbol.asyncIterator]=="function"}async function*xe(e,n,t){let r={choices:[{message:{content:"",tool_calls:[]},finish_reason:""}],usage:{prompt_tokens:0,completion_tokens:0}},o=null,s,i=false,u=new Map;try{for await(let c of e){let a=c,l=a?.choices?.[0]?.delta?.content;l&&(i||(i=!0,s=Date.now()-t),r.choices[0].message.content+=l);let v=a?.choices?.[0]?.delta?.tool_calls;if(v)for(let g of v){u.has(g.index)||u.set(g.index,{id:"",function:{name:"",arguments:""}});let A=u.get(g.index);g.id&&(A.id=g.id),g.function?.name&&(A.function.name=g.function.name),g.function?.arguments&&(A.function.arguments+=g.function.arguments);}let L=a?.choices?.[0]?.finish_reason;L&&(r.choices[0].finish_reason=L),a?.usage&&(r.usage=a.usage),yield c;}}catch(c){throw o=c instanceof Error?c:new Error(String(c)),c}finally{let c=Date.now()-t;if(u.size>0&&(r.choices[0].message.tool_calls=Array.from(u.entries()).sort((a,l)=>a[0]-l[0]).map(([,a])=>a)),o)T({provider:d,model:n.model||"unknown",input:n.messages,error:o,durationMs:c,streaming:true});else {let a=k({provider:d,model:n.model||"unknown",input:n.messages,rawResponse:r,durationMs:c,status:"success",streaming:true,firstTokenMs:s});if(a){let l=ae(r);l.length>0&&N(l,a);}}}}function oe(e){return async function(...t){let r=Date.now(),o=t[0]||{},s=o.stream===true;try{let i=await e(...t);if(s&&re(i))return Ee(i,o,r);let u=Date.now()-r;return k({provider:d,model:o.model||"unknown",input:{instructions:o.instructions,input:o.input},rawResponse:i,durationMs:u,status:"success",streaming:!1}),i}catch(i){let u=Date.now()-r;throw T({provider:d,model:o.model||"unknown",input:{instructions:o.instructions,input:o.input},error:i instanceof Error?i:new Error(String(i)),durationMs:u,streaming:s}),i}}}async function*Ee(e,n,t){let r=[],o=null,s=null;try{for await(let i of e){r.push(i);let u=i;u.type==="response.done"&&u.response&&(o=u.response),yield i;}}catch(i){throw s=i instanceof Error?i:new Error(String(i)),i}finally{let i=Date.now()-t;s?T({provider:d,model:n.model||"unknown",input:{instructions:n.instructions,input:n.input},error:s,durationMs:i,streaming:true}):k({provider:d,model:n.model||"unknown",input:{instructions:n.instructions,input:n.input},rawResponse:o||{streamEvents:r},durationMs:i,status:"success",streaming:true});}}function se(e){return async function(...t){let r=Date.now(),o=t[0]||{};try{let s=await e(...t),i=Date.now()-r;return k({provider:d,model:o.model||"unknown",input:o.prompt,rawResponse:s,durationMs:i,status:"success",streaming:!1}),s}catch(s){let i=Date.now()-r;throw T({provider:d,model:o.model||"unknown",input:o.prompt,error:s instanceof Error?s:new Error(String(s)),durationMs:i,streaming:false}),s}}}function ie(e){return async function(...t){let r=Date.now(),o=t[0]||{};try{let s=await e(...t),i=Date.now()-r;return k({provider:d,model:o.model||"unknown",input:o.input,rawResponse:s,durationMs:i,status:"success",streaming:!1,spanType:"embedding"}),s}catch(s){let i=Date.now()-r;throw T({provider:d,model:o.model||"unknown",input:o.input,error:s instanceof Error?s:new Error(String(s)),durationMs:i,streaming:false}),s}}}function ae(e){let n=[],t=e.choices?.[0]?.message?.tool_calls;if(Array.isArray(t))for(let r of t)r.id&&n.push(r.id);return n}function dn(e,n){return n&&Q(n),V().disabled?(p("Tracing disabled, returning unwrapped client"),e):ne(e)?(K("openai"),Me(e)):(x("Client is not an OpenAI client. Use @lelemondev/sdk/openai only with OpenAI SDK."),e)}function Me(e){let n=e;return new Proxy(n,{get(t,r,o){let s=Reflect.get(t,r,o);return r==="chat"&&s&&typeof s=="object"?Ae(s):r==="responses"&&s&&typeof s=="object"?Pe(s):r==="completions"&&s&&typeof s=="object"?_e(s):r==="embeddings"&&s&&typeof s=="object"?$e(s):s}})}function Ae(e){return new Proxy(e,{get(n,t,r){let o=Reflect.get(n,t,r);return t==="completions"&&o&&typeof o=="object"?Oe(o):o}})}function Oe(e){return new Proxy(e,{get(n,t,r){let o=Reflect.get(n,t,r);return t==="create"&&typeof o=="function"?te(o.bind(n)):o}})}function Pe(e){return new Proxy(e,{get(n,t,r){let o=Reflect.get(n,t,r);return t==="create"&&typeof o=="function"?oe(o.bind(n)):o}})}function _e(e){return new Proxy(e,{get(n,t,r){let o=Reflect.get(n,t,r);return t==="create"&&typeof o=="function"?se(o.bind(n)):o}})}function $e(e){return new Proxy(e,{get(n,t,r){let o=Reflect.get(n,t,r);return t==="create"&&typeof o=="function"?ie(o.bind(n)):o}})}
3
- exports.captureSpan=D;exports.flush=he;exports.getTraceContext=m;exports.init=ge;exports.isEnabled=we;exports.observe=dn;exports.span=ve;exports.trace=Ie;//# sourceMappingURL=openai.js.map
2
+ var fe=Object.defineProperty;var ge=(e,n,t)=>n in e?fe(e,n,{enumerable:true,configurable:true,writable:true,value:t}):e[n]=t;var z=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(n,t)=>(typeof require<"u"?require:n)[t]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var we=(e,n)=>()=>(n||e((n={exports:{}}).exports,n),n.exports);var I=(e,n,t)=>ge(e,typeof n!="symbol"?n+"":n,t);var X=we((sn,Te)=>{Te.exports={name:"@lelemondev/sdk",version:"0.9.2",description:"Automatic LLM observability. Wrap your client, everything is traced.",author:"Lelemon <info@lelemon.dev>",license:"MIT",repository:{type:"git",url:"git+https://github.com/lelemondev/lelemondev-sdk.git"},homepage:"https://lelemon.dev",bugs:{url:"https://github.com/lelemondev/lelemondev-sdk/issues"},keywords:["llm","observability","tracing","openai","anthropic","nextjs","lambda","express","hono","claude","gpt","ai","monitoring","serverless"],main:"./dist/index.js",module:"./dist/index.mjs",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.mjs",require:"./dist/index.js"},"./openai":{types:"./dist/openai.d.ts",import:"./dist/openai.mjs",require:"./dist/openai.js"},"./anthropic":{types:"./dist/anthropic.d.ts",import:"./dist/anthropic.mjs",require:"./dist/anthropic.js"},"./bedrock":{types:"./dist/bedrock.d.ts",import:"./dist/bedrock.mjs",require:"./dist/bedrock.js"},"./gemini":{types:"./dist/gemini.d.ts",import:"./dist/gemini.mjs",require:"./dist/gemini.js"},"./openrouter":{types:"./dist/openrouter.d.ts",import:"./dist/openrouter.mjs",require:"./dist/openrouter.js"},"./next":{types:"./dist/next.d.ts",import:"./dist/next.mjs",require:"./dist/next.js"},"./lambda":{types:"./dist/lambda.d.ts",import:"./dist/lambda.mjs",require:"./dist/lambda.js"},"./express":{types:"./dist/express.d.ts",import:"./dist/express.mjs",require:"./dist/express.js"},"./hono":{types:"./dist/hono.d.ts",import:"./dist/hono.mjs",require:"./dist/hono.js"},"./integrations":{types:"./dist/integrations.d.ts",import:"./dist/integrations.mjs",require:"./dist/integrations.js"},"./package.json":"./package.json"},typesVersions:{"*":{openai:["./dist/openai.d.ts"],anthropic:["./dist/anthropic.d.ts"],bedrock:["./dist/bedrock.d.ts"],gemini:["./dist/gemini.d.ts"],openrouter:["./dist/openrouter.d.ts"],next:["./dist/next.d.ts"],lambda:["./dist/lambda.d.ts"],express:["./dist/express.d.ts"],hono:["./dist/hono.d.ts"],integrations:["./dist/integrations.d.ts"],"*":["./dist/index.d.ts"]}},files:["dist","README.md"],sideEffects:false,engines:{node:">=18.0.0"},scripts:{build:"tsup",dev:"tsup --watch",docs:"typedoc && node scripts/generate-llms-txt.mjs",prepublishOnly:"npm run build",lint:"eslint src/",test:"vitest","test:run":"vitest run","test:coverage":"vitest run --coverage","test:e2e":"vitest run tests/e2e",typecheck:"tsc --noEmit"},devDependencies:{"@aws-sdk/client-bedrock-runtime":"^3.962.0","@google/generative-ai":"^0.24.1","@types/node":"^20.0.0","@vitest/coverage-v8":"^2.0.0",dotenv:"^17.2.3",openai:"^6.15.0",tsup:"^8.5.1",typedoc:"^0.28.15",typescript:"^5.9.3",vitest:"^2.0.0"}};});var U=false;function V(e){U=e;}function w(){return U?true:he("LELEMON_DEBUG")==="true"}var m="[Lelemon]";function d(e,n){w()&&q("debug",e,n);}function D(e,n){w()&&q("info",e,n);}function R(e,n){q("warn",e,n);}function P(e,n,t,r){w()&&console.log(`${m} Captured trace: provider=${e} model=${n} duration=${t}ms status=${r}`);}function _(e,n){console.error(`${m} Failed to capture trace: provider=${e} error=${n.message}`);}function B(e){w()&&console.log(`${m} Wrapped client: provider=${e}`);}function G(e,n){w()&&console.log(`${m} Sending batch: count=${e} endpoint=${n}`);}function H(e,n){w()&&console.log(`${m} Batch sent successfully: count=${e} duration=${n}ms`);}function W(e,n){let t=n instanceof Error?n.message:String(n);console.error(`${m} Batch send failed: count=${e} error=${t}`);}function Y(e,n,t){w()&&console.log(`${m} Request: ${e} ${n} (${t} bytes)`);}function J(e,n){w()&&console.log(`${m} Response: status=${e} duration=${n}ms`);}function q(e,n,t){let r=e==="error"?console.error:e==="warn"?console.warn:console.log;t!==void 0?r(`${m} ${n}`,t):r(`${m} ${n}`);}function he(e){if(typeof process<"u"&&process.env)return process.env[e]}var ye=10,be=1e3,ke=1e4,A=class{constructor(n){I(this,"config");I(this,"queue",[]);I(this,"flushPromise",null);I(this,"flushTimer",null);this.config={apiKey:n.apiKey,endpoint:n.endpoint,debug:n.debug,disabled:n.disabled,batchSize:n.batchSize??ye,flushIntervalMs:n.flushIntervalMs??be,requestTimeoutMs:n.requestTimeoutMs??ke};}isEnabled(){return !this.config.disabled&&!!this.config.apiKey}enqueue(n){this.config.disabled||(this.queue.push(n),this.queue.length>=this.config.batchSize?this.flush():this.scheduleFlush());}async flush(){if(this.flushPromise)return this.flushPromise;if(this.queue.length===0)return;this.cancelScheduledFlush();let n=this.queue;return this.queue=[],this.flushPromise=this.sendBatch(n).finally(()=>{this.flushPromise=null;}),this.flushPromise}getPendingCount(){return this.queue.length}scheduleFlush(){this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush();},this.config.flushIntervalMs));}cancelScheduledFlush(){this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null);}async sendBatch(n){if(n.length===0)return;let t=Date.now();G(n.length,`${this.config.endpoint}/api/v1/ingest`);try{await this.request("POST","/api/v1/ingest",{events:n}),H(n.length,Date.now()-t);}catch(r){W(n.length,r);}}async request(n,t,r){let o=`${this.config.endpoint}${t}`,s=new AbortController,i=r?JSON.stringify(r):void 0;Y(n,o,i?.length??0);let a=setTimeout(()=>{s.abort();},this.config.requestTimeoutMs),c=Date.now();try{let u=await fetch(o,{method:n,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:i,signal:s.signal});if(clearTimeout(a),J(u.status,Date.now()-c),!u.ok){let E=await u.text().catch(()=>"Unknown error");throw new Error(`HTTP ${u.status}: ${E}`)}let l=await u.text();return l?JSON.parse(l):{}}catch(u){throw clearTimeout(a),u instanceof Error&&u.name==="AbortError"?new Error(`Request timeout after ${this.config.requestTimeoutMs}ms`):u}}};var ve="@lelemondev/sdk",Ce="nodejs";function Ie(){return typeof process<"u"&&process.versions?.node?{name:"nodejs",version:process.versions.node}:typeof Deno<"u"?{name:"deno",version:Deno.version?.deno??"unknown"}:typeof Bun<"u"?{name:"bun",version:Bun.version??"unknown"}:typeof window<"u"&&typeof navigator<"u"?{name:"browser",version:navigator.userAgent}:null}function xe(){if(typeof process<"u"&&process.platform){let e=process.platform;switch(e){case "darwin":return "darwin";case "win32":return "windows";case "linux":return "linux";default:return e}}if(typeof navigator<"u"){let e=navigator.userAgent.toLowerCase();if(e.includes("mac"))return "darwin";if(e.includes("win"))return "windows";if(e.includes("linux"))return "linux"}return null}function Se(){try{if(typeof z<"u")return X().version??"unknown"}catch{}return "unknown"}var v=null;function Z(e){if(!v){let t=Ie(),r=xe();v={"telemetry.sdk.name":ve,"telemetry.sdk.version":Se(),"telemetry.sdk.language":Ce},t&&(v["process.runtime.name"]=t.name,v["process.runtime.version"]=t.version),r&&(v["os.type"]=r);}let n={...v};return e?.name&&(n["service.name"]=e.name),e?.version&&(n["service.version"]=e.version),e?.environment&&(n["deployment.environment"]=e.environment),n}var j={},y=null,$=null,ee="https://www.lelemon.dev";function Re(e={}){j=e,e.debug&&V(true),$=Z(e.service),D("Initializing SDK",{endpoint:e.endpoint??ee,debug:e.debug??false,disabled:e.disabled??false,telemetry:$}),y=te(e),y.isEnabled()?D("SDK initialized - tracing enabled"):d("SDK initialized - tracing disabled (no API key or explicitly disabled)");}function ne(){return j}function M(){return $}function _e(){return b().isEnabled()}function b(){return y||(y=te(j)),y}async function Ae(){y&&await y.flush();}function te(e){let n=e.apiKey??Me("LELEMON_API_KEY");return !n&&!e.disabled&&R("No API key provided. Set apiKey in init() or LELEMON_API_KEY env var. Tracing disabled."),new A({apiKey:n??"",endpoint:e.endpoint??ee,debug:e.debug??false,disabled:e.disabled??!n,batchSize:e.batchSize,flushIntervalMs:e.flushIntervalMs,requestTimeoutMs:e.requestTimeoutMs})}function Me(e){if(typeof process<"u"&&process.env)return process.env[e]}var oe={};function se(e){oe=e,d("Global context updated",e);}function S(){return oe}function k(e){try{let n=b();if(!n.isEnabled()){d("Transport disabled, skipping trace capture");return}let t=S(),r=f(),o=C(),s=M(),i={provider:e.provider,model:e.model,input:K(e.input),rawResponse:e.rawResponse?x(e.rawResponse,0):void 0,durationMs:e.durationMs,status:e.status,streaming:e.streaming,firstTokenMs:e.firstTokenMs,sessionId:t.sessionId,userId:t.userId,traceId:r?.traceId,spanId:o,parentSpanId:r?.currentSpanId,metadata:{...t.metadata,...e.metadata,...r?{_traceName:r.name}:{},...s?{_telemetry:s}:{}},tags:t.tags,spanType:e.spanType,name:e.name};return P(e.provider,e.model,e.durationMs,e.status),n.enqueue(i),o}catch(n){_(e.provider,n instanceof Error?n:new Error(String(n)));return}}function T(e){try{let n=b();if(!n.isEnabled()){d("Transport disabled, skipping error capture");return}let t=S(),r=f(),o=M(),s={provider:e.provider,model:e.model,input:K(e.input),durationMs:e.durationMs,status:"error",errorMessage:e.error.message,streaming:e.streaming,sessionId:t.sessionId,userId:t.userId,traceId:r?.traceId,spanId:C(),parentSpanId:r?.currentSpanId,metadata:{...t.metadata,...e.metadata,...r?{_traceName:r.name}:{},...o?{_telemetry:o}:{}},tags:t.tags};P(e.provider,e.model,e.durationMs,"error"),d("Error details",{message:e.error.message,stack:e.error.stack}),n.enqueue(s);}catch(n){_(e.provider,n instanceof Error?n:new Error(String(n)));}}function N(e){try{let n=b();if(!n.isEnabled()){d("Transport disabled, skipping span capture");return}let t=S(),r=f(),o=e.metadata?._traceId,s=e.metadata?._parentSpanId,i=M(),a={...t.metadata,...e.metadata,...i?{_telemetry:i}:{}};delete a._traceId,delete a._parentSpanId;let c={spanType:e.type,name:e.name,provider:"unknown",model:e.name,input:K(e.input),output:x(e.output,0),durationMs:e.durationMs,status:e.status||"success",errorMessage:e.errorMessage,streaming:!1,sessionId:t.sessionId,userId:t.userId,traceId:o??r?.traceId,spanId:C(),parentSpanId:s??r?.currentSpanId,toolCallId:e.toolCallId,metadata:a,tags:t.tags};d(`Span captured: ${e.type}/${e.name}`,{durationMs:e.durationMs}),n.enqueue(c);}catch(n){_("unknown",n instanceof Error?n:new Error(String(n)));}}var re=1e5,Oe=["api_key","apikey","password","secret","authorization"],De=["access_token","auth_token","bearer_token","refresh_token","id_token","session_token"],Pe=["inputtokens","outputtokens","totaltokens","prompttokens","completiontokens","cachereadtokens","cachewritetokens","cachereadinputtokens","cachewriteinputtokens","reasoningtokens"];function qe(e){let n=e.toLowerCase();return Pe.includes(n)?false:!!(Oe.some(t=>n.includes(t))||De.some(t=>n.includes(t)))}function K(e){return x(e,0)}function x(e,n){if(n>10)return "[max depth exceeded]";if(e==null)return e;if(typeof e=="string")return e.length>re?e.slice(0,re)+"...[truncated]":e;if(typeof e=="number"||typeof e=="boolean")return e;if(Array.isArray(e))return e.map(t=>x(t,n+1));if(typeof e=="object"){let t={};for(let[r,o]of Object.entries(e))qe(r)?t[r]="[REDACTED]":t[r]=x(o,n+1);return t}return String(e)}var ie=new async_hooks.AsyncLocalStorage;function C(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,11)}`}function f(){return ie.getStore()}function L(e,n){let t=f();if(t)for(let r of e)t.pendingToolCalls.set(r,n),d(`Registered tool call ${r} \u2192 LLM span ${n}`);}function je(e){let n=f();if(n)return e&&n.pendingToolCalls.has(e)?n.pendingToolCalls.get(e):n.currentSpanId}function Ne(e){let n=f();n&&n.pendingToolCalls.delete(e);}async function Ke(e,n){let t=typeof e=="string"?{name:e}:e,r=f(),o=r?.traceId??C(),s=C(),i={traceId:o,rootSpanId:s,currentSpanId:s,parentSpanId:r?.currentSpanId,name:t.name,startTime:Date.now(),input:t.input,metadata:t.metadata,tags:t.tags,pendingToolCalls:new Map};return ie.run(i,async()=>{let a,c;try{return a=await n(),a}catch(u){throw c=u instanceof Error?u:new Error(String(u)),u}finally{Le(i,c?void 0:a,c);}})}function Le(e,n,t){let r=b();if(!r.isEnabled()){d("Transport disabled, skipping root span");return}let o=S(),s=Date.now()-e.startTime,i=t?null:n,a={spanType:"agent",name:e.name,provider:"agent",model:e.name,traceId:e.traceId,spanId:e.rootSpanId,parentSpanId:e.parentSpanId,input:e.input,output:i,inputTokens:0,outputTokens:0,durationMs:s,status:t?"error":"success",errorMessage:t?.message,streaming:false,sessionId:o.sessionId,userId:o.userId,metadata:{...o.metadata,...e.metadata},tags:e.tags??o.tags};d(`Sending root span: ${e.name}`,{durationMs:s,hasError:!!t}),r.enqueue(a);}function Fe(e){let n=f();if(!n){process.env.NODE_ENV!=="production"&&console.warn("[Lelemon] span() called outside of trace() - span will not be captured");return}let t=je(e.toolCallId);N({type:e.type,name:e.name,input:e.input,output:e.output,durationMs:e.durationMs??0,status:e.status??"success",errorMessage:e.errorMessage,toolCallId:e.toolCallId,metadata:{...e.metadata,_traceId:n.traceId,_parentSpanId:t}}),e.toolCallId&&Ne(e.toolCallId);}var p="openai";function ae(e){if(!e||typeof e!="object")return false;if(e.constructor?.name==="OpenAI")return true;let t=e;return !!(t.chat&&t.completions)||!!t.responses}function ue(e){return async function(...t){let r=Date.now(),o=t[0]||{},s=o.stream===true;try{let i=await e(...t);if(s&&ce(i))return ze(i,o,r);let a=Date.now()-r,c=i,u=k({provider:p,model:o.model||c.model||"unknown",input:o.messages,rawResponse:i,durationMs:a,status:"success",streaming:!1});if(u){let l=me(c);l.length>0&&L(l,u);}return i}catch(i){let a=Date.now()-r;throw T({provider:p,model:o.model||"unknown",input:o.messages,error:i instanceof Error?i:new Error(String(i)),durationMs:a,streaming:s}),i}}}function ce(e){return e!=null&&typeof e[Symbol.asyncIterator]=="function"}async function*ze(e,n,t){let r={choices:[{message:{content:"",tool_calls:[]},finish_reason:""}],usage:{prompt_tokens:0,completion_tokens:0}},o=null,s,i=false,a=new Map;try{for await(let c of e){let u=c,l=u?.choices?.[0]?.delta?.content;l&&(i||(i=!0,s=Date.now()-t),r.choices[0].message.content+=l);let E=u?.choices?.[0]?.delta?.tool_calls;if(E)for(let g of E){a.has(g.index)||a.set(g.index,{id:"",function:{name:"",arguments:""}});let O=a.get(g.index);g.id&&(O.id=g.id),g.function?.name&&(O.function.name=g.function.name),g.function?.arguments&&(O.function.arguments+=g.function.arguments);}let F=u?.choices?.[0]?.finish_reason;F&&(r.choices[0].finish_reason=F),u?.usage&&(r.usage=u.usage),yield c;}}catch(c){throw o=c instanceof Error?c:new Error(String(c)),c}finally{let c=Date.now()-t;if(a.size>0&&(r.choices[0].message.tool_calls=Array.from(a.entries()).sort((u,l)=>u[0]-l[0]).map(([,u])=>u)),o)T({provider:p,model:n.model||"unknown",input:n.messages,error:o,durationMs:c,streaming:true});else {let u=k({provider:p,model:n.model||"unknown",input:n.messages,rawResponse:r,durationMs:c,status:"success",streaming:true,firstTokenMs:s});if(u){let l=me(r);l.length>0&&L(l,u);}}}}function de(e){return async function(...t){let r=Date.now(),o=t[0]||{},s=o.stream===true;try{let i=await e(...t);if(s&&ce(i))return Ue(i,o,r);let a=Date.now()-r;return k({provider:p,model:o.model||"unknown",input:{instructions:o.instructions,input:o.input},rawResponse:i,durationMs:a,status:"success",streaming:!1}),i}catch(i){let a=Date.now()-r;throw T({provider:p,model:o.model||"unknown",input:{instructions:o.instructions,input:o.input},error:i instanceof Error?i:new Error(String(i)),durationMs:a,streaming:s}),i}}}async function*Ue(e,n,t){let r=[],o=null,s=null;try{for await(let i of e){r.push(i);let a=i;a.type==="response.done"&&a.response&&(o=a.response),yield i;}}catch(i){throw s=i instanceof Error?i:new Error(String(i)),i}finally{let i=Date.now()-t;s?T({provider:p,model:n.model||"unknown",input:{instructions:n.instructions,input:n.input},error:s,durationMs:i,streaming:true}):k({provider:p,model:n.model||"unknown",input:{instructions:n.instructions,input:n.input},rawResponse:o||{streamEvents:r},durationMs:i,status:"success",streaming:true});}}function le(e){return async function(...t){let r=Date.now(),o=t[0]||{};try{let s=await e(...t),i=Date.now()-r;return k({provider:p,model:o.model||"unknown",input:o.prompt,rawResponse:s,durationMs:i,status:"success",streaming:!1}),s}catch(s){let i=Date.now()-r;throw T({provider:p,model:o.model||"unknown",input:o.prompt,error:s instanceof Error?s:new Error(String(s)),durationMs:i,streaming:false}),s}}}function pe(e){return async function(...t){let r=Date.now(),o=t[0]||{};try{let s=await e(...t),i=Date.now()-r;return k({provider:p,model:o.model||"unknown",input:o.input,rawResponse:s,durationMs:i,status:"success",streaming:!1,spanType:"embedding"}),s}catch(s){let i=Date.now()-r;throw T({provider:p,model:o.model||"unknown",input:o.input,error:s instanceof Error?s:new Error(String(s)),durationMs:i,streaming:false}),s}}}function me(e){let n=[],t=e.choices?.[0]?.message?.tool_calls;if(Array.isArray(t))for(let r of t)r.id&&n.push(r.id);return n}function Dn(e,n){return n&&se(n),ne().disabled?(d("Tracing disabled, returning unwrapped client"),e):ae(e)?(B("openai"),Be(e)):(R("Client is not an OpenAI client. Use @lelemondev/sdk/openai only with OpenAI SDK."),e)}function Be(e){let n=e;return new Proxy(n,{get(t,r,o){let s=Reflect.get(t,r,o);return r==="chat"&&s&&typeof s=="object"?Ge(s):r==="responses"&&s&&typeof s=="object"?We(s):r==="completions"&&s&&typeof s=="object"?Ye(s):r==="embeddings"&&s&&typeof s=="object"?Je(s):s}})}function Ge(e){return new Proxy(e,{get(n,t,r){let o=Reflect.get(n,t,r);return t==="completions"&&o&&typeof o=="object"?He(o):o}})}function He(e){return new Proxy(e,{get(n,t,r){let o=Reflect.get(n,t,r);return t==="create"&&typeof o=="function"?ue(o.bind(n)):o}})}function We(e){return new Proxy(e,{get(n,t,r){let o=Reflect.get(n,t,r);return t==="create"&&typeof o=="function"?de(o.bind(n)):o}})}function Ye(e){return new Proxy(e,{get(n,t,r){let o=Reflect.get(n,t,r);return t==="create"&&typeof o=="function"?le(o.bind(n)):o}})}function Je(e){return new Proxy(e,{get(n,t,r){let o=Reflect.get(n,t,r);return t==="create"&&typeof o=="function"?pe(o.bind(n)):o}})}
3
+ exports.captureSpan=N;exports.flush=Ae;exports.getTraceContext=f;exports.init=Re;exports.isEnabled=_e;exports.observe=Dn;exports.span=Fe;exports.trace=Ke;//# sourceMappingURL=openai.js.map
4
4
  //# sourceMappingURL=openai.js.map