{"version":3,"file":"transports-COPWmlF1.cjs","names":["proc","LOG_LEVELS"],"sources":["../../src/types/transports.ts","../../src/transports/ConsoleTransport.ts","../../src/transports/FileTransport.ts","../../src/transports/HttpTransport.ts","../../src/transports/OtlpTransport.ts","../../src/transports/TransportManager.ts"],"sourcesContent":["import type { LogLevel, LogTag, StackInfo } from './core.js';\n\n/**\n * Map a `LogLevel` to the OpenTelemetry numeric severity (1-24) used by\n * SigNoz / any OTLP/HTTP backend. Spec-compliant banded values:\n *   TRACE=1-4, DEBUG=5-8, INFO=9-12, WARN=13-16, ERROR=17-20, FATAL=21-24\n * We use the canonical mid-band value per level.\n *\n * @see https://opentelemetry.io/docs/specs/otel/logs/data-model/#severity-fields\n */\nexport const LOG_LEVEL_TO_SEVERITY_NUMBER: Record<LogLevel, number> = {\n    trace: 1,    // TRACE\n    debug: 5,    // DEBUG\n    info: 9,     // INFO\n    warn: 13,    // WARN\n    error: 17,   // ERROR\n    critical: 21 // FATAL\n} as const;\n\n/**\n * Map a `LogLevel` to its OpenTelemetry severity name (uppercase, OTel spec).\n */\nexport const LOG_LEVEL_TO_SEVERITY_TEXT: Record<LogLevel, string> = {\n    trace: 'TRACE',\n    debug: 'DEBUG',\n    info: 'INFO',\n    warn: 'WARN',\n    error: 'ERROR',\n    critical: 'FATAL'\n} as const;\n\n/**\n * OTel resource attributes attached once per batch (service.name, version, env, ...).\n * Values are string-coerced by the transport layer.\n */\nexport interface ILogResource {\n    'service.name': string;\n    'service.version'?: string;\n    'deployment.environment'?: string;\n    [key: string]: string | undefined;\n}\n\n/**\n * Structured attribute bag (OpenTelemetry-compatible). Every key maps to\n * a typed value; the transport layer decides how to serialise it.\n */\nexport type LogAttributeValue = string | number | boolean | null | LogAttributeValue[] | { [k: string]: LogAttributeValue };\nexport interface ILogAttributes {\n    [key: string]: LogAttributeValue;\n}\n\n/**\n * The payload sent to every transport on each `log()` call. Fields are\n * deliberately explicit (no `[key: string]: any` safety hatch) so transport\n * implementations like `OtlpTransport` can map 1:1 to OTLP `logRecords`.\n */\nexport interface TransportRecord {\n    /** Canonical log level (trace/debug/info/warn/error/critical). */\n    level: LogLevel;\n    /** Numeric severity, copied from `LOG_LEVELS[level]`. */\n    levelValue: number;\n    /** OTel numeric severity (1-24). Set automatically by Logger. */\n    severityNumber: number;\n    /** OTel severity name (TRACE/DEBUG/INFO/WARN/ERROR/FATAL). */\n    severityText: string;\n    /** Epoch milliseconds at log time. */\n    time: number;\n    /** Final, post-hook message text. */\n    msg: string;\n    /** Optional logical scope (e.g. \"Auth\", \"API:Users\"). */\n    prefix?: string;\n    /** Caller location, only when `enableStackTrace` is true. */\n    location?: {\n        file: string;\n        line: number;\n        column: number;\n        function?: string;\n    };\n    /** 32-char hex trace id (OTel), when correlated with an active span. */\n    traceId?: string;\n    /** 16-char hex span id (OTel), when correlated with an active span. */\n    spanId?: string;\n    /** Structured attributes (requestId, userId, custom tags). */\n    attributes?: ILogAttributes;\n    /** Per-log resource (overrides Transport-level resource). */\n    resource?: Partial<ILogResource>;\n    /** Special \"success\" tag — set by `Logger.success()`. */\n    tag?: LogTag;\n}\n\n/**\n * Options accepted by any transport at registration time.\n */\nexport interface TransportOptions {\n    level?: LogLevel;\n    /** Transform the record before it's serialised. Return null to drop. */\n    transform?: (record: TransportRecord) => TransportRecord | null;\n    /** Flush once the buffer reaches this many records. */\n    batchSize?: number;\n    /** Flush periodically at this interval (ms). */\n    flushInterval?: number;\n    /** Hard cap on buffered records. Older entries are dropped on overflow. */\n    maxBufferSize?: number;\n}\n\n/**\n * A transport registration. `target` can be:\n *   - An `ITransport` instance (legacy / inline).\n *   - A string registered in `TransportManager`'s built-in registry\n *     (`'console' | 'file' | 'http' | 'otlp'`).\n */\nexport interface TransportTarget {\n    target: string | ITransport;\n    options?: TransportOptions;\n    level?: LogLevel;\n}\n\n/**\n * Minimal contract every transport must satisfy.\n */\nexport interface ITransport {\n    readonly name: string;\n    write(record: TransportRecord): void | Promise<void>;\n    flush?(): void | Promise<void>;\n    close?(): void | Promise<void>;\n    isReady?(): boolean;\n}\n\n/**\n * Buffered transport contract. Concrete transports like `HttpTransport`,\n * `FileTransport` and `OtlpTransport` extend this.\n */\nexport interface IBufferedTransport extends ITransport {\n    readonly bufferSize: number;\n    readonly maxBufferSize: number;\n    flush(): Promise<void>;\n}\n\n/**\n * Transport registry / dispatch contract.\n */\nexport interface ITransportManager {\n    add(target: TransportTarget): string;\n    remove(id: string): boolean;\n    write(record: TransportRecord): Promise<void>;\n    flush(): Promise<void>;\n    close(): Promise<void>;\n}\n","import type { TransportRecord, TransportOptions, ITransport, LogLevel } from '../types/index.js';\n\nexport class ConsoleTransport implements ITransport {\n    readonly name = 'console';\n\n    constructor(private options?: TransportOptions) {}\n\n    write(record: TransportRecord): void {\n        const method = this.getConsoleMethod(record.level);\n        const prefix = record.prefix ? `[${record.prefix}] ` : '';\n        const location = record.location\n            ? ` (${record.location.file}:${record.location.line})`\n            : '';\n\n        console[method](`[${record.level.toUpperCase()}]${prefix} ${record.msg}${location}`);\n    }\n\n    private getConsoleMethod(level: LogLevel): 'log' | 'info' | 'warn' | 'error' {\n        switch (level) {\n            case 'debug': return 'log';\n            case 'info': return 'info';\n            case 'warn': return 'warn';\n            case 'error':\n            case 'critical': return 'error';\n            default: return 'log';\n        }\n    }\n}\n","import type {\n    TransportRecord,\n    TransportOptions,\n    ITransport,\n    IBufferedTransport,\n    HookLogEntry,\n    HookEvent\n} from '../types/index.js';\n\nconst MAX_BUFFER_DEFAULT = 10_000;\nconst BATCH_SIZE_DEFAULT = 100;\nconst FS_PROMISES_LOAD_TIMEOUT_MS = 50;\nconst LOCAL_STORAGE_KEY_PREFIX = 'better-logger:';\n\n/**\n * Options for {@link FileTransport}. Uses `destination` as the file path in\n * Node and as a `localStorage` key in the browser (the path component is\n * sanitised to `[a-zA-Z0-9_-]`).\n *\n */\nexport interface FileTransportOptions extends TransportOptions {\n    /**\n     * Where to write. In Node this is a file path (resolved relative to\n     * `process.cwd()` and sanitised against path traversal). In the browser\n     * this is a localStorage key (sanitised to alphanumeric + `-_`).\n     * @default 'app.log' (Node) | 'better-logger:default' (browser)\n     */\n    destination?: string;\n    /**\n     * Optional hook fired when the transport cannot write (FS error,\n     * quota exceeded, browser tab in private mode, ...). Receives a\n     * synthetic {@link HookLogEntry}.\n     */\n    onError?: (entry: HookLogEntry) => void | Promise<void>;\n}\n\n/**\n * File-based transport.\n *\n * - In Node, writes batches via `fs.promises.appendFile` (non-blocking).\n * - In the browser, writes batches into `localStorage` (fallback no-op if\n *   `localStorage` is unavailable — e.g. private mode, sandboxed iframes).\n *\n * Fixed in 5.1.0:\n *   - BUG-N3: uses async `fs.promises.appendFile` instead of sync `appendFileSync`.\n *   - BUG-N4: destination is sanitised to reject path traversal (`..`, `~`, abs paths).\n *   - BUG-N5: dynamic `import('node:fs/promises')` instead of CJS `require('fs')`.\n *   - BUG-N6: browser case uses `localStorage` with try/catch (was silent no-op).\n *\n */\nexport class FileTransport implements IBufferedTransport {\n    readonly name = 'file';\n\n    private buffer: string[] = [];\n    private flushTimer?: ReturnType<typeof setInterval>;\n    private options: FileTransportOptions;\n    private closed = false;\n\n    constructor(options?: FileTransportOptions) {\n        this.options = {\n            batchSize: BATCH_SIZE_DEFAULT,\n            maxBufferSize: MAX_BUFFER_DEFAULT,\n            ...(options ?? {})\n        };\n\n        if (this.options.flushInterval) {\n            this.flushTimer = setInterval(() => {\n                void this.flush();\n            }, this.options.flushInterval);\n        }\n    }\n\n    get bufferSize(): number {\n        return this.buffer.length;\n    }\n\n    get maxBufferSize(): number {\n        return this.options.maxBufferSize ?? MAX_BUFFER_DEFAULT;\n    }\n\n    isReady(): boolean {\n        return !this.closed;\n    }\n\n    write(record: TransportRecord): void {\n        if (this.closed) return;\n\n        // Drop the oldest record when the buffer is already at the cap\n        // (BUG-N3 follow-up — without this the file transport grows\n        // unbounded under a sustained outage, mirroring the old HttpTransport\n        // leak that F005 already fixed).\n        if (this.buffer.length >= this.maxBufferSize) {\n            const dropped = this.buffer.shift();\n            if (dropped && this.options.onError) {\n                const entry: HookLogEntry = {\n                    level: 'warn',\n                    message: 'FileTransport buffer overflow: oldest record dropped',\n                    args: [],\n                    timestamp: new Date().toISOString(),\n                    hookEvent: 'onError' as HookEvent,\n                    error: new Error('FileTransport buffer overflow'),\n                    extra: { droppedRecord: dropped }\n                };\n                void this.options.onError(entry);\n            }\n        }\n\n        this.buffer.push(JSON.stringify(record) + '\\n');\n\n        const batchSize = this.options.batchSize ?? BATCH_SIZE_DEFAULT;\n        if (this.buffer.length >= batchSize) {\n            void this.flush();\n        }\n    }\n\n    async flush(): Promise<void> {\n        if (this.closed || this.buffer.length === 0) return;\n\n        const payload = this.buffer.join('');\n        this.buffer = [];\n\n        if (isNodeLike()) {\n            await this.flushNode(payload);\n        } else {\n            await this.flushBrowser(payload);\n        }\n    }\n\n    private async flushNode(payload: string): Promise<void> {\n        const destination = this.resolveNodeDestination();\n        try {\n            // Dynamic import so we don't ship Node-only code into the\n            // browser bundle and so ESM consumers don't have to deal with\n            // `require` being undefined.\n            const fsPromises = await loadNodeFsPromises();\n            await fsPromises.appendFile(destination, payload, 'utf8');\n        } catch (error) {\n            this.emitError('FileTransport failed to write to disk', error);\n        }\n    }\n\n    private async flushBrowser(payload: string): Promise<void> {\n        if (typeof localStorage === 'undefined') {\n            this.emitError('FileTransport: localStorage is not available in this environment', null);\n            return;\n        }\n        try {\n            const key = LOCAL_STORAGE_KEY_PREFIX + this.resolveBrowserKey();\n            const existing = localStorage.getItem(key) ?? '';\n            localStorage.setItem(key, existing + payload);\n        } catch (error) {\n            this.emitError('FileTransport: localStorage write failed (quota? private mode?)', error);\n        }\n    }\n\n    async close(): Promise<void> {\n        this.closed = true;\n        if (this.flushTimer) {\n            clearInterval(this.flushTimer);\n            this.flushTimer = undefined;\n        }\n        await this.flush();\n    }\n\n    private resolveNodeDestination(): string {\n        const requested = this.options.destination ?? 'app.log';\n        const sanitised = sanitiseNodePath(requested);\n        if (sanitised === null) {\n            this.emitError(`FileTransport: refusing destination with traversal segment: ${requested}`, null);\n            return 'app.log';\n        }\n        return sanitised;\n    }\n\n    private resolveBrowserKey(): string {\n        const requested = this.options.destination ?? 'default';\n        return sanitiseBrowserKey(requested);\n    }\n\n    private emitError(message: string, cause: unknown): void {\n        if (!this.options.onError) return;\n        const entry: HookLogEntry = {\n            level: 'error',\n            message,\n            args: [],\n            timestamp: new Date().toISOString(),\n            hookEvent: 'onError' as HookEvent,\n            error: cause instanceof Error ? cause : new Error(String(cause))\n        };\n        void this.options.onError(entry);\n    }\n}\n\n// ===== Environment helpers =====\n\nfunction isNodeLike(): boolean {\n    return typeof process !== 'undefined'\n        && process.versions != null\n        && process.versions.node != null;\n}\n\n// ===== Sanitisers =====\n\n/**\n * Reject paths that escape the working directory. Allows relative paths\n * under `cwd/`. Absolute paths are rejected by default — if a caller needs\n * an absolute location, pass it through a documented escape hatch (not\n * exposed here on purpose).\n */\nfunction sanitiseNodePath(input: string): string | null {\n    if (!input) return null;\n    const normalised = input.replace(/\\\\/g, '/').trim();\n    if (normalised.length === 0) return null;\n    if (normalised.startsWith('/') || /^[a-zA-Z]:\\//.test(normalised)) return null;\n    const segments = normalised.split('/').filter(s => s.length > 0 && s !== '.');\n    if (segments.some(s => s === '..' || s === '~')) return null;\n    return segments.join('/');\n}\n\nfunction sanitiseBrowserKey(input: string): string {\n    return input.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 64) || 'default';\n}\n\n// ===== Node fs loader =====\n\n/**\n * Cached dynamic import of `node:fs/promises`. The cache is intentionally\n * module-scoped so subsequent flushes don't pay the import cost.\n */\nlet _fsPromisesPromise: Promise<typeof import('node:fs/promises')> | null = null;\n\nasync function loadNodeFsPromises(): Promise<typeof import('node:fs/promises')> {\n    if (_fsPromisesPromise) return _fsPromisesPromise;\n\n    // Race the dynamic import against a short timeout so a hung Node\n    // environment (corrupted native bindings, etc.) doesn't block the\n    // transport forever.\n    const importPromise = import('node:fs/promises');\n    const timeoutPromise = new Promise<never>((_, reject) => {\n        setTimeout(() => reject(new Error(`fs/promises import timed out after ${FS_PROMISES_LOAD_TIMEOUT_MS}ms`)), FS_PROMISES_LOAD_TIMEOUT_MS);\n    });\n    _fsPromisesPromise = Promise.race([importPromise, timeoutPromise]).catch(err => {\n        _fsPromisesPromise = null;\n        throw err;\n    }) as Promise<typeof import('node:fs/promises')>;\n    return _fsPromisesPromise;\n}","import type {\n    TransportRecord,\n    TransportOptions,\n    ITransport,\n    IBufferedTransport,\n    HookEvent,\n    HookLogEntry\n} from '../types/index.js';\n\n/**\n * Configuration for {@link HttpTransport}. Extends {@link TransportOptions}\n * with HTTP-specific knobs.\n *\n */\nexport interface HttpTransportOptions extends TransportOptions {\n    /** Target URL. POST is used with a JSON-encoded body. */\n    url?: string;\n    /** Extra request headers (e.g. `Authorization: Bearer ...`). */\n    headers?: Record<string, string>;\n    /** Hard cap on buffered records. Older entries dropped on overflow. */\n    maxBufferSize?: number;\n    /** Max consecutive retry attempts per batch before the entries are dropped. */\n    maxRetries?: number;\n    /** Initial backoff in ms. Doubles per attempt up to `maxBackoffMs`. */\n    initialBackoffMs?: number;\n    /** Backoff ceiling in ms. */\n    maxBackoffMs?: number;\n    /** Fetch timeout in ms (per attempt). Default 10_000. */\n    fetchTimeoutMs?: number;\n    /**\n     * Optional hook fired when the buffer overflows or a batch is dropped\n     * after `maxRetries`. The hook receives a synthetic {@link HookLogEntry}.\n     */\n    onError?: (entry: HookLogEntry) => void | Promise<void>;\n}\n\nconst DEFAULT_MAX_BUFFER = 10_000;\nconst DEFAULT_BATCH_SIZE = 50;\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_INITIAL_BACKOFF = 250;\nconst DEFAULT_MAX_BACKOFF = 5_000;\nconst DEFAULT_FETCH_TIMEOUT = 10_000;\n\n/**\n * HTTP-based transport. Buffers records, batches them on size or interval,\n * POSTs the batch as JSON, and surfaces failures via retry, bounded buffer,\n * and an `onError` hook — never a silent `.catch(() => {})`.\n *\n * Extending this class is the recommended way to ship a new transport:\n * see {@link OtlpTransport}.\n *\n */\nexport class HttpTransport implements IBufferedTransport {\n    readonly name: string = 'http';\n\n    private buffer: TransportRecord[] = [];\n    private flushTimer?: ReturnType<typeof setInterval>;\n    private closed = false;\n\n    /** Options bag — `protected` so subclasses (e.g. {@link OtlpTransport}) can read or extend it. */\n    protected options: HttpTransportOptions;\n\n    constructor(options?: HttpTransportOptions) {\n        this.options = {\n            batchSize: DEFAULT_BATCH_SIZE,\n            maxBufferSize: DEFAULT_MAX_BUFFER,\n            maxRetries: DEFAULT_MAX_RETRIES,\n            initialBackoffMs: DEFAULT_INITIAL_BACKOFF,\n            maxBackoffMs: DEFAULT_MAX_BACKOFF,\n            fetchTimeoutMs: DEFAULT_FETCH_TIMEOUT,\n            ...(options ?? {})\n        };\n\n        if (this.options.flushInterval) {\n            this.flushTimer = setInterval(() => {\n                void this.flush();\n            }, this.options.flushInterval);\n        }\n    }\n\n    get bufferSize(): number {\n        return this.buffer.length;\n    }\n\n    get maxBufferSize(): number {\n        return this.options.maxBufferSize ?? DEFAULT_MAX_BUFFER;\n    }\n\n    isReady(): boolean {\n        return !this.closed && Boolean(this.options.url);\n    }\n\n    write(record: TransportRecord): void {\n        if (this.closed) return;\n\n        if (this.buffer.length >= this.maxBufferSize) {\n            this.applyOverflowPolicy();\n        }\n\n        this.buffer.push(record);\n\n        const batchSize = this.options.batchSize ?? DEFAULT_BATCH_SIZE;\n        if (this.buffer.length >= batchSize) {\n            void this.flush();\n        }\n    }\n\n    /**\n     * Serialises a batch into the request body. Subclasses override to\n     * switch encodings (e.g. {@link OtlpTransport} produces OTLP/HTTP JSON\n     * instead of the default `{ logs: [...] }` envelope).\n     *\n     */\n    protected serializeBody(records: TransportRecord[]): string {\n        return JSON.stringify({ logs: records });\n    }\n\n    /**\n     * Builds the request headers. Subclasses may prepend transport-specific\n     * headers (e.g. `signoz-ingestion-key`).\n     *\n     */\n    protected buildHeaders(): Record<string, string> {\n        return {\n            'Content-Type': 'application/json',\n            ...(this.options.headers ?? {})\n        };\n    }\n\n    private applyOverflowPolicy(): void {\n        const dropped = this.buffer.shift();\n        if (dropped && this.options.onError) {\n            const entry: HookLogEntry = {\n                level: 'warn',\n                message: 'HttpTransport buffer overflow: oldest record dropped',\n                args: [dropped],\n                timestamp: new Date().toISOString(),\n                hookEvent: 'onError' as HookEvent,\n                error: new Error('HttpTransport buffer overflow'),\n                extra: { droppedRecord: dropped }\n            };\n            void this.options.onError(entry);\n        }\n    }\n\n    async flush(): Promise<void> {\n        if (this.closed || this.buffer.length === 0 || !this.options.url) return;\n\n        const records = [...this.buffer];\n        this.buffer = [];\n\n        const success = await this.sendWithRetry(records);\n        if (!success) {\n            // Re-buffer at the front to preserve order; if we'd overflow\n            // again, the policy above will trim the oldest and surface it.\n            const combined = records.concat(this.buffer);\n            if (combined.length > this.maxBufferSize) {\n                const trimmed = combined.slice(combined.length - this.maxBufferSize);\n                const droppedCount = combined.length - trimmed.length;\n                if (droppedCount > 0 && this.options.onError) {\n                    const entry: HookLogEntry = {\n                        level: 'error',\n                        message: `HttpTransport dropped ${droppedCount} records after retry exhaustion`,\n                        args: [],\n                        timestamp: new Date().toISOString(),\n                        hookEvent: 'onError' as HookEvent,\n                        error: new Error('HttpTransport retry exhaustion'),\n                        extra: { droppedCount }\n                    };\n                    void this.options.onError(entry);\n                }\n                this.buffer = trimmed;\n            } else {\n                this.buffer = combined;\n            }\n        }\n    }\n\n    private async sendWithRetry(records: TransportRecord[]): Promise<boolean> {\n        const url = this.options.url;\n        if (!url) return false;\n\n        const maxRetries = this.options.maxRetries ?? DEFAULT_MAX_RETRIES;\n        const initialBackoff = this.options.initialBackoffMs ?? DEFAULT_INITIAL_BACKOFF;\n        const maxBackoff = this.options.maxBackoffMs ?? DEFAULT_MAX_BACKOFF;\n        const fetchTimeout = this.options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT;\n        const body = this.serializeBody(records);\n        const headers = this.buildHeaders();\n\n        let attempt = 0;\n        let backoff = initialBackoff;\n\n        while (attempt <= maxRetries) {\n            try {\n                const controller = new AbortController();\n                const timeoutId = setTimeout(() => controller.abort(), fetchTimeout);\n\n                const response = await fetch(url, {\n                    method: 'POST',\n                    headers,\n                    body,\n                    signal: controller.signal\n                });\n                clearTimeout(timeoutId);\n\n                if (response.ok) {\n                    return true;\n                }\n\n                // Non-2xx is a logical failure — do NOT retry on 4xx (client\n                // mistakes are not transient). 5xx is retried.\n                if (response.status >= 400 && response.status < 500) {\n                    if (this.options.onError) {\n                        const entry: HookLogEntry = {\n                            level: 'error',\n                            message: `HttpTransport ${response.status} ${response.statusText} (not retried)`,\n                            args: [],\n                            timestamp: new Date().toISOString(),\n                            hookEvent: 'onError' as HookEvent,\n                            error: new Error(`HTTP ${response.status}`),\n                            extra: { responseStatus: response.status }\n                        };\n                        void this.options.onError(entry);\n                    }\n                    return false;\n                }\n\n                // 5xx → retry with backoff\n                if (attempt === maxRetries) break;\n                await sleep(backoff);\n                backoff = Math.min(backoff * 2, maxBackoff);\n            } catch (error) {\n                if (attempt === maxRetries) {\n                    if (this.options.onError) {\n                        const entry: HookLogEntry = {\n                            level: 'error',\n                            message: `HttpTransport fetch failed after ${maxRetries + 1} attempts`,\n                            args: [],\n                            timestamp: new Date().toISOString(),\n                            hookEvent: 'onError' as HookEvent,\n                            error: error instanceof Error ? error : new Error(String(error))\n                        };\n                        void this.options.onError(entry);\n                    }\n                    return false;\n                }\n                await sleep(backoff);\n                backoff = Math.min(backoff * 2, maxBackoff);\n            }\n            attempt++;\n        }\n        return false;\n    }\n\n    async close(): Promise<void> {\n        this.closed = true;\n        if (this.flushTimer) {\n            clearInterval(this.flushTimer);\n            this.flushTimer = undefined;\n        }\n        await this.flush();\n    }\n}\n\nfunction sleep(ms: number): Promise<void> {\n    return new Promise(resolve => setTimeout(resolve, ms));\n}","import type {\n    TransportRecord,\n    HookLogEntry,\n    HookEvent,\n    ILogResource\n} from '../types/index.js';\nimport { LOG_LEVEL_TO_SEVERITY_NUMBER } from '../types/index.js';\nimport { HttpTransport, type HttpTransportOptions } from './HttpTransport.js';\n\n/**\n * Options for {@link OtlpTransport}.\n *\n */\nexport interface OtlpTransportOptions {\n    /**\n     * OTLP/HTTP collector base URL, e.g. `https://collector.example.com:4318`.\n     * The transport POSTs to `<endpoint>/v1/logs`.\n     */\n    endpoint: string;\n    /** `service.name` resource attribute. Required by OTel spec. */\n    serviceName: string;\n    /** `service.version` resource attribute. Recommended. */\n    serviceVersion?: string;\n    /** `deployment.environment` resource attribute (production/staging/dev). */\n    environment?: string;\n    /** Extra resource attributes merged into the resource block. */\n    resourceAttributes?: Record<string, string>;\n    /**\n     * Name of an env var whose value is sent as the `signoz-ingestion-key`\n     * header. The transport reads `process.env[ingestKeyEnvVar]` at\n     * construction time — never from a string literal. If the env var is\n     * unset, the header is silently omitted (OTLP collector uses default\n     * no-auth path).\n     */\n    ingestKeyEnvVar?: string;\n    /** Extra headers merged in (Authorization, custom X-*). */\n    headers?: Record<string, string>;\n    /** Batch size (records per POST). Default 50. */\n    batchSize?: number;\n    /** Flush interval in ms. */\n    flushInterval?: number;\n    /** Hard cap on buffered records. Default 10_000. */\n    maxBufferSize?: number;\n    /** Max retry attempts per batch. Default 3. */\n    maxRetries?: number;\n    /** Initial backoff in ms. Default 250. */\n    initialBackoffMs?: number;\n    /** Backoff ceiling in ms. Default 5_000. */\n    maxBackoffMs?: number;\n    /** Per-fetch timeout in ms. Default 10_000. */\n    fetchTimeoutMs?: number;\n    /** Hook fired on transport failure (drop, retry exhaustion, ...). */\n    onError?: (entry: HookLogEntry) => void | Promise<void>;\n}\n\n/**\n * Shape of the OTLP/HTTP JSON request body. Matches the `LogsData` proto\n * JSON mapping for `/v1/logs`. See\n * https://opentelemetry.io/docs/specs/otlp/#json-protobuf-encoding\n */\ninterface OtlpLogsPayload {\n    resourceLogs: Array<{\n        resource: {\n            attributes: Array<{ key: string; value: { stringValue: string } }>;\n        };\n        scopeLogs: Array<{\n            scope: {\n                name: string;\n                version: string;\n            };\n            logRecords: Array<OtlpLogRecord>;\n        }>;\n    }>;\n}\n\ninterface OtlpLogRecord {\n    timeUnixNano: string;\n    observedTimeUnixNano: string;\n    severityNumber: number;\n    severityText: string;\n    body: { stringValue: string };\n    attributes?: Array<{ key: string; value: OtlpAttributeValue }>;\n    traceId?: string;\n    spanId?: string;\n}\n\ntype OtlpAttributeValue =\n    | { stringValue: string }\n    | { intValue: number }\n    | { doubleValue: number }\n    | { boolValue: boolean }\n    | { arrayValue: { values: OtlpAttributeValue[] } };\n\n/**\n * OTLP/HTTP transport for SigNoz (or any OTLP-compliant backend).\n *\n * Extends {@link HttpTransport} — inherits retry, bounded buffer, status\n * check, async close, and the on-error hook. Overrides only the payload\n * shape and the request headers.\n *\n * ```ts\n * logger.addTransport({\n *   target: new OtlpTransport({\n *     endpoint: 'https://otelcollector.example.com:4318',\n *     serviceName: 'my-app',\n *     serviceVersion: '1.2.3',\n *     environment: 'production',\n *     ingestKeyEnvVar: 'SIGNOZ_KEY'\n *   })\n * });\n * ```\n *\n */\nexport class OtlpTransport extends HttpTransport {\n    override readonly name = 'otlp';\n\n    private readonly resource: ILogResource;\n    /** Resolved at construction. Never logged, never written to source. */\n    private readonly ingestKeyValue: string | undefined;\n\n    constructor(options: OtlpTransportOptions) {\n        if (!options.endpoint) {\n            throw new Error('OtlpTransport: `endpoint` is required');\n        }\n        if (!options.serviceName) {\n            throw new Error('OtlpTransport: `serviceName` is required');\n        }\n\n        const ingestKey = readIngestKey(options.ingestKeyEnvVar);\n\n        const httpOptions: HttpTransportOptions = {\n            url: `${stripTrailingSlash(options.endpoint)}/v1/logs`,\n            headers: {\n                ...(ingestKey ? { 'signoz-ingestion-key': ingestKey } : {}),\n                ...(options.headers ?? {})\n            },\n            batchSize: options.batchSize,\n            flushInterval: options.flushInterval,\n            maxBufferSize: options.maxBufferSize,\n            maxRetries: options.maxRetries,\n            initialBackoffMs: options.initialBackoffMs,\n            maxBackoffMs: options.maxBackoffMs,\n            fetchTimeoutMs: options.fetchTimeoutMs,\n            onError: options.onError\n        };\n\n        super(httpOptions);\n\n        this.resource = {\n            'service.name': options.serviceName,\n            ...(options.serviceVersion ? { 'service.version': options.serviceVersion } : {}),\n            ...(options.environment ? { 'deployment.environment': options.environment } : {}),\n            ...(options.resourceAttributes ?? {})\n        };\n        this.ingestKeyValue = ingestKey;\n    }\n\n    /**\n     * Builds the OTLP/HTTP JSON payload from the currently buffered records.\n     * One `resourceLogs` block per batch (matches OTel collector batching\n     * guidance). Exposed for tests + custom transport subclasses.\n     *\n     */\n    buildPayload(records: TransportRecord[]): OtlpLogsPayload {\n        const resourceAttrs = Object.entries(this.resource)\n            .filter((entry): entry is [string, string] => typeof entry[1] === 'string')\n            .map(([key, value]) => ({ key, value: { stringValue: value } }));\n\n        return {\n            resourceLogs: [\n                {\n                    resource: { attributes: resourceAttrs },\n                    scopeLogs: [\n                        {\n                            scope: {\n                                name: 'better-logger',\n                                version: '5.1.0'\n                            },\n                            logRecords: records.map(r => this.toLogRecord(r))\n                        }\n                    ]\n                }\n            ]\n        };\n    }\n\n    /**\n     * Serialises a batch into the OTLP/HTTP JSON request body. Overrides\n     * {@link HttpTransport.serializeBody}.\n     *\n     */\n    protected override serializeBody(records: TransportRecord[]): string {\n        return JSON.stringify(this.buildPayload(records));\n    }\n\n    /**\n     * Builds request headers. Adds `signoz-ingestion-key` from the value\n     * resolved at construction time (never logged, never written to source).\n     *\n     */\n    protected override buildHeaders(): Record<string, string> {\n        return {\n            'Content-Type': 'application/json',\n            ...(this.ingestKeyValue ? { 'signoz-ingestion-key': this.ingestKeyValue } : {}),\n            ...(this.options.headers ?? {})\n        };\n    }\n\n    private toLogRecord(record: TransportRecord): OtlpLogRecord {\n        const timeUnixNano = String(BigInt(record.time) * 1_000_000n);\n        const observedTimeUnixNano = timeUnixNano;\n        const severityNumber = LOG_LEVEL_TO_SEVERITY_NUMBER[record.level];\n\n        const base: OtlpLogRecord = {\n            timeUnixNano,\n            observedTimeUnixNano,\n            severityNumber,\n            severityText: record.severityText,\n            body: { stringValue: record.msg }\n        };\n\n        const attributes = collectAttributes(record);\n        if (attributes.length > 0) {\n            base.attributes = attributes;\n        }\n\n        if (record.traceId) base.traceId = record.traceId;\n        if (record.spanId) base.spanId = record.spanId;\n\n        return base;\n    }\n}\n\n// ===== Internal helpers =====\n\nfunction stripTrailingSlash(value: string): string {\n    return value.endsWith('/') ? value.slice(0, -1) : value;\n}\n\n/**\n * Reads the ingest API key from `process.env[name]`. Returns undefined\n * silently if `process` is unavailable (strict browser bundles) or the\n * variable is unset. Never throws, never logs the value.\n */\nfunction readIngestKey(envVarName: string | undefined): string | undefined {\n    if (!envVarName) return undefined;\n    if (typeof process === 'undefined') return undefined;\n    const proc = process as { env?: Record<string, string | undefined> };\n    const value = proc.env?.[envVarName];\n    if (!value) return undefined;\n    return value;\n}\n\nfunction collectAttributes(record: TransportRecord): Array<{ key: string; value: OtlpAttributeValue }> {\n    const out: Array<{ key: string; value: OtlpAttributeValue }> = [];\n\n    if (record.prefix) {\n        out.push({ key: 'logger.prefix', value: { stringValue: record.prefix } });\n    }\n    if (record.tag) {\n        out.push({ key: 'logger.tag', value: { stringValue: record.tag } });\n    }\n    if (record.location) {\n        out.push({ key: 'code.filepath', value: { stringValue: record.location.file } });\n        out.push({ key: 'code.lineno', value: { intValue: record.location.line } });\n        if (record.location.function) {\n            out.push({ key: 'code.function', value: { stringValue: record.location.function } });\n        }\n    }\n\n    if (record.attributes) {\n        for (const [key, value] of Object.entries(record.attributes)) {\n            const mapped = toOtlpAttribute(value);\n            if (mapped) out.push({ key, value: mapped });\n        }\n    }\n\n    return out;\n}\n\nfunction toOtlpAttribute(value: unknown): OtlpAttributeValue | null {\n    if (value === null || value === undefined) return null;\n    if (typeof value === 'string') return { stringValue: value };\n    if (typeof value === 'number') {\n        if (Number.isInteger(value)) return { intValue: value };\n        return { doubleValue: value };\n    }\n    if (typeof value === 'boolean') return { boolValue: value };\n    if (Array.isArray(value)) {\n        return {\n            arrayValue: {\n                values: value\n                    .map(v => toOtlpAttribute(v))\n                    .filter((v): v is OtlpAttributeValue => v !== null)\n            }\n        };\n    }\n    return { stringValue: JSON.stringify(value) };\n}","import type {\n    TransportRecord,\n    TransportTarget,\n    TransportOptions,\n    ITransport,\n    ITransportManager,\n    LogLevel\n} from '../types/index.js';\nimport { LOG_LEVELS } from '../types/index.js';\nimport { ConsoleTransport } from './ConsoleTransport.js';\nimport { FileTransport } from './FileTransport.js';\nimport { HttpTransport } from './HttpTransport.js';\nimport { OtlpTransport } from './OtlpTransport.js';\n\nfunction generateTransportId(): string {\n    return `transport-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\n/**\n * Constructor signature for transports registered in the built-in registry.\n * Accepts the transport's own options type; pass-through is enforced at\n * registration time via TypeScript but erased at runtime.\n */\nexport type TransportConstructor = new (options?: TransportOptions) => ITransport;\n\n/**\n * Built-in registry of named transports. Users can call\n * {@link TransportManager.register} to add their own (e.g. a custom\n * Datadog or Loki transport) and then instantiate it via\n * `addTransport({ target: 'datadog', options })`.\n *\n * The four built-ins are registered automatically:\n *   - `'console'` → {@link ConsoleTransport}\n *   - `'file'`    → {@link FileTransport}\n *   - `'http'`    → {@link HttpTransport}\n *   - `'otlp'`    → {@link OtlpTransport}\n */\nconst BUILTIN_REGISTRY: Map<string, TransportConstructor> = new Map([\n    ['console', ConsoleTransport as unknown as TransportConstructor],\n    ['file', FileTransport as unknown as TransportConstructor],\n    ['http', HttpTransport as unknown as TransportConstructor],\n    ['otlp', OtlpTransport as unknown as TransportConstructor]\n]);\n\ninterface TransportEntry {\n    id: string;\n    transport: ITransport;\n    options: TransportOptions;\n    level: LogLevel;\n    levelValue: number;\n}\n\nexport class TransportManager implements ITransportManager {\n    private transports: Map<string, TransportEntry> = new Map();\n    private defaultLevel: LogLevel = 'info';\n    private readonly registry: Map<string, TransportConstructor> = new Map(BUILTIN_REGISTRY);\n\n    constructor(defaultLevel?: LogLevel) {\n        if (defaultLevel) {\n            this.defaultLevel = defaultLevel;\n        }\n    }\n\n    /**\n     * Registers a custom transport under a string name. Once registered,\n     * `addTransport({ target: 'name', options })` instantiates it.\n     *\n     * @example\n     * transportManager.register('datadog', DatadogTransport);\n     * transportManager.add({ target: 'datadog', options: { apiKey: env('DD_KEY') } });\n     *\n     */\n    register(name: string, ctor: TransportConstructor): void {\n        if (BUILTIN_REGISTRY.has(name)) {\n            throw new Error(`TransportManager.register: '${name}' is a built-in and cannot be overridden`);\n        }\n        this.registry.set(name, ctor);\n    }\n\n    /**\n     * Lists all registered transport names (built-ins + custom).\n     *\n     */\n    listRegistered(): string[] {\n        return [...this.registry.keys()];\n    }\n\n    add(target: TransportTarget): string {\n        const id = generateTransportId();\n        const level = target.level || this.defaultLevel;\n\n        let transport: ITransport;\n\n        if (typeof target.target === 'string') {\n            const ctor = this.registry.get(target.target);\n            if (!ctor) {\n                throw new Error(\n                    `TransportManager.add: unknown transport name '${target.target}'. ` +\n                    `Registered: ${this.listRegistered().join(', ')}`\n                );\n            }\n            transport = new ctor(target.options ?? {});\n        } else {\n            transport = target.target;\n        }\n\n        const entry: TransportEntry = {\n            id,\n            transport,\n            options: target.options || {},\n            level,\n            levelValue: LOG_LEVELS[level]\n        };\n\n        this.transports.set(id, entry);\n        return id;\n    }\n\n    remove(id: string): boolean {\n        const entry = this.transports.get(id);\n        if (entry) {\n            const closeResult = entry.transport.close?.();\n            if (closeResult instanceof Promise) {\n                void closeResult.catch(() => {\n                    // close failures are best-effort during remove\n                });\n            }\n            return this.transports.delete(id);\n        }\n        return false;\n    }\n\n    async write(record: TransportRecord): Promise<void> {\n        const promises: Promise<unknown>[] = [];\n\n        for (const entry of this.transports.values()) {\n            if (record.levelValue < entry.levelValue) {\n                continue;\n            }\n\n            let transformedRecord: TransportRecord = record;\n            if (entry.options.transform) {\n                const result = entry.options.transform(record);\n                if (result === null) continue;\n                transformedRecord = result;\n            }\n\n            try {\n                const result = entry.transport.write(transformedRecord);\n                if (result instanceof Promise) {\n                    promises.push(\n                        result.catch(err => {\n                            // Surface write failures through console (no silent drop)\n                            // without throwing — the logger's main path stays sync.\n                            // eslint-disable-next-line no-console\n                            console.error('TransportManager.write: transport failed:', err);\n                        })\n                    );\n                }\n            } catch (error) {\n                // Synchronous write errors are surfaced but never break the log call.\n                // eslint-disable-next-line no-console\n                console.error('TransportManager.write: transport threw synchronously:', error);\n            }\n        }\n\n        await Promise.all(promises);\n    }\n\n    async flush(): Promise<void> {\n        const promises: Promise<unknown>[] = [];\n\n        for (const entry of this.transports.values()) {\n            if (entry.transport.flush) {\n                try {\n                    const result = entry.transport.flush();\n                    if (result instanceof Promise) {\n                        promises.push(result.catch(err => {\n                            // eslint-disable-next-line no-console\n                            console.error('TransportManager.flush: transport failed:', err);\n                        }));\n                    }\n                } catch (error) {\n                    // eslint-disable-next-line no-console\n                    console.error('TransportManager.flush: transport threw synchronously:', error);\n                }\n            }\n        }\n\n        await Promise.all(promises);\n    }\n\n    async close(): Promise<void> {\n        await this.flush();\n\n        const promises: Promise<unknown>[] = [];\n\n        for (const entry of this.transports.values()) {\n            if (entry.transport.close) {\n                try {\n                    const result = entry.transport.close();\n                    if (result instanceof Promise) {\n                        promises.push(result.catch(err => {\n                            // eslint-disable-next-line no-console\n                            console.error('TransportManager.close: transport failed:', err);\n                        }));\n                    }\n                } catch (error) {\n                    // eslint-disable-next-line no-console\n                    console.error('TransportManager.close: transport threw synchronously:', error);\n                }\n            }\n        }\n\n        await Promise.all(promises);\n        this.transports.clear();\n    }\n\n    get count(): number {\n        return this.transports.size;\n    }\n\n    list(): string[] {\n        return Array.from(this.transports.keys());\n    }\n}"],"mappings":"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"}