@lelemondev/sdk 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/config.ts","../src/integrations/express.ts"],"names":[],"mappings":";;;;AA2FA,eAAsB,KAAA,GAAuB;AAI7C;;;ACrBO,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, 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://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 * 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"]}
1
+ {"version":3,"sources":["../src/core/config.ts","../src/integrations/express.ts"],"names":[],"mappings":";;;;AA2FA,eAAsB,KAAA,GAAuB;AAI7C;;;ACrBO,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, 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 * 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"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/config.ts","../src/integrations/express.ts"],"names":[],"mappings":";;AA2FA,eAAsB,KAAA,GAAuB;AAI7C;;;ACrBO,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, 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://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 * 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"]}
1
+ {"version":3,"sources":["../src/core/config.ts","../src/integrations/express.ts"],"names":[],"mappings":";;AA2FA,eAAsB,KAAA,GAAuB;AAI7C;;;ACrBO,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, 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 * 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":";;;;AA2FA,eAAsB,KAAA,GAAuB;AAI7C;;;ACZO,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, 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://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 * 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"]}
1
+ {"version":3,"sources":["../src/core/config.ts","../src/integrations/hono.ts"],"names":[],"mappings":";;;;AA2FA,eAAsB,KAAA,GAAuB;AAI7C;;;ACZO,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, 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 * 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":";;AA2FA,eAAsB,KAAA,GAAuB;AAI7C;;;ACZO,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, 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://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 * 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"]}
1
+ {"version":3,"sources":["../src/core/config.ts","../src/integrations/hono.ts"],"names":[],"mappings":";;AA2FA,eAAsB,KAAA,GAAuB;AAI7C;;;ACZO,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, 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 * 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.d.mts CHANGED
@@ -28,6 +28,27 @@ interface ObserveOptions {
28
28
  /** Tags for filtering */
29
29
  tags?: string[];
30
30
  }
31
+ type SpanType = 'llm' | 'tool' | 'retrieval' | 'custom';
32
+ interface CaptureSpanOptions {
33
+ /** Span type */
34
+ type: SpanType;
35
+ /** Span name (tool name, retrieval source, custom name) */
36
+ name: string;
37
+ /** Input data */
38
+ input: unknown;
39
+ /** Output data */
40
+ output: unknown;
41
+ /** Duration in milliseconds */
42
+ durationMs: number;
43
+ /** Status */
44
+ status?: 'success' | 'error';
45
+ /** Error message if status is 'error' */
46
+ errorMessage?: string;
47
+ /** Tool call ID (for linking tool results) */
48
+ toolCallId?: string;
49
+ /** Custom metadata */
50
+ metadata?: Record<string, unknown>;
51
+ }
31
52
 
32
53
  /**
33
54
  * Global Configuration
@@ -85,4 +106,37 @@ declare function observe<T>(client: T, options?: ObserveOptions): T;
85
106
  */
86
107
  declare function createObserve(defaultOptions: ObserveOptions): <T>(client: T, options?: ObserveOptions) => T;
87
108
 
88
- export { type LelemonConfig, type ObserveOptions, type ProviderName, createObserve, flush, init, isEnabled, observe };
109
+ /**
110
+ * Capture Module
111
+ *
112
+ * Handles trace capture and batching.
113
+ * Called by providers to record LLM calls.
114
+ */
115
+
116
+ /**
117
+ * Manually capture a span (tool call, retrieval, custom)
118
+ * Use this when auto-detection doesn't cover your use case
119
+ *
120
+ * @example
121
+ * // Capture a tool call
122
+ * captureSpan({
123
+ * type: 'tool',
124
+ * name: 'get_weather',
125
+ * input: { location: 'San Francisco' },
126
+ * output: { temperature: 72, conditions: 'sunny' },
127
+ * durationMs: 150,
128
+ * });
129
+ *
130
+ * @example
131
+ * // Capture a retrieval/RAG operation
132
+ * captureSpan({
133
+ * type: 'retrieval',
134
+ * name: 'vector_search',
135
+ * input: { query: 'user question', k: 5 },
136
+ * output: { documents: [...] },
137
+ * durationMs: 50,
138
+ * });
139
+ */
140
+ declare function captureSpan(options: CaptureSpanOptions): void;
141
+
142
+ export { type CaptureSpanOptions, type LelemonConfig, type ObserveOptions, type ProviderName, type SpanType, captureSpan, createObserve, flush, init, isEnabled, observe };
package/dist/index.d.ts CHANGED
@@ -28,6 +28,27 @@ interface ObserveOptions {
28
28
  /** Tags for filtering */
29
29
  tags?: string[];
30
30
  }
31
+ type SpanType = 'llm' | 'tool' | 'retrieval' | 'custom';
32
+ interface CaptureSpanOptions {
33
+ /** Span type */
34
+ type: SpanType;
35
+ /** Span name (tool name, retrieval source, custom name) */
36
+ name: string;
37
+ /** Input data */
38
+ input: unknown;
39
+ /** Output data */
40
+ output: unknown;
41
+ /** Duration in milliseconds */
42
+ durationMs: number;
43
+ /** Status */
44
+ status?: 'success' | 'error';
45
+ /** Error message if status is 'error' */
46
+ errorMessage?: string;
47
+ /** Tool call ID (for linking tool results) */
48
+ toolCallId?: string;
49
+ /** Custom metadata */
50
+ metadata?: Record<string, unknown>;
51
+ }
31
52
 
32
53
  /**
33
54
  * Global Configuration
@@ -85,4 +106,37 @@ declare function observe<T>(client: T, options?: ObserveOptions): T;
85
106
  */
86
107
  declare function createObserve(defaultOptions: ObserveOptions): <T>(client: T, options?: ObserveOptions) => T;
87
108
 
88
- export { type LelemonConfig, type ObserveOptions, type ProviderName, createObserve, flush, init, isEnabled, observe };
109
+ /**
110
+ * Capture Module
111
+ *
112
+ * Handles trace capture and batching.
113
+ * Called by providers to record LLM calls.
114
+ */
115
+
116
+ /**
117
+ * Manually capture a span (tool call, retrieval, custom)
118
+ * Use this when auto-detection doesn't cover your use case
119
+ *
120
+ * @example
121
+ * // Capture a tool call
122
+ * captureSpan({
123
+ * type: 'tool',
124
+ * name: 'get_weather',
125
+ * input: { location: 'San Francisco' },
126
+ * output: { temperature: 72, conditions: 'sunny' },
127
+ * durationMs: 150,
128
+ * });
129
+ *
130
+ * @example
131
+ * // Capture a retrieval/RAG operation
132
+ * captureSpan({
133
+ * type: 'retrieval',
134
+ * name: 'vector_search',
135
+ * input: { query: 'user question', k: 5 },
136
+ * output: { documents: [...] },
137
+ * durationMs: 50,
138
+ * });
139
+ */
140
+ declare function captureSpan(options: CaptureSpanOptions): void;
141
+
142
+ export { type CaptureSpanOptions, type LelemonConfig, type ObserveOptions, type ProviderName, type SpanType, captureSpan, createObserve, flush, init, isEnabled, observe };
package/dist/index.js CHANGED
@@ -205,7 +205,7 @@ var Transport = class {
205
205
  // src/core/config.ts
206
206
  var globalConfig = {};
207
207
  var globalTransport = null;
208
- var DEFAULT_ENDPOINT = "https://lelemon.dev";
208
+ var DEFAULT_ENDPOINT = "https://www.lelemon.dev";
209
209
  function init(config = {}) {
210
210
  globalConfig = config;
211
211
  if (config.debug) {
@@ -359,6 +359,74 @@ function captureError(params) {
359
359
  traceCaptureError(params.provider, err instanceof Error ? err : new Error(String(err)));
360
360
  }
361
361
  }
362
+ function captureSpan(options) {
363
+ try {
364
+ const transport = getTransport();
365
+ if (!transport.isEnabled()) {
366
+ debug("Transport disabled, skipping span capture");
367
+ return;
368
+ }
369
+ const context = getGlobalContext();
370
+ const request = {
371
+ spanType: options.type,
372
+ name: options.name,
373
+ provider: "unknown",
374
+ // Manual spans don't have a provider
375
+ model: options.name,
376
+ // Use name as model for compatibility
377
+ input: sanitizeInput(options.input),
378
+ output: sanitizeOutput(options.output),
379
+ inputTokens: 0,
380
+ outputTokens: 0,
381
+ durationMs: options.durationMs,
382
+ status: options.status || "success",
383
+ errorMessage: options.errorMessage,
384
+ streaming: false,
385
+ sessionId: context.sessionId,
386
+ userId: context.userId,
387
+ toolCallId: options.toolCallId,
388
+ metadata: { ...context.metadata, ...options.metadata },
389
+ tags: context.tags
390
+ };
391
+ debug(`Span captured: ${options.type}/${options.name}`, { durationMs: options.durationMs });
392
+ transport.enqueue(request);
393
+ } catch (err) {
394
+ traceCaptureError("unknown", err instanceof Error ? err : new Error(String(err)));
395
+ }
396
+ }
397
+ function captureToolSpans(toolCalls, provider) {
398
+ for (const tool of toolCalls) {
399
+ try {
400
+ const transport = getTransport();
401
+ if (!transport.isEnabled()) continue;
402
+ const context = getGlobalContext();
403
+ const request = {
404
+ spanType: "tool",
405
+ name: tool.name,
406
+ provider,
407
+ model: tool.name,
408
+ input: sanitizeInput(tool.input),
409
+ output: null,
410
+ // Tool result will come later
411
+ inputTokens: 0,
412
+ outputTokens: 0,
413
+ durationMs: 0,
414
+ // Duration unknown at this point
415
+ status: "success",
416
+ streaming: false,
417
+ sessionId: context.sessionId,
418
+ userId: context.userId,
419
+ toolCallId: tool.id,
420
+ metadata: { ...context.metadata, toolUseDetected: true },
421
+ tags: context.tags
422
+ };
423
+ debug(`Tool span captured: ${tool.name}`, { toolCallId: tool.id });
424
+ transport.enqueue(request);
425
+ } catch (err) {
426
+ traceCaptureError(provider, err instanceof Error ? err : new Error(String(err)));
427
+ }
428
+ }
429
+ }
362
430
  var MAX_STRING_LENGTH = 1e5;
363
431
  var SENSITIVE_KEYS = ["api_key", "apikey", "password", "secret", "token", "authorization"];
364
432
  function sanitizeInput(input) {
@@ -770,7 +838,8 @@ function wrapMessagesCreate(originalFn) {
770
838
  return wrapStream2(response, request, startTime);
771
839
  }
772
840
  const durationMs = Date.now() - startTime;
773
- const extracted = extractMessageResponse(response);
841
+ const messageResponse = response;
842
+ const extracted = extractMessageResponse(messageResponse);
774
843
  captureTrace({
775
844
  provider: PROVIDER_NAME2,
776
845
  model: request.model || extracted.model || "unknown",
@@ -782,6 +851,10 @@ function wrapMessagesCreate(originalFn) {
782
851
  status: "success",
783
852
  streaming: false
784
853
  });
854
+ const toolCalls = extractToolCalls(messageResponse);
855
+ if (toolCalls.length > 0) {
856
+ captureToolSpans(toolCalls, PROVIDER_NAME2);
857
+ }
785
858
  return response;
786
859
  } catch (error) {
787
860
  const durationMs = Date.now() - startTime;
@@ -834,6 +907,8 @@ function wrapAnthropicStream(stream, request, startTime) {
834
907
  let outputTokens = 0;
835
908
  let model = request.model || "unknown";
836
909
  let captured = false;
910
+ const toolCalls = [];
911
+ let currentToolIndex = null;
837
912
  const wrappedIterator = async function* () {
838
913
  try {
839
914
  for await (const event of originalStream) {
@@ -846,6 +921,34 @@ function wrapAnthropicStream(stream, request, startTime) {
846
921
  if (event.type === "content_block_delta" && event.delta?.text) {
847
922
  chunks.push(event.delta.text);
848
923
  }
924
+ if (event.type === "content_block_start" && event.content_block?.type === "tool_use") {
925
+ const block = event.content_block;
926
+ if (block.id && block.name) {
927
+ currentToolIndex = event.index ?? toolCalls.length;
928
+ toolCalls.push({
929
+ id: block.id,
930
+ name: block.name,
931
+ input: block.input ?? {},
932
+ inputJson: ""
933
+ });
934
+ }
935
+ }
936
+ if (event.type === "content_block_delta" && event.delta?.partial_json && currentToolIndex !== null) {
937
+ const tool = toolCalls.find((_, i) => i === currentToolIndex);
938
+ if (tool) {
939
+ tool.inputJson += event.delta.partial_json;
940
+ }
941
+ }
942
+ if (event.type === "content_block_stop" && currentToolIndex !== null) {
943
+ const tool = toolCalls[currentToolIndex];
944
+ if (tool && tool.inputJson) {
945
+ try {
946
+ tool.input = JSON.parse(tool.inputJson);
947
+ } catch {
948
+ }
949
+ }
950
+ currentToolIndex = null;
951
+ }
849
952
  if (event.type === "message_delta" && event.usage) {
850
953
  outputTokens = event.usage.output_tokens || 0;
851
954
  }
@@ -880,6 +983,12 @@ function wrapAnthropicStream(stream, request, startTime) {
880
983
  status: "success",
881
984
  streaming: true
882
985
  });
986
+ if (toolCalls.length > 0) {
987
+ captureToolSpans(
988
+ toolCalls.map((t) => ({ id: t.id, name: t.name, input: t.input })),
989
+ PROVIDER_NAME2
990
+ );
991
+ }
883
992
  }
884
993
  }
885
994
  };
@@ -898,6 +1007,8 @@ async function* wrapStream2(stream, request, startTime) {
898
1007
  let outputTokens = 0;
899
1008
  let model = request.model || "unknown";
900
1009
  let error = null;
1010
+ const toolCalls = [];
1011
+ let currentToolIndex = null;
901
1012
  try {
902
1013
  for await (const event of stream) {
903
1014
  if (event.type === "message_start" && event.message) {
@@ -909,6 +1020,34 @@ async function* wrapStream2(stream, request, startTime) {
909
1020
  if (event.type === "content_block_delta" && event.delta?.text) {
910
1021
  chunks.push(event.delta.text);
911
1022
  }
1023
+ if (event.type === "content_block_start" && event.content_block?.type === "tool_use") {
1024
+ const block = event.content_block;
1025
+ if (block.id && block.name) {
1026
+ currentToolIndex = event.index ?? toolCalls.length;
1027
+ toolCalls.push({
1028
+ id: block.id,
1029
+ name: block.name,
1030
+ input: block.input ?? {},
1031
+ inputJson: ""
1032
+ });
1033
+ }
1034
+ }
1035
+ if (event.type === "content_block_delta" && event.delta?.partial_json && currentToolIndex !== null) {
1036
+ const tool = toolCalls.find((_, i) => i === currentToolIndex);
1037
+ if (tool) {
1038
+ tool.inputJson += event.delta.partial_json;
1039
+ }
1040
+ }
1041
+ if (event.type === "content_block_stop" && currentToolIndex !== null) {
1042
+ const tool = toolCalls[currentToolIndex];
1043
+ if (tool && tool.inputJson) {
1044
+ try {
1045
+ tool.input = JSON.parse(tool.inputJson);
1046
+ } catch {
1047
+ }
1048
+ }
1049
+ currentToolIndex = null;
1050
+ }
912
1051
  if (event.type === "message_delta" && event.usage) {
913
1052
  outputTokens = event.usage.output_tokens || 0;
914
1053
  }
@@ -940,6 +1079,12 @@ async function* wrapStream2(stream, request, startTime) {
940
1079
  status: "success",
941
1080
  streaming: true
942
1081
  });
1082
+ if (toolCalls.length > 0) {
1083
+ captureToolSpans(
1084
+ toolCalls.map((t) => ({ id: t.id, name: t.name, input: t.input })),
1085
+ PROVIDER_NAME2
1086
+ );
1087
+ }
943
1088
  }
944
1089
  }
945
1090
  }
@@ -971,6 +1116,22 @@ function extractTokens2(response) {
971
1116
  return null;
972
1117
  }
973
1118
  }
1119
+ function extractToolCalls(response) {
1120
+ try {
1121
+ if (!response.content || !Array.isArray(response.content)) {
1122
+ return [];
1123
+ }
1124
+ return response.content.filter(
1125
+ (block) => block.type === "tool_use" && !!block.id && !!block.name
1126
+ ).map((block) => ({
1127
+ id: block.id,
1128
+ name: block.name,
1129
+ input: block.input ?? {}
1130
+ }));
1131
+ } catch {
1132
+ return [];
1133
+ }
1134
+ }
974
1135
 
975
1136
  // src/providers/bedrock.ts
976
1137
  var PROVIDER_NAME3 = "bedrock";
@@ -1037,6 +1198,10 @@ async function handleConverse(send, command) {
1037
1198
  latencyMs: response.metrics?.latencyMs
1038
1199
  }
1039
1200
  });
1201
+ const toolCalls = extractToolCalls2(response);
1202
+ if (toolCalls.length > 0) {
1203
+ captureToolSpans(toolCalls, PROVIDER_NAME3);
1204
+ }
1040
1205
  return response;
1041
1206
  } catch (error) {
1042
1207
  captureError({
@@ -1079,11 +1244,26 @@ async function* wrapConverseStream(stream, input, startTime) {
1079
1244
  let inputTokens = 0;
1080
1245
  let outputTokens = 0;
1081
1246
  let error = null;
1247
+ const toolCalls = /* @__PURE__ */ new Map();
1082
1248
  try {
1083
1249
  for await (const event of stream) {
1084
1250
  if (event.contentBlockDelta?.delta?.text) {
1085
1251
  chunks.push(event.contentBlockDelta.delta.text);
1086
1252
  }
1253
+ if (event.contentBlockStart?.start?.toolUse) {
1254
+ const tool = event.contentBlockStart.start.toolUse;
1255
+ toolCalls.set(event.contentBlockStart.contentBlockIndex, {
1256
+ id: tool.toolUseId,
1257
+ name: tool.name,
1258
+ inputJson: ""
1259
+ });
1260
+ }
1261
+ if (event.contentBlockDelta?.delta?.toolUse?.input) {
1262
+ const tool = toolCalls.get(event.contentBlockDelta.contentBlockIndex);
1263
+ if (tool) {
1264
+ tool.inputJson += event.contentBlockDelta.delta.toolUse.input;
1265
+ }
1266
+ }
1087
1267
  if (event.metadata?.usage) {
1088
1268
  inputTokens = event.metadata.usage.inputTokens || 0;
1089
1269
  outputTokens = event.metadata.usage.outputTokens || 0;
@@ -1116,6 +1296,19 @@ async function* wrapConverseStream(stream, input, startTime) {
1116
1296
  status: "success",
1117
1297
  streaming: true
1118
1298
  });
1299
+ if (toolCalls.size > 0) {
1300
+ const tools = Array.from(toolCalls.values()).map((t) => {
1301
+ let parsedInput = {};
1302
+ try {
1303
+ if (t.inputJson) {
1304
+ parsedInput = JSON.parse(t.inputJson);
1305
+ }
1306
+ } catch {
1307
+ }
1308
+ return { id: t.id, name: t.name, input: parsedInput };
1309
+ });
1310
+ captureToolSpans(tools, PROVIDER_NAME3);
1311
+ }
1119
1312
  }
1120
1313
  }
1121
1314
  }
@@ -1240,6 +1433,23 @@ function extractConverseOutput(response) {
1240
1433
  hasToolUse
1241
1434
  };
1242
1435
  }
1436
+ function extractToolCalls2(response) {
1437
+ try {
1438
+ const content = response.output?.message?.content;
1439
+ if (!content || !Array.isArray(content)) {
1440
+ return [];
1441
+ }
1442
+ return content.filter(
1443
+ (block) => !!block.toolUse && !!block.toolUse.toolUseId && !!block.toolUse.name
1444
+ ).map((block) => ({
1445
+ id: block.toolUse.toolUseId,
1446
+ name: block.toolUse.name,
1447
+ input: block.toolUse.input ?? {}
1448
+ }));
1449
+ } catch {
1450
+ return [];
1451
+ }
1452
+ }
1243
1453
  function parseInvokeModelBody(body) {
1244
1454
  try {
1245
1455
  const text = new TextDecoder().decode(body);
@@ -1909,6 +2119,7 @@ function createObserve(defaultOptions) {
1909
2119
  };
1910
2120
  }
1911
2121
 
2122
+ exports.captureSpan = captureSpan;
1912
2123
  exports.createObserve = createObserve;
1913
2124
  exports.flush = flush;
1914
2125
  exports.init = init;