@lelemondev/sdk 0.6.0 → 0.6.1
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/express.js.map +1 -1
- package/dist/express.mjs.map +1 -1
- package/dist/hono.js.map +1 -1
- package/dist/hono.mjs.map +1 -1
- package/dist/index.js +115 -39
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +115 -39
- package/dist/index.mjs.map +1 -1
- package/dist/integrations.js.map +1 -1
- package/dist/integrations.mjs.map +1 -1
- package/dist/lambda.js.map +1 -1
- package/dist/lambda.mjs.map +1 -1
- package/dist/next.js.map +1 -1
- package/dist/next.mjs.map +1 -1
- package/package.json +1 -1
package/dist/express.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/config.ts","../src/integrations/express.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"sources":["../src/core/config.ts","../src/integrations/express.ts"],"names":[],"mappings":";;;;AAsFA,eAAsB,KAAA,GAAuB;AAI7C;;;AChBO,SAAS,gBAAA,GAAsC;AACpD,EAAA,OAAO,CAAC,IAAA,EAAM,GAAA,EAAK,IAAA,KAAS;AAE1B,IAAA,GAAA,CAAI,EAAA,CAAG,UAAU,MAAM;AACrB,MAAA,KAAA,EAAM,CAAE,MAAM,MAAM;AAAA,MAEpB,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,IAAA,EAAK;AAAA,EACP,CAAA;AACF","file":"express.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 } 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://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 info('SDK initialized successfully');\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 * Express Integration\n *\n * Middleware that automatically flushes traces when response finishes.\n *\n * @example\n * import express from 'express';\n * import { createMiddleware } from '@lelemondev/sdk/express';\n *\n * const app = express();\n * app.use(createMiddleware());\n */\n\nimport { flush } from '../core/config';\n\n// ─────────────────────────────────────────────────────────────\n// Types (minimal to avoid requiring express as dependency)\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Minimal Express request type (avoids requiring express as dependency)\n */\nexport interface ExpressRequest {\n [key: string]: unknown;\n}\n\n/**\n * Minimal Express response type (avoids requiring express as dependency)\n */\nexport interface ExpressResponse {\n on(event: 'finish' | 'close' | 'error', listener: () => void): this;\n [key: string]: unknown;\n}\n\n/**\n * Express next function type\n */\nexport type ExpressNextFunction = (error?: unknown) => void;\n\n/**\n * Express middleware function type\n *\n * @param req - Express request object\n * @param res - Express response object\n * @param next - Next function to pass control\n */\nexport type ExpressMiddleware = (\n req: ExpressRequest,\n res: ExpressResponse,\n next: ExpressNextFunction\n) => void;\n\n// ─────────────────────────────────────────────────────────────\n// Middleware\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Create Express middleware for automatic trace flushing\n *\n * Flushes traces when the response finishes (after res.send/res.json).\n * This is fire-and-forget and doesn't block the response.\n *\n * @returns Express middleware function\n *\n * @example\n * // Global middleware\n * app.use(createMiddleware());\n *\n * @example\n * // Per-route middleware\n * app.post('/chat', createMiddleware(), async (req, res) => {\n * res.json({ ok: true });\n * });\n */\nexport function createMiddleware(): ExpressMiddleware {\n return (_req, res, next) => {\n // Flush when response is finished (after headers + body sent)\n res.on('finish', () => {\n flush().catch(() => {\n // Silently ignore flush errors - fire and forget\n });\n });\n\n next();\n };\n}\n"]}
|
package/dist/express.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/config.ts","../src/integrations/express.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"sources":["../src/core/config.ts","../src/integrations/express.ts"],"names":[],"mappings":";;AAsFA,eAAsB,KAAA,GAAuB;AAI7C;;;AChBO,SAAS,gBAAA,GAAsC;AACpD,EAAA,OAAO,CAAC,IAAA,EAAM,GAAA,EAAK,IAAA,KAAS;AAE1B,IAAA,GAAA,CAAI,EAAA,CAAG,UAAU,MAAM;AACrB,MAAA,KAAA,EAAM,CAAE,MAAM,MAAM;AAAA,MAEpB,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,IAAA,EAAK;AAAA,EACP,CAAA;AACF","file":"express.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 } 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://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 info('SDK initialized successfully');\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 * Express Integration\n *\n * Middleware that automatically flushes traces when response finishes.\n *\n * @example\n * import express from 'express';\n * import { createMiddleware } from '@lelemondev/sdk/express';\n *\n * const app = express();\n * app.use(createMiddleware());\n */\n\nimport { flush } from '../core/config';\n\n// ─────────────────────────────────────────────────────────────\n// Types (minimal to avoid requiring express as dependency)\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Minimal Express request type (avoids requiring express as dependency)\n */\nexport interface ExpressRequest {\n [key: string]: unknown;\n}\n\n/**\n * Minimal Express response type (avoids requiring express as dependency)\n */\nexport interface ExpressResponse {\n on(event: 'finish' | 'close' | 'error', listener: () => void): this;\n [key: string]: unknown;\n}\n\n/**\n * Express next function type\n */\nexport type ExpressNextFunction = (error?: unknown) => void;\n\n/**\n * Express middleware function type\n *\n * @param req - Express request object\n * @param res - Express response object\n * @param next - Next function to pass control\n */\nexport type ExpressMiddleware = (\n req: ExpressRequest,\n res: ExpressResponse,\n next: ExpressNextFunction\n) => void;\n\n// ─────────────────────────────────────────────────────────────\n// Middleware\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Create Express middleware for automatic trace flushing\n *\n * Flushes traces when the response finishes (after res.send/res.json).\n * This is fire-and-forget and doesn't block the response.\n *\n * @returns Express middleware function\n *\n * @example\n * // Global middleware\n * app.use(createMiddleware());\n *\n * @example\n * // Per-route middleware\n * app.post('/chat', createMiddleware(), async (req, res) => {\n * res.json({ ok: true });\n * });\n */\nexport function createMiddleware(): ExpressMiddleware {\n return (_req, res, next) => {\n // Flush when response is finished (after headers + body sent)\n res.on('finish', () => {\n flush().catch(() => {\n // Silently ignore flush errors - fire and forget\n });\n });\n\n next();\n };\n}\n"]}
|
package/dist/hono.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/config.ts","../src/integrations/hono.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"sources":["../src/core/config.ts","../src/integrations/hono.ts"],"names":[],"mappings":";;;;AAsFA,eAAsB,KAAA,GAAuB;AAI7C;;;ACPO,SAAS,gBAAA,GAAmC;AACjD,EAAA,OAAO,OAAO,GAAG,IAAA,KAAS;AACxB,IAAA,MAAM,IAAA,EAAK;AAGX,IAAA,IAAI,CAAA,CAAE,cAAc,SAAA,EAAW;AAC7B,MAAA,CAAA,CAAE,YAAA,CAAa,SAAA,CAAU,KAAA,EAAO,CAAA;AAAA,IAClC,CAAA,MAAO;AAEL,MAAA,KAAA,EAAM,CAAE,MAAM,MAAM;AAAA,MAAC,CAAC,CAAA;AAAA,IACxB;AAAA,EACF,CAAA;AACF","file":"hono.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 } 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://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 info('SDK initialized successfully');\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 * Hono Integration\n *\n * Middleware for Hono framework (Cloudflare Workers, Deno, Bun, Node.js).\n * Uses executionCtx.waitUntil() when available for non-blocking flush.\n *\n * @example\n * import { Hono } from 'hono';\n * import { createMiddleware } from '@lelemondev/sdk/hono';\n *\n * const app = new Hono();\n * app.use(createMiddleware());\n */\n\nimport { flush } from '../core/config';\n\n// ─────────────────────────────────────────────────────────────\n// Types (minimal to avoid requiring hono as dependency)\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Execution context for edge runtimes (Cloudflare Workers, Deno Deploy)\n */\nexport interface ExecutionContext {\n waitUntil(promise: Promise<unknown>): void;\n passThroughOnException(): void;\n}\n\n/**\n * Minimal Hono context type (avoids requiring hono as dependency)\n */\nexport interface HonoContext {\n req: {\n raw: Request;\n [key: string]: unknown;\n };\n res: Response | undefined;\n executionCtx?: ExecutionContext;\n [key: string]: unknown;\n}\n\n/**\n * Hono next function type\n */\nexport type HonoNextFunction = () => Promise<void>;\n\n/**\n * Hono middleware function type\n *\n * @param c - Hono context object\n * @param next - Next function to continue middleware chain\n */\nexport type HonoMiddleware = (c: HonoContext, next: HonoNextFunction) => Promise<void>;\n\n// ─────────────────────────────────────────────────────────────\n// Middleware\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Create Hono middleware for automatic trace flushing\n *\n * On Cloudflare Workers/Deno Deploy: uses executionCtx.waitUntil() for non-blocking flush\n * On Node.js/Bun: flushes after response (fire-and-forget)\n *\n * @returns Hono middleware function\n *\n * @example\n * import { Hono } from 'hono';\n * import { createMiddleware } from '@lelemondev/sdk/hono';\n *\n * const app = new Hono();\n *\n * // Global middleware\n * app.use(createMiddleware());\n *\n * app.post('/chat', async (c) => {\n * const openai = observe(new OpenAI());\n * const result = await openai.chat.completions.create({...});\n * return c.json(result);\n * });\n *\n * export default app;\n */\nexport function createMiddleware(): HonoMiddleware {\n return async (c, next) => {\n await next();\n\n // Use waitUntil if available (Cloudflare Workers, Deno Deploy)\n if (c.executionCtx?.waitUntil) {\n c.executionCtx.waitUntil(flush());\n } else {\n // Fire-and-forget for Node.js/Bun\n flush().catch(() => {});\n }\n };\n}\n"]}
|
package/dist/hono.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/config.ts","../src/integrations/hono.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"sources":["../src/core/config.ts","../src/integrations/hono.ts"],"names":[],"mappings":";;AAsFA,eAAsB,KAAA,GAAuB;AAI7C;;;ACPO,SAAS,gBAAA,GAAmC;AACjD,EAAA,OAAO,OAAO,GAAG,IAAA,KAAS;AACxB,IAAA,MAAM,IAAA,EAAK;AAGX,IAAA,IAAI,CAAA,CAAE,cAAc,SAAA,EAAW;AAC7B,MAAA,CAAA,CAAE,YAAA,CAAa,SAAA,CAAU,KAAA,EAAO,CAAA;AAAA,IAClC,CAAA,MAAO;AAEL,MAAA,KAAA,EAAM,CAAE,MAAM,MAAM;AAAA,MAAC,CAAC,CAAA;AAAA,IACxB;AAAA,EACF,CAAA;AACF","file":"hono.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 } 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://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 info('SDK initialized successfully');\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 * Hono Integration\n *\n * Middleware for Hono framework (Cloudflare Workers, Deno, Bun, Node.js).\n * Uses executionCtx.waitUntil() when available for non-blocking flush.\n *\n * @example\n * import { Hono } from 'hono';\n * import { createMiddleware } from '@lelemondev/sdk/hono';\n *\n * const app = new Hono();\n * app.use(createMiddleware());\n */\n\nimport { flush } from '../core/config';\n\n// ─────────────────────────────────────────────────────────────\n// Types (minimal to avoid requiring hono as dependency)\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Execution context for edge runtimes (Cloudflare Workers, Deno Deploy)\n */\nexport interface ExecutionContext {\n waitUntil(promise: Promise<unknown>): void;\n passThroughOnException(): void;\n}\n\n/**\n * Minimal Hono context type (avoids requiring hono as dependency)\n */\nexport interface HonoContext {\n req: {\n raw: Request;\n [key: string]: unknown;\n };\n res: Response | undefined;\n executionCtx?: ExecutionContext;\n [key: string]: unknown;\n}\n\n/**\n * Hono next function type\n */\nexport type HonoNextFunction = () => Promise<void>;\n\n/**\n * Hono middleware function type\n *\n * @param c - Hono context object\n * @param next - Next function to continue middleware chain\n */\nexport type HonoMiddleware = (c: HonoContext, next: HonoNextFunction) => Promise<void>;\n\n// ─────────────────────────────────────────────────────────────\n// Middleware\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Create Hono middleware for automatic trace flushing\n *\n * On Cloudflare Workers/Deno Deploy: uses executionCtx.waitUntil() for non-blocking flush\n * On Node.js/Bun: flushes after response (fire-and-forget)\n *\n * @returns Hono middleware function\n *\n * @example\n * import { Hono } from 'hono';\n * import { createMiddleware } from '@lelemondev/sdk/hono';\n *\n * const app = new Hono();\n *\n * // Global middleware\n * app.use(createMiddleware());\n *\n * app.post('/chat', async (c) => {\n * const openai = observe(new OpenAI());\n * const result = await openai.chat.completions.create({...});\n * return c.json(result);\n * });\n *\n * export default app;\n */\nexport function createMiddleware(): HonoMiddleware {\n return async (c, next) => {\n await next();\n\n // Use waitUntil if available (Cloudflare Workers, Deno Deploy)\n if (c.executionCtx?.waitUntil) {\n c.executionCtx.waitUntil(flush());\n } else {\n // Fire-and-forget for Node.js/Bun\n flush().catch(() => {});\n }\n };\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,77 @@ var __defProp = Object.defineProperty;
|
|
|
5
5
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
6
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
7
|
|
|
8
|
+
// src/core/logger.ts
|
|
9
|
+
var debugEnabled = false;
|
|
10
|
+
function setDebug(enabled) {
|
|
11
|
+
debugEnabled = enabled;
|
|
12
|
+
}
|
|
13
|
+
function isDebugEnabled() {
|
|
14
|
+
if (debugEnabled) return true;
|
|
15
|
+
return getEnvVar("LELEMON_DEBUG") === "true";
|
|
16
|
+
}
|
|
17
|
+
var PREFIX = "[Lelemon]";
|
|
18
|
+
function debug(message, data) {
|
|
19
|
+
if (!isDebugEnabled()) return;
|
|
20
|
+
logWithPrefix("debug", message, data);
|
|
21
|
+
}
|
|
22
|
+
function info(message, data) {
|
|
23
|
+
if (!isDebugEnabled()) return;
|
|
24
|
+
logWithPrefix("info", message, data);
|
|
25
|
+
}
|
|
26
|
+
function warn(message, data) {
|
|
27
|
+
logWithPrefix("warn", message, data);
|
|
28
|
+
}
|
|
29
|
+
function traceCapture(provider, model, durationMs, status) {
|
|
30
|
+
if (!isDebugEnabled()) return;
|
|
31
|
+
console.log(
|
|
32
|
+
`${PREFIX} Captured trace: provider=${provider} model=${model} duration=${durationMs}ms status=${status}`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
function traceCaptureError(provider, error) {
|
|
36
|
+
if (!isDebugEnabled()) return;
|
|
37
|
+
console.log(`${PREFIX} Failed to capture trace: provider=${provider} error=${error.message}`);
|
|
38
|
+
}
|
|
39
|
+
function clientWrapped(provider) {
|
|
40
|
+
if (!isDebugEnabled()) return;
|
|
41
|
+
console.log(`${PREFIX} Wrapped client: provider=${provider}`);
|
|
42
|
+
}
|
|
43
|
+
function batchSend(count, endpoint) {
|
|
44
|
+
if (!isDebugEnabled()) return;
|
|
45
|
+
console.log(`${PREFIX} Sending batch: count=${count} endpoint=${endpoint}`);
|
|
46
|
+
}
|
|
47
|
+
function batchSuccess(count, durationMs) {
|
|
48
|
+
if (!isDebugEnabled()) return;
|
|
49
|
+
console.log(`${PREFIX} Batch sent successfully: count=${count} duration=${durationMs}ms`);
|
|
50
|
+
}
|
|
51
|
+
function batchError(count, error) {
|
|
52
|
+
if (!isDebugEnabled()) return;
|
|
53
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
54
|
+
console.log(`${PREFIX} Batch send failed: count=${count} error=${message}`);
|
|
55
|
+
}
|
|
56
|
+
function requestDetails(method, url, bodySize) {
|
|
57
|
+
if (!isDebugEnabled()) return;
|
|
58
|
+
console.log(`${PREFIX} Request: ${method} ${url} (${bodySize} bytes)`);
|
|
59
|
+
}
|
|
60
|
+
function responseDetails(status, durationMs) {
|
|
61
|
+
if (!isDebugEnabled()) return;
|
|
62
|
+
console.log(`${PREFIX} Response: status=${status} duration=${durationMs}ms`);
|
|
63
|
+
}
|
|
64
|
+
function logWithPrefix(level, message, data) {
|
|
65
|
+
const logFn = level === "error" ? console.error : level === "warn" ? console.warn : console.log;
|
|
66
|
+
if (data !== void 0) {
|
|
67
|
+
logFn(`${PREFIX} ${message}`, data);
|
|
68
|
+
} else {
|
|
69
|
+
logFn(`${PREFIX} ${message}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function getEnvVar(name) {
|
|
73
|
+
if (typeof process !== "undefined" && process.env) {
|
|
74
|
+
return process.env[name];
|
|
75
|
+
}
|
|
76
|
+
return void 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
8
79
|
// src/core/transport.ts
|
|
9
80
|
var DEFAULT_BATCH_SIZE = 10;
|
|
10
81
|
var DEFAULT_FLUSH_INTERVAL_MS = 1e3;
|
|
@@ -87,19 +158,24 @@ var Transport = class {
|
|
|
87
158
|
}
|
|
88
159
|
async sendBatch(items) {
|
|
89
160
|
if (items.length === 0) return;
|
|
90
|
-
|
|
161
|
+
const startTime = Date.now();
|
|
162
|
+
batchSend(items.length, `${this.config.endpoint}/api/v1/ingest`);
|
|
91
163
|
try {
|
|
92
164
|
await this.request("POST", "/api/v1/ingest", { events: items });
|
|
165
|
+
batchSuccess(items.length, Date.now() - startTime);
|
|
93
166
|
} catch (error) {
|
|
94
|
-
|
|
167
|
+
batchError(items.length, error);
|
|
95
168
|
}
|
|
96
169
|
}
|
|
97
170
|
async request(method, path, body) {
|
|
98
171
|
const url = `${this.config.endpoint}${path}`;
|
|
99
172
|
const controller = new AbortController();
|
|
173
|
+
const bodyStr = body ? JSON.stringify(body) : void 0;
|
|
174
|
+
requestDetails(method, url, bodyStr?.length ?? 0);
|
|
100
175
|
const timeoutId = setTimeout(() => {
|
|
101
176
|
controller.abort();
|
|
102
177
|
}, this.config.requestTimeoutMs);
|
|
178
|
+
const startTime = Date.now();
|
|
103
179
|
try {
|
|
104
180
|
const response = await fetch(url, {
|
|
105
181
|
method,
|
|
@@ -107,10 +183,11 @@ var Transport = class {
|
|
|
107
183
|
"Content-Type": "application/json",
|
|
108
184
|
"Authorization": `Bearer ${this.config.apiKey}`
|
|
109
185
|
},
|
|
110
|
-
body:
|
|
186
|
+
body: bodyStr,
|
|
111
187
|
signal: controller.signal
|
|
112
188
|
});
|
|
113
189
|
clearTimeout(timeoutId);
|
|
190
|
+
responseDetails(response.status, Date.now() - startTime);
|
|
114
191
|
if (!response.ok) {
|
|
115
192
|
const errorText = await response.text().catch(() => "Unknown error");
|
|
116
193
|
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
@@ -125,15 +202,6 @@ var Transport = class {
|
|
|
125
202
|
throw error;
|
|
126
203
|
}
|
|
127
204
|
}
|
|
128
|
-
log(message, data) {
|
|
129
|
-
if (this.config.debug) {
|
|
130
|
-
if (data !== void 0) {
|
|
131
|
-
console.log(`[Lelemon] ${message}`, data);
|
|
132
|
-
} else {
|
|
133
|
-
console.log(`[Lelemon] ${message}`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
205
|
};
|
|
138
206
|
|
|
139
207
|
// src/core/config.ts
|
|
@@ -142,7 +210,16 @@ var globalTransport = null;
|
|
|
142
210
|
var DEFAULT_ENDPOINT = "https://lelemon.dev";
|
|
143
211
|
function init(config = {}) {
|
|
144
212
|
globalConfig = config;
|
|
213
|
+
if (config.debug) {
|
|
214
|
+
setDebug(true);
|
|
215
|
+
}
|
|
216
|
+
info("Initializing SDK", {
|
|
217
|
+
endpoint: config.endpoint ?? DEFAULT_ENDPOINT,
|
|
218
|
+
debug: config.debug ?? false,
|
|
219
|
+
disabled: config.disabled ?? false
|
|
220
|
+
});
|
|
145
221
|
globalTransport = createTransport(config);
|
|
222
|
+
info("SDK initialized successfully");
|
|
146
223
|
}
|
|
147
224
|
function getConfig() {
|
|
148
225
|
return globalConfig;
|
|
@@ -162,11 +239,9 @@ async function flush() {
|
|
|
162
239
|
}
|
|
163
240
|
}
|
|
164
241
|
function createTransport(config) {
|
|
165
|
-
const apiKey = config.apiKey ??
|
|
242
|
+
const apiKey = config.apiKey ?? getEnvVar2("LELEMON_API_KEY");
|
|
166
243
|
if (!apiKey && !config.disabled) {
|
|
167
|
-
|
|
168
|
-
"[Lelemon] No API key provided. Set apiKey in init() or LELEMON_API_KEY env var. Tracing disabled."
|
|
169
|
-
);
|
|
244
|
+
warn("No API key provided. Set apiKey in init() or LELEMON_API_KEY env var. Tracing disabled.");
|
|
170
245
|
}
|
|
171
246
|
return new Transport({
|
|
172
247
|
apiKey: apiKey ?? "",
|
|
@@ -178,7 +253,7 @@ function createTransport(config) {
|
|
|
178
253
|
requestTimeoutMs: config.requestTimeoutMs
|
|
179
254
|
});
|
|
180
255
|
}
|
|
181
|
-
function
|
|
256
|
+
function getEnvVar2(name) {
|
|
182
257
|
if (typeof process !== "undefined" && process.env) {
|
|
183
258
|
return process.env[name];
|
|
184
259
|
}
|
|
@@ -216,6 +291,7 @@ function isValidNumber(value) {
|
|
|
216
291
|
var globalContext = {};
|
|
217
292
|
function setGlobalContext(options) {
|
|
218
293
|
globalContext = options;
|
|
294
|
+
debug("Global context updated", options);
|
|
219
295
|
}
|
|
220
296
|
function getGlobalContext() {
|
|
221
297
|
return globalContext;
|
|
@@ -223,7 +299,10 @@ function getGlobalContext() {
|
|
|
223
299
|
function captureTrace(params) {
|
|
224
300
|
try {
|
|
225
301
|
const transport = getTransport();
|
|
226
|
-
if (!transport.isEnabled())
|
|
302
|
+
if (!transport.isEnabled()) {
|
|
303
|
+
debug("Transport disabled, skipping trace capture");
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
227
306
|
const context = getGlobalContext();
|
|
228
307
|
const request = {
|
|
229
308
|
provider: params.provider,
|
|
@@ -240,14 +319,19 @@ function captureTrace(params) {
|
|
|
240
319
|
metadata: { ...context.metadata, ...params.metadata },
|
|
241
320
|
tags: context.tags
|
|
242
321
|
};
|
|
322
|
+
traceCapture(params.provider, params.model, params.durationMs, params.status);
|
|
243
323
|
transport.enqueue(request);
|
|
244
|
-
} catch {
|
|
324
|
+
} catch (err) {
|
|
325
|
+
traceCaptureError(params.provider, err instanceof Error ? err : new Error(String(err)));
|
|
245
326
|
}
|
|
246
327
|
}
|
|
247
328
|
function captureError(params) {
|
|
248
329
|
try {
|
|
249
330
|
const transport = getTransport();
|
|
250
|
-
if (!transport.isEnabled())
|
|
331
|
+
if (!transport.isEnabled()) {
|
|
332
|
+
debug("Transport disabled, skipping error capture");
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
251
335
|
const context = getGlobalContext();
|
|
252
336
|
const request = {
|
|
253
337
|
provider: params.provider,
|
|
@@ -266,8 +350,11 @@ function captureError(params) {
|
|
|
266
350
|
metadata: { ...context.metadata, ...params.metadata },
|
|
267
351
|
tags: context.tags
|
|
268
352
|
};
|
|
353
|
+
traceCapture(params.provider, params.model, params.durationMs, "error");
|
|
354
|
+
debug("Error details", { message: params.error.message, stack: params.error.stack });
|
|
269
355
|
transport.enqueue(request);
|
|
270
|
-
} catch {
|
|
356
|
+
} catch (err) {
|
|
357
|
+
traceCaptureError(params.provider, err instanceof Error ? err : new Error(String(err)));
|
|
271
358
|
}
|
|
272
359
|
}
|
|
273
360
|
var MAX_STRING_LENGTH = 1e5;
|
|
@@ -1686,41 +1773,30 @@ function observe(client, options) {
|
|
|
1686
1773
|
}
|
|
1687
1774
|
const config = getConfig();
|
|
1688
1775
|
if (config.disabled) {
|
|
1776
|
+
debug("Tracing disabled, returning unwrapped client");
|
|
1689
1777
|
return client;
|
|
1690
1778
|
}
|
|
1691
1779
|
if (canHandle5(client)) {
|
|
1692
|
-
|
|
1693
|
-
console.log("[Lelemon] Wrapping OpenRouter client");
|
|
1694
|
-
}
|
|
1780
|
+
clientWrapped("openrouter");
|
|
1695
1781
|
return wrap3(client);
|
|
1696
1782
|
}
|
|
1697
1783
|
if (canHandle(client)) {
|
|
1698
|
-
|
|
1699
|
-
console.log("[Lelemon] Wrapping OpenAI client");
|
|
1700
|
-
}
|
|
1784
|
+
clientWrapped("openai");
|
|
1701
1785
|
return wrapOpenAI(client);
|
|
1702
1786
|
}
|
|
1703
1787
|
if (canHandle2(client)) {
|
|
1704
|
-
|
|
1705
|
-
console.log("[Lelemon] Wrapping Anthropic client");
|
|
1706
|
-
}
|
|
1788
|
+
clientWrapped("anthropic");
|
|
1707
1789
|
return wrapAnthropic(client);
|
|
1708
1790
|
}
|
|
1709
1791
|
if (canHandle3(client)) {
|
|
1710
|
-
|
|
1711
|
-
console.log("[Lelemon] Wrapping Bedrock client");
|
|
1712
|
-
}
|
|
1792
|
+
clientWrapped("bedrock");
|
|
1713
1793
|
return wrap(client);
|
|
1714
1794
|
}
|
|
1715
1795
|
if (canHandle4(client)) {
|
|
1716
|
-
|
|
1717
|
-
console.log("[Lelemon] Wrapping Gemini client");
|
|
1718
|
-
}
|
|
1796
|
+
clientWrapped("gemini");
|
|
1719
1797
|
return wrap2(client);
|
|
1720
1798
|
}
|
|
1721
|
-
|
|
1722
|
-
"[Lelemon] Unknown client type. Tracing not enabled. Supported: OpenAI, OpenRouter, Anthropic, Bedrock, Gemini"
|
|
1723
|
-
);
|
|
1799
|
+
warn("Unknown client type. Tracing not enabled. Supported: OpenAI, OpenRouter, Anthropic, Bedrock, Gemini");
|
|
1724
1800
|
return client;
|
|
1725
1801
|
}
|
|
1726
1802
|
function wrapOpenAI(client) {
|