loggily 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 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":["_process","pc"],"sources":["../src/colors.ts","../src/tracing.ts","../src/core.ts","../src/file-writer.ts"],"sourcesContent":["/**\n * Vendored ANSI color functions — replaces picocolors dependency.\n * Supports NO_COLOR, FORCE_COLOR, and TTY detection.\n */\n\nconst _process = typeof process !== \"undefined\" ? process : undefined\n\nconst enabled =\n _process?.env?.[\"FORCE_COLOR\"] !== undefined && _process?.env?.[\"FORCE_COLOR\"] !== \"0\"\n ? true\n : _process?.env?.[\"NO_COLOR\"] !== undefined\n ? false\n : (_process?.stdout?.isTTY ?? false)\n\nfunction wrap(open: string, close: string): (str: string) => string {\n if (!enabled) return (str) => str\n return (str) => open + str + close\n}\n\nexport const colors = {\n dim: wrap(\"\\x1b[2m\", \"\\x1b[22m\"),\n blue: wrap(\"\\x1b[34m\", \"\\x1b[39m\"),\n yellow: wrap(\"\\x1b[33m\", \"\\x1b[39m\"),\n red: wrap(\"\\x1b[31m\", \"\\x1b[39m\"),\n magenta: wrap(\"\\x1b[35m\", \"\\x1b[39m\"),\n cyan: wrap(\"\\x1b[36m\", \"\\x1b[39m\"),\n}\n","/**\n * Distributed tracing utilities for loggily.\n *\n * Provides W3C-compatible trace/span ID generation, traceparent header formatting,\n * and head-based sampling. All features are opt-in and don't break the existing API.\n */\n\nimport type { SpanData } from \"./core.js\"\n\n// ============ ID Format ============\n\n/** Supported ID formats */\nexport type IdFormat = \"simple\" | \"w3c\"\n\nlet currentIdFormat: IdFormat = \"simple\"\n\n/**\n * Set the ID format for new spans and traces.\n * - \"simple\": sp_1, sp_2, tr_1, tr_2 (default, lightweight)\n * - \"w3c\": 32-char hex trace ID, 16-char hex span ID (W3C Trace Context compatible)\n */\nexport function setIdFormat(format: IdFormat): void {\n currentIdFormat = format\n}\n\n/** Get the current ID format */\nexport function getIdFormat(): IdFormat {\n return currentIdFormat\n}\n\n// Simple format counters (used by core.ts via the generator functions)\nlet simpleSpanCounter = 0\nlet simpleTraceCounter = 0\n\n/** Generate a hex string of the given byte length using crypto.randomUUID */\nfunction randomHex(bytes: number): string {\n // crypto.randomUUID() gives us 32 hex chars (128 bits) after removing dashes\n // For 16 bytes (32 hex chars) we use one UUID, for 8 bytes (16 hex chars) we take a slice\n const uuid = crypto.randomUUID().replace(/-/g, \"\")\n return uuid.slice(0, bytes * 2)\n}\n\n/** Generate a span ID according to the current format */\nexport function generateSpanId(): string {\n if (currentIdFormat === \"w3c\") {\n return randomHex(8) // 16-char hex\n }\n return `sp_${(++simpleSpanCounter).toString(36)}`\n}\n\n/** Generate a trace ID according to the current format */\nexport function generateTraceId(): string {\n if (currentIdFormat === \"w3c\") {\n return randomHex(16) // 32-char hex\n }\n return `tr_${(++simpleTraceCounter).toString(36)}`\n}\n\n/** Reset ID counters (for testing) */\nexport function resetIdCounters(): void {\n simpleSpanCounter = 0\n simpleTraceCounter = 0\n}\n\n// ============ W3C Traceparent ============\n\n/** Options for traceparent header formatting */\nexport interface TraceparentOptions {\n /** Whether this span is sampled. Defaults to true for backwards compatibility. */\n sampled?: boolean\n}\n\n/**\n * Format a W3C traceparent header from span data.\n *\n * Format: `{version}-{trace-id}-{span-id}-{trace-flags}`\n * - version: \"00\" (current W3C spec version)\n * - trace-id: 32 hex chars (128 bits)\n * - span-id: 16 hex chars (64 bits)\n * - trace-flags: \"01\" (sampled) or \"00\" (not sampled)\n *\n * Works with both simple and W3C ID formats. Simple IDs are zero-padded to spec length.\n *\n * @param spanData - Span data with id and traceId\n * @param options - Optional settings (sampled flag). Defaults to sampled=true.\n * @returns W3C traceparent header string\n *\n * @example\n * ```typescript\n * const span = log.span(\"http-request\")\n * const header = traceparent(span.spanData)\n * // → \"00-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6-1a2b3c4d5e6f7a8b-01\"\n * fetch(url, { headers: { traceparent: header } })\n * ```\n */\nexport function traceparent(spanData: SpanData, options?: TraceparentOptions): string {\n const traceId = padHex(spanData.traceId, 32)\n const spanId = padHex(spanData.id, 16)\n const flags = (options?.sampled ?? true) ? \"01\" : \"00\"\n return `00-${traceId}-${spanId}-${flags}`\n}\n\n/** Pad or hash an ID to the specified hex length */\nfunction padHex(id: string, length: number): string {\n // If it's already the right length and looks like hex, use as-is\n if (id.length === length && /^[0-9a-f]+$/.test(id)) {\n return id\n }\n\n // For simple IDs (sp_1, tr_1), create a deterministic hex representation\n // by encoding the string as hex bytes, zero-padded to the target length\n let hex = \"\"\n for (let i = 0; i < id.length; i++) {\n hex += id.charCodeAt(i).toString(16).padStart(2, \"0\")\n }\n // Pad or truncate to target length\n return hex.padStart(length, \"0\").slice(-length)\n}\n\n// ============ Sampling ============\n\nlet sampleRate = 1.0\n\n/**\n * Set the head-based sampling rate for new traces.\n * Applied at trace creation — all spans within a sampled trace are kept.\n *\n * @param rate - Sampling rate from 0.0 (sample nothing) to 1.0 (sample everything, default)\n */\nexport function setSampleRate(rate: number): void {\n if (rate < 0 || rate > 1) {\n throw new Error(`Sample rate must be between 0.0 and 1.0, got ${rate}`)\n }\n sampleRate = rate\n}\n\n/** Get the current sampling rate */\nexport function getSampleRate(): number {\n return sampleRate\n}\n\n/**\n * Determine whether a new trace should be sampled.\n * Called at trace creation time (head-based sampling).\n */\nexport function shouldSample(): boolean {\n if (sampleRate >= 1.0) return true\n if (sampleRate <= 0.0) return false\n return Math.random() < sampleRate\n}\n","/**\n * loggily - Structured logging with spans\n *\n * Logger-first architecture: Span = Logger + Duration\n *\n * @example\n * const log = createLogger('myapp')\n *\n * // Simple logging\n * log.info('starting')\n *\n * // Lazy messages (function not called when level is disabled)\n * log.debug?.(() => `expensive: ${computeState()}`)\n *\n * // Child loggers with context fields\n * const reqLog = log.child({ requestId: 'abc' })\n * reqLog.info('handling request') // includes requestId in every message\n *\n * // With timing (span)\n * {\n * using task = log.span('import', { file: 'data.csv' })\n * task.info('importing')\n * task.spanData.count = 42 // Set span attributes\n * // Auto-disposal on block exit → SPAN myapp:import (15ms)\n * }\n */\n\nimport { colors as pc } from \"./colors.js\"\n\n// ============ Metrics ============\n\n/** Data passed to span recorders on disposal */\nexport interface SpanRecord {\n readonly name: string\n readonly durationMs: number\n}\n\n/** Interface for span duration recording — implemented by createMetricsCollector() in metrics.ts */\nexport interface SpanRecorder {\n recordSpan(data: SpanRecord): void\n}\n\n/**\n * Ambient span recorder — auto-records when TRACE is active.\n * Set by metrics.ts on import; can be replaced for testing.\n * @internal\n */\nexport let _ambientRecorder: SpanRecorder | null = null\nexport function _setAmbientRecorder(recorder: SpanRecorder | null): void {\n _ambientRecorder = recorder\n}\n\n// ============ Runtime Detection ============\n\n/** Cached process reference — undefined in browser/edge runtimes */\nconst _process = typeof process !== \"undefined\" ? process : undefined\n\n/** Read an environment variable, returning undefined in non-Node runtimes */\nfunction getEnv(key: string): string | undefined {\n return _process?.env?.[key]\n}\n\n/** Write to stderr with console.error fallback for non-Node runtimes */\nfunction writeStderr(text: string): void {\n if (_process?.stderr?.write) {\n _process.stderr.write(text + \"\\n\")\n } else {\n console.error(text)\n }\n}\n\n// ============ Types ============\n\n/** Log levels that produce output */\nexport type OutputLogLevel = \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\"\n\n/** All log levels including silent (for filtering) */\nexport type LogLevel = OutputLogLevel | \"silent\"\n\n/** Message can be a string or a lazy function that returns a string */\nexport type LazyMessage = string | (() => string)\n\n/** Span props can be an object or a lazy function (skipped entirely via ?. when tracing is off) */\nexport type LazyProps = Record<string, unknown> | (() => Record<string, unknown>)\n\n/** Span data accessible via logger.spanData */\nexport interface SpanData {\n readonly id: string\n readonly traceId: string\n readonly parentId: string | null\n readonly startTime: number\n readonly endTime: number | null\n readonly duration: number | null\n /** Custom attributes - set via direct property assignment */\n [key: string]: unknown\n}\n\n/** Logger interface */\nexport interface Logger {\n /** Logger namespace (e.g., 'myapp:import') */\n readonly name: string\n /** Props inherited from parent + own props */\n readonly props: Readonly<Record<string, unknown>>\n /** Span data (non-null for span loggers, null for regular loggers) */\n readonly spanData: SpanData | null\n\n // Logging methods (accept string or lazy () => string)\n trace(message: LazyMessage, data?: Record<string, unknown>): void\n debug(message: LazyMessage, data?: Record<string, unknown>): void\n info(message: LazyMessage, data?: Record<string, unknown>): void\n warn(message: LazyMessage, data?: Record<string, unknown>): void\n error(message: LazyMessage, data?: Record<string, unknown>): void\n /** Error overload - extracts message, stack, code from Error */\n error(error: Error, data?: Record<string, unknown>): void\n\n // Create children\n /** Create child logger (extends namespace, inherits props) */\n logger(namespace?: string, props?: Record<string, unknown>): Logger\n /** Create child span (extends namespace, inherits props, adds timing). Props can be lazy. */\n span(namespace?: string, props?: LazyProps): SpanLogger\n\n /** Create child logger with context fields merged into every message */\n child(context: Record<string, unknown>): Logger\n /** @deprecated Use .logger() instead for namespace-based children */\n child(context: string): Logger\n\n /** End span manually (alternative to using keyword) */\n end(): void\n}\n\n/** Span logger - Logger with active span (spanData is non-null, implements Disposable) */\nexport interface SpanLogger extends Logger, Disposable {\n readonly spanData: SpanData & {\n /** Mutable attributes - set directly */\n [key: string]: unknown\n }\n}\n\n// ============ Writers ============\n\ntype LogWriter = (formatted: string, level: string) => void\nconst writers: LogWriter[] = []\n\n/** Add a writer that receives all formatted log output. Returns unsubscribe. */\nexport function addWriter(writer: LogWriter): () => void {\n writers.push(writer)\n return () => {\n const idx = writers.indexOf(writer)\n if (idx !== -1) writers.splice(idx, 1)\n }\n}\n\nlet suppressConsole = false\n\n/** Suppress console output from the logger (writers still receive output). */\nexport function setSuppressConsole(value: boolean): void {\n suppressConsole = value\n}\n\n/** Output mode for writeLog */\nexport type OutputMode = \"console\" | \"stderr\" | \"writers-only\"\nlet outputMode: OutputMode = \"console\"\n\n/** Set output mode for log messages (not spans — spans always use stderr). */\nexport function setOutputMode(mode: OutputMode): void {\n outputMode = mode\n}\n\n/** Get current output mode */\nexport function getOutputMode(): OutputMode {\n return outputMode\n}\n\n// ============ Configuration ============\n\nconst LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n trace: 0,\n debug: 1,\n info: 2,\n warn: 3,\n error: 4,\n silent: 5,\n}\n\n// Initialize from environment\nconst envLogLevel = getEnv(\"LOG_LEVEL\")?.toLowerCase()\nlet currentLogLevel: LogLevel =\n envLogLevel === \"trace\" ||\n envLogLevel === \"debug\" ||\n envLogLevel === \"info\" ||\n envLogLevel === \"warn\" ||\n envLogLevel === \"error\" ||\n envLogLevel === \"silent\"\n ? envLogLevel\n : \"info\"\n\n// Span output control (TRACE=1 or TRACE=myapp,other)\nconst traceEnv = getEnv(\"TRACE\")\nlet spansEnabled = traceEnv === \"1\" || traceEnv === \"true\"\nlet traceFilter: Set<string> | null = null\nif (traceEnv && traceEnv !== \"1\" && traceEnv !== \"true\") {\n traceFilter = new Set(traceEnv.split(\",\").map((s) => s.trim()))\n spansEnabled = true\n}\n\n// Debug namespace filter (DEBUG=myapp or DEBUG=myapp,-myapp:noisy or DEBUG=*)\n// Supports negative patterns with `-` prefix (like the `debug` npm package)\n\n/** Parse a comma-separated namespace filter into include/exclude sets */\nfunction parseNamespaceFilter(input: string[]): {\n includes: Set<string> | null\n excludes: Set<string> | null\n} {\n const includeList: string[] = []\n const excludeList: string[] = []\n for (const part of input) {\n if (part.startsWith(\"-\")) {\n excludeList.push(part.slice(1))\n } else {\n includeList.push(part)\n }\n }\n return {\n includes: includeList.length > 0 ? new Set(includeList) : null,\n excludes: excludeList.length > 0 ? new Set(excludeList) : null,\n }\n}\n\nconst debugEnv = getEnv(\"DEBUG\")\nlet debugIncludes: Set<string> | null = null\nlet debugExcludes: Set<string> | null = null\nif (debugEnv) {\n const parts = debugEnv.split(\",\").map((s) => s.trim())\n const parsed = parseNamespaceFilter(parts)\n debugIncludes = parsed.includes\n // Normalize wildcard variants\n if (debugIncludes && [...debugIncludes].some((p) => p === \"*\" || p === \"1\" || p === \"true\")) {\n debugIncludes = new Set([\"*\"])\n }\n debugExcludes = parsed.excludes\n // Auto-lower log level to at least debug when DEBUG is set\n if (LOG_LEVEL_PRIORITY[currentLogLevel] > LOG_LEVEL_PRIORITY.debug) {\n currentLogLevel = \"debug\"\n }\n}\n\n/** Set minimum log level */\nexport function setLogLevel(level: LogLevel): void {\n currentLogLevel = level\n}\n\n/** Get current log level */\nexport function getLogLevel(): LogLevel {\n return currentLogLevel\n}\n\n/** Enable span output */\nexport function enableSpans(): void {\n spansEnabled = true\n}\n\n/** Disable span output */\nexport function disableSpans(): void {\n spansEnabled = false\n}\n\n/** Check if spans are enabled */\nexport function spansAreEnabled(): boolean {\n return spansEnabled\n}\n\n/**\n * Set trace filter for namespace-based span output control.\n * Only spans matching these namespace prefixes will be output.\n * @param namespaces - Array of namespace prefixes, or null to disable filtering\n */\nexport function setTraceFilter(namespaces: string[] | null): void {\n if (namespaces === null || namespaces.length === 0) {\n traceFilter = null\n } else {\n traceFilter = new Set(namespaces)\n spansEnabled = true\n }\n}\n\n/** Get current trace filter (null means no filtering) */\nexport function getTraceFilter(): string[] | null {\n return traceFilter ? [...traceFilter] : null\n}\n\n/**\n * Set debug namespace filter (like the `debug` npm package).\n * When set, only loggers matching these namespace prefixes produce output.\n * Supports negative patterns with `-` prefix (e.g., [\"-km:noisy\"]).\n * Also ensures log level is at least `debug`.\n * @param namespaces - Array of namespace prefixes (prefix with `-` to exclude), or null to disable\n */\nexport function setDebugFilter(namespaces: string[] | null): void {\n if (namespaces === null || namespaces.length === 0) {\n debugIncludes = null\n debugExcludes = null\n } else {\n const parsed = parseNamespaceFilter(namespaces)\n debugIncludes = parsed.includes\n debugExcludes = parsed.excludes\n if (LOG_LEVEL_PRIORITY[currentLogLevel] > LOG_LEVEL_PRIORITY.debug) {\n currentLogLevel = \"debug\"\n }\n }\n}\n\n/** Get current debug namespace filter (null means no filtering) */\nexport function getDebugFilter(): string[] | null {\n if (!debugIncludes && !debugExcludes) return null\n const result: string[] = []\n if (debugIncludes) result.push(...debugIncludes)\n if (debugExcludes) result.push(...[...debugExcludes].map((e) => `-${e}`))\n return result\n}\n\n// ============ Log Format ============\n\n/** Output format: human-readable console or structured JSON */\nexport type LogFormat = \"console\" | \"json\"\n\n// Initialize from LOG_FORMAT env var, falling back to auto-detect\nconst envLogFormat = getEnv(\"LOG_FORMAT\")?.toLowerCase()\nlet currentLogFormat: LogFormat = envLogFormat === \"json\" ? \"json\" : envLogFormat === \"console\" ? \"console\" : \"console\"\n\n/** Set log output format */\nexport function setLogFormat(format: LogFormat): void {\n currentLogFormat = format\n}\n\n/** Get current log output format */\nexport function getLogFormat(): LogFormat {\n return currentLogFormat\n}\n\n/** Determine whether to use JSON formatting for the current call */\nfunction useJsonFormat(): boolean {\n return currentLogFormat === \"json\" || getEnv(\"NODE_ENV\") === \"production\" || getEnv(\"TRACE_FORMAT\") === \"json\"\n}\n\n// ============ ID Generation (delegated to tracing.ts) ============\n\nimport { generateSpanId, generateTraceId, resetIdCounters, shouldSample } from \"./tracing.js\"\n\n// Reset for testing\nexport function resetIds(): void {\n resetIdCounters()\n}\n\n// ============ Context Propagation Hooks ============\n\n// These are set by context.ts when enableContextPropagation() is called.\n// Kept as nullable callbacks to avoid importing AsyncLocalStorage in browser.\n\n/** Hook to get current span context tags (trace_id, span_id) for auto-tagging logs */\nlet _getContextTags: (() => Record<string, string>) | null = null\n\n/** Hook to get parent span info from async context */\nlet _getContextParent: (() => { spanId: string; traceId: string } | null) | null = null\n\n/** Hook to enter a span context (sets AsyncLocalStorage for the current async scope) */\nlet _enterContext: ((spanId: string, traceId: string, parentId: string | null) => void) | null = null\n\n/** Hook to exit a span context (restores previous context snapshot) */\nlet _exitContext: ((spanId: string) => void) | null = null\n\n/**\n * Register context propagation hooks (called by context.ts).\n * @internal\n */\nexport function _setContextHooks(hooks: {\n getContextTags: () => Record<string, string>\n getContextParent: () => { spanId: string; traceId: string } | null\n enterContext: (spanId: string, traceId: string, parentId: string | null) => void\n exitContext: (spanId: string) => void\n}): void {\n _getContextTags = hooks.getContextTags\n _getContextParent = hooks.getContextParent\n _enterContext = hooks.enterContext\n _exitContext = hooks.exitContext\n}\n\n/**\n * Clear context propagation hooks (called by disableContextPropagation).\n * @internal\n */\nexport function _clearContextHooks(): void {\n _getContextTags = null\n _getContextParent = null\n _enterContext = null\n _exitContext = null\n}\n\n// ============ Formatting ============\n\nfunction shouldLog(level: LogLevel): boolean {\n return LOG_LEVEL_PRIORITY[level] >= LOG_LEVEL_PRIORITY[currentLogLevel]\n}\n\nfunction shouldTraceNamespace(namespace: string): boolean {\n if (!spansEnabled) return false\n if (!traceFilter) return true\n return matchesNamespaceSet(namespace, traceFilter)\n}\n\n/**\n * Safe JSON.stringify that handles bigint, circular refs, symbols, and Error objects.\n * Prevents crashes from non-serializable values in log data.\n */\nfunction safeStringify(value: unknown): string {\n const seen = new WeakSet()\n return JSON.stringify(value, (_key, val) => {\n if (typeof val === \"bigint\") return val.toString()\n if (typeof val === \"symbol\") return val.toString()\n if (val instanceof Error) return { message: val.message, stack: val.stack, name: val.name }\n if (typeof val === \"object\" && val !== null) {\n if (seen.has(val)) return \"[Circular]\"\n seen.add(val)\n }\n return val\n })\n}\n\nfunction formatConsole(namespace: string, level: string, message: string, data?: Record<string, unknown>): string {\n const time = pc.dim(new Date().toISOString().split(\"T\")[1]?.split(\".\")[0] || \"\")\n\n let levelStr = \"\"\n switch (level) {\n case \"trace\":\n levelStr = pc.dim(\"TRACE\")\n break\n case \"debug\":\n levelStr = pc.dim(\"DEBUG\")\n break\n case \"info\":\n levelStr = pc.blue(\"INFO\")\n break\n case \"warn\":\n levelStr = pc.yellow(\"WARN\")\n break\n case \"error\":\n levelStr = pc.red(\"ERROR\")\n break\n case \"span\":\n levelStr = pc.magenta(\"SPAN\")\n break\n }\n\n const ns = pc.cyan(namespace)\n let output = `${time} ${levelStr} ${ns} ${message}`\n\n if (data && Object.keys(data).length > 0) {\n output += ` ${pc.dim(safeStringify(data))}`\n }\n\n return output\n}\n\nfunction formatJSON(namespace: string, level: string, message: string, data?: Record<string, unknown>): string {\n const entry = {\n time: new Date().toISOString(),\n level,\n name: namespace,\n msg: message,\n ...data,\n }\n return safeStringify(entry)\n}\n\nfunction matchesNamespaceSet(namespace: string, set: Set<string>): boolean {\n if (set.has(\"*\")) return true\n for (const filter of set) {\n if (namespace === filter || namespace.startsWith(filter + \":\")) {\n return true\n }\n }\n return false\n}\n\nfunction shouldDebugNamespace(namespace: string): boolean {\n if (!debugIncludes && !debugExcludes) return true\n // Excludes take priority\n if (debugExcludes && matchesNamespaceSet(namespace, debugExcludes)) {\n return false\n }\n // If includes are set, namespace must match\n if (debugIncludes) return matchesNamespaceSet(namespace, debugIncludes)\n return true\n}\n\n/** Resolve a lazy message: if it's a function, call it; otherwise return the string */\nfunction resolveMessage(msg: LazyMessage): string {\n return typeof msg === \"function\" ? msg() : msg\n}\n\nfunction writeLog(\n namespace: string,\n level: OutputLogLevel,\n message: LazyMessage,\n data?: Record<string, unknown>,\n): void {\n if (!shouldLog(level)) return\n if (!shouldDebugNamespace(namespace)) return\n\n // Resolve lazy message only after level/namespace checks pass\n const resolved = resolveMessage(message)\n\n // Auto-tag with trace/span context when context propagation is enabled\n const contextTags = _getContextTags?.()\n const mergedData = contextTags && Object.keys(contextTags).length > 0 ? { ...contextTags, ...data } : data\n\n const formatted = useJsonFormat()\n ? formatJSON(namespace, level, resolved, mergedData)\n : formatConsole(namespace, level, resolved, mergedData)\n\n for (const w of writers) w(formatted, level)\n\n if (suppressConsole || outputMode === \"writers-only\") return\n\n if (outputMode === \"stderr\") {\n writeStderr(formatted)\n return\n }\n\n // Default: use console methods (captured by Ink's patchConsole for TUI panel)\n switch (level) {\n case \"trace\":\n case \"debug\":\n console.debug(formatted)\n break\n case \"info\":\n console.info(formatted)\n break\n case \"warn\":\n console.warn(formatted)\n break\n case \"error\":\n console.error(formatted)\n break\n }\n}\n\nexport function writeSpan(namespace: string, duration: number, attrs: Record<string, unknown>): void {\n if (!shouldTraceNamespace(namespace)) return\n if (!shouldDebugNamespace(namespace)) return\n\n const message = `(${duration}ms)`\n const formatted = useJsonFormat()\n ? formatJSON(namespace, \"span\", message, { duration, ...attrs })\n : formatConsole(namespace, \"span\", message, { duration, ...attrs })\n\n for (const w of writers) w(formatted, \"span\")\n if (!suppressConsole) writeStderr(formatted)\n}\n\n// ============ Shared SpanData Proxy ============\n\ninterface SpanDataFields {\n id: string\n traceId: string\n parentId: string | null\n startTime: number\n endTime: number | null\n duration: number | null\n}\n\n/**\n * Create a proxy that exposes span metadata as readonly and custom attributes as writable.\n * Shared between core logger spans and worker logger spans.\n */\nexport function createSpanDataProxy(getFields: () => SpanDataFields, attrs: Record<string, unknown>): SpanData {\n const READONLY_KEYS = new Set([\"id\", \"traceId\", \"parentId\", \"startTime\", \"endTime\", \"duration\"])\n return new Proxy(attrs, {\n get(_target, prop) {\n if (READONLY_KEYS.has(prop as string)) {\n return getFields()[prop as keyof SpanDataFields]\n }\n return attrs[prop as string]\n },\n set(_target, prop, value) {\n if (READONLY_KEYS.has(prop as string)) {\n return false\n }\n attrs[prop as string] = value\n return true\n },\n }) as SpanData\n}\n\n// ============ Implementation ============\n\ninterface MutableSpanData {\n id: string\n traceId: string\n parentId: string | null\n startTime: number\n endTime: number | null\n duration: number | null\n attrs: Record<string, unknown>\n}\n\nfunction createLoggerImpl(\n name: string,\n props: Record<string, unknown>,\n spanMeta: MutableSpanData | null,\n parentSpanId: string | null,\n traceId: string | null,\n traceSampled: boolean = true,\n): Logger {\n const log = (level: OutputLogLevel, msgOrError: LazyMessage | Error, data?: Record<string, unknown>): void => {\n if (msgOrError instanceof Error) {\n const err = msgOrError\n writeLog(name, level, err.message, {\n ...props,\n ...data,\n error_type: err.name,\n error_stack: err.stack,\n error_code: (err as { code?: string }).code,\n })\n } else {\n writeLog(name, level, msgOrError, { ...props, ...data })\n }\n }\n\n const logger: Logger = {\n name,\n props: Object.freeze({ ...props }),\n\n get spanData(): SpanData | null {\n if (!spanMeta) return null\n return createSpanDataProxy(\n () => ({\n id: spanMeta.id,\n traceId: spanMeta.traceId,\n parentId: spanMeta.parentId,\n startTime: spanMeta.startTime,\n endTime: spanMeta.endTime,\n duration: spanMeta.endTime !== null ? spanMeta.endTime - spanMeta.startTime : Date.now() - spanMeta.startTime,\n }),\n spanMeta.attrs,\n )\n },\n\n trace: (msg, data) => log(\"trace\", msg, data),\n debug: (msg, data) => log(\"debug\", msg, data),\n info: (msg, data) => log(\"info\", msg, data),\n warn: (msg, data) => log(\"warn\", msg, data),\n error: (msgOrError, data) => log(\"error\", msgOrError as string, data),\n\n logger(namespace?: string, childProps?: Record<string, unknown>): Logger {\n const childName = namespace ? `${name}:${namespace}` : name\n const mergedProps = { ...props, ...childProps }\n return createLoggerImpl(childName, mergedProps, null, parentSpanId, traceId, traceSampled)\n },\n\n span(namespace?: string, childProps?: LazyProps): SpanLogger {\n const childName = namespace ? `${name}:${namespace}` : name\n const resolvedChildProps = typeof childProps === \"function\" ? childProps() : childProps\n const mergedProps = { ...props, ...resolvedChildProps }\n const newSpanId = generateSpanId()\n\n // Resolve parent from context propagation if not explicitly set\n let resolvedParentId = parentSpanId\n let resolvedTraceId = traceId\n\n if (!resolvedParentId && _getContextParent) {\n const ctxParent = _getContextParent()\n if (ctxParent) {\n resolvedParentId = ctxParent.spanId\n resolvedTraceId = resolvedTraceId || ctxParent.traceId\n }\n }\n\n // Determine trace ID — generate new one if starting a new trace\n const isNewTrace = !resolvedTraceId\n const finalTraceId = resolvedTraceId || generateTraceId()\n\n // Head-based sampling: inherit from parent, or decide at trace creation\n const sampled = isNewTrace ? shouldSample() : traceSampled\n\n const newSpanData: MutableSpanData = {\n id: newSpanId,\n traceId: finalTraceId,\n parentId: resolvedParentId,\n startTime: Date.now(),\n endTime: null,\n duration: null,\n attrs: {},\n }\n\n const spanLogger = createLoggerImpl(\n childName,\n mergedProps,\n newSpanData,\n newSpanId,\n finalTraceId,\n sampled,\n ) as SpanLogger\n\n // Enter span context for async propagation (if enabled)\n _enterContext?.(newSpanId, finalTraceId, resolvedParentId)\n\n // Add disposal\n ;(spanLogger as unknown as { [Symbol.dispose]: () => void })[Symbol.dispose] = () => {\n if (newSpanData.endTime !== null) return // Already disposed\n\n newSpanData.endTime = Date.now()\n newSpanData.duration = newSpanData.endTime - newSpanData.startTime\n\n // Collect span data if collection is active\n if (collectSpans) {\n collectedSpans.push(\n createSpanDataProxy(\n () => ({\n id: newSpanData.id,\n traceId: newSpanData.traceId,\n parentId: newSpanData.parentId,\n startTime: newSpanData.startTime,\n endTime: newSpanData.endTime,\n duration: newSpanData.duration,\n }),\n { ...newSpanData.attrs },\n ),\n )\n }\n\n // Exit span context (restore previous context snapshot)\n _exitContext?.(newSpanId)\n\n // Record to ambient recorder (auto-active when TRACE is on, set by metrics.ts)\n _ambientRecorder?.recordSpan({ name: childName, durationMs: newSpanData.duration })\n\n // Only emit span if sampled\n if (sampled) {\n writeSpan(childName, newSpanData.duration, {\n span_id: newSpanData.id,\n trace_id: newSpanData.traceId,\n parent_id: newSpanData.parentId,\n ...mergedProps,\n ...newSpanData.attrs,\n })\n }\n }\n\n return spanLogger\n },\n\n child(context: string | Record<string, unknown>): Logger {\n if (typeof context === \"string\") {\n // Deprecated string overload - use .logger() instead\n return this.logger(context)\n }\n // Context object overload: merge context fields into props\n return createLoggerImpl(name, { ...props, ...context }, null, parentSpanId, traceId, traceSampled)\n },\n\n end(): void {\n if (spanMeta?.endTime === null) {\n ;(this as unknown as { [Symbol.dispose]: () => void })[Symbol.dispose]?.()\n }\n },\n }\n\n return logger\n}\n\n/**\n * Create a plain logger for a component (internal use).\n * For application code, use createLogger() instead which returns undefined for disabled levels.\n */\nfunction createPlainLogger(name: string, props?: Record<string, unknown>): Logger {\n return createLoggerImpl(name, props || {}, null, null, null)\n}\n\n// ============ Collected Spans (for analysis) ============\n\nconst collectedSpans: SpanData[] = []\nlet collectSpans = false\n\n/** Enable span collection for analysis */\nexport function startCollecting(): void {\n collectSpans = true\n collectedSpans.length = 0\n}\n\n/** Stop collecting and return collected spans */\nexport function stopCollecting(): SpanData[] {\n collectSpans = false\n return [...collectedSpans]\n}\n\n/** Get collected spans */\nexport function getCollectedSpans(): SpanData[] {\n return [...collectedSpans]\n}\n\n/** Clear collected spans */\nexport function clearCollectedSpans(): void {\n collectedSpans.length = 0\n}\n\n// ============ Conditional Logger (Zero-Overhead Pattern) ============\n\n/**\n * Logger with optional methods — returns undefined for disabled levels.\n * Use with optional chaining: `log.debug?.(\"msg\")` for zero-overhead when disabled.\n *\n * Defined as an explicit interface (not Omit<Logger,...>) so that\n * oxlint's type-aware mode can resolve it without advanced type inference.\n */\nexport interface ConditionalLogger {\n readonly name: string\n readonly props: Readonly<Record<string, unknown>>\n readonly spanData: SpanData | null\n\n trace?: (message: LazyMessage, data?: Record<string, unknown>) => void\n debug?: (message: LazyMessage, data?: Record<string, unknown>) => void\n info?: (message: LazyMessage, data?: Record<string, unknown>) => void\n warn?: (message: LazyMessage, data?: Record<string, unknown>) => void\n error?: {\n (message: LazyMessage, data?: Record<string, unknown>): void\n (error: Error, data?: Record<string, unknown>): void\n }\n\n logger(namespace?: string, props?: Record<string, unknown>): Logger\n span(namespace?: string, props?: LazyProps): SpanLogger\n child(context: Record<string, unknown>): Logger\n child(context: string): Logger\n end(): void\n}\n\n/**\n * Create a logger for a component.\n * Returns undefined for disabled levels - use with optional chaining for zero overhead.\n *\n * Log levels (most → least verbose): trace < debug < info < warn < error < silent\n * Default level: info (trace and debug disabled)\n *\n * @example\n * const log = createLogger('myapp')\n *\n * // All methods support ?. for zero-overhead when disabled\n * log.trace?.(`very verbose: ${expensiveDebug()}`) // Skipped at info level\n * log.debug?.(`debug: ${getState()}`) // Skipped at info level\n * log.info?.('starting') // Enabled at info level\n * log.warn?.('deprecated') // Enabled at info level\n * log.error?.('failed') // Enabled at info level\n *\n * // With -q flag or LOG_LEVEL=warn:\n * log.info?.('starting') // Now skipped - info < warn\n *\n * // With initial props\n * const log = createLogger('myapp', { version: '1.0' })\n *\n * // Create spans\n * {\n * using task = log.span('import', { file: 'data.csv' })\n * task.info?.('importing')\n * task.spanData.count = 42\n * }\n */\nexport function createLogger(name: string, props?: Record<string, unknown>): ConditionalLogger {\n const baseLog = createPlainLogger(name, props)\n\n return new Proxy(baseLog as ConditionalLogger, {\n get(target, prop: string) {\n if (prop in LOG_LEVEL_PRIORITY && prop !== \"silent\") {\n const current = LOG_LEVEL_PRIORITY[currentLogLevel]\n if (LOG_LEVEL_PRIORITY[prop as keyof typeof LOG_LEVEL_PRIORITY] < current) {\n return undefined\n }\n }\n return (target as unknown as Record<string, unknown>)[prop]\n },\n })\n}\n","/**\n * File writer for loggily — Node.js/Bun only.\n *\n * Separated from core logger to allow tree-shaking in browser bundles.\n * Uses dynamic import(\"node:fs\") to avoid static dependency on Node APIs.\n */\n\nimport { openSync, writeSync, closeSync } from \"node:fs\"\n\n/** Options for creating an async buffered file writer */\nexport interface FileWriterOptions {\n /** Buffer size threshold in bytes before flushing (default: 4096) */\n bufferSize?: number\n /** Flush interval in milliseconds (default: 100) */\n flushInterval?: number\n}\n\n/** An async buffered file writer with automatic flushing */\nexport interface FileWriter {\n /** Write a line to the buffer (appends newline) */\n write(line: string): void\n /** Flush the buffer immediately */\n flush(): void\n /** Close the writer and flush remaining buffer */\n close(): void\n}\n\n/**\n * Create an async buffered file writer for log output.\n * Buffers writes and flushes on size threshold or interval.\n * Registers a process.on('exit') handler to flush remaining buffer.\n *\n * **Node.js/Bun only** — not available in browser environments.\n *\n * @param filePath - Path to the log file (opened in append mode)\n * @param options - Buffer size and flush interval configuration\n * @returns FileWriter with write, flush, and close methods\n *\n * @example\n * const writer = createFileWriter('/tmp/app.log')\n * const unsubscribe = addWriter((formatted) => writer.write(formatted))\n *\n * // On shutdown:\n * unsubscribe()\n * writer.close()\n */\nexport function createFileWriter(filePath: string, options: FileWriterOptions = {}): FileWriter {\n const bufferSize = options.bufferSize ?? 4096\n const flushInterval = options.flushInterval ?? 100\n\n let buffer = \"\"\n let fd: number | null = null\n let timer: ReturnType<typeof setInterval> | null = null\n let closed = false\n\n // Open file in append mode\n fd = openSync(filePath, \"a\")\n\n /** Flush buffer contents to disk synchronously */\n function flush(): void {\n if (buffer.length === 0 || fd === null) return\n const data = buffer\n writeSync(fd, data)\n buffer = \"\"\n }\n\n // Set up periodic flush\n timer = setInterval(flush, flushInterval)\n // Don't let the timer keep the process alive\n if (timer && typeof timer === \"object\" && \"unref\" in timer) {\n ;(timer as { unref(): void }).unref()\n }\n\n // Flush on process exit to avoid data loss\n const exitHandler = (): void => flush()\n process.on(\"exit\", exitHandler)\n\n return {\n write(line: string): void {\n if (closed) return\n buffer += line + \"\\n\"\n if (buffer.length >= bufferSize) {\n flush()\n }\n },\n\n flush,\n\n close(): void {\n if (closed) return\n closed = true\n if (timer !== null) {\n clearInterval(timer)\n timer = null\n }\n try {\n flush()\n } catch {\n // Swallow flush errors during close — data loss is unavoidable\n // at this point, but we must still release the fd and exit handler.\n } finally {\n if (fd !== null) {\n closeSync(fd)\n fd = null\n }\n process.removeListener(\"exit\", exitHandler)\n }\n },\n }\n}\n"],"mappings":";;;;;;AAKA,MAAMA,aAAW,OAAO,YAAY,cAAc,UAAU,KAAA;AAE5D,MAAM,UACJA,YAAU,MAAM,mBAAmB,KAAA,KAAaA,YAAU,MAAM,mBAAmB,MAC/E,OACAA,YAAU,MAAM,gBAAgB,KAAA,IAC9B,QACCA,YAAU,QAAQ,SAAS;AAEpC,SAAS,KAAK,MAAc,OAAwC;AAClE,KAAI,CAAC,QAAS,SAAQ,QAAQ;AAC9B,SAAQ,QAAQ,OAAO,MAAM;;AAG/B,MAAa,SAAS;CACpB,KAAK,KAAK,WAAW,WAAW;CAChC,MAAM,KAAK,YAAY,WAAW;CAClC,QAAQ,KAAK,YAAY,WAAW;CACpC,KAAK,KAAK,YAAY,WAAW;CACjC,SAAS,KAAK,YAAY,WAAW;CACrC,MAAM,KAAK,YAAY,WAAW;CACnC;;;ACZD,IAAI,kBAA4B;;;;;;AAOhC,SAAgB,YAAY,QAAwB;AAClD,mBAAkB;;;AAIpB,SAAgB,cAAwB;AACtC,QAAO;;AAIT,IAAI,oBAAoB;AACxB,IAAI,qBAAqB;;AAGzB,SAAS,UAAU,OAAuB;AAIxC,QADa,OAAO,YAAY,CAAC,QAAQ,MAAM,GAAG,CACtC,MAAM,GAAG,QAAQ,EAAE;;;AAIjC,SAAgB,iBAAyB;AACvC,KAAI,oBAAoB,MACtB,QAAO,UAAU,EAAE;AAErB,QAAO,OAAO,EAAE,mBAAmB,SAAS,GAAG;;;AAIjD,SAAgB,kBAA0B;AACxC,KAAI,oBAAoB,MACtB,QAAO,UAAU,GAAG;AAEtB,QAAO,OAAO,EAAE,oBAAoB,SAAS,GAAG;;;AAIlD,SAAgB,kBAAwB;AACtC,qBAAoB;AACpB,sBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;AAkCvB,SAAgB,YAAY,UAAoB,SAAsC;AAIpF,QAAO,MAHS,OAAO,SAAS,SAAS,GAAG,CAGvB,GAFN,OAAO,SAAS,IAAI,GAAG,CAEP,GADhB,SAAS,WAAW,OAAQ,OAAO;;;AAKpD,SAAS,OAAO,IAAY,QAAwB;AAElD,KAAI,GAAG,WAAW,UAAU,cAAc,KAAK,GAAG,CAChD,QAAO;CAKT,IAAI,MAAM;AACV,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,QAAQ,IAC7B,QAAO,GAAG,WAAW,EAAE,CAAC,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI;AAGvD,QAAO,IAAI,SAAS,QAAQ,IAAI,CAAC,MAAM,CAAC,OAAO;;AAKjD,IAAI,aAAa;;;;;;;AAQjB,SAAgB,cAAc,MAAoB;AAChD,KAAI,OAAO,KAAK,OAAO,EACrB,OAAM,IAAI,MAAM,gDAAgD,OAAO;AAEzE,cAAa;;;AAIf,SAAgB,gBAAwB;AACtC,QAAO;;;;;;AAOT,SAAgB,eAAwB;AACtC,KAAI,cAAc,EAAK,QAAO;AAC9B,KAAI,cAAc,EAAK,QAAO;AAC9B,QAAO,KAAK,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrGzB,IAAW,mBAAwC;AACnD,SAAgB,oBAAoB,UAAqC;AACvE,oBAAmB;;;AAMrB,MAAM,WAAW,OAAO,YAAY,cAAc,UAAU,KAAA;;AAG5D,SAAS,OAAO,KAAiC;AAC/C,QAAO,UAAU,MAAM;;;AAIzB,SAAS,YAAY,MAAoB;AACvC,KAAI,UAAU,QAAQ,MACpB,UAAS,OAAO,MAAM,OAAO,KAAK;KAElC,SAAQ,MAAM,KAAK;;AA0EvB,MAAM,UAAuB,EAAE;;AAG/B,SAAgB,UAAU,QAA+B;AACvD,SAAQ,KAAK,OAAO;AACpB,cAAa;EACX,MAAM,MAAM,QAAQ,QAAQ,OAAO;AACnC,MAAI,QAAQ,GAAI,SAAQ,OAAO,KAAK,EAAE;;;AAI1C,IAAI,kBAAkB;;AAGtB,SAAgB,mBAAmB,OAAsB;AACvD,mBAAkB;;AAKpB,IAAI,aAAyB;;AAG7B,SAAgB,cAAc,MAAwB;AACpD,cAAa;;;AAIf,SAAgB,gBAA4B;AAC1C,QAAO;;AAKT,MAAM,qBAA+C;CACnD,OAAO;CACP,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACP,QAAQ;CACT;AAGD,MAAM,cAAc,OAAO,YAAY,EAAE,aAAa;AACtD,IAAI,kBACF,gBAAgB,WAChB,gBAAgB,WAChB,gBAAgB,UAChB,gBAAgB,UAChB,gBAAgB,WAChB,gBAAgB,WACZ,cACA;AAGN,MAAM,WAAW,OAAO,QAAQ;AAChC,IAAI,eAAe,aAAa,OAAO,aAAa;AACpD,IAAI,cAAkC;AACtC,IAAI,YAAY,aAAa,OAAO,aAAa,QAAQ;AACvD,eAAc,IAAI,IAAI,SAAS,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC;AAC/D,gBAAe;;;AAOjB,SAAS,qBAAqB,OAG5B;CACA,MAAM,cAAwB,EAAE;CAChC,MAAM,cAAwB,EAAE;AAChC,MAAK,MAAM,QAAQ,MACjB,KAAI,KAAK,WAAW,IAAI,CACtB,aAAY,KAAK,KAAK,MAAM,EAAE,CAAC;KAE/B,aAAY,KAAK,KAAK;AAG1B,QAAO;EACL,UAAU,YAAY,SAAS,IAAI,IAAI,IAAI,YAAY,GAAG;EAC1D,UAAU,YAAY,SAAS,IAAI,IAAI,IAAI,YAAY,GAAG;EAC3D;;AAGH,MAAM,WAAW,OAAO,QAAQ;AAChC,IAAI,gBAAoC;AACxC,IAAI,gBAAoC;AACxC,IAAI,UAAU;CAEZ,MAAM,SAAS,qBADD,SAAS,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CACZ;AAC1C,iBAAgB,OAAO;AAEvB,KAAI,iBAAiB,CAAC,GAAG,cAAc,CAAC,MAAM,MAAM,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,CACzF,iBAAgB,IAAI,IAAI,CAAC,IAAI,CAAC;AAEhC,iBAAgB,OAAO;AAEvB,KAAI,mBAAmB,mBAAmB,mBAAmB,MAC3D,mBAAkB;;;AAKtB,SAAgB,YAAY,OAAuB;AACjD,mBAAkB;;;AAIpB,SAAgB,cAAwB;AACtC,QAAO;;;AAIT,SAAgB,cAAoB;AAClC,gBAAe;;;AAIjB,SAAgB,eAAqB;AACnC,gBAAe;;;AAIjB,SAAgB,kBAA2B;AACzC,QAAO;;;;;;;AAQT,SAAgB,eAAe,YAAmC;AAChE,KAAI,eAAe,QAAQ,WAAW,WAAW,EAC/C,eAAc;MACT;AACL,gBAAc,IAAI,IAAI,WAAW;AACjC,iBAAe;;;;AAKnB,SAAgB,iBAAkC;AAChD,QAAO,cAAc,CAAC,GAAG,YAAY,GAAG;;;;;;;;;AAU1C,SAAgB,eAAe,YAAmC;AAChE,KAAI,eAAe,QAAQ,WAAW,WAAW,GAAG;AAClD,kBAAgB;AAChB,kBAAgB;QACX;EACL,MAAM,SAAS,qBAAqB,WAAW;AAC/C,kBAAgB,OAAO;AACvB,kBAAgB,OAAO;AACvB,MAAI,mBAAmB,mBAAmB,mBAAmB,MAC3D,mBAAkB;;;;AAMxB,SAAgB,iBAAkC;AAChD,KAAI,CAAC,iBAAiB,CAAC,cAAe,QAAO;CAC7C,MAAM,SAAmB,EAAE;AAC3B,KAAI,cAAe,QAAO,KAAK,GAAG,cAAc;AAChD,KAAI,cAAe,QAAO,KAAK,GAAG,CAAC,GAAG,cAAc,CAAC,KAAK,MAAM,IAAI,IAAI,CAAC;AACzE,QAAO;;AAST,MAAM,eAAe,OAAO,aAAa,EAAE,aAAa;AACxD,IAAI,mBAA8B,iBAAiB,SAAS,SAAS,iBAAiB,YAAY,YAAY;;AAG9G,SAAgB,aAAa,QAAyB;AACpD,oBAAmB;;;AAIrB,SAAgB,eAA0B;AACxC,QAAO;;;AAIT,SAAS,gBAAyB;AAChC,QAAO,qBAAqB,UAAU,OAAO,WAAW,KAAK,gBAAgB,OAAO,eAAe,KAAK;;AAQ1G,SAAgB,WAAiB;AAC/B,kBAAiB;;;AASnB,IAAI,kBAAyD;;AAG7D,IAAI,oBAA+E;;AAGnF,IAAI,gBAA6F;;AAGjG,IAAI,eAAkD;;;;;AAMtD,SAAgB,iBAAiB,OAKxB;AACP,mBAAkB,MAAM;AACxB,qBAAoB,MAAM;AAC1B,iBAAgB,MAAM;AACtB,gBAAe,MAAM;;;;;;AAOvB,SAAgB,qBAA2B;AACzC,mBAAkB;AAClB,qBAAoB;AACpB,iBAAgB;AAChB,gBAAe;;AAKjB,SAAS,UAAU,OAA0B;AAC3C,QAAO,mBAAmB,UAAU,mBAAmB;;AAGzD,SAAS,qBAAqB,WAA4B;AACxD,KAAI,CAAC,aAAc,QAAO;AAC1B,KAAI,CAAC,YAAa,QAAO;AACzB,QAAO,oBAAoB,WAAW,YAAY;;;;;;AAOpD,SAAS,cAAc,OAAwB;CAC7C,MAAM,uBAAO,IAAI,SAAS;AAC1B,QAAO,KAAK,UAAU,QAAQ,MAAM,QAAQ;AAC1C,MAAI,OAAO,QAAQ,SAAU,QAAO,IAAI,UAAU;AAClD,MAAI,OAAO,QAAQ,SAAU,QAAO,IAAI,UAAU;AAClD,MAAI,eAAe,MAAO,QAAO;GAAE,SAAS,IAAI;GAAS,OAAO,IAAI;GAAO,MAAM,IAAI;GAAM;AAC3F,MAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,OAAI,KAAK,IAAI,IAAI,CAAE,QAAO;AAC1B,QAAK,IAAI,IAAI;;AAEf,SAAO;GACP;;AAGJ,SAAS,cAAc,WAAmB,OAAe,SAAiB,MAAwC;CAChH,MAAM,OAAOC,OAAG,qBAAI,IAAI,MAAM,EAAC,aAAa,CAAC,MAAM,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,MAAM,GAAG;CAEhF,IAAI,WAAW;AACf,SAAQ,OAAR;EACE,KAAK;AACH,cAAWA,OAAG,IAAI,QAAQ;AAC1B;EACF,KAAK;AACH,cAAWA,OAAG,IAAI,QAAQ;AAC1B;EACF,KAAK;AACH,cAAWA,OAAG,KAAK,OAAO;AAC1B;EACF,KAAK;AACH,cAAWA,OAAG,OAAO,OAAO;AAC5B;EACF,KAAK;AACH,cAAWA,OAAG,IAAI,QAAQ;AAC1B;EACF,KAAK;AACH,cAAWA,OAAG,QAAQ,OAAO;AAC7B;;CAGJ,MAAM,KAAKA,OAAG,KAAK,UAAU;CAC7B,IAAI,SAAS,GAAG,KAAK,GAAG,SAAS,GAAG,GAAG,GAAG;AAE1C,KAAI,QAAQ,OAAO,KAAK,KAAK,CAAC,SAAS,EACrC,WAAU,IAAIA,OAAG,IAAI,cAAc,KAAK,CAAC;AAG3C,QAAO;;AAGT,SAAS,WAAW,WAAmB,OAAe,SAAiB,MAAwC;AAQ7G,QAAO,cAPO;EACZ,uBAAM,IAAI,MAAM,EAAC,aAAa;EAC9B;EACA,MAAM;EACN,KAAK;EACL,GAAG;EACJ,CAC0B;;AAG7B,SAAS,oBAAoB,WAAmB,KAA2B;AACzE,KAAI,IAAI,IAAI,IAAI,CAAE,QAAO;AACzB,MAAK,MAAM,UAAU,IACnB,KAAI,cAAc,UAAU,UAAU,WAAW,SAAS,IAAI,CAC5D,QAAO;AAGX,QAAO;;AAGT,SAAS,qBAAqB,WAA4B;AACxD,KAAI,CAAC,iBAAiB,CAAC,cAAe,QAAO;AAE7C,KAAI,iBAAiB,oBAAoB,WAAW,cAAc,CAChE,QAAO;AAGT,KAAI,cAAe,QAAO,oBAAoB,WAAW,cAAc;AACvE,QAAO;;;AAIT,SAAS,eAAe,KAA0B;AAChD,QAAO,OAAO,QAAQ,aAAa,KAAK,GAAG;;AAG7C,SAAS,SACP,WACA,OACA,SACA,MACM;AACN,KAAI,CAAC,UAAU,MAAM,CAAE;AACvB,KAAI,CAAC,qBAAqB,UAAU,CAAE;CAGtC,MAAM,WAAW,eAAe,QAAQ;CAGxC,MAAM,cAAc,mBAAmB;CACvC,MAAM,aAAa,eAAe,OAAO,KAAK,YAAY,CAAC,SAAS,IAAI;EAAE,GAAG;EAAa,GAAG;EAAM,GAAG;CAEtG,MAAM,YAAY,eAAe,GAC7B,WAAW,WAAW,OAAO,UAAU,WAAW,GAClD,cAAc,WAAW,OAAO,UAAU,WAAW;AAEzD,MAAK,MAAM,KAAK,QAAS,GAAE,WAAW,MAAM;AAE5C,KAAI,mBAAmB,eAAe,eAAgB;AAEtD,KAAI,eAAe,UAAU;AAC3B,cAAY,UAAU;AACtB;;AAIF,SAAQ,OAAR;EACE,KAAK;EACL,KAAK;AACH,WAAQ,MAAM,UAAU;AACxB;EACF,KAAK;AACH,WAAQ,KAAK,UAAU;AACvB;EACF,KAAK;AACH,WAAQ,KAAK,UAAU;AACvB;EACF,KAAK;AACH,WAAQ,MAAM,UAAU;AACxB;;;AAIN,SAAgB,UAAU,WAAmB,UAAkB,OAAsC;AACnG,KAAI,CAAC,qBAAqB,UAAU,CAAE;AACtC,KAAI,CAAC,qBAAqB,UAAU,CAAE;CAEtC,MAAM,UAAU,IAAI,SAAS;CAC7B,MAAM,YAAY,eAAe,GAC7B,WAAW,WAAW,QAAQ,SAAS;EAAE;EAAU,GAAG;EAAO,CAAC,GAC9D,cAAc,WAAW,QAAQ,SAAS;EAAE;EAAU,GAAG;EAAO,CAAC;AAErE,MAAK,MAAM,KAAK,QAAS,GAAE,WAAW,OAAO;AAC7C,KAAI,CAAC,gBAAiB,aAAY,UAAU;;;;;;AAkB9C,SAAgB,oBAAoB,WAAiC,OAA0C;CAC7G,MAAM,gBAAgB,IAAI,IAAI;EAAC;EAAM;EAAW;EAAY;EAAa;EAAW;EAAW,CAAC;AAChG,QAAO,IAAI,MAAM,OAAO;EACtB,IAAI,SAAS,MAAM;AACjB,OAAI,cAAc,IAAI,KAAe,CACnC,QAAO,WAAW,CAAC;AAErB,UAAO,MAAM;;EAEf,IAAI,SAAS,MAAM,OAAO;AACxB,OAAI,cAAc,IAAI,KAAe,CACnC,QAAO;AAET,SAAM,QAAkB;AACxB,UAAO;;EAEV,CAAC;;AAeJ,SAAS,iBACP,MACA,OACA,UACA,cACA,SACA,eAAwB,MAChB;CACR,MAAM,OAAO,OAAuB,YAAiC,SAAyC;AAC5G,MAAI,sBAAsB,OAAO;GAC/B,MAAM,MAAM;AACZ,YAAS,MAAM,OAAO,IAAI,SAAS;IACjC,GAAG;IACH,GAAG;IACH,YAAY,IAAI;IAChB,aAAa,IAAI;IACjB,YAAa,IAA0B;IACxC,CAAC;QAEF,UAAS,MAAM,OAAO,YAAY;GAAE,GAAG;GAAO,GAAG;GAAM,CAAC;;AA+I5D,QA3IuB;EACrB;EACA,OAAO,OAAO,OAAO,EAAE,GAAG,OAAO,CAAC;EAElC,IAAI,WAA4B;AAC9B,OAAI,CAAC,SAAU,QAAO;AACtB,UAAO,2BACE;IACL,IAAI,SAAS;IACb,SAAS,SAAS;IAClB,UAAU,SAAS;IACnB,WAAW,SAAS;IACpB,SAAS,SAAS;IAClB,UAAU,SAAS,YAAY,OAAO,SAAS,UAAU,SAAS,YAAY,KAAK,KAAK,GAAG,SAAS;IACrG,GACD,SAAS,MACV;;EAGH,QAAQ,KAAK,SAAS,IAAI,SAAS,KAAK,KAAK;EAC7C,QAAQ,KAAK,SAAS,IAAI,SAAS,KAAK,KAAK;EAC7C,OAAO,KAAK,SAAS,IAAI,QAAQ,KAAK,KAAK;EAC3C,OAAO,KAAK,SAAS,IAAI,QAAQ,KAAK,KAAK;EAC3C,QAAQ,YAAY,SAAS,IAAI,SAAS,YAAsB,KAAK;EAErE,OAAO,WAAoB,YAA8C;AAGvE,UAAO,iBAFW,YAAY,GAAG,KAAK,GAAG,cAAc,MACnC;IAAE,GAAG;IAAO,GAAG;IAAY,EACC,MAAM,cAAc,SAAS,aAAa;;EAG5F,KAAK,WAAoB,YAAoC;GAC3D,MAAM,YAAY,YAAY,GAAG,KAAK,GAAG,cAAc;GACvD,MAAM,qBAAqB,OAAO,eAAe,aAAa,YAAY,GAAG;GAC7E,MAAM,cAAc;IAAE,GAAG;IAAO,GAAG;IAAoB;GACvD,MAAM,YAAY,gBAAgB;GAGlC,IAAI,mBAAmB;GACvB,IAAI,kBAAkB;AAEtB,OAAI,CAAC,oBAAoB,mBAAmB;IAC1C,MAAM,YAAY,mBAAmB;AACrC,QAAI,WAAW;AACb,wBAAmB,UAAU;AAC7B,uBAAkB,mBAAmB,UAAU;;;GAKnD,MAAM,aAAa,CAAC;GACpB,MAAM,eAAe,mBAAmB,iBAAiB;GAGzD,MAAM,UAAU,aAAa,cAAc,GAAG;GAE9C,MAAM,cAA+B;IACnC,IAAI;IACJ,SAAS;IACT,UAAU;IACV,WAAW,KAAK,KAAK;IACrB,SAAS;IACT,UAAU;IACV,OAAO,EAAE;IACV;GAED,MAAM,aAAa,iBACjB,WACA,aACA,aACA,WACA,cACA,QACD;AAGD,mBAAgB,WAAW,cAAc,iBAAiB;AAGxD,cAA2D,OAAO,iBAAiB;AACnF,QAAI,YAAY,YAAY,KAAM;AAElC,gBAAY,UAAU,KAAK,KAAK;AAChC,gBAAY,WAAW,YAAY,UAAU,YAAY;AAGzD,QAAI,aACF,gBAAe,KACb,2BACS;KACL,IAAI,YAAY;KAChB,SAAS,YAAY;KACrB,UAAU,YAAY;KACtB,WAAW,YAAY;KACvB,SAAS,YAAY;KACrB,UAAU,YAAY;KACvB,GACD,EAAE,GAAG,YAAY,OAAO,CACzB,CACF;AAIH,mBAAe,UAAU;AAGzB,sBAAkB,WAAW;KAAE,MAAM;KAAW,YAAY,YAAY;KAAU,CAAC;AAGnF,QAAI,QACF,WAAU,WAAW,YAAY,UAAU;KACzC,SAAS,YAAY;KACrB,UAAU,YAAY;KACtB,WAAW,YAAY;KACvB,GAAG;KACH,GAAG,YAAY;KAChB,CAAC;;AAIN,UAAO;;EAGT,MAAM,SAAmD;AACvD,OAAI,OAAO,YAAY,SAErB,QAAO,KAAK,OAAO,QAAQ;AAG7B,UAAO,iBAAiB,MAAM;IAAE,GAAG;IAAO,GAAG;IAAS,EAAE,MAAM,cAAc,SAAS,aAAa;;EAGpG,MAAY;AACV,OAAI,UAAU,YAAY,KACtB,MAAqD,OAAO,YAAY;;EAG/E;;;;;;AASH,SAAS,kBAAkB,MAAc,OAAyC;AAChF,QAAO,iBAAiB,MAAM,SAAS,EAAE,EAAE,MAAM,MAAM,KAAK;;AAK9D,MAAM,iBAA6B,EAAE;AACrC,IAAI,eAAe;;AAGnB,SAAgB,kBAAwB;AACtC,gBAAe;AACf,gBAAe,SAAS;;;AAI1B,SAAgB,iBAA6B;AAC3C,gBAAe;AACf,QAAO,CAAC,GAAG,eAAe;;;AAI5B,SAAgB,oBAAgC;AAC9C,QAAO,CAAC,GAAG,eAAe;;;AAI5B,SAAgB,sBAA4B;AAC1C,gBAAe,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+D1B,SAAgB,aAAa,MAAc,OAAoD;CAC7F,MAAM,UAAU,kBAAkB,MAAM,MAAM;AAE9C,QAAO,IAAI,MAAM,SAA8B,EAC7C,IAAI,QAAQ,MAAc;AACxB,MAAI,QAAQ,sBAAsB,SAAS,UAAU;GACnD,MAAM,UAAU,mBAAmB;AACnC,OAAI,mBAAmB,QAA2C,QAChE;;AAGJ,SAAQ,OAA8C;IAEzD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACh0BJ,SAAgB,iBAAiB,UAAkB,UAA6B,EAAE,EAAc;CAC9F,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,gBAAgB,QAAQ,iBAAiB;CAE/C,IAAI,SAAS;CACb,IAAI,KAAoB;CACxB,IAAI,QAA+C;CACnD,IAAI,SAAS;AAGb,MAAK,SAAS,UAAU,IAAI;;CAG5B,SAAS,QAAc;AACrB,MAAI,OAAO,WAAW,KAAK,OAAO,KAAM;AAExC,YAAU,IADG,OACM;AACnB,WAAS;;AAIX,SAAQ,YAAY,OAAO,cAAc;AAEzC,KAAI,SAAS,OAAO,UAAU,YAAY,WAAW,MACjD,OAA4B,OAAO;CAIvC,MAAM,oBAA0B,OAAO;AACvC,SAAQ,GAAG,QAAQ,YAAY;AAE/B,QAAO;EACL,MAAM,MAAoB;AACxB,OAAI,OAAQ;AACZ,aAAU,OAAO;AACjB,OAAI,OAAO,UAAU,WACnB,QAAO;;EAIX;EAEA,QAAc;AACZ,OAAI,OAAQ;AACZ,YAAS;AACT,OAAI,UAAU,MAAM;AAClB,kBAAc,MAAM;AACpB,YAAQ;;AAEV,OAAI;AACF,WAAO;WACD,WAGE;AACR,QAAI,OAAO,MAAM;AACf,eAAU,GAAG;AACb,UAAK;;AAEP,YAAQ,eAAe,QAAQ,YAAY;;;EAGhD"}