@unhingged/logit 0.0.0-stage → 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/logit/logit/packages/logit/dist/chunk-3FU7DTQE.cjs","../src/levels.ts","../src/template.ts","../src/capture.ts","../src/format/render.ts","../src/event.ts","../src/context.ts","../src/enrichers.ts","../src/filters.ts","../src/selflog.ts","../src/format/text.ts","../src/format/clef.ts","../src/format/json.ts","../src/format/pretty.ts","../src/format/index.ts","../src/sinks/basic.ts","../src/sinks/console.ts","../src/sinks/wrappers.ts","../src/sinks/batching.ts","../src/sinks/http.ts","../src/logger.ts"],"names":[],"mappings":"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AACf,MAAA;AACT,IAAA;AACc,IAAA;AACI,IAAA;AACpB,EAAA;AAEuB,mBAAA;AACJ,IAAA;AACD,MAAA;AACP,MAAA;AACT,IAAA;AACwB,IAAA;AACR,MAAA;AACP,MAAA;AACT,IAAA;AAC0B,IAAA;AACV,MAAA;AACP,MAAA;AACT,IAAA;AACmE,IAAA;AACnD,MAAA;AACP,MAAA;AACT,IAAA;AAC+E,IAAA;AACxB;AAEH,IAAA;AACpC,MAAA;AACP,MAAA;AACT,IAAA;AACF,EAAA;AAEoB,mBAAA;AAAA;AAEc,IAAA;AAClC,EAAA;AAAA;AAGyC,EAAA;AACzB,IAAA;AACP,IAAA;AACT,EAAA;AAAA;AAG2B,EAAA;AACC,IAAA;AAC5B,EAAA;AAEuB,EAAA;AACI,IAAA;AAC3B,EAAA;AACF;AAI0C;AAQK;AAG2B;AAC3D,EAAA;AACc,EAAA;AACpB,EAAA;AACT;AAG+C;AAC5B,EAAA;AACnB;ApB46C8B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/logit/logit/packages/logit/dist/chunk-3FU7DTQE.cjs","sourcesContent":[null,"/**\n * Serilog's six levels. The names are the JS-idiomatic short forms\n * (`info`, `warn`), with Serilog's own (`information`, `warning`) and\n * pino's (`trace`) accepted wherever a level is parsed from text.\n */\nexport type LogLevel = 'verbose' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';\n\nexport const LEVELS: readonly LogLevel[] = ['verbose', 'debug', 'info', 'warn', 'error', 'fatal'];\n\nexport const LEVEL_ORDER: Readonly<Record<LogLevel, number>> = {\n verbose: 0,\n debug: 1,\n info: 2,\n warn: 3,\n error: 4,\n fatal: 5,\n};\n\n/** Serilog's level names — what CLEF (`@l`) and `{Level}` in an output template print. */\nexport const SERILOG_LEVEL_NAMES: Readonly<Record<LogLevel, string>> = {\n verbose: 'Verbose',\n debug: 'Debug',\n info: 'Information',\n warn: 'Warning',\n error: 'Error',\n fatal: 'Fatal',\n};\n\n/** Serilog's three-letter codes (`{Level:u3}`). */\nexport const LEVEL_CODES: Readonly<Record<LogLevel, string>> = {\n verbose: 'VRB',\n debug: 'DBG',\n info: 'INF',\n warn: 'WRN',\n error: 'ERR',\n fatal: 'FTL',\n};\n\n/** pino / bunyan numeric levels, for the JSON formatter's `levelFormat: 'number'`. */\nexport const LEVEL_NUMBERS: Readonly<Record<LogLevel, number>> = {\n verbose: 10,\n debug: 20,\n info: 30,\n warn: 40,\n error: 50,\n fatal: 60,\n};\n\nconst ALIASES: Record<string, LogLevel> = {\n verbose: 'verbose',\n trace: 'verbose',\n vrb: 'verbose',\n debug: 'debug',\n dbg: 'debug',\n info: 'info',\n information: 'info',\n informational: 'info',\n inf: 'info',\n warn: 'warn',\n warning: 'warn',\n wrn: 'warn',\n error: 'error',\n err: 'error',\n fatal: 'fatal',\n critical: 'fatal',\n crit: 'fatal',\n ftl: 'fatal',\n silent: 'fatal',\n};\n\n/**\n * Parses a level from any of its spellings (`'Information'`, `'warning'`,\n * `'trace'`, `'ERR'`, pino's `30`). Throws on anything it cannot read, so a\n * typo in configuration fails at startup rather than silencing a logger.\n */\nexport function parseLevel(input: LogLevel | string | number): LogLevel {\n if (typeof input === 'number') {\n if (input <= 10) return 'verbose';\n if (input <= 20) return 'debug';\n if (input <= 30) return 'info';\n if (input <= 40) return 'warn';\n if (input <= 50) return 'error';\n return 'fatal';\n }\n const level = ALIASES[String(input).trim().toLowerCase()];\n if (!level) throw new Error(`logit: unknown log level \"${input}\" (expected one of ${LEVELS.join(', ')})`);\n return level;\n}\n\nexport function isLevel(input: unknown): input is LogLevel {\n return typeof input === 'string' && Object.prototype.hasOwnProperty.call(LEVEL_ORDER, input);\n}\n\n/** `true` when `level` is at or above `minimum`. */\nexport function levelAtLeast(level: LogLevel, minimum: LogLevel): boolean {\n return LEVEL_ORDER[level] >= LEVEL_ORDER[minimum];\n}\n\n/**\n * A level that can be changed while the application runs — Serilog's\n * `LoggingLevelSwitch`. Hand the same instance to a logger's `minimumLevel`,\n * an override, or a sink's `restrictedToMinimumLevel`, and flip it from an\n * admin endpoint or a signal handler without recreating anything.\n */\nexport class LevelSwitch {\n #level: LogLevel;\n #listeners = new Set<(level: LogLevel) => void>();\n\n constructor(initial: LogLevel | string = 'info') {\n this.#level = parseLevel(initial);\n }\n\n get level(): LogLevel {\n return this.#level;\n }\n\n set level(next: LogLevel | string) {\n const parsed = parseLevel(next);\n if (parsed === this.#level) return;\n this.#level = parsed;\n for (const listener of this.#listeners) listener(parsed);\n }\n\n /** Called with the new level on every change; returns an unsubscribe function. */\n onChange(listener: (level: LogLevel) => void): () => void {\n this.#listeners.add(listener);\n return () => this.#listeners.delete(listener);\n }\n}\n\nexport type LevelOrSwitch = LogLevel | string | LevelSwitch;\n\n/** Resolves a configured level — static or a switch — to its current value. */\nexport function resolveLevel(value: LevelOrSwitch): LogLevel {\n return value instanceof LevelSwitch ? value.level : parseLevel(value);\n}\n","/**\n * Message templates (https://messagetemplates.org): `\"User {UserId} bought {@Order}\"`.\n *\n * A template is parsed once (cached by its text) into text and hole tokens.\n * Holes carry the `@` / `$` capturing operator, an optional `,alignment` and\n * `:format`. Malformed holes are kept as literal text, as Serilog does, so a\n * stray brace never throws from a logging call.\n */\n\nexport interface TextToken {\n readonly kind: 'text';\n readonly text: string;\n}\n\nexport interface HoleToken {\n readonly kind: 'hole';\n /** The hole exactly as written, braces included — used when no value binds to it. */\n readonly raw: string;\n /** Property name, or the digits of a positional hole. */\n readonly name: string;\n /** Set for positional holes (`{0}`). */\n readonly index?: number;\n /** `@` destructures, `$` stringifies, undefined leaves it to the capture rules. */\n readonly operator?: '@' | '$';\n /** Positive pads on the left, negative on the right (`{Name,-10}`). */\n readonly alignment?: number;\n /** `{Elapsed:0.00}` — passed through to the renderer. */\n readonly format?: string;\n}\n\nexport type TemplateToken = TextToken | HoleToken;\n\nexport interface MessageTemplate {\n readonly raw: string;\n readonly tokens: readonly TemplateToken[];\n /** The holes in order of appearance — what positional arguments bind to. */\n readonly holes: readonly HoleToken[];\n /** All holes are numeric (`{0} {1}`), so arguments bind by index. */\n readonly positional: boolean;\n}\n\nconst HOLE = /^([@$])?([0-9A-Za-z_]+)(?:,(-?\\d+))?(?::([^}]+))?$/;\n\nconst CACHE_LIMIT = 2000;\nconst cache = new Map<string, MessageTemplate>();\n\n/** Parses a template, memoised by text. The cache is bounded; a flood of unique templates just costs a reparse. */\nexport function parseTemplate(raw: string): MessageTemplate {\n const cached = cache.get(raw);\n if (cached) return cached;\n const parsed = parse(raw);\n if (cache.size >= CACHE_LIMIT) cache.clear();\n cache.set(raw, parsed);\n return parsed;\n}\n\nfunction parse(raw: string): MessageTemplate {\n const tokens: TemplateToken[] = [];\n const holes: HoleToken[] = [];\n let text = '';\n let i = 0;\n const n = raw.length;\n\n while (i < n) {\n const ch = raw[i];\n if (ch === '{') {\n if (raw[i + 1] === '{') {\n text += '{';\n i += 2;\n continue;\n }\n const close = raw.indexOf('}', i + 1);\n if (close !== -1) {\n const body = raw.slice(i + 1, close);\n const m = HOLE.exec(body);\n if (m) {\n if (text) {\n tokens.push({ kind: 'text', text });\n text = '';\n }\n const name = m[2];\n const isIndex = /^\\d+$/.test(name);\n const hole: HoleToken = {\n kind: 'hole',\n raw: raw.slice(i, close + 1),\n name,\n ...(isIndex ? { index: Number(name) } : {}),\n ...(m[1] ? { operator: m[1] as '@' | '$' } : {}),\n ...(m[3] !== undefined ? { alignment: Number(m[3]) } : {}),\n ...(m[4] !== undefined ? { format: m[4] } : {}),\n };\n tokens.push(hole);\n holes.push(hole);\n i = close + 1;\n continue;\n }\n }\n // Not a hole: a lone brace is literal text.\n text += '{';\n i += 1;\n continue;\n }\n if (ch === '}' && raw[i + 1] === '}') {\n text += '}';\n i += 2;\n continue;\n }\n text += ch;\n i += 1;\n }\n if (text) tokens.push({ kind: 'text', text });\n\n const positional = holes.length > 0 && holes.every((h) => h.index !== undefined);\n return { raw, tokens, holes, positional };\n}\n\n/**\n * Serilog's event-type id: Jenkins one-at-a-time over the template's UTF-16\n * code units, as eight hex digits — the same value Seq shows as `@i`, so\n * \"all events of this kind\" queries match across both ecosystems.\n */\nexport function templateHash(raw: string): string {\n let hash = 0;\n for (let i = 0; i < raw.length; i++) {\n hash = (hash + raw.charCodeAt(i)) >>> 0;\n hash = (hash + (hash << 10)) >>> 0;\n hash = (hash ^ (hash >>> 6)) >>> 0;\n }\n hash = (hash + (hash << 3)) >>> 0;\n hash = (hash ^ (hash >>> 11)) >>> 0;\n hash = (hash + (hash << 15)) >>> 0;\n return hash.toString(16).padStart(8, '0');\n}\n\n/** Pads a rendered value per `{Name,alignment}` — positive aligns right, negative left. */\nexport function align(text: string, alignment: number | undefined): string {\n if (!alignment) return text;\n const width = Math.abs(alignment);\n if (text.length >= width) return text;\n return alignment > 0 ? text.padStart(width) : text.padEnd(width);\n}\n","/**\n * Capturing — turning the arguments of a logging call into the values stored\n * on the event. This is Serilog's destructuring step, with JS defaults:\n *\n * scalars kept as they are (Date stays a Date; bigint, symbol and\n * functions become strings)\n * plain objects, captured structurally — they are data\n * arrays, Map, Set\n * class instances rendered with their own `toString()` / `toJSON()`, or\n * the class name — they are behaviour — unless `@` is used\n * `@` destructures anything, class instances included (`$type`\n * carries the class name)\n * `$` stringifies anything\n * Error always captured as a structure (name, message, stack,\n * own properties, `cause` chain)\n *\n * Depth, string and collection limits, redaction by key and transforming\n * policies all apply here, once, at capture time — so every sink sees the\n * same, already-safe value.\n */\n\nexport interface CapturedError {\n $type: 'Error';\n name: string;\n message: string;\n stack?: string;\n cause?: unknown;\n errors?: unknown[];\n [key: string]: unknown;\n}\n\n/**\n * A policy sees every non-scalar value before the default rules and may\n * replace it. Return `undefined` to decline; return `{ value }` to substitute\n * (the substitute is captured again, so return something simpler than you\n * were given or the policy recurses — Serilog's rule).\n */\nexport type DestructuringPolicy = (value: object) => { value: unknown } | undefined;\n\nexport interface DestructuringOptions {\n /** Nesting depth beyond which values are replaced by `'[Object]'` / `'[Array]'`. */\n maxDepth: number;\n /** Strings longer than this are cut and end with `…`. `Infinity` = no limit. */\n maxStringLength: number;\n /** Arrays, Sets and Maps are cut to this many elements. `Infinity` = no limit. */\n maxCollectionCount: number;\n /**\n * Keys whose values are replaced by `redactedValue`, at any depth.\n * A bare name (`'password'`) matches that key anywhere, case-insensitively.\n * A dotted path (`'headers.authorization'`, `'*.token'`, `'user.*.ssn'`) is\n * matched from the root of the captured value; `*` is one segment.\n */\n redact: readonly string[];\n redactedValue: unknown;\n /** Policies run in order; the first that answers wins. */\n policies: readonly DestructuringPolicy[];\n /** Add `$type` (the class name) when a class instance is destructured with `@`. */\n typeTag: boolean;\n}\n\nexport const DEFAULT_DESTRUCTURING: DestructuringOptions = {\n maxDepth: 10,\n maxStringLength: Infinity,\n maxCollectionCount: Infinity,\n redact: [],\n redactedValue: '[Redacted]',\n policies: [],\n typeTag: true,\n};\n\nexport function resolveDestructuring(partial?: Partial<DestructuringOptions>): DestructuringOptions {\n return { ...DEFAULT_DESTRUCTURING, ...partial };\n}\n\n/** Serilog's `Destructure.ByTransforming<T>()`: when a value is an instance of `type`, log `transform(value)` instead. */\nexport function byTransforming<T extends object>(\n type: abstract new (...args: never[]) => T,\n transform: (value: T) => unknown,\n): DestructuringPolicy {\n return (value) => (value instanceof type ? { value: transform(value) } : undefined);\n}\n\nexport type CaptureOperator = '@' | '$' | undefined;\n\nconst PLAIN_PROTOS = new Set<unknown>([Object.prototype, null]);\n\nfunction isPlainObject(value: object): boolean {\n return PLAIN_PROTOS.has(Object.getPrototypeOf(value));\n}\n\nfunction className(value: object): string | undefined {\n const name = value.constructor?.name;\n return typeof name === 'string' && name.length > 0 && name !== 'Object' ? name : undefined;\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length > max ? `${text.slice(0, max)}…` : text;\n}\n\n/** One compiled redaction rule. */\ninterface RedactRule {\n /** Lower-cased key for bare rules, or the dotted path segments. */\n key?: string;\n path?: string[];\n}\n\nfunction compileRedact(rules: readonly string[]): RedactRule[] {\n return rules.map((rule) => (rule.includes('.') ? { path: rule.toLowerCase().split('.') } : { key: rule.toLowerCase() }));\n}\n\nconst redactCache = new WeakMap<readonly string[], RedactRule[]>();\n\nfunction redactRules(options: DestructuringOptions): RedactRule[] {\n let rules = redactCache.get(options.redact);\n if (!rules) {\n rules = compileRedact(options.redact);\n redactCache.set(options.redact, rules);\n }\n return rules;\n}\n\nfunction isRedacted(rules: RedactRule[], path: string[]): boolean {\n if (rules.length === 0) return false;\n const last = path[path.length - 1];\n for (const rule of rules) {\n if (rule.key !== undefined) {\n if (rule.key === last) return true;\n continue;\n }\n const segs = rule.path!;\n if (segs.length !== path.length) continue;\n let ok = true;\n for (let i = 0; i < segs.length; i++) {\n if (segs[i] !== '*' && segs[i] !== path[i]) {\n ok = false;\n break;\n }\n }\n if (ok) return true;\n }\n return false;\n}\n\n/**\n * Captures one value. `operator` is the hole's `@` / `$`; `path` is the key\n * path from the root (for redaction) and `seen` guards against cycles.\n */\nexport function captureValue(\n value: unknown,\n operator: CaptureOperator,\n options: DestructuringOptions,\n path: string[] = [],\n seen: Set<object> = new Set(),\n depth = 0,\n): unknown {\n switch (typeof value) {\n case 'string':\n return truncate(value, options.maxStringLength);\n case 'number':\n // NaN / ±Infinity would become `null` in JSON; keep them legible.\n return Number.isFinite(value) ? value : String(value);\n case 'boolean':\n return value;\n case 'undefined':\n return null;\n case 'bigint':\n return Number.isSafeInteger(Number(value)) ? Number(value) : value.toString();\n case 'symbol':\n return value.toString();\n case 'function':\n return `[Function${value.name ? ` ${value.name}` : ''}]`;\n case 'object':\n if (value === null) return null;\n return captureObject(value, operator, options, path, seen, depth);\n default:\n return String(value);\n }\n}\n\n/**\n * Captures a value that is about to become the property `name` — the root\n * of its redaction path, so `redact: ['password']` also covers\n * `log.info('Login {Password}', pw)` and `forContext('password', …)`.\n */\nexport function captureProperty(name: string, value: unknown, operator: CaptureOperator, options: DestructuringOptions): unknown {\n const path = [name.toLowerCase()];\n if (isRedacted(redactRules(options), path)) return options.redactedValue;\n return captureValue(value, operator, options, path);\n}\n\nfunction captureObject(\n value: object,\n operator: CaptureOperator,\n options: DestructuringOptions,\n path: string[],\n seen: Set<object>,\n depth: number,\n): unknown {\n if (operator === '$') return stringify(value, options);\n\n // Policies first — they are how an application teaches the logger about its own types.\n for (const policy of options.policies) {\n let answer: { value: unknown } | undefined;\n try {\n answer = policy(value);\n } catch {\n answer = undefined;\n }\n if (answer) return captureValue(answer.value, undefined, options, path, seen, depth);\n }\n\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;\n if (value instanceof Error) return captureError(value, options, path, seen, depth);\n\n if (seen.has(value)) return '[Circular]';\n if (depth >= options.maxDepth) return Array.isArray(value) ? '[Array]' : '[Object]';\n\n if (Array.isArray(value)) return captureArray(value, options, path, seen, depth);\n if (value instanceof Set) return captureArray(Array.from(value), options, path, seen, depth);\n if (value instanceof Map) return captureMap(value, options, path, seen, depth);\n if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {\n return captureArray(Array.from(value as unknown as ArrayLike<unknown>), options, path, seen, depth);\n }\n\n const plain = isPlainObject(value);\n if (!plain && operator !== '@') return stringify(value, options);\n\n return captureStructure(value, plain, options, path, seen, depth);\n}\n\n/** How a class instance is logged without `@`: its own `toString`, else `toJSON`, else the class name. */\nfunction stringify(value: object, options: DestructuringOptions): unknown {\n const asString = (value as { toString?: unknown }).toString;\n if (typeof asString === 'function' && asString !== Object.prototype.toString && asString !== Error.prototype.toString) {\n try {\n return truncate(String(value), options.maxStringLength);\n } catch {\n /* fall through */\n }\n }\n const toJSON = (value as { toJSON?: unknown }).toJSON;\n if (typeof toJSON === 'function') {\n try {\n const json = toJSON.call(value);\n if (typeof json === 'string') return truncate(json, options.maxStringLength);\n if (json !== null && typeof json === 'object') return captureValue(json, '@', options);\n return json;\n } catch {\n /* fall through */\n }\n }\n if (Array.isArray(value)) return `[Array(${value.length})]`;\n return className(value) ?? '[object Object]';\n}\n\nfunction captureArray(items: unknown[], options: DestructuringOptions, path: string[], seen: Set<object>, depth: number): unknown[] {\n seen.add(items);\n const limit = Math.min(items.length, options.maxCollectionCount);\n const out = new Array<unknown>(limit);\n for (let i = 0; i < limit; i++) out[i] = captureValue(items[i], '@', options, path, seen, depth + 1);\n seen.delete(items);\n return out;\n}\n\nfunction captureMap(map: Map<unknown, unknown>, options: DestructuringOptions, path: string[], seen: Set<object>, depth: number): unknown {\n seen.add(map);\n const rules = redactRules(options);\n let count = 0;\n let allScalarKeys = true;\n for (const key of map.keys()) {\n if (typeof key !== 'string' && typeof key !== 'number') {\n allScalarKeys = false;\n break;\n }\n }\n let result: unknown;\n if (allScalarKeys) {\n const out: Record<string, unknown> = {};\n for (const [key, item] of map) {\n if (count++ >= options.maxCollectionCount) break;\n const name = String(key);\n const next = [...path, name.toLowerCase()];\n out[name] = isRedacted(rules, next) ? options.redactedValue : captureValue(item, '@', options, next, seen, depth + 1);\n }\n result = out;\n } else {\n const out: unknown[] = [];\n for (const [key, item] of map) {\n if (count++ >= options.maxCollectionCount) break;\n out.push([captureValue(key, '@', options, path, seen, depth + 1), captureValue(item, '@', options, path, seen, depth + 1)]);\n }\n result = out;\n }\n seen.delete(map);\n return result;\n}\n\nfunction captureStructure(\n value: object,\n plain: boolean,\n options: DestructuringOptions,\n path: string[],\n seen: Set<object>,\n depth: number,\n): Record<string, unknown> {\n seen.add(value);\n const rules = redactRules(options);\n const out: Record<string, unknown> = {};\n if (!plain && options.typeTag) {\n const name = className(value);\n if (name) out.$type = name;\n }\n for (const key of Object.keys(value)) {\n const next = [...path, key.toLowerCase()];\n if (isRedacted(rules, next)) {\n out[key] = options.redactedValue;\n continue;\n }\n let item: unknown;\n try {\n item = (value as Record<string, unknown>)[key];\n } catch (error) {\n item = `[Throws: ${error instanceof Error ? error.message : String(error)}]`;\n }\n out[key] = captureValue(item, '@', options, next, seen, depth + 1);\n }\n seen.delete(value);\n return out;\n}\n\n/**\n * Errors are always structured: name, message, stack, every own enumerable\n * property (the `code` on a Node error, the `status` on an HTTP one), the\n * `cause` chain and an `AggregateError`'s `errors`.\n */\nexport function captureError(\n error: Error,\n options: DestructuringOptions = DEFAULT_DESTRUCTURING,\n path: string[] = [],\n seen: Set<object> = new Set(),\n depth = 0,\n): CapturedError {\n const out: CapturedError = {\n $type: 'Error',\n name: error.name || 'Error',\n message: truncate(String(error.message ?? ''), options.maxStringLength),\n };\n if (typeof error.stack === 'string' && error.stack) out.stack = error.stack;\n if (seen.has(error) || depth >= options.maxDepth) return out;\n seen.add(error);\n const rules = redactRules(options);\n for (const key of Object.keys(error)) {\n if (key === 'name' || key === 'message' || key === 'stack') continue;\n const next = [...path, key.toLowerCase()];\n out[key] = isRedacted(rules, next)\n ? options.redactedValue\n : captureValue((error as unknown as Record<string, unknown>)[key], '@', options, next, seen, depth + 1);\n }\n if ('cause' in error && error.cause !== undefined && !('cause' in out)) {\n out.cause = captureValue(error.cause, '@', options, [...path, 'cause'], seen, depth + 1);\n }\n if (error instanceof AggregateError && !('errors' in out)) {\n out.errors = captureArray(error.errors, options, [...path, 'errors'], seen, depth + 1);\n }\n seen.delete(error);\n return out;\n}\n\n/** Binds a template's holes to the call's arguments, capturing each. Extra arguments are dropped, as in Serilog. */\nexport function captureArguments(\n holes: ReadonlyArray<{ name: string; index?: number; operator?: '@' | '$' }>,\n positional: boolean,\n args: readonly unknown[],\n options: DestructuringOptions,\n into: Record<string, unknown>,\n): void {\n if (positional) {\n for (const hole of holes) {\n const i = hole.index!;\n if (i < args.length) into[hole.name] = captureProperty(hole.name, args[i], hole.operator, options);\n }\n return;\n }\n const n = Math.min(holes.length, args.length);\n for (let i = 0; i < n; i++) {\n const hole = holes[i];\n into[hole.name] = captureProperty(hole.name, args[i], hole.operator, options);\n }\n}\n","/**\n * Rendering captured values and templates to text — shared by\n * `renderMessage()`, the text / pretty formatters and CLEF's `@r`.\n *\n * Rules follow Serilog's: strings are quoted unless the hole says `:l`,\n * structures print as `Type { Key: value }` (or JSON with `:j`), sequences\n * as `[a, b]`, dates as ISO 8601. Numbers accept `.NET`-style `0.00` / `F2`\n * / `N0` patterns, dates the `yyyy-MM-dd HH:mm:ss.fff zzz` family.\n */\n\nimport type { HoleToken, MessageTemplate } from '../template';\nimport { align } from '../template';\n\n/** Hooks for colouring (the pretty formatter); each receives text and returns styled text. */\nexport interface ValueStyles {\n string?: (text: string) => string;\n number?: (text: string) => string;\n boolean?: (text: string) => string;\n null?: (text: string) => string;\n name?: (text: string) => string;\n punctuation?: (text: string) => string;\n /** Raw hole text when nothing bound to it. */\n missing?: (text: string) => string;\n}\n\nexport interface RenderOptions {\n /** Strings print bare instead of quoted (`:l`). */\n literal?: boolean;\n /** Structures and sequences print as JSON (`:j`). */\n json?: boolean;\n /** Dates in text output print in UTC (default: local time). */\n utc?: boolean;\n styles?: ValueStyles;\n}\n\nconst NONE = (text: string) => text;\nconst NO_STYLES: Required<ValueStyles> = Object.freeze({ string: NONE, number: NONE, boolean: NONE, null: NONE, name: NONE, punctuation: NONE, missing: NONE });\n\n/** Fills in identity functions so the renderer never has to branch on a missing style. */\nexport function resolveStyles(styles: ValueStyles | undefined): Required<ValueStyles> {\n return styles ? { ...NO_STYLES, ...styles } : NO_STYLES;\n}\n\nconst EMPTY: RenderOptions = {};\n\nexport function renderValue(value: unknown, format?: string, options: RenderOptions = EMPTY): string {\n const S = options.styles ? resolveStyles(options.styles) : NO_STYLES;\n const literal = options.literal || (format !== undefined && format.includes('l'));\n const json = options.json || (format !== undefined && format.includes('j'));\n\n if (value === null || value === undefined) return S.null('null');\n switch (typeof value) {\n case 'string':\n return S.string(literal ? value : JSON.stringify(value));\n case 'number':\n return S.number(format === undefined ? String(value) : formatNumber(value, format));\n case 'boolean':\n return S.boolean(value ? 'true' : 'false');\n case 'bigint':\n return S.number(value.toString());\n default:\n break;\n }\n if (value instanceof Date) {\n const text = format && !/^[lj]+$/.test(format) ? formatDate(value, format, options.utc) : value.toISOString();\n return S.string(literal || json ? text : JSON.stringify(text));\n }\n if (json) return S.string(toJson(value));\n const nested: RenderOptions = options.literal ? { ...options, literal: false } : options;\n if (Array.isArray(value)) {\n let out = S.punctuation('[');\n for (let i = 0; i < value.length; i++) {\n if (i) out += S.punctuation(', ');\n out += renderValue(value[i], undefined, nested);\n }\n return out + S.punctuation(']');\n }\n if (typeof value === 'object') return renderStructure(value as Record<string, unknown>, nested, S);\n return String(value);\n}\n\nfunction renderStructure(value: Record<string, unknown>, options: RenderOptions, S: Required<ValueStyles>): string {\n const type = value.$type;\n if (type === 'Error' && typeof value.message === 'string') {\n // An error reads as \"Name: message\" inside a message; the stack is for the Exception token.\n const name = typeof value.name === 'string' ? value.name : 'Error';\n return `${S.name(name)}${S.punctuation(':')} ${S.string(value.message)}`;\n }\n const tag = typeof type === 'string' ? `${S.name(type)} ` : '';\n let inner = '';\n for (const key of Object.keys(value)) {\n if (key === '$type') continue;\n if (inner) inner += S.punctuation(', ');\n inner += `${S.name(key)}${S.punctuation(':')} ${renderValue(value[key], undefined, options)}`;\n }\n if (!inner) return `${tag}${S.punctuation('{ }')}`;\n return `${tag}${S.punctuation('{ ')}${inner}${S.punctuation(' }')}`;\n}\n\n/**\n * JSON that never throws. Captured values are already JSON-safe (capture\n * turns bigint, NaN and Infinity into numbers or strings; Dates have\n * `toJSON`), so the fast path is a plain `JSON.stringify` — a replacer\n * function would cost a call per key on every event. The replacer only\n * runs if something un-captured (a raw bigint) slipped through.\n */\nexport function toJson(value: unknown): string {\n try {\n return JSON.stringify(value) ?? 'null';\n } catch {\n try {\n return JSON.stringify(value, jsonReplacer) ?? 'null';\n } catch {\n return '\"[Unserializable]\"';\n }\n }\n}\n\nexport function jsonReplacer(this: unknown, _key: string, value: unknown): unknown {\n if (typeof value === 'bigint') return value.toString();\n if (typeof value === 'number' && !Number.isFinite(value)) return String(value);\n return value;\n}\n\ntype NumberFormatter = (value: number) => string;\n\nconst PLAIN: NumberFormatter = (value) => String(value);\nconst numberFormats = new Map<string, NumberFormatter>();\n\n/** `0.00`, `0.####`, `F2`, `N0`, `P1`, `D3`, `X` — the common .NET numeric formats; anything else prints the number as is. */\nexport function formatNumber(value: number, format?: string): string {\n if (!format) return String(value);\n let formatter = numberFormats.get(format);\n if (!formatter) {\n formatter = compileNumberFormat(format);\n if (numberFormats.size > 500) numberFormats.clear();\n numberFormats.set(format, formatter);\n }\n return formatter(value);\n}\n\nfunction compileNumberFormat(format: string): NumberFormatter {\n const f = format.replace(/[lj]/g, '');\n if (!f) return PLAIN;\n const fixed = /^[Ff](\\d*)$/.exec(f);\n if (fixed) {\n const digits = fixed[1] ? Number(fixed[1]) : 2;\n return (value) => value.toFixed(digits);\n }\n const grouped = /^[Nn](\\d*)$/.exec(f);\n if (grouped) {\n const digits = grouped[1] ? Number(grouped[1]) : 2;\n const nf = new Intl.NumberFormat('en-US', { minimumFractionDigits: digits, maximumFractionDigits: digits });\n return (value) => nf.format(value);\n }\n const percent = /^[Pp](\\d*)$/.exec(f);\n if (percent) {\n const digits = percent[1] ? Number(percent[1]) : 2;\n return (value) => `${(value * 100).toFixed(digits)} %`;\n }\n const padded = /^[Dd](\\d+)$/.exec(f);\n if (padded) {\n const width = Number(padded[1]);\n return (value) => String(Math.trunc(value)).padStart(width, '0');\n }\n if (/^[Xx]\\d*$/.test(f)) {\n const width = Number(f.slice(1) || 0);\n const upper = f[0] === 'X';\n return (value) => {\n const hex = Math.trunc(value).toString(16);\n return (upper ? hex.toUpperCase() : hex).padStart(width, '0');\n };\n }\n const pattern = /^0*(?:\\.(0*)(#*))?$/.exec(f);\n if (pattern) {\n const min = pattern[1]?.length ?? 0;\n const max = min + (pattern[2]?.length ?? 0);\n const hasFraction = pattern[1] !== undefined || pattern[2] !== undefined;\n const intMin = f.split('.')[0].length;\n const optional = max > min;\n return (value) => {\n let text = hasFraction ? (optional ? trimFraction(value.toFixed(max), min) : value.toFixed(max)) : String(Math.round(value));\n if (intMin > 1) {\n const [whole, frac] = text.replace('-', '').split('.');\n text = `${value < 0 ? '-' : ''}${whole.padStart(intMin, '0')}${frac !== undefined ? `.${frac}` : ''}`;\n }\n return text;\n };\n }\n return PLAIN;\n}\n\n/**\n * ISO 8601 (`toISOString()`), with the per-second prefix cached: a busy\n * process formats thousands of timestamps a second and `toISOString` is one\n * of the slowest things it would otherwise do per event.\n */\nlet cachedSecond = Number.NaN;\nlet cachedPrefix = '';\n\nexport function isoTimestamp(date: Date): string {\n const ms = date.getTime();\n if (Number.isNaN(ms)) return 'Invalid Date';\n const second = Math.floor(ms / 1000);\n if (second !== cachedSecond) {\n cachedSecond = second;\n cachedPrefix = new Date(second * 1000).toISOString().slice(0, 19);\n }\n const millis = ms - second * 1000;\n return `${cachedPrefix}.${millis < 10 ? '00' : millis < 100 ? '0' : ''}${millis}Z`;\n}\n\nfunction trimFraction(text: string, keep: number): string {\n if (!text.includes('.')) return text;\n let [whole, frac] = text.split('.');\n while (frac.length > keep && frac.endsWith('0')) frac = frac.slice(0, -1);\n return frac.length ? `${whole}.${frac}` : whole;\n}\n\nconst pad = (n: number, width = 2) => String(n).padStart(width, '0');\n\n/**\n * .NET-style date patterns: `yyyy MM dd HH hh mm ss fff tt zzz K`, quoted\n * literals, plus `o` / `O` for ISO 8601. Local time unless `utc`.\n */\nexport function formatDate(date: Date, pattern: string, utc = false): string {\n if (pattern === 'o' || pattern === 'O') return date.toISOString();\n const get = utc\n ? {\n year: date.getUTCFullYear(),\n month: date.getUTCMonth() + 1,\n day: date.getUTCDate(),\n hours: date.getUTCHours(),\n minutes: date.getUTCMinutes(),\n seconds: date.getUTCSeconds(),\n ms: date.getUTCMilliseconds(),\n offset: 0,\n }\n : {\n year: date.getFullYear(),\n month: date.getMonth() + 1,\n day: date.getDate(),\n hours: date.getHours(),\n minutes: date.getMinutes(),\n seconds: date.getSeconds(),\n ms: date.getMilliseconds(),\n offset: -date.getTimezoneOffset(),\n };\n const offsetText = (short: boolean) => {\n const sign = get.offset >= 0 ? '+' : '-';\n const abs = Math.abs(get.offset);\n const h = pad(Math.floor(abs / 60));\n const m = pad(abs % 60);\n return short ? `${sign}${h}` : `${sign}${h}:${m}`;\n };\n\n let out = '';\n let i = 0;\n while (i < pattern.length) {\n const ch = pattern[i];\n if (ch === \"'\" || ch === '\"') {\n const end = pattern.indexOf(ch, i + 1);\n out += pattern.slice(i + 1, end === -1 ? pattern.length : end);\n i = end === -1 ? pattern.length : end + 1;\n continue;\n }\n if (ch === '\\\\') {\n out += pattern[i + 1] ?? '';\n i += 2;\n continue;\n }\n let run = 1;\n while (pattern[i + run] === ch) run++;\n switch (ch) {\n case 'y':\n out += run >= 4 ? String(get.year) : pad(get.year % 100);\n break;\n case 'M':\n out += run >= 2 ? pad(get.month) : String(get.month);\n break;\n case 'd':\n out += run >= 2 ? pad(get.day) : String(get.day);\n break;\n case 'H':\n out += run >= 2 ? pad(get.hours) : String(get.hours);\n break;\n case 'h': {\n const h = get.hours % 12 || 12;\n out += run >= 2 ? pad(h) : String(h);\n break;\n }\n case 'm':\n out += run >= 2 ? pad(get.minutes) : String(get.minutes);\n break;\n case 's':\n out += run >= 2 ? pad(get.seconds) : String(get.seconds);\n break;\n case 'f':\n case 'F': {\n const frac = pad(get.ms, 3).padEnd(run, '0').slice(0, run);\n out += ch === 'F' ? frac.replace(/0+$/, '') : frac;\n break;\n }\n case 't':\n out += run >= 2 ? (get.hours < 12 ? 'AM' : 'PM') : get.hours < 12 ? 'A' : 'P';\n break;\n case 'z':\n out += offsetText(run < 3);\n break;\n case 'K':\n out += utc || get.offset === 0 ? 'Z' : offsetText(false);\n break;\n default:\n out += ch.repeat(run);\n }\n i += run;\n }\n return out;\n}\n\n/**\n * Renders a template against captured properties. Holes with no bound value\n * print as written (`{Missing}`), Serilog's behaviour, so a typo is visible.\n * `renderings`, when given, collects the text of every formatted hole — the\n * CLEF `@r` array.\n */\nexport function renderTemplate(\n template: MessageTemplate,\n properties: Record<string, unknown>,\n options: RenderOptions = {},\n renderings?: string[],\n): string {\n let out = '';\n for (const token of template.tokens) {\n if (token.kind === 'text') {\n out += token.text;\n continue;\n }\n out += renderHole(token, properties, options, renderings);\n }\n return out;\n}\n\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nfunction renderHole(hole: HoleToken, properties: Record<string, unknown>, options: RenderOptions, renderings?: string[]): string {\n if (!hasOwn.call(properties, hole.name)) {\n return options.styles?.missing ? options.styles.missing(hole.raw) : hole.raw;\n }\n const text = renderValue(properties[hole.name], hole.format, options);\n if (renderings && hole.format) renderings.push(text);\n return align(text, hole.alignment);\n}\n","import { type CapturedError, type DestructuringOptions, captureError, captureProperty } from './capture';\nimport type { LogLevel } from './levels';\nimport { type RenderOptions, renderTemplate } from './format/render';\nimport { type MessageTemplate, templateHash } from './template';\n\nexport interface LogEventInit {\n timestamp?: Date;\n level: LogLevel;\n template: MessageTemplate;\n properties?: Record<string, unknown>;\n error?: Error;\n traceId?: string;\n spanId?: string;\n}\n\n/**\n * One logged event: when, how severe, the template it was written with, the\n * captured properties, and — separately from the properties, as in Serilog —\n * the error and the trace/span ids.\n *\n * Sinks receive the same instance; enrichers mutate it through the\n * `add*` methods so that every value goes through the logger's capture rules.\n */\nexport class LogEvent {\n readonly timestamp: Date;\n readonly level: LogLevel;\n readonly template: MessageTemplate;\n readonly properties: Record<string, unknown>;\n error: Error | undefined;\n traceId: string | undefined;\n spanId: string | undefined;\n\n #destructuring: DestructuringOptions;\n #capturedError: CapturedError | undefined;\n #eventId: string | undefined;\n\n constructor(init: LogEventInit, destructuring: DestructuringOptions) {\n this.timestamp = init.timestamp ?? new Date();\n this.level = init.level;\n this.template = init.template;\n this.properties = init.properties ?? {};\n this.error = init.error;\n this.traceId = init.traceId;\n this.spanId = init.spanId;\n this.#destructuring = destructuring;\n }\n\n /** The template text, e.g. `\"User {UserId} logged in\"`. */\n get messageTemplate(): string {\n return this.template.raw;\n }\n\n /** Serilog's `SourceContext` — set by `logger.forSource()`. */\n get sourceContext(): string | undefined {\n const value = this.properties.SourceContext;\n return typeof value === 'string' ? value : undefined;\n }\n\n /** Eight hex digits identifying the template (Seq's `@i`). */\n get eventId(): string {\n return (this.#eventId ??= templateHash(this.template.raw));\n }\n\n /** The error as a structure (name, message, stack, own properties, cause chain), captured once. */\n get errorProperties(): CapturedError | undefined {\n if (!this.error) return undefined;\n return (this.#capturedError ??= captureError(this.error, this.#destructuring));\n }\n\n /** Captures and adds `value` under `name` unless the event already has it — the rule enrichers follow. */\n addPropertyIfAbsent(name: string, value: unknown, destructure = false): void {\n if (Object.prototype.hasOwnProperty.call(this.properties, name)) return;\n this.properties[name] = captureProperty(name, value, destructure ? '@' : undefined, this.#destructuring);\n }\n\n /** Captures and adds `value` under `name`, replacing any existing value. */\n addOrUpdateProperty(name: string, value: unknown, destructure = false): void {\n this.properties[name] = captureProperty(name, value, destructure ? '@' : undefined, this.#destructuring);\n }\n\n removeProperty(name: string): void {\n delete this.properties[name];\n }\n\n hasProperty(name: string): boolean {\n return Object.prototype.hasOwnProperty.call(this.properties, name);\n }\n\n /** The template rendered with this event's properties. */\n renderMessage(options?: RenderOptions): string {\n return renderTemplate(this.template, this.properties, options);\n }\n\n /** Properties that are not holes in the template — the \"extra\" context, in Serilog's `{Properties}` sense. */\n extraProperties(): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n const holes = this.template.holes;\n for (const key of Object.keys(this.properties)) {\n if (!holes.some((h) => h.name === key)) out[key] = this.properties[key];\n }\n return out;\n }\n}\n","/**\n * Ambient properties — Serilog's `LogContext`. Everything logged inside\n * `LogContext.run({ requestId }, fn)` carries `requestId`, however deep the\n * call stack and across `await`s, because the frames live in an\n * `AsyncLocalStorage` when one is available (Node, Bun, Deno, Next.js\n * middleware and the edge runtime). Where there is none (a browser) the\n * frames fall back to a plain stack, which is right for synchronous code.\n *\n * `push()` is the no-callback form, for `using`:\n *\n * using _ = LogContext.push({ userId });\n */\n\nexport interface ContextFrame {\n readonly properties: Readonly<Record<string, unknown>>;\n readonly parent: ContextFrame | null;\n /** Serilog's `IDiagnosticContext`: values collected during a request for its completion event. */\n readonly diagnostics?: Map<string, unknown>;\n}\n\n/** The subset of `AsyncLocalStorage` we need — structural, so any implementation (or a test double) fits. */\nexport interface ContextStore {\n getStore(): ContextFrame | undefined;\n run<R>(frame: ContextFrame | undefined, fn: () => R): R;\n enterWith?(frame: ContextFrame | undefined): void;\n}\n\n/** Synchronous fallback for runtimes without AsyncLocalStorage. */\nclass StackStore implements ContextStore {\n private current: ContextFrame | undefined;\n getStore() {\n return this.current;\n }\n run<R>(frame: ContextFrame | undefined, fn: () => R): R {\n const previous = this.current;\n this.current = frame;\n try {\n return fn();\n } finally {\n this.current = previous;\n }\n }\n enterWith(frame: ContextFrame | undefined) {\n this.current = frame;\n }\n}\n\n/**\n * Node ≥ 20.16 and Bun expose built-ins without an import through\n * `process.getBuiltinModule`, which keeps this module free of `node:`\n * imports and therefore safe to bundle for a browser. Next.js's edge\n * runtime has no `process.getBuiltinModule`; `@unhingged/logit/next` installs\n * the store there with a static import.\n */\nfunction detectStore(): ContextStore {\n try {\n const proc = (globalThis as { process?: { getBuiltinModule?: (id: string) => unknown } }).process;\n const hooks = proc?.getBuiltinModule?.('node:async_hooks') as\n | { AsyncLocalStorage?: new () => ContextStore }\n | undefined;\n if (hooks?.AsyncLocalStorage) return new hooks.AsyncLocalStorage();\n } catch {\n /* not Node */\n }\n try {\n // CJS builds (and Bun) have `require`; ESM in a browser does not.\n const req = (globalThis as { require?: (id: string) => unknown }).require ?? (typeof require === 'function' ? require : undefined);\n const hooks = req?.('node:async_hooks') as { AsyncLocalStorage?: new () => ContextStore } | undefined;\n if (hooks?.AsyncLocalStorage) return new hooks.AsyncLocalStorage();\n } catch {\n /* not available */\n }\n return new StackStore();\n}\n\nlet store: ContextStore = detectStore();\n\nconst DISPOSE = ((Symbol as { dispose?: symbol }).dispose ?? Symbol.for('Symbol.dispose')) as typeof Symbol.dispose;\n\nexport interface ContextHandle {\n /** Restores the previous frame. Calling it twice is harmless. */\n dispose(): void;\n [Symbol.dispose](): void;\n}\n\nfunction makeFrame(properties: Record<string, unknown>, parent: ContextFrame | undefined, diagnostics?: Map<string, unknown>): ContextFrame {\n return { properties, parent: parent ?? null, diagnostics: diagnostics ?? parent?.diagnostics };\n}\n\nexport const LogContext = {\n /**\n * Runs `fn` with `properties` added to the ambient context. Async\n * functions are followed through every `await` when an\n * AsyncLocalStorage-backed store is active.\n */\n run<R>(properties: Record<string, unknown>, fn: () => R): R {\n return store.run(makeFrame(properties, store.getStore()), fn);\n },\n\n /**\n * Pushes properties onto the ambient context until the handle is disposed.\n * Prefer `run()` for async code; `push()` relies on `enterWith`, which\n * binds the rest of the *current* async scope.\n */\n push(properties: Record<string, unknown>): ContextHandle {\n const previous = store.getStore();\n if (!store.enterWith) throw new Error('logit: this context store has no enterWith(); use LogContext.run() instead');\n store.enterWith(makeFrame(properties, previous));\n let disposed = false;\n const dispose = () => {\n if (disposed) return;\n disposed = true;\n store.enterWith!(previous);\n };\n return { dispose, [DISPOSE]: dispose } as unknown as ContextHandle;\n },\n\n /** The merged ambient properties, innermost frame winning. */\n current(): Record<string, unknown> {\n const frame = store.getStore();\n if (!frame) return {};\n const frames: ContextFrame[] = [];\n for (let f: ContextFrame | null = frame; f; f = f.parent) frames.push(f);\n const out: Record<string, unknown> = {};\n for (let i = frames.length - 1; i >= 0; i--) Object.assign(out, frames[i].properties);\n return out;\n },\n\n /** The innermost frame, for enrichers that want to walk it themselves. */\n frame(): ContextFrame | undefined {\n return store.getStore();\n },\n\n /**\n * Starts a request scope: ambient `properties` plus a fresh diagnostic\n * bag that `diagnosticContext.set()` writes to and the request-completion\n * event reads. Used by the Next.js and Express integrations.\n */\n runScope<R>(properties: Record<string, unknown>, fn: (diagnostics: Map<string, unknown>) => R): R {\n const diagnostics = new Map<string, unknown>();\n return store.run(makeFrame(properties, store.getStore(), diagnostics), () => fn(diagnostics));\n },\n\n /** Replaces the backing store — `new AsyncLocalStorage()` on runtimes we cannot detect. */\n use(next: ContextStore): void {\n store = next;\n },\n\n /** `true` when frames follow async execution (an AsyncLocalStorage-like store is active). */\n get isAsync(): boolean {\n return !(store instanceof StackStore);\n },\n};\n\n/**\n * Serilog's `IDiagnosticContext`: set a property from anywhere inside a\n * request scope and it lands on that request's single completion event —\n * one place for \"which user, which tenant, how many rows\" instead of a log\n * line per fact.\n */\nexport const diagnosticContext = {\n set(name: string, value: unknown): void {\n store.getStore()?.diagnostics?.set(name, value);\n },\n /** `true` inside a request scope (so a library can skip the work of computing a value nobody will collect). */\n get active(): boolean {\n return store.getStore()?.diagnostics !== undefined;\n },\n};\n","import { LogContext } from './context';\nimport type { LogEvent } from './event';\n\n/**\n * An enricher adds properties to every event that passes through a logger\n * (Serilog's `ILogEventEnricher`). Use `addPropertyIfAbsent` so that a\n * value written in the message, or bound closer to the call, wins.\n */\nexport type Enricher = (event: LogEvent) => void;\n\n/** A fixed property on every event: `withProperty('Application', 'shop')`. */\nexport function withProperty(name: string, value: unknown, destructure = false): Enricher {\n return (event) => event.addPropertyIfAbsent(name, value, destructure);\n}\n\n/** Several fixed properties at once. */\nexport function withProperties(properties: Record<string, unknown>, destructure = false): Enricher {\n const entries = Object.entries(properties);\n return (event) => {\n for (const [name, value] of entries) event.addPropertyIfAbsent(name, value, destructure);\n };\n}\n\n/** A property computed per event — `withComputed('Memory', () => process.memoryUsage().rss)`. */\nexport function withComputed(name: string, compute: (event: LogEvent) => unknown, destructure = false): Enricher {\n return (event) => {\n if (event.hasProperty(name)) return;\n event.addPropertyIfAbsent(name, compute(event), destructure);\n };\n}\n\n/**\n * Copies the ambient `LogContext` onto the event — Serilog's\n * `Enrich.FromLogContext()`. `createLogger` includes it unless told not to.\n * `traceId` / `spanId` in the context become the event's trace fields.\n */\nexport function fromLogContext(): Enricher {\n return (event) => {\n const frame = LogContext.frame();\n if (!frame) return;\n // Innermost frame first; addPropertyIfAbsent keeps the first value seen, so inner wins.\n for (let f = frame; f; f = f.parent!) {\n for (const name of Object.keys(f.properties)) {\n const value = f.properties[name];\n if (name === 'traceId') {\n if (event.traceId === undefined && typeof value === 'string') event.traceId = value;\n continue;\n }\n if (name === 'spanId') {\n if (event.spanId === undefined && typeof value === 'string') event.spanId = value;\n continue;\n }\n event.addPropertyIfAbsent(name, value, true);\n }\n if (!f.parent) break;\n }\n };\n}\n\n/** `Environment` from `NODE_ENV` (or the value given). No-op where there is no `process.env`. */\nexport function withEnvironment(name?: string): Enricher {\n const env = name ?? (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env?.NODE_ENV;\n return (event) => {\n if (env) event.addPropertyIfAbsent('Environment', env);\n };\n}\n\nexport interface TraceContext {\n traceId?: string;\n spanId?: string;\n}\n\n/**\n * Sets the event's trace and span ids from a getter — wire it to\n * `trace.getActiveSpan()?.spanContext()` from `@opentelemetry/api`, or to\n * whatever carries your correlation ids.\n */\nexport function withTraceContext(get: () => TraceContext | undefined | null): Enricher {\n return (event) => {\n if (event.traceId !== undefined && event.spanId !== undefined) return;\n let ctx: TraceContext | undefined | null;\n try {\n ctx = get();\n } catch {\n return;\n }\n if (!ctx) return;\n if (event.traceId === undefined && ctx.traceId) event.traceId = ctx.traceId;\n if (event.spanId === undefined && ctx.spanId) event.spanId = ctx.spanId;\n };\n}\n","import type { LogEvent } from './event';\n\n/** `true` keeps the event. Filters run after enrichment, before the sinks. */\nexport type Filter = (event: LogEvent) => boolean;\n\n/** Serilog's `Filter.ByExcluding`: drop events the predicate matches. */\nexport function byExcluding(predicate: (event: LogEvent) => boolean): Filter {\n return (event) => !predicate(event);\n}\n\n/** Serilog's `Filter.ByIncludingOnly`: keep only events the predicate matches. */\nexport function byIncludingOnly(predicate: (event: LogEvent) => boolean): Filter {\n return predicate;\n}\n\n/** Serilog's `Matching` helpers — predicates for the two filters above and for `conditional()` sinks. */\nexport const Matching = {\n /** Events whose `SourceContext` is `source` or starts with `source.`. */\n fromSource(source: string): (event: LogEvent) => boolean {\n const prefix = `${source}.`;\n return (event) => {\n const ctx = event.sourceContext;\n return ctx !== undefined && (ctx === source || ctx.startsWith(prefix));\n };\n },\n /** Events that carry `name` — optionally with a value the predicate accepts. */\n withProperty<T = unknown>(name: string, predicate?: (value: T) => boolean): (event: LogEvent) => boolean {\n return (event) => event.hasProperty(name) && (predicate ? predicate(event.properties[name] as T) : true);\n },\n /** Events written with exactly this template text. */\n withTemplate(template: string): (event: LogEvent) => boolean {\n return (event) => event.messageTemplate === template;\n },\n /** Events whose rendered message matches the pattern. */\n messageMatches(pattern: RegExp): (event: LogEvent) => boolean {\n return (event) => pattern.test(event.renderMessage({ literal: true }));\n },\n};\n\n/** Keeps a fraction of matching events — `sampled(0.1, Matching.fromSource('http'))` keeps one in ten request logs. */\nexport function sampled(rate: number, predicate: (event: LogEvent) => boolean = () => true, random: () => number = Math.random): Filter {\n return (event) => !predicate(event) || random() < rate;\n}\n\n/**\n * Lets at most `max` matching events through per `windowMs`; the rest are\n * dropped. For the error that fires ten thousand times a second.\n */\nexport function rateLimited(max: number, windowMs: number, predicate: (event: LogEvent) => boolean = () => true, now: () => number = Date.now): Filter {\n let windowStart = 0;\n let count = 0;\n return (event) => {\n if (!predicate(event)) return true;\n const t = now();\n if (t - windowStart >= windowMs) {\n windowStart = t;\n count = 0;\n }\n return ++count <= max;\n };\n}\n","/**\n * The logger's own diagnostics — Serilog's `SelfLog`. Off by default: a\n * sink that fails must never take the application down, so failures go here\n * and nowhere else. Enable it while setting up a sink, or point it at\n * `console.error` in development.\n */\ntype SelfLogOutput = (message: string) => void;\n\nlet output: SelfLogOutput | null = null;\n\nexport const selfLog = {\n /** `'stderr'` writes to `console.error`; a function receives each line. */\n enable(target: SelfLogOutput | 'stderr'): void {\n output = target === 'stderr' ? (line) => console.error(line) : target;\n },\n disable(): void {\n output = null;\n },\n get enabled(): boolean {\n return output !== null;\n },\n /** Writes one line (prefixed with the time) if enabled; swallows its own errors. */\n write(message: string, error?: unknown): void {\n if (!output) return;\n try {\n const detail = error instanceof Error ? ` — ${error.stack ?? error.message}` : error !== undefined ? ` — ${String(error)}` : '';\n output(`${new Date().toISOString()} logit: ${message}${detail}`);\n } catch {\n // Diagnostics must not throw.\n }\n },\n};\n","/**\n * Serilog's output templates: `\"{Timestamp:HH:mm:ss} [{Level:u3}] {SourceContext} {Message:lj}{NewLine}{Exception}\"`.\n *\n * The template is parsed with the message-template parser — it IS one —\n * and the well-known holes are filled from the event's own fields; any other\n * name reads a property. `{Properties}` prints every property not already\n * used by the message or the output template.\n */\nimport type { LogEvent } from '../event';\nimport { LEVEL_CODES, SERILOG_LEVEL_NAMES } from '../levels';\nimport { parseTemplate, align, type HoleToken } from '../template';\nimport { type RenderOptions, type ValueStyles, formatDate, renderTemplate, renderValue, toJson } from './render';\nimport type { Formatter } from './types';\n\nexport const DEFAULT_OUTPUT_TEMPLATE = '{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}';\n\nexport interface TextFormatterOptions {\n outputTemplate?: string;\n /** Timestamps in UTC instead of local time. */\n utc?: boolean;\n /** Colour hooks for the message's values (used by the pretty formatter). */\n styles?: ValueStyles;\n /** Hooks for the structural holes. */\n tokenStyles?: Partial<Record<'Timestamp' | 'Level' | 'SourceContext' | 'Exception' | 'Properties' | 'Message', (text: string, event: LogEvent) => string>>;\n}\n\nexport function formatLevel(level: LogEvent['level'], format?: string): string {\n const name = SERILOG_LEVEL_NAMES[level];\n if (!format) return name;\n const m = /^([uw])(\\d*)$/.exec(format);\n if (!m) return name;\n const width = m[2] ? Number(m[2]) : 0;\n let text = width === 3 ? LEVEL_CODES[level] : width > 0 ? name.slice(0, width) : name;\n if (width > 0 && text.length < width) text = text.padEnd(width);\n return m[1] === 'u' ? text.toUpperCase() : text.toLowerCase();\n}\n\n/** The error as text: stack (or name + message), then each cause indented — Node's own \"caused by\" shape. */\nexport function formatError(error: Error | undefined, indent = ''): string {\n if (!error) return '';\n const lines: string[] = [];\n let current: unknown = error;\n let depth = 0;\n const seen = new Set<unknown>();\n while (current !== undefined && current !== null && depth < 10 && !seen.has(current)) {\n seen.add(current);\n const prefix = depth === 0 ? indent : `${indent}${' '.repeat(depth)}caused by: `;\n if (current instanceof Error) {\n const body = current.stack && current.stack.includes(current.message) ? current.stack : `${current.name}: ${current.message}${current.stack ? `\\n${current.stack}` : ''}`;\n lines.push(prefix + body.split('\\n').join(`\\n${indent}${' '.repeat(depth)}`));\n if (current instanceof AggregateError && current.errors.length) {\n current.errors.forEach((inner, i) => {\n lines.push(`${indent}${' '.repeat(depth + 1)}[${i}] ${formatError(inner instanceof Error ? inner : new Error(String(inner)), `${indent}${' '.repeat(depth + 1)}`).trimStart()}`);\n });\n }\n current = (current as { cause?: unknown }).cause;\n } else {\n lines.push(prefix + String(current));\n current = undefined;\n }\n depth++;\n }\n return lines.join('\\n');\n}\n\nexport function textFormatter(options: TextFormatterOptions = {}): Formatter {\n const template = parseTemplate(options.outputTemplate ?? DEFAULT_OUTPUT_TEMPLATE);\n const utc = options.utc ?? false;\n const styles = options.styles;\n const tokenStyles = options.tokenStyles ?? {};\n const usedNames = new Set(template.holes.map((h) => h.name));\n\n return (event) => {\n let out = '';\n for (const token of template.tokens) {\n if (token.kind === 'text') {\n out += token.text;\n continue;\n }\n out += align(renderToken(token, event), token.alignment);\n }\n return out;\n };\n\n function renderToken(hole: HoleToken, event: LogEvent): string {\n switch (hole.name) {\n case 'Timestamp': {\n const text = hole.format ? formatDate(event.timestamp, hole.format, utc) : event.timestamp.toISOString();\n return tokenStyles.Timestamp?.(text, event) ?? text;\n }\n case 'Level': {\n const text = formatLevel(event.level, hole.format);\n return tokenStyles.Level?.(text, event) ?? text;\n }\n case 'Message': {\n const renderOptions: RenderOptions = { literal: hole.format?.includes('l'), json: hole.format?.includes('j'), utc, styles };\n const text = renderTemplate(event.template, event.properties, renderOptions);\n return tokenStyles.Message?.(text, event) ?? text;\n }\n case 'NewLine':\n return '\\n';\n case 'Exception': {\n if (!event.error) return '';\n const text = formatError(event.error);\n return tokenStyles.Exception?.(text, event) ?? text;\n }\n case 'Properties': {\n const extra: Record<string, unknown> = {};\n for (const key of Object.keys(event.properties)) {\n if (usedNames.has(key) || event.template.holes.some((h) => h.name === key)) continue;\n extra[key] = event.properties[key];\n }\n if (Object.keys(extra).length === 0) return '';\n const text = hole.format?.includes('j') ? toJson(extra) : renderValue(extra, undefined, { styles });\n return tokenStyles.Properties?.(text, event) ?? text;\n }\n case 'TraceId':\n return event.traceId ?? '';\n case 'SpanId':\n return event.spanId ?? '';\n case 'EventId':\n return event.eventId;\n default: {\n if (!event.hasProperty(hole.name)) return '';\n const text = renderValue(event.properties[hole.name], hole.format ?? 'l', { utc, styles });\n return hole.name === 'SourceContext' ? (tokenStyles.SourceContext?.(text, event) ?? text) : text;\n }\n }\n }\n}\n","/**\n * CLEF — the Compact Log Event Format (https://clef-json.org), Serilog's\n * own wire format and what Seq ingests natively:\n *\n * {\"@t\":\"2026-10-08T06:00:00.000Z\",\"@mt\":\"User {UserId} in\",\"@l\":\"Debug\",\"@i\":\"a1b2c3d4\",\"UserId\":42}\n *\n * `@l` is omitted for `info`, `@x` carries the error text, `@r` the\n * pre-rendered values of holes that have a format, `@tr` / `@sp` the trace\n * context. A user property starting with `@` is escaped as `@@`.\n */\nimport type { LogEvent } from '../event';\nimport { SERILOG_LEVEL_NAMES } from '../levels';\nimport { isoTimestamp, renderTemplate, toJson } from './render';\nimport { formatError } from './text';\nimport type { Formatter } from './types';\n\nexport const CLEF_MEDIA_TYPE = 'application/vnd.serilog.clef';\n\nexport interface ClefFormatterOptions {\n /** Also write the rendered message as `@m` (Serilog's \"rendered compact\" variant). Default false. */\n renderMessage?: boolean;\n}\n\nexport function clefFormatter(options: ClefFormatterOptions = {}): Formatter {\n return (event: LogEvent) => {\n const out: Record<string, unknown> = { '@t': isoTimestamp(event.timestamp) };\n if (options.renderMessage) out['@m'] = event.renderMessage({ literal: true });\n out['@mt'] = event.messageTemplate;\n if (event.level !== 'info') out['@l'] = SERILOG_LEVEL_NAMES[event.level];\n if (event.error) out['@x'] = formatError(event.error);\n out['@i'] = event.eventId;\n const renderings: string[] = [];\n renderTemplate(event.template, event.properties, {}, renderings);\n if (renderings.length) out['@r'] = renderings;\n if (event.traceId) out['@tr'] = event.traceId;\n if (event.spanId) out['@sp'] = event.spanId;\n for (const key of Object.keys(event.properties)) {\n out[key.startsWith('@') ? `@${key}` : key] = event.properties[key];\n }\n return toJson(out);\n };\n}\n","/**\n * One JSON object per event, flat: the reified fields first, then every\n * property at the root (what Datadog, Loki, CloudWatch, Vercel and friends\n * index best). A property that collides with a reified key keeps its value\n * under `<name>_`, so nothing is lost silently.\n */\nimport type { LogEvent } from '../event';\nimport { LEVELS, LEVEL_NUMBERS, SERILOG_LEVEL_NAMES, type LogLevel } from '../levels';\nimport { isoTimestamp, toJson } from './render';\nimport type { MessageTemplate } from '../template';\nimport type { Formatter } from './types';\n\nexport interface JsonFormatterOptions {\n /** Rename the reified keys, e.g. `{ timestamp: 'time', message: 'msg' }` for pino-shaped output. */\n keys?: Partial<Record<'timestamp' | 'level' | 'message' | 'template' | 'source' | 'error' | 'traceId' | 'spanId' | 'eventId', string>>;\n /** `'name'` → `\"info\"`, `'serilog'` → `\"Information\"`, `'upper'` → `\"INFO\"`, `'number'` → pino's 30. */\n levelFormat?: 'name' | 'serilog' | 'upper' | 'number';\n /** Include the rendered message (default true) and / or the template (default true). */\n message?: boolean;\n template?: boolean;\n /** Include the template hash as `eventId` (default false). */\n eventId?: boolean;\n /** Timestamp as ISO 8601 (default) or epoch milliseconds. */\n timestampFormat?: 'iso' | 'epoch';\n}\n\nconst DEFAULT_KEYS = {\n timestamp: 'timestamp',\n level: 'level',\n message: 'message',\n template: 'template',\n source: 'source',\n error: 'error',\n traceId: 'traceId',\n spanId: 'spanId',\n eventId: 'eventId',\n} as const;\n\nconst templateJson = new WeakMap<MessageTemplate, string>();\n\n/**\n * The line is assembled from fragments rather than built as an object and\n * stringified whole: the reified keys are constant strings, the level's\n * fragment is precomputed, the template's JSON is cached per template, and\n * only the message and the properties are escaped per event.\n */\nexport function jsonFormatter(options: JsonFormatterOptions = {}): Formatter {\n const keys = { ...DEFAULT_KEYS, ...options.keys };\n const reserved = Object.values(keys);\n const levelFormat = options.levelFormat ?? 'name';\n const withMessage = options.message ?? true;\n const withTemplate = options.template ?? true;\n const withEventId = options.eventId ?? false;\n const epoch = options.timestampFormat === 'epoch';\n\n const key = (name: string) => `,${JSON.stringify(name)}:`;\n const timestampKey = `{${JSON.stringify(keys.timestamp)}:`;\n const levelFragment = {} as Record<LogLevel, string>;\n for (const level of LEVELS) {\n const value =\n levelFormat === 'number' ? LEVEL_NUMBERS[level] : levelFormat === 'serilog' ? SERILOG_LEVEL_NAMES[level] : levelFormat === 'upper' ? level.toUpperCase() : level;\n levelFragment[level] = `${key(keys.level)}${JSON.stringify(value)}`;\n }\n const messageKey = key(keys.message);\n const templateKey = key(keys.template);\n const eventIdKey = key(keys.eventId);\n const sourceKey = key(keys.source);\n const traceKey = key(keys.traceId);\n const spanKey = key(keys.spanId);\n const errorKey = key(keys.error);\n\n return (event: LogEvent) => {\n let out = timestampKey + (epoch ? String(event.timestamp.getTime()) : `\"${isoTimestamp(event.timestamp)}\"`) + levelFragment[event.level];\n if (withMessage) out += messageKey + JSON.stringify(event.renderMessage({ literal: true }));\n if (withTemplate) {\n let cached = templateJson.get(event.template);\n if (cached === undefined) {\n cached = JSON.stringify(event.messageTemplate);\n templateJson.set(event.template, cached);\n }\n out += templateKey + cached;\n }\n if (withEventId) out += `${eventIdKey}\"${event.eventId}\"`;\n const properties = event.properties;\n const source = properties.SourceContext;\n if (typeof source === 'string') out += sourceKey + JSON.stringify(source);\n if (event.traceId) out += traceKey + JSON.stringify(event.traceId);\n if (event.spanId) out += spanKey + JSON.stringify(event.spanId);\n\n let rest: Record<string, unknown> | undefined;\n let needsCopy = source !== undefined;\n if (!needsCopy) {\n for (let i = 0; i < reserved.length; i++) {\n if (Object.prototype.hasOwnProperty.call(properties, reserved[i])) {\n needsCopy = true;\n break;\n }\n }\n }\n if (needsCopy) {\n rest = {};\n for (const name of Object.keys(properties)) {\n if (name === 'SourceContext') continue;\n rest[reserved.includes(name) ? `${name}_` : name] = properties[name];\n }\n } else {\n rest = properties;\n }\n const propsJson = toJson(rest);\n if (propsJson.length > 2) out += `,${propsJson.slice(1, -1)}`;\n if (event.error) out += errorKey + toJson(event.errorProperties);\n return `${out}}`;\n };\n}\n","/**\n * The development console: a short time, a coloured three-letter level, the\n * source, the message with its values lit, the extra properties dimmed, the\n * error block indented underneath. Colours are ANSI and off when the output\n * is not a terminal (`NO_COLOR` is honoured, `FORCE_COLOR` overrides).\n */\nimport type { LogEvent } from '../event';\nimport type { LogLevel } from '../levels';\nimport { type ValueStyles, renderTemplate, renderValue } from './render';\nimport { formatError, formatLevel } from './text';\nimport { formatDate } from './render';\nimport type { Formatter } from './types';\n\nconst ESC = '\\u001b[';\nconst code = (open: number, close: number) => (text: string) => `${ESC}${open}m${text}${ESC}${close}m`;\n\nexport const ansi = {\n bold: code(1, 22),\n dim: code(2, 22),\n italic: code(3, 23),\n underline: code(4, 24),\n red: code(31, 39),\n green: code(32, 39),\n yellow: code(33, 39),\n blue: code(34, 39),\n magenta: code(35, 39),\n cyan: code(36, 39),\n white: code(37, 39),\n gray: code(90, 39),\n bgRed: code(41, 49),\n};\n\nconst LEVEL_STYLE: Record<LogLevel, (text: string) => string> = {\n verbose: ansi.gray,\n debug: ansi.blue,\n info: ansi.green,\n warn: ansi.yellow,\n error: ansi.red,\n fatal: (text) => ansi.bold(ansi.bgRed(ansi.white(text))),\n};\n\nexport interface PrettyFormatterOptions {\n colors?: boolean;\n /** Timestamp pattern; default `HH:mm:ss.fff`. `false` hides it. */\n timestamp?: string | false;\n utc?: boolean;\n /** Show properties that are not part of the message, as `key=value`. Default true. */\n extras?: boolean;\n /** Show the source context. Default true. */\n source?: boolean;\n}\n\n/** Detects colour support the way most CLIs do. Exported so sinks can share the decision. */\nexport function detectColors(stream?: { isTTY?: boolean }): boolean {\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env;\n if (!env) return false;\n if (env.NO_COLOR !== undefined && env.NO_COLOR !== '') return false;\n if (env.FORCE_COLOR !== undefined && env.FORCE_COLOR !== '0' && env.FORCE_COLOR !== '') return true;\n if (env.TERM === 'dumb') return false;\n return stream?.isTTY === true;\n}\n\nexport function prettyFormatter(options: PrettyFormatterOptions = {}): Formatter {\n const colors = options.colors ?? false;\n const c = colors ? ansi : identityAnsi;\n const styles: ValueStyles | undefined = colors\n ? {\n string: ansi.cyan,\n number: ansi.magenta,\n boolean: ansi.magenta,\n null: ansi.gray,\n name: ansi.white,\n punctuation: ansi.gray,\n missing: ansi.gray,\n }\n : undefined;\n const timestamp = options.timestamp ?? 'HH:mm:ss.fff';\n const showExtras = options.extras ?? true;\n const showSource = options.source ?? true;\n\n return (event: LogEvent) => {\n const parts: string[] = [];\n if (timestamp) parts.push(c.dim(formatDate(event.timestamp, timestamp, options.utc)));\n parts.push(LEVEL_STYLE[event.level] === undefined || !colors ? formatLevel(event.level, 'u3') : LEVEL_STYLE[event.level](formatLevel(event.level, 'u3')));\n const source = showSource ? event.sourceContext : undefined;\n if (source) parts.push(c.dim(`[${source}]`));\n parts.push(renderTemplate(event.template, event.properties, { literal: true, styles }));\n\n if (showExtras) {\n const extras = event.extraProperties();\n const pairs: string[] = [];\n for (const key of Object.keys(extras)) {\n if (key === 'SourceContext') continue;\n pairs.push(`${key}=${renderValue(extras[key], undefined, { literal: true, json: true })}`);\n }\n if (pairs.length) parts.push(c.dim(pairs.join(' ')));\n }\n\n let line = parts.join(' ');\n if (event.error) {\n const block = formatError(event.error, ' ');\n line += `\\n${colors ? ansi.red(block) : block}`;\n }\n return line;\n };\n}\n\nconst identityAnsi: typeof ansi = Object.fromEntries(Object.keys(ansi).map((key) => [key, (text: string) => text])) as typeof ansi;\n","import type { Formatter } from './types';\nimport { clefFormatter } from './clef';\nimport { jsonFormatter } from './json';\nimport { prettyFormatter } from './pretty';\nimport { textFormatter } from './text';\n\nexport type FormatName = 'pretty' | 'json' | 'clef' | 'text';\n\n/** `'json'` / `'clef'` / `'text'` / `'pretty'` by name, or a formatter function as given. */\nexport function resolveFormatter(\n format: FormatName | Formatter | undefined,\n defaults: { outputTemplate?: string; colors?: boolean; utc?: boolean } = {},\n fallback: FormatName = 'json',\n): Formatter {\n if (typeof format === 'function') return format;\n switch (format ?? fallback) {\n case 'pretty':\n return prettyFormatter({ colors: defaults.colors, utc: defaults.utc });\n case 'text':\n return textFormatter({ outputTemplate: defaults.outputTemplate, utc: defaults.utc });\n case 'clef':\n return clefFormatter();\n case 'json':\n default:\n return jsonFormatter();\n }\n}\n\nexport * from './types';\nexport * from './render';\nexport * from './text';\nexport * from './pretty';\nexport * from './json';\nexport * from './clef';\n","import type { LogEvent } from '../event';\nimport type { Formatter } from '../format/types';\nimport { type FormatName, resolveFormatter } from '../format';\nimport { detectColors } from '../format/pretty';\nimport type { Sink, SinkOptions } from './types';\n\n/** The simplest sink: a function per event. */\nexport function callbackSink(fn: (event: LogEvent) => void, options: SinkOptions = {}): Sink {\n return { name: 'callback', emit: fn, ...options };\n}\n\nexport interface MemorySink extends Sink {\n readonly events: LogEvent[];\n clear(): void;\n /** The rendered messages, for assertions. */\n messages(): string[];\n}\n\n/** Keeps events in an array — for tests, and for the \"last N events\" page every ops team ends up wanting. */\nexport function memorySink(options: SinkOptions & { capacity?: number } = {}): MemorySink {\n const events: LogEvent[] = [];\n const capacity = options.capacity ?? Infinity;\n return {\n name: 'memory',\n events,\n restrictedToMinimumLevel: options.restrictedToMinimumLevel,\n audit: options.audit,\n emit(event) {\n events.push(event);\n if (events.length > capacity) events.splice(0, events.length - capacity);\n },\n clear() {\n events.length = 0;\n },\n messages() {\n return events.map((e) => e.renderMessage({ literal: true }));\n },\n };\n}\n\nexport interface StreamLike {\n write(chunk: string): boolean | void;\n isTTY?: boolean;\n once?(event: 'drain', listener: () => void): unknown;\n}\n\nexport interface StreamSinkOptions extends SinkOptions {\n format?: FormatName | Formatter;\n outputTemplate?: string;\n colors?: boolean;\n utc?: boolean;\n}\n\n/** Writes formatted lines to anything with `write(string)` — a Node stream, a socket, a custom transport. */\nexport function streamSink(stream: StreamLike, options: StreamSinkOptions = {}): Sink {\n const formatter = resolveFormatter(options.format, {\n outputTemplate: options.outputTemplate,\n colors: options.colors ?? detectColors(stream),\n utc: options.utc,\n });\n let pendingDrain: Promise<void> | null = null;\n return {\n name: 'stream',\n restrictedToMinimumLevel: options.restrictedToMinimumLevel,\n audit: options.audit,\n emit(event) {\n const ok = stream.write(`${formatter(event)}\\n`);\n if (ok === false && stream.once && !pendingDrain) {\n pendingDrain = new Promise<void>((resolve) => stream.once!('drain', () => resolve())).then(() => {\n pendingDrain = null;\n });\n }\n },\n async flush() {\n if (pendingDrain) await pendingDrain;\n },\n };\n}\n","import type { LogEvent } from '../event';\nimport { type FormatName, resolveFormatter } from '../format';\nimport { detectColors } from '../format/pretty';\nimport type { Formatter } from '../format/types';\nimport { type LogLevel, levelAtLeast, parseLevel } from '../levels';\nimport { type StreamLike, streamSink } from './basic';\nimport type { Sink, SinkOptions } from './types';\n\nexport interface ConsoleSinkOptions extends SinkOptions {\n /**\n * `'pretty'` for people, `'json'` for machines, `'clef'` for Seq, `'text'` for\n * a Serilog output template — or a formatter function. Default: `'pretty'` on\n * a terminal and in browsers, `'json'` otherwise (a pipe, a container, Vercel).\n */\n format?: FormatName | Formatter;\n outputTemplate?: string;\n colors?: boolean;\n utc?: boolean;\n /** Events at or above this level go to stderr (Serilog's `standardErrorFromLevel`). Default: everything to stdout. */\n stderrFrom?: LogLevel | string;\n}\n\ninterface ProcessLike {\n stdout?: StreamLike;\n stderr?: StreamLike;\n env?: Record<string, string | undefined>;\n}\n\nfunction nodeProcess(): ProcessLike | undefined {\n const proc = (globalThis as { process?: ProcessLike }).process;\n return proc && typeof proc.stdout?.write === 'function' ? proc : undefined;\n}\n\n/**\n * stdout / stderr in Node, Bun and Deno. Elsewhere the console: in a real\n * browser the pretty format hands it objects so they stay expandable; on an\n * edge runtime or in a worker (no `document`) the default is JSON lines,\n * which is what the platform's log collector expects to parse.\n */\nexport function consoleSink(options: ConsoleSinkOptions = {}): Sink {\n const proc = nodeProcess();\n if (proc?.stdout) {\n const colors = options.colors ?? detectColors(proc.stdout);\n const format: FormatName | Formatter = options.format ?? (colors || proc.stdout.isTTY ? 'pretty' : 'json');\n const out = streamSink(proc.stdout, { ...options, format, colors });\n if (!options.stderrFrom) return { ...out, name: 'console' };\n const err = streamSink(proc.stderr ?? proc.stdout, { ...options, format, colors: options.colors ?? detectColors(proc.stderr) });\n const threshold = parseLevel(options.stderrFrom);\n return {\n name: 'console',\n restrictedToMinimumLevel: options.restrictedToMinimumLevel,\n audit: options.audit,\n emit(event) {\n (levelAtLeast(event.level, threshold) ? err : out).emit(event);\n },\n async flush() {\n await out.flush?.();\n await err.flush?.();\n },\n };\n }\n return browserConsoleSink(options);\n}\n\nconst BROWSER_METHOD: Record<LogLevel, 'debug' | 'info' | 'warn' | 'error'> = {\n verbose: 'debug',\n debug: 'debug',\n info: 'info',\n warn: 'warn',\n error: 'error',\n fatal: 'error',\n};\n\nfunction browserConsoleSink(options: ConsoleSinkOptions): Sink {\n const isBrowser = typeof (globalThis as { document?: unknown }).document !== 'undefined';\n const format = options.format ?? (isBrowser ? 'pretty' : 'json');\n const formatter = typeof format === 'function' || format !== 'pretty' ? resolveFormatter(format, { outputTemplate: options.outputTemplate, colors: false, utc: options.utc }) : null;\n return {\n name: 'console',\n restrictedToMinimumLevel: options.restrictedToMinimumLevel,\n audit: options.audit,\n emit(event: LogEvent) {\n const method = BROWSER_METHOD[event.level];\n if (formatter) {\n console[method](formatter(event));\n return;\n }\n const extras = event.extraProperties();\n delete extras.SourceContext; // already the prefix\n const args: unknown[] = [`${event.sourceContext ? `[${event.sourceContext}] ` : ''}${event.renderMessage({ literal: true })}`];\n if (Object.keys(extras).length) args.push(extras);\n if (event.error) args.push(event.error);\n console[method](...args);\n },\n };\n}\n","import type { LogEvent } from '../event';\nimport type { LevelOrSwitch } from '../levels';\nimport { selfLog } from '../selflog';\nimport type { Sink } from './types';\n\n/** A sink that only sees events at or above `level` (Serilog's `restrictedToMinimumLevel`, for sinks that do not take the option themselves). */\nexport function restricted(sink: Sink, level: LevelOrSwitch): Sink {\n return { ...sink, emit: (e) => sink.emit(e), restrictedToMinimumLevel: level };\n}\n\n/** Serilog's `WriteTo.Conditional`: events the predicate accepts go to the sink, the rest are skipped. */\nexport function conditional(predicate: (event: LogEvent) => boolean, sink: Sink): Sink {\n return {\n name: sink.name ? `conditional(${sink.name})` : 'conditional',\n restrictedToMinimumLevel: sink.restrictedToMinimumLevel,\n audit: sink.audit,\n emit(event) {\n if (predicate(event)) sink.emit(event);\n },\n flush: sink.flush ? () => sink.flush!() : undefined,\n close: sink.close ? () => sink.close!() : undefined,\n };\n}\n\n/** Serilog's `AuditTo`: a failure in this sink propagates to the logging call instead of being swallowed. */\nexport function audit(sink: Sink): Sink {\n return { ...sink, emit: (e) => sink.emit(e), audit: true };\n}\n\nexport interface MapSinkOptions {\n /** Sinks kept open at once; the least recently used is closed beyond this. Default 100. */\n maxSinks?: number;\n restrictedToMinimumLevel?: LevelOrSwitch;\n}\n\n/**\n * Serilog.Sinks.Map: one sink per value of a key — a file per tenant, a\n * stream per job. `keyOf` reads the key from the event (return `undefined`\n * to skip); `create` builds the sink the first time a key is seen.\n */\nexport function mapSink<K extends string | number>(\n keyOf: (event: LogEvent) => K | undefined,\n create: (key: K) => Sink,\n options: MapSinkOptions = {},\n): Sink {\n const max = options.maxSinks ?? 100;\n const sinks = new Map<K, Sink>();\n const closeQuietly = async (key: K, sink: Sink) => {\n try {\n await sink.close?.();\n } catch (error) {\n selfLog.write(`mapSink: closing sink for ${String(key)} failed`, error);\n }\n };\n return {\n name: 'map',\n restrictedToMinimumLevel: options.restrictedToMinimumLevel,\n emit(event) {\n const key = keyOf(event);\n if (key === undefined) return;\n let sink = sinks.get(key);\n if (sink) {\n // Re-insert to mark it most recently used.\n sinks.delete(key);\n sinks.set(key, sink);\n } else {\n sink = create(key);\n sinks.set(key, sink);\n if (sinks.size > max) {\n const [oldestKey, oldest] = sinks.entries().next().value as [K, Sink];\n sinks.delete(oldestKey);\n void closeQuietly(oldestKey, oldest);\n }\n }\n sink.emit(event);\n },\n async flush() {\n await Promise.all(Array.from(sinks.values(), (s) => s.flush?.()));\n },\n async close() {\n const entries = Array.from(sinks.entries());\n sinks.clear();\n await Promise.all(entries.map(([key, sink]) => closeQuietly(key, sink)));\n },\n };\n}\n","/**\n * The batching core behind every network sink: events queue up, go out in\n * batches on a timer or when the batch fills, retry with backoff on failure,\n * and are dropped — with a selfLog note — rather than grow without bound.\n * `flush()` sends what is queued and waits; `close()` flushes and stops.\n */\nimport type { LogEvent } from '../event';\nimport { selfLog } from '../selflog';\nimport type { Sink, SinkOptions } from './types';\n\nexport interface BatchingOptions extends SinkOptions {\n /** Send when this many events are queued. Default 100. */\n batchSize?: number;\n /** Send at least this often (ms) while events are queued. Default 2000. */\n flushInterval?: number;\n /** Events kept while the network is down; beyond it the oldest are dropped. Default 10 000. */\n maxQueue?: number;\n /** Attempts per batch (first try included). Default 3. */\n retries?: number;\n /** Base delay between attempts (ms), doubled each time. Default 500. */\n retryDelay?: number;\n /** Called when a batch is given up on. */\n onError?: (error: unknown, events: LogEvent[]) => void;\n name?: string;\n}\n\nexport interface BatchingSink extends Sink {\n /** Events waiting to be sent. */\n readonly queued: number;\n flush(): Promise<void>;\n close(): Promise<void>;\n}\n\ntype Timer = ReturnType<typeof setTimeout>;\n\nexport function batchingSink(send: (events: LogEvent[]) => Promise<void>, options: BatchingOptions = {}): BatchingSink {\n const batchSize = options.batchSize ?? 100;\n const flushInterval = options.flushInterval ?? 2000;\n const maxQueue = options.maxQueue ?? 10_000;\n const retries = Math.max(1, options.retries ?? 3);\n const retryDelay = options.retryDelay ?? 500;\n const name = options.name ?? 'batching';\n\n let queue: LogEvent[] = [];\n let timer: Timer | null = null;\n let inFlight: Promise<void> | null = null;\n let closed = false;\n let dropped = 0;\n\n const schedule = () => {\n if (timer || closed) return;\n timer = setTimeout(() => {\n timer = null;\n void drain();\n }, flushInterval);\n (timer as { unref?: () => void }).unref?.();\n };\n\n const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));\n\n async function sendWithRetry(batch: LogEvent[]): Promise<void> {\n let delay = retryDelay;\n for (let attempt = 1; ; attempt++) {\n try {\n await send(batch);\n return;\n } catch (error) {\n if (attempt >= retries) {\n selfLog.write(`${name}: giving up on a batch of ${batch.length} after ${attempt} attempts`, error);\n options.onError?.(error, batch);\n return;\n }\n await sleep(delay);\n delay *= 2;\n }\n }\n }\n\n async function drain(): Promise<void> {\n if (inFlight) return inFlight;\n inFlight = (async () => {\n while (queue.length) {\n const batch = queue.splice(0, batchSize);\n await sendWithRetry(batch);\n }\n })().finally(() => {\n inFlight = null;\n });\n return inFlight;\n }\n\n return {\n name,\n restrictedToMinimumLevel: options.restrictedToMinimumLevel,\n audit: options.audit,\n get queued() {\n return queue.length;\n },\n emit(event) {\n if (closed) return;\n if (queue.length >= maxQueue) {\n queue.shift();\n if (dropped++ % 1000 === 0) selfLog.write(`${name}: queue full (${maxQueue}), dropping oldest events`);\n }\n queue.push(event);\n if (queue.length >= batchSize) void drain();\n else schedule();\n },\n async flush() {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n await drain();\n },\n async close() {\n await this.flush();\n closed = true;\n queue = [];\n },\n };\n}\n","import type { LogEvent } from '../event';\nimport { clefFormatter, CLEF_MEDIA_TYPE } from '../format/clef';\nimport { jsonFormatter } from '../format/json';\nimport type { Formatter } from '../format/types';\nimport { type BatchingOptions, type BatchingSink, batchingSink } from './batching';\n\nexport type FetchLike = (url: string, init: { method: string; headers: Record<string, string>; body: string; signal?: AbortSignal; keepalive?: boolean }) => Promise<{ ok: boolean; status: number; text(): Promise<string> }>;\n\nexport interface HttpSinkOptions extends BatchingOptions {\n url: string;\n headers?: Record<string, string> | (() => Record<string, string>);\n /**\n * How a batch becomes a body: `'ndjson'` (one JSON event per line — Loki,\n * Splunk HEC, Datadog, most collectors), `'array'` (a JSON array), `'clef'`\n * (newline-delimited CLEF, Seq), or your own function.\n */\n body?: 'ndjson' | 'array' | 'clef' | ((events: LogEvent[]) => string);\n /** Formatter for each event in `ndjson` / `array` mode. Default: the JSON formatter. */\n formatter?: Formatter;\n contentType?: string;\n /** Request timeout in ms. Default 10 000. */\n timeout?: number;\n /** Supplied for tests and exotic runtimes; defaults to `globalThis.fetch`. */\n fetch?: FetchLike;\n}\n\n/**\n * POSTs batches of events to any HTTP endpoint. In a browser the request is\n * sent with `keepalive`, and the queue is flushed on `pagehide`, so the last\n * events of a session still leave.\n */\nexport function httpSink(options: HttpSinkOptions): BatchingSink {\n const fetchImpl: FetchLike = options.fetch ?? ((globalThis as { fetch?: FetchLike }).fetch as FetchLike);\n if (!fetchImpl) throw new Error('logit: httpSink needs fetch — pass one in options.fetch');\n const mode = options.body ?? 'ndjson';\n const formatter = options.formatter ?? (mode === 'clef' ? clefFormatter() : jsonFormatter());\n const contentType =\n options.contentType ?? (mode === 'clef' ? CLEF_MEDIA_TYPE : mode === 'array' ? 'application/json' : 'application/x-ndjson');\n const timeout = options.timeout ?? 10_000;\n\n const encode = (events: LogEvent[]): string => {\n if (typeof mode === 'function') return mode(events);\n const lines = events.map(formatter);\n return mode === 'array' ? `[${lines.join(',')}]` : `${lines.join('\\n')}\\n`;\n };\n\n const sink = batchingSink(\n async (events) => {\n const headers = { 'content-type': contentType, ...(typeof options.headers === 'function' ? options.headers() : options.headers) };\n const controller = typeof AbortController === 'function' ? new AbortController() : undefined;\n const timer = controller ? setTimeout(() => controller.abort(), timeout) : undefined;\n (timer as { unref?: () => void } | undefined)?.unref?.();\n try {\n const response = await fetchImpl(options.url, {\n method: 'POST',\n headers,\n body: encode(events),\n signal: controller?.signal,\n keepalive: true,\n });\n if (!response.ok) {\n let detail = '';\n try {\n detail = (await response.text()).slice(0, 500);\n } catch {\n /* ignore */\n }\n throw new Error(`HTTP ${response.status}${detail ? `: ${detail}` : ''}`);\n }\n } finally {\n if (timer) clearTimeout(timer);\n }\n },\n { name: `http(${options.url})`, ...options },\n );\n\n const win = (globalThis as { addEventListener?: (type: string, fn: () => void) => void; document?: unknown }).document\n ? (globalThis as { addEventListener?: (type: string, fn: () => void) => void })\n : undefined;\n win?.addEventListener?.('pagehide', () => {\n void sink.flush();\n });\n\n return sink;\n}\n\nexport interface SeqSinkOptions extends Omit<HttpSinkOptions, 'url' | 'body' | 'formatter' | 'contentType'> {\n /** e.g. `http://localhost:5341` */\n serverUrl: string;\n apiKey?: string;\n}\n\n/** Seq (https://datalust.co/seq): CLEF over HTTP to `/ingest/clef`, with the API key header. */\nexport function seqSink(options: SeqSinkOptions): BatchingSink {\n const { serverUrl, apiKey, headers, ...rest } = options;\n const base = serverUrl.replace(/\\/$/, '');\n return httpSink({\n ...rest,\n url: `${base}/ingest/clef`,\n body: 'clef',\n headers: () => ({\n ...(typeof headers === 'function' ? headers() : headers),\n ...(apiKey ? { 'X-Seq-ApiKey': apiKey } : {}),\n }),\n name: `seq(${base})`,\n });\n}\n","import { type DestructuringOptions, type DestructuringPolicy, byTransforming, captureArguments, captureProperty, resolveDestructuring } from './capture';\nimport { type Enricher, fromLogContext, withProperties, withProperty } from './enrichers';\nimport { LogEvent } from './event';\nimport { type Filter, byExcluding, byIncludingOnly } from './filters';\nimport { type LevelOrSwitch, type LogLevel, LevelSwitch, levelAtLeast, parseLevel, resolveLevel } from './levels';\nimport { selfLog } from './selflog';\nimport { type ConsoleSinkOptions, consoleSink } from './sinks/console';\nimport { type HttpSinkOptions, type SeqSinkOptions, httpSink, seqSink } from './sinks/http';\nimport { type StreamLike, type StreamSinkOptions, streamSink } from './sinks/basic';\nimport type { Sink } from './sinks/types';\nimport { parseTemplate } from './template';\n\nexport interface LoggerOptions {\n /** Default `'info'`, or `LOGIT_LEVEL` from the environment when set. A `LevelSwitch` makes it changeable at runtime. */\n minimumLevel?: LevelOrSwitch;\n /**\n * Per-source levels — Serilog's `MinimumLevel.Override`. Keys are\n * `SourceContext` prefixes on dot boundaries (`'app.db'` covers\n * `app.db.query`); the longest match wins.\n */\n overrides?: Record<string, LevelOrSwitch>;\n /** Where events go (`writeTo`). A `Logger` is a valid sink. */\n sinks?: Sink[];\n /** Serilog's `AuditTo`: sinks whose failures propagate to the caller. */\n auditSinks?: Sink[];\n enrichers?: Enricher[];\n filters?: Filter[];\n destructuring?: Partial<DestructuringOptions>;\n /** Fixed properties on every event — shorthand for `withProperties()`. */\n properties?: Record<string, unknown>;\n /** Read the ambient `LogContext` onto every event. Default true. */\n logContext?: boolean;\n /** Where a non-audit sink's failure is reported. Default: `selfLog`. */\n onSinkError?: (error: unknown, sink: Sink, event: LogEvent) => void;\n}\n\ninterface Override {\n prefix: string;\n level: LevelOrSwitch;\n}\n\ninterface Pipeline {\n minimumLevel: LevelOrSwitch;\n overrides: Override[];\n sinks: Sink[];\n enrichers: Enricher[];\n filters: Filter[];\n destructuring: DestructuringOptions;\n onSinkError?: LoggerOptions['onSinkError'];\n}\n\n/** Loggers read their pipeline through a ref, so `configure()` can swap the global one under every child. */\ninterface PipelineRef {\n current: Pipeline;\n}\n\nfunction envLevel(): LogLevel | undefined {\n const raw = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env?.LOGIT_LEVEL;\n if (!raw) return undefined;\n try {\n return parseLevel(raw);\n } catch (error) {\n selfLog.write(`ignoring LOGIT_LEVEL=\"${raw}\"`, error);\n return undefined;\n }\n}\n\n/** `LOGIT_OVERRIDES=\"next=warn,app.db=debug\"` */\nfunction envOverrides(): Record<string, LogLevel> | undefined {\n const raw = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env?.LOGIT_OVERRIDES;\n if (!raw) return undefined;\n const out: Record<string, LogLevel> = {};\n for (const pair of raw.split(',')) {\n const [source, level] = pair.split('=').map((s) => s.trim());\n if (!source || !level) continue;\n try {\n out[source] = parseLevel(level);\n } catch (error) {\n selfLog.write(`ignoring LOGIT_OVERRIDES entry \"${pair}\"`, error);\n }\n }\n return out;\n}\n\nfunction buildPipeline(options: LoggerOptions): Pipeline {\n const overrides = Object.entries({ ...envOverrides(), ...options.overrides })\n .map(([prefix, level]) => ({ prefix, level: level instanceof LevelSwitch ? level : parseLevel(level) }))\n .sort((a, b) => b.prefix.length - a.prefix.length);\n const enrichers: Enricher[] = [];\n if (options.logContext ?? true) enrichers.push(fromLogContext());\n if (options.properties) enrichers.push(withProperties(options.properties));\n enrichers.push(...(options.enrichers ?? []));\n const sinks = [...(options.sinks ?? []), ...(options.auditSinks ?? []).map((sink) => ({ ...sink, emit: (e: LogEvent) => sink.emit(e), audit: true }))];\n const minimumLevel = options.minimumLevel ?? envLevel() ?? 'info';\n return {\n minimumLevel: minimumLevel instanceof LevelSwitch ? minimumLevel : parseLevel(minimumLevel),\n overrides,\n sinks,\n enrichers,\n filters: [...(options.filters ?? [])],\n destructuring: resolveDestructuring(options.destructuring),\n onSinkError: options.onSinkError,\n };\n}\n\nfunction matchOverride(overrides: Override[], source: string): LevelOrSwitch | undefined {\n for (const o of overrides) {\n if (source === o.prefix || source.startsWith(`${o.prefix}.`)) return o.level;\n }\n return undefined;\n}\n\n/** Escapes braces so a string logged *as* the template renders verbatim. */\nfunction escapeTemplate(text: string): string {\n return text.replace(/{/g, '{{').replace(/}/g, '}}');\n}\n\ntype LogArgs = unknown[];\n\nexport interface LogMethod {\n (template: string, ...args: unknown[]): void;\n (error: Error, template?: string, ...args: unknown[]): void;\n (properties: Record<string, unknown>, template?: string, ...args: unknown[]): void;\n}\n\nexport interface OperationOptions {\n /** Level of the completion event. Default `'info'`. */\n completeLevel?: LogLevel;\n /** Level of the abandonment event. Default `'warn'`. */\n abandonLevel?: LogLevel;\n /** Completions slower than this (ms) log at `warn` instead. */\n warnAfter?: number;\n}\n\n/**\n * A timed operation (SerilogTimings): begin it, do the work, `complete()`\n * or `abandon()` — one event with `Outcome` and `Elapsed`. Disposing an\n * unfinished operation abandons it.\n */\nexport class Operation {\n #logger: Logger;\n #template: string;\n #args: unknown[];\n #options: OperationOptions;\n #start: number;\n #done = false;\n #extra: Record<string, unknown> = {};\n\n constructor(logger: Logger, template: string, args: unknown[], options: OperationOptions = {}) {\n this.#logger = logger;\n this.#template = template;\n this.#args = args;\n this.#options = options;\n this.#start = now();\n }\n\n /** Milliseconds since the operation began. */\n get elapsed(): number {\n return now() - this.#start;\n }\n\n /** Adds a property to the completion event. */\n enrich(name: string, value: unknown, destructure = false): this {\n this.#extra[name] = destructure ? { __destructure: value } : value;\n return this;\n }\n\n complete(): void;\n complete(name: string, value: unknown): void;\n complete(name?: string, value?: unknown): void {\n if (name !== undefined) this.enrich(name, value);\n this.#finish('completed', undefined);\n }\n\n abandon(error?: Error): void {\n this.#finish('abandoned', error);\n }\n\n /** Ends the operation without logging anything. */\n cancel(): void {\n this.#done = true;\n }\n\n [Symbol.dispose](): void {\n if (!this.#done) this.abandon();\n }\n\n #finish(outcome: 'completed' | 'abandoned', error: Error | undefined): void {\n if (this.#done) return;\n this.#done = true;\n const elapsed = this.elapsed;\n let level = outcome === 'completed' ? (this.#options.completeLevel ?? 'info') : (this.#options.abandonLevel ?? 'warn');\n if (outcome === 'completed' && this.#options.warnAfter !== undefined && elapsed > this.#options.warnAfter && levelAtLeast('warn', level)) level = 'warn';\n const props: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(this.#extra)) {\n props[key] = value && typeof value === 'object' && '__destructure' in value ? (value as { __destructure: unknown }).__destructure : value;\n }\n const logger = Object.keys(props).length ? this.#logger.forContext(props) : this.#logger;\n const template = `${this.#template} {Outcome:l} in {Elapsed:0.0} ms`;\n const args = [...this.#args, outcome, elapsed];\n if (error) logger.write(level, error, template, ...args);\n else logger.write(level, template, ...args);\n }\n}\n\nfunction now(): number {\n const perf = (globalThis as { performance?: { now(): number } }).performance;\n return perf ? perf.now() : Date.now();\n}\n\n/**\n * The logger. Immutable: `forContext` / `forSource` return a new logger\n * bound to extra properties, sharing the pipeline. Also a `Sink`, so a\n * logger can be written to by another (sub-loggers).\n */\nexport class Logger implements Sink {\n readonly #ref: PipelineRef;\n readonly #context: Record<string, unknown> | null;\n readonly #source: string | undefined;\n #overrideFor: Pipeline | null = null;\n #override: LevelOrSwitch | undefined;\n\n /** @internal */\n constructor(ref: PipelineRef, context: Record<string, unknown> | null = null, source?: string) {\n this.#ref = ref;\n this.#context = context;\n this.#source = source;\n }\n\n readonly name = 'logger';\n\n /** The `SourceContext` this logger is bound to, if any. */\n get source(): string | undefined {\n return this.#source;\n }\n\n /** The current minimum level for this logger's source. */\n get minimumLevel(): LogLevel {\n return resolveLevel(this.#effectiveMinimum());\n }\n\n #effectiveMinimum(): LevelOrSwitch {\n const pipeline = this.#ref.current;\n if (this.#source === undefined) return pipeline.minimumLevel;\n if (this.#overrideFor !== pipeline) {\n this.#overrideFor = pipeline;\n this.#override = matchOverride(pipeline.overrides, this.#source);\n }\n return this.#override ?? pipeline.minimumLevel;\n }\n\n /** Cheap check before building anything expensive to log. */\n isEnabled(level: LogLevel): boolean {\n return levelAtLeast(level, resolveLevel(this.#effectiveMinimum()));\n }\n\n verbose: LogMethod = (...args: LogArgs) => this.write('verbose', ...args);\n debug: LogMethod = (...args: LogArgs) => this.write('debug', ...args);\n info: LogMethod = (...args: LogArgs) => this.write('info', ...args);\n warn: LogMethod = (...args: LogArgs) => this.write('warn', ...args);\n error: LogMethod = (...args: LogArgs) => this.write('error', ...args);\n fatal: LogMethod = (...args: LogArgs) => this.write('fatal', ...args);\n\n /**\n * Writes an event at `level`. Argument shapes:\n * `(template, ...args)`\n * `(error, template?, ...args)`\n * `(properties, template?, ...args)` — one-off properties on this event\n */\n write(level: LogLevel, ...args: LogArgs): void {\n if (!this.isEnabled(level)) return;\n const pipeline = this.#ref.current;\n let i = 0;\n let error: Error | undefined;\n let extra: Record<string, unknown> | undefined;\n if (args[0] instanceof Error) {\n error = args[0];\n i = 1;\n } else if (args[0] !== null && typeof args[0] === 'object' && !Array.isArray(args[0])) {\n extra = args[0] as Record<string, unknown>;\n i = 1;\n }\n const head = args[i];\n let raw: string;\n if (typeof head === 'string') raw = head;\n else if (head === undefined) raw = error ? escapeTemplate(error.message || error.name) : '';\n else raw = escapeTemplate(String(head));\n const template = parseTemplate(raw);\n const properties: Record<string, unknown> = {};\n if (template.holes.length) captureArguments(template.holes, template.positional, args.slice(i + 1), pipeline.destructuring, properties);\n\n const event = new LogEvent({ level, template, properties, error }, pipeline.destructuring);\n if (extra) for (const key of Object.keys(extra)) event.addPropertyIfAbsent(key, extra[key], true);\n this.#dispatch(event, pipeline);\n }\n\n /** Sink entry point: an event from another logger, re-dispatched through this one's level, context, enrichers, filters and sinks. */\n emit(event: LogEvent): void {\n if (!this.isEnabled(event.level)) return;\n this.#dispatch(event, this.#ref.current);\n }\n\n #dispatch(event: LogEvent, pipeline: Pipeline): void {\n if (this.#context) {\n for (const key of Object.keys(this.#context)) {\n if (!event.hasProperty(key)) event.properties[key] = this.#context[key];\n }\n }\n if (this.#source !== undefined && !event.hasProperty('SourceContext')) event.properties.SourceContext = this.#source;\n for (const enricher of pipeline.enrichers) {\n try {\n enricher(event);\n } catch (error) {\n selfLog.write('an enricher threw', error);\n }\n }\n for (const filter of pipeline.filters) {\n if (!filter(event)) return;\n }\n for (const sink of pipeline.sinks) {\n if (sink.restrictedToMinimumLevel !== undefined && !levelAtLeast(event.level, resolveLevel(sink.restrictedToMinimumLevel))) continue;\n try {\n sink.emit(event);\n } catch (error) {\n if (sink.audit) throw error;\n if (pipeline.onSinkError) pipeline.onSinkError(error, sink, event);\n else selfLog.write(`sink ${sink.name ?? '(anonymous)'} threw`, error);\n }\n }\n }\n\n /** A logger bound to `name = value` (Serilog's `ForContext`), or to several properties at once. */\n forContext(name: string, value: unknown, destructure?: boolean): Logger;\n forContext(properties: Record<string, unknown>, destructure?: boolean): Logger;\n forContext(nameOrProps: string | Record<string, unknown>, valueOrDestructure?: unknown, destructure = false): Logger {\n const options = this.#ref.current.destructuring;\n const context: Record<string, unknown> = { ...this.#context };\n if (typeof nameOrProps === 'string') {\n context[nameOrProps] = captureProperty(nameOrProps, valueOrDestructure, destructure ? '@' : undefined, options);\n } else {\n const d = valueOrDestructure === true;\n for (const key of Object.keys(nameOrProps)) context[key] = captureProperty(key, nameOrProps[key], d ? '@' : undefined, options);\n }\n return new Logger(this.#ref, context, this.#source);\n }\n\n /** A logger whose events carry `SourceContext` — the name level overrides match on. Dotted names nest: `'app.db'`. */\n forSource(source: string): Logger {\n return new Logger(this.#ref, this.#context, source);\n }\n\n /** pino / bunyan spelling of `forContext`. */\n child(properties: Record<string, unknown>, destructure = false): Logger {\n return this.forContext(properties, destructure);\n }\n\n /** Starts a timed operation; `complete()` / `abandon()` log one event with `Outcome` and `Elapsed`. */\n beginOperation(template: string, ...args: unknown[]): Operation {\n return new Operation(this, template, args);\n }\n\n /** `beginOperation` with options (levels, `warnAfter`). */\n operation(options: OperationOptions, template: string, ...args: unknown[]): Operation {\n return new Operation(this, template, args, options);\n }\n\n /**\n * Runs `fn` as a timed operation: completes when it returns (or its\n * promise resolves), abandons with the error when it throws (or rejects),\n * then rethrows.\n */\n timed<R>(template: string, fn: (operation: Operation) => R, ...args: unknown[]): R {\n const op = new Operation(this, template, args);\n let result: R;\n try {\n result = fn(op);\n } catch (error) {\n op.abandon(error instanceof Error ? error : undefined);\n throw error;\n }\n if (result instanceof Promise) {\n return result.then(\n (value) => {\n op.complete();\n return value;\n },\n (error) => {\n op.abandon(error instanceof Error ? error : undefined);\n throw error;\n },\n ) as R;\n }\n op.complete();\n return result;\n }\n\n /** Waits for every sink that buffers to send what it holds. */\n async flush(): Promise<void> {\n await Promise.all(this.#ref.current.sinks.map((sink) => safely(() => sink.flush?.(), sink, 'flush')));\n }\n\n /** Flushes, then closes the sinks — call once, before the process exits (Serilog's `CloseAndFlush`). */\n async close(): Promise<void> {\n await this.flush();\n await Promise.all(this.#ref.current.sinks.map((sink) => safely(() => sink.close?.(), sink, 'close')));\n }\n\n /** The sinks this logger writes to. */\n get sinks(): readonly Sink[] {\n return this.#ref.current.sinks;\n }\n\n /** @internal — swaps the pipeline for every logger sharing this ref. */\n _replace(options: LoggerOptions): void {\n this.#ref.current = buildPipeline(options);\n }\n}\n\nasync function safely(fn: () => Promise<void> | void, sink: Sink, what: string): Promise<void> {\n try {\n await fn();\n } catch (error) {\n if (sink.audit) throw error;\n selfLog.write(`sink ${sink.name ?? '(anonymous)'} failed to ${what}`, error);\n }\n}\n\n/** Creates an independent logger. With no options: `info` and above, to the console (pretty on a terminal, JSON elsewhere). */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const withDefaults = options.sinks || options.auditSinks ? options : { ...options, sinks: [consoleSink()] };\n return new Logger({ current: buildPipeline(withDefaults) });\n}\n\n/**\n * Serilog's fluent `LoggerConfiguration`, for muscle memory:\n *\n * const log = new LoggerConfiguration()\n * .minimumLevel.debug()\n * .minimumLevel.override('next', 'warn')\n * .enrich.withProperty('Application', 'shop')\n * .writeTo.console()\n * .createLogger();\n */\nexport class LoggerConfiguration {\n #options: LoggerOptions & { sinks: Sink[]; auditSinks: Sink[]; enrichers: Enricher[]; filters: Filter[]; overrides: Record<string, LevelOrSwitch>; destructuring: Partial<DestructuringOptions> & { policies: DestructuringPolicy[]; redact: string[] } } = {\n sinks: [],\n auditSinks: [],\n enrichers: [],\n filters: [],\n overrides: {},\n destructuring: { policies: [], redact: [] },\n };\n\n readonly minimumLevel = {\n verbose: () => this.minimumLevel.is('verbose'),\n debug: () => this.minimumLevel.is('debug'),\n info: () => this.minimumLevel.is('info'),\n information: () => this.minimumLevel.is('info'),\n warn: () => this.minimumLevel.is('warn'),\n warning: () => this.minimumLevel.is('warn'),\n error: () => this.minimumLevel.is('error'),\n fatal: () => this.minimumLevel.is('fatal'),\n is: (level: LevelOrSwitch): LoggerConfiguration => {\n this.#options.minimumLevel = level;\n return this;\n },\n controlledBy: (levelSwitch: LevelSwitch): LoggerConfiguration => {\n this.#options.minimumLevel = levelSwitch;\n return this;\n },\n override: (source: string, level: LevelOrSwitch): LoggerConfiguration => {\n this.#options.overrides[source] = level;\n return this;\n },\n };\n\n readonly writeTo = {\n sink: (...sinks: Sink[]): LoggerConfiguration => {\n this.#options.sinks.push(...sinks);\n return this;\n },\n console: (options?: ConsoleSinkOptions): LoggerConfiguration => this.writeTo.sink(consoleSink(options)),\n stream: (stream: StreamLike, options?: StreamSinkOptions): LoggerConfiguration => this.writeTo.sink(streamSink(stream, options)),\n http: (options: HttpSinkOptions): LoggerConfiguration => this.writeTo.sink(httpSink(options)),\n seq: (options: SeqSinkOptions): LoggerConfiguration => this.writeTo.sink(seqSink(options)),\n /** A sub-logger with its own filters, enrichers and sinks (Serilog's `WriteTo.Logger`). */\n logger: (configure: (configuration: LoggerConfiguration) => void, restrictedToMinimumLevel?: LevelOrSwitch): LoggerConfiguration => {\n const child = new LoggerConfiguration();\n configure(child);\n const sink = child.createLogger();\n return this.writeTo.sink(restrictedToMinimumLevel ? { ...sink, emit: (e) => sink.emit(e), restrictedToMinimumLevel, flush: () => sink.flush(), close: () => sink.close() } : sink);\n },\n };\n\n readonly auditTo = {\n sink: (...sinks: Sink[]): LoggerConfiguration => {\n this.#options.auditSinks.push(...sinks);\n return this;\n },\n };\n\n readonly enrich = {\n with: (...enrichers: Enricher[]): LoggerConfiguration => {\n this.#options.enrichers.push(...enrichers);\n return this;\n },\n fromLogContext: (): LoggerConfiguration => {\n this.#options.logContext = true;\n return this;\n },\n withProperty: (name: string, value: unknown, destructure = false): LoggerConfiguration => this.enrich.with(withProperty(name, value, destructure)),\n withProperties: (properties: Record<string, unknown>, destructure = false): LoggerConfiguration => this.enrich.with(withProperties(properties, destructure)),\n };\n\n readonly filter = {\n with: (...filters: Filter[]): LoggerConfiguration => {\n this.#options.filters.push(...filters);\n return this;\n },\n byExcluding: (predicate: (event: LogEvent) => boolean): LoggerConfiguration => this.filter.with(byExcluding(predicate)),\n byIncludingOnly: (predicate: (event: LogEvent) => boolean): LoggerConfiguration => this.filter.with(byIncludingOnly(predicate)),\n };\n\n readonly destructure = {\n toMaximumDepth: (depth: number): LoggerConfiguration => {\n this.#options.destructuring.maxDepth = depth;\n return this;\n },\n toMaximumStringLength: (length: number): LoggerConfiguration => {\n this.#options.destructuring.maxStringLength = length;\n return this;\n },\n toMaximumCollectionCount: (count: number): LoggerConfiguration => {\n this.#options.destructuring.maxCollectionCount = count;\n return this;\n },\n with: (...policies: DestructuringPolicy[]): LoggerConfiguration => {\n this.#options.destructuring.policies.push(...policies);\n return this;\n },\n byTransforming: <T extends object>(type: abstract new (...args: never[]) => T, transform: (value: T) => unknown): LoggerConfiguration =>\n this.destructure.with(byTransforming(type, transform)),\n /** Keys (or dotted paths) whose values are replaced by `[Redacted]`. */\n redact: (...keys: string[]): LoggerConfiguration => {\n this.#options.destructuring.redact.push(...keys);\n return this;\n },\n };\n\n readonly readFrom = {\n /** `LOGIT_LEVEL` and `LOGIT_OVERRIDES` from the environment (they are read by default; this makes it explicit). */\n env: (): LoggerConfiguration => this,\n };\n\n /** Disables the automatic `LogContext` enricher. */\n withoutLogContext(): LoggerConfiguration {\n this.#options.logContext = false;\n return this;\n }\n\n /** The options as a plain object, for `createLogger()` or `configure()`. */\n toOptions(): LoggerOptions {\n return { ...this.#options };\n }\n\n createLogger(): Logger {\n return createLogger(this.toOptions());\n }\n}\n\n// ─── The global logger — Serilog's static `Log` ───────────────────────────\n\nconst globalRef: PipelineRef = { current: buildPipeline({ sinks: [consoleSink()] }) };\n\n/**\n * The default logger: `import { log } from '@unhingged/logit'` and go.\n * Until `configure()` is called it writes `info` and above to the console —\n * pretty on a terminal, JSON in a container or on Vercel. Every logger made\n * from it (`log.forSource(...)`) follows a later `configure()`.\n */\nexport const log: Logger = new Logger(globalRef);\n\n/** Reconfigures the global `log` (and every logger derived from it) in place. Returns it. */\nexport function configure(options: LoggerOptions | LoggerConfiguration = {}): Logger {\n const opts = options instanceof LoggerConfiguration ? options.toOptions() : options;\n log._replace(opts.sinks || opts.auditSinks ? opts : { ...opts, sinks: [consoleSink()] });\n return log;\n}\n\n/** Flushes and closes the global logger's sinks — Serilog's `Log.CloseAndFlush()`. */\nexport function closeAndFlush(): Promise<void> {\n return log.close();\n}\n"]}
@@ -0,0 +1,72 @@
1
+ import {
2
+ LogContext
3
+ } from "./chunk-GW7WQELF.js";
4
+
5
+ // src/request.ts
6
+ var REQUEST_COMPLETION_TEMPLATE = "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms";
7
+ function defaultGetLevel(status, _elapsed, error) {
8
+ return error !== void 0 || status >= 500 ? "error" : "info";
9
+ }
10
+ function readHeader(headers, name) {
11
+ if (!headers) return void 0;
12
+ if (typeof headers.get === "function") {
13
+ const value2 = headers.get(name);
14
+ return value2 ?? void 0;
15
+ }
16
+ const value = headers[name] ?? headers[name.toLowerCase()];
17
+ return Array.isArray(value) ? value[0] : value;
18
+ }
19
+ function resolveRequestId(request, options) {
20
+ if (request.requestId) return request.requestId;
21
+ const names = options.requestIdHeader === void 0 ? ["x-request-id", "x-vercel-id"] : [].concat(options.requestIdHeader);
22
+ for (const name of names) {
23
+ const value = readHeader(request.headers, name);
24
+ if (value) return value;
25
+ }
26
+ if (options.generateRequestId) return options.generateRequestId();
27
+ const c = globalThis.crypto;
28
+ return c?.randomUUID ? c.randomUUID() : Math.random().toString(36).slice(2, 12);
29
+ }
30
+ function now() {
31
+ const perf = globalThis.performance;
32
+ return perf ? perf.now() : Date.now();
33
+ }
34
+ function runRequestScope(request, options, logger, fn) {
35
+ const requestId = resolveRequestId(request, options);
36
+ const started = now();
37
+ const source = options.source ?? "http";
38
+ const getLevel = options.getLevel ?? defaultGetLevel;
39
+ const template = options.messageTemplate ?? REQUEST_COMPLETION_TEMPLATE;
40
+ return LogContext.runScope({ RequestId: requestId, RequestMethod: request.method, RequestPath: request.path }, (diagnostics) => {
41
+ let completed = false;
42
+ const scope = {
43
+ requestId,
44
+ logger: logger.forSource(source),
45
+ complete(status, error) {
46
+ if (completed) return;
47
+ completed = true;
48
+ const elapsed = now() - started;
49
+ const set = (name, value) => diagnostics.set(name, value);
50
+ try {
51
+ options.enrich?.(set, request, { status });
52
+ } catch (e) {
53
+ if (e instanceof Error) scope.logger.warn(e, "request logging enricher threw");
54
+ else scope.logger.warn("request logging enricher threw: {Reason}", String(e));
55
+ }
56
+ const extra = { RequestId: requestId };
57
+ for (const [name, value] of diagnostics) extra[name] = value;
58
+ const target = scope.logger.forContext(extra, true);
59
+ const level = getLevel(status, elapsed, error);
60
+ if (error instanceof Error) target.write(level, error, template, request.method, request.path, status, elapsed);
61
+ else target.write(level, template, request.method, request.path, status, elapsed);
62
+ }
63
+ };
64
+ return fn(scope);
65
+ });
66
+ }
67
+
68
+ export {
69
+ REQUEST_COMPLETION_TEMPLATE,
70
+ runRequestScope
71
+ };
72
+ //# sourceMappingURL=chunk-7J27DQIR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/request.ts"],"sourcesContent":["/**\n * Request-completion logging shared by the Next.js and Express adapters —\n * Serilog.AspNetCore's `UseSerilogRequestLogging`: one event per request,\n * `\"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms\"`,\n * at `error` when it failed or returned 5xx, `info` otherwise, carrying\n * whatever the handler put in the diagnostic context.\n */\nimport { LogContext } from './context';\nimport type { LogLevel } from './levels';\nimport type { Logger } from './logger';\n\nexport const REQUEST_COMPLETION_TEMPLATE = 'HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms';\n\nexport interface RequestInfo {\n method: string;\n path: string;\n /** Full URL or path + query, used for the log only when `includeQuery`. */\n url?: string;\n requestId?: string;\n headers?: { get(name: string): string | null | undefined } | Record<string, string | string[] | undefined>;\n}\n\nexport interface RequestLoggingOptions {\n logger?: Logger;\n /** The completion message. Default `REQUEST_COMPLETION_TEMPLATE`. */\n messageTemplate?: string;\n /** Picks the level — the default is `error` for an exception or a 5xx, `info` otherwise. */\n getLevel?: (status: number, elapsedMs: number, error: unknown) => LogLevel;\n /** Adds properties to the completion event (Serilog's `EnrichDiagnosticContext`). */\n enrich?: (set: (name: string, value: unknown) => void, request: RequestInfo, response: { status: number }) => void;\n /** Requests to skip entirely — health checks, static assets. */\n ignore?: (request: RequestInfo) => boolean;\n /** Header to read a request id from (set by load balancers; Vercel sends `x-vercel-id`). Default `x-request-id`, then `x-vercel-id`. */\n requestIdHeader?: string | string[];\n /** Generate an id when the request has none. Default: `crypto.randomUUID()`. */\n generateRequestId?: () => string;\n /** `SourceContext` for the completion event. Default `'http'`. */\n source?: string;\n}\n\nexport function defaultGetLevel(status: number, _elapsed: number, error: unknown): LogLevel {\n return error !== undefined || status >= 500 ? 'error' : 'info';\n}\n\nfunction readHeader(headers: RequestInfo['headers'], name: string): string | undefined {\n if (!headers) return undefined;\n if (typeof (headers as { get?: unknown }).get === 'function') {\n const value = (headers as { get(name: string): string | null | undefined }).get(name);\n return value ?? undefined;\n }\n const value = (headers as Record<string, string | string[] | undefined>)[name] ?? (headers as Record<string, string | string[] | undefined>)[name.toLowerCase()];\n return Array.isArray(value) ? value[0] : value;\n}\n\nexport function resolveRequestId(request: RequestInfo, options: RequestLoggingOptions): string {\n if (request.requestId) return request.requestId;\n const names = options.requestIdHeader === undefined ? ['x-request-id', 'x-vercel-id'] : ([] as string[]).concat(options.requestIdHeader);\n for (const name of names) {\n const value = readHeader(request.headers, name);\n if (value) return value;\n }\n if (options.generateRequestId) return options.generateRequestId();\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n return c?.randomUUID ? c.randomUUID() : Math.random().toString(36).slice(2, 12);\n}\n\nexport interface RequestScope {\n requestId: string;\n logger: Logger;\n /** Call once with the outcome; logs the completion event. */\n complete(status: number, error?: unknown): void;\n}\n\nfunction now(): number {\n const perf = (globalThis as { performance?: { now(): number } }).performance;\n return perf ? perf.now() : Date.now();\n}\n\n/**\n * Runs `fn` inside a request scope: `RequestId`, `RequestPath` and\n * `RequestMethod` are ambient for everything logged within, the diagnostic\n * context collects completion properties, and `scope.complete()` writes the\n * one completion event.\n */\nexport function runRequestScope<R>(request: RequestInfo, options: RequestLoggingOptions, logger: Logger, fn: (scope: RequestScope) => R): R {\n const requestId = resolveRequestId(request, options);\n const started = now();\n const source = options.source ?? 'http';\n const getLevel = options.getLevel ?? defaultGetLevel;\n const template = options.messageTemplate ?? REQUEST_COMPLETION_TEMPLATE;\n\n return LogContext.runScope({ RequestId: requestId, RequestMethod: request.method, RequestPath: request.path }, (diagnostics) => {\n let completed = false;\n const scope: RequestScope = {\n requestId,\n logger: logger.forSource(source),\n complete(status, error) {\n if (completed) return;\n completed = true;\n const elapsed = now() - started;\n const set = (name: string, value: unknown) => diagnostics.set(name, value);\n try {\n options.enrich?.(set, request, { status });\n } catch (e) {\n if (e instanceof Error) scope.logger.warn(e, 'request logging enricher threw');\n else scope.logger.warn('request logging enricher threw: {Reason}', String(e));\n }\n // Bound explicitly: `res.on('finish')` can fire outside the request's async context.\n const extra: Record<string, unknown> = { RequestId: requestId };\n for (const [name, value] of diagnostics) extra[name] = value;\n const target = scope.logger.forContext(extra, true);\n const level = getLevel(status, elapsed, error);\n if (error instanceof Error) target.write(level, error, template, request.method, request.path, status, elapsed);\n else target.write(level, template, request.method, request.path, status, elapsed);\n },\n };\n return fn(scope);\n });\n}\n"],"mappings":";;;;;AAWO,IAAM,8BAA8B;AA6BpC,SAAS,gBAAgB,QAAgB,UAAkB,OAA0B;AAC1F,SAAO,UAAU,UAAa,UAAU,MAAM,UAAU;AAC1D;AAEA,SAAS,WAAW,SAAiC,MAAkC;AACrF,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,OAAQ,QAA8B,QAAQ,YAAY;AAC5D,UAAMA,SAAS,QAA6D,IAAI,IAAI;AACpF,WAAOA,UAAS;AAAA,EAClB;AACA,QAAM,QAAS,QAA0D,IAAI,KAAM,QAA0D,KAAK,YAAY,CAAC;AAC/J,SAAO,MAAM,QAAQ,KAAK,IAAI,MAAM,CAAC,IAAI;AAC3C;AAEO,SAAS,iBAAiB,SAAsB,SAAwC;AAC7F,MAAI,QAAQ,UAAW,QAAO,QAAQ;AACtC,QAAM,QAAQ,QAAQ,oBAAoB,SAAY,CAAC,gBAAgB,aAAa,IAAK,CAAC,EAAe,OAAO,QAAQ,eAAe;AACvI,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,WAAW,QAAQ,SAAS,IAAI;AAC9C,QAAI,MAAO,QAAO;AAAA,EACpB;AACA,MAAI,QAAQ,kBAAmB,QAAO,QAAQ,kBAAkB;AAChE,QAAM,IAAK,WAA0D;AACrE,SAAO,GAAG,aAAa,EAAE,WAAW,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE;AAChF;AASA,SAAS,MAAc;AACrB,QAAM,OAAQ,WAAmD;AACjE,SAAO,OAAO,KAAK,IAAI,IAAI,KAAK,IAAI;AACtC;AAQO,SAAS,gBAAmB,SAAsB,SAAgC,QAAgB,IAAmC;AAC1I,QAAM,YAAY,iBAAiB,SAAS,OAAO;AACnD,QAAM,UAAU,IAAI;AACpB,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,WAAW,QAAQ,mBAAmB;AAE5C,SAAO,WAAW,SAAS,EAAE,WAAW,WAAW,eAAe,QAAQ,QAAQ,aAAa,QAAQ,KAAK,GAAG,CAAC,gBAAgB;AAC9H,QAAI,YAAY;AAChB,UAAM,QAAsB;AAAA,MAC1B;AAAA,MACA,QAAQ,OAAO,UAAU,MAAM;AAAA,MAC/B,SAAS,QAAQ,OAAO;AACtB,YAAI,UAAW;AACf,oBAAY;AACZ,cAAM,UAAU,IAAI,IAAI;AACxB,cAAM,MAAM,CAAC,MAAc,UAAmB,YAAY,IAAI,MAAM,KAAK;AACzE,YAAI;AACF,kBAAQ,SAAS,KAAK,SAAS,EAAE,OAAO,CAAC;AAAA,QAC3C,SAAS,GAAG;AACV,cAAI,aAAa,MAAO,OAAM,OAAO,KAAK,GAAG,gCAAgC;AAAA,cACxE,OAAM,OAAO,KAAK,4CAA4C,OAAO,CAAC,CAAC;AAAA,QAC9E;AAEA,cAAM,QAAiC,EAAE,WAAW,UAAU;AAC9D,mBAAW,CAAC,MAAM,KAAK,KAAK,YAAa,OAAM,IAAI,IAAI;AACvD,cAAM,SAAS,MAAM,OAAO,WAAW,OAAO,IAAI;AAClD,cAAM,QAAQ,SAAS,QAAQ,SAAS,KAAK;AAC7C,YAAI,iBAAiB,MAAO,QAAO,MAAM,OAAO,OAAO,UAAU,QAAQ,QAAQ,QAAQ,MAAM,QAAQ,OAAO;AAAA,YACzG,QAAO,MAAM,OAAO,UAAU,QAAQ,QAAQ,QAAQ,MAAM,QAAQ,OAAO;AAAA,MAClF;AAAA,IACF;AACA,WAAO,GAAG,KAAK;AAAA,EACjB,CAAC;AACH;","names":["value"]}