@vielzeug/rune 26.10.0 → 26.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/_prototype.cjs.map +1 -1
- package/dist/_prototype.js.map +1 -1
- package/dist/console.cjs.map +1 -1
- package/dist/console.d.ts +4 -4
- package/dist/console.js.map +1 -1
- package/dist/lazy.cjs.map +1 -1
- package/dist/lazy.d.ts +1 -1
- package/dist/lazy.d.ts.map +1 -1
- package/dist/lazy.js.map +1 -1
- package/dist/logger.cjs.map +1 -1
- package/dist/logger.d.ts +2 -2
- package/dist/logger.js.map +1 -1
- package/dist/rune.cjs.map +1 -1
- package/dist/rune.iife.js.map +1 -1
- package/dist/rune.js.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.ts +10 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,4 +44,4 @@ console.log(users);
|
|
|
44
44
|
|
|
45
45
|
## License
|
|
46
46
|
|
|
47
|
-
MIT © [Helmuth Saatkamp](https://github.com/helmuthdu)
|
|
47
|
+
MIT © [Helmuth Saatkamp](https://github.com/helmuthdu): part of the [Vielzeug](https://github.com/helmuthdu/vielzeug) monorepo.
|
package/dist/_prototype.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_prototype.cjs","names":[],"sources":["../src/_prototype.ts"],"sourcesContent":["/**\n * Property names that must never be used as a bracket-assignment key on a plain object literal
|
|
1
|
+
{"version":3,"file":"_prototype.cjs","names":[],"sources":["../src/_prototype.ts"],"sourcesContent":["/**\n * Property names that must never be used as a bracket-assignment key on a plain object literal :\n * `obj[key] = value` for `key === '__proto__'` invokes `Object.prototype`'s `__proto__` accessor\n * and reassigns `obj`'s own prototype instead of setting an own property. `constructor` and\n * `prototype` are excluded defensively for the same class of risk.\n *\n * Used when rebuilding a caller-supplied `Bindings` object key-by-key (`logger.ts`'s\n * `serializeErrors()`, `transports.ts`'s `redactObject()`): bindings/context ultimately come\n * from application code, but nothing prevents an app from passing through attacker-controlled\n * data (e.g. `log.info(JSON.parse(untrustedInput))`).\n *\n * @internal\n */\nconst UNSAFE_OBJECT_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** @internal */\nexport function isUnsafeObjectKey(key: string): boolean {\n return UNSAFE_OBJECT_KEYS.has(key);\n}\n"],"mappings":"AAaA,IAAM,EAAqB,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAG5E,SAAgB,kBAAkB,EAAsB,CACtD,OAAO,EAAmB,IAAI,CAAG,CACnC"}
|
package/dist/_prototype.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_prototype.js","names":[],"sources":["../src/_prototype.ts"],"sourcesContent":["/**\n * Property names that must never be used as a bracket-assignment key on a plain object literal
|
|
1
|
+
{"version":3,"file":"_prototype.js","names":[],"sources":["../src/_prototype.ts"],"sourcesContent":["/**\n * Property names that must never be used as a bracket-assignment key on a plain object literal :\n * `obj[key] = value` for `key === '__proto__'` invokes `Object.prototype`'s `__proto__` accessor\n * and reassigns `obj`'s own prototype instead of setting an own property. `constructor` and\n * `prototype` are excluded defensively for the same class of risk.\n *\n * Used when rebuilding a caller-supplied `Bindings` object key-by-key (`logger.ts`'s\n * `serializeErrors()`, `transports.ts`'s `redactObject()`): bindings/context ultimately come\n * from application code, but nothing prevents an app from passing through attacker-controlled\n * data (e.g. `log.info(JSON.parse(untrustedInput))`).\n *\n * @internal\n */\nconst UNSAFE_OBJECT_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** @internal */\nexport function isUnsafeObjectKey(key: string): boolean {\n return UNSAFE_OBJECT_KEYS.has(key);\n}\n"],"mappings":"AAaA,IAAM,EAAqB,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAG5E,SAAgB,kBAAkB,EAAsB,CACtD,OAAO,EAAmB,IAAI,CAAG,CACnC"}
|
package/dist/console.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"console.cjs","names":[],"sources":["../src/console.ts"],"sourcesContent":["import type { Bindings, LogEntry, LogLevel, LogType, Transport } from './types';\n\nimport { isLevelEnabled } from './types';\n\n/* ─── Console theme types ─── */\n\n/**\n * Per-level style definition for the console transport.\n * All fields are optional when providing a level override — unspecified fields fall back to the default theme.\n */\nexport type ConsoleThemeEntry = {\n badge: string;\n bg: string;\n border: string;\n color: string;\n};\n\n/**\n * Partial theme overrides merged on top of the default theme.\n * Each level entry is also partial — only specify the fields you want to change.\n *\n * @example\n * consoleTransport({ theme: { error: { badge: '✖' } } })\n */\nexport type ConsoleTheme = Partial<Record<LogType | 'group' | 'ns', Partial<ConsoleThemeEntry>>>;\n\n/**\n * Fully-resolved console theme where every level and every field is populated.\n */\nexport type ResolvedTheme = Record<LogType | 'group' | 'ns', ConsoleThemeEntry>;\n\n/* ─── ConsoleTransportOptions ─── */\n\nexport type ConsoleTransportOptions = {\n /**\n * Enable ANSI 24-bit color output in Node.js.\n * Default: true when process.stdout.isTTY is true, false otherwise.\n */\n ansi?: boolean;\n /**\n * Object serialization format for Node.js output.\n * - 'json' — JSON.stringify (machine-readable, fails on circular refs)\n * - 'raw' — pass the object directly to the console method (default)\n * Default: 'raw'.\n */\n format?: 'json' | 'raw';\n /**\n * Custom object inspector function. When provided, the `data` object is\n * passed through this function before being written to the console.\n */\n inspectFn?: (value: unknown) => string;\n /** Minimum level to output. Default: 'debug'. */\n level?: LogLevel;\n /** Partial theme overrides merged on top of the default theme. */\n theme?: ConsoleTheme;\n /** Whether to include timestamp in console output. Default: true. */\n timestamp?: boolean;\n};\n\n/* ─── Payload builder ─── */\n\nfunction buildPayload(\n data: Readonly<Bindings>,\n message: string | undefined,\n inspectFn: ((v: unknown) => string) | undefined,\n): unknown[] {\n const hasData = Object.keys(data).length > 0;\n const formatted: unknown = inspectFn && hasData ? inspectFn(data) : hasData ? data : undefined;\n\n if (formatted !== undefined && message !== undefined) return [message, formatted];\n\n if (formatted !== undefined) return [formatted];\n\n if (message !== undefined) return [message];\n\n return [];\n}\n\n/* ─── Console theme ─── */\n\nexport const DEFAULT_THEME: ResolvedTheme = {\n debug: { badge: '🅳', bg: '#616161', border: '#424242', color: '#e0e0e0' },\n error: { badge: '🅴', bg: '#d32f2f', border: '#c62828', color: '#fff' },\n fatal: { badge: '🅵', bg: '#4a148c', border: '#38006b', color: '#fff' },\n group: { badge: '🅶', bg: '#546e7a', border: '#455a64', color: '#fff' },\n info: { badge: '🅸', bg: '#1976d2', border: '#1565c0', color: '#fff' },\n ns: { badge: '', bg: '#424242', border: '#212121', color: '#fff' },\n warn: { badge: '🆆', bg: '#ffb300', border: '#ffa000', color: '#212121' },\n};\n\nconst NS_STYLE = 'border-radius: 8px; font: italic small-caps bold 12px; font-weight: lighter; padding: 0 4px;';\n\nconst LOG_METHOD: Record<LogType, 'error' | 'info' | 'log' | 'warn'> = {\n debug: 'log',\n error: 'error',\n fatal: 'error',\n info: 'info',\n warn: 'warn',\n};\n\n/** Deep-merges per-level overrides onto the default theme. Only specified fields within each level entry are replaced. */\nexport function resolveTheme(override: ConsoleTheme | undefined): ResolvedTheme {\n if (!override) return DEFAULT_THEME;\n\n const result: ResolvedTheme = { ...DEFAULT_THEME };\n\n for (const key of Object.keys(override) as Array<LogType | 'group' | 'ns'>) {\n const entry = override[key];\n\n if (entry) result[key] = { ...DEFAULT_THEME[key], ...entry };\n }\n\n return result;\n}\n\n/* ─── ANSI helpers (Node) ─── */\n\nfunction hexToRgb(hex: string): [number, number, number] {\n return [parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16)];\n}\n\nfunction ansiColor(hex: string, text: string): string {\n const [r, g, b] = hexToRgb(hex);\n\n return `\\x1b[38;2;${r};${g};${b}m${text}\\x1b[0m`;\n}\n\nfunction ansiMuted(text: string): string {\n return `\\x1b[90m${text}\\x1b[0m`;\n}\n\nfunction supportsAnsi(): boolean {\n if (typeof window !== 'undefined') return false;\n\n return (\n (globalThis as Record<string, unknown> & { process?: { stdout?: { isTTY?: boolean } } }).process?.stdout?.isTTY ===\n true\n );\n}\n\nfunction badgeStyle(entry: ConsoleThemeEntry, extra = ''): string {\n return `background: ${entry.bg}; color: ${entry.color}; border: 1px solid ${entry.border}; border-radius: 4px; padding: 0 1px${extra}`;\n}\n\nfunction escapeConsoleFormat(s: string): string {\n return s.replace(/%/g, '%%');\n}\n\n/**\n * Builds the Node console prefix string, passed as the first argument to `console.log()`/etc.\n * alongside the payload. `namespace` is escaped because Node's `console.*` methods run the first\n * string argument through `util.format` — an unescaped `%s`/`%d`/`%o`/etc. in a caller-controlled\n * namespace would consume and hide the actual payload arguments that follow (log forging).\n */\nfunction buildNodePrefix(\n theme: ResolvedTheme,\n type: LogType,\n namespace: string,\n timestamp: string,\n useAnsi: boolean,\n): string {\n const t = theme[type];\n const safeBadge = escapeConsoleFormat(t.badge);\n const badgeText = useAnsi ? ansiColor(t.bg, safeBadge) : safeBadge;\n const meta = [badgeText];\n\n if (namespace) {\n const safeNamespace = escapeConsoleFormat(namespace);\n\n meta.push(useAnsi ? ansiMuted(`[${safeNamespace}]`) : `[${safeNamespace}]`);\n }\n\n if (timestamp) meta.push(useAnsi ? ansiMuted(timestamp) : timestamp);\n\n return `${meta.join(' | ')} |`;\n}\n\nfunction buildBrowserPrefix(\n theme: ResolvedTheme,\n type: LogType,\n namespace: string,\n timestamp: string,\n): { fmt: string; parts: string[] } {\n let fmt = `%c${escapeConsoleFormat(theme[type].badge)}%c`;\n const parts: string[] = [badgeStyle(theme[type]), ''];\n\n if (namespace) {\n fmt += ` %c${escapeConsoleFormat(namespace)}%c`;\n parts.push(badgeStyle(theme.ns, `; ${NS_STYLE}`), '');\n }\n\n if (timestamp) {\n fmt += ` %c${timestamp}%c`;\n parts.push('color: gray', '');\n }\n\n return { fmt, parts };\n}\n\n/* ─── consoleTransport ─── */\n\n/**\n * Formats and writes log entries to the browser or Node.js console.\n * Uses CSS-styled badges in browsers and plain text in Node.\n * Accepts an optional partial `theme` to override colors and badges per level.\n *\n * @example\n * consoleTransport()\n * consoleTransport({ level: 'warn', timestamp: false })\n * consoleTransport({ theme: { error: { badge: '✖' } } })\n * consoleTransport({ inspectFn: (v) => require('util').inspect(v, { colors: true, depth: 4 }) })\n */\nexport function consoleTransport(options: ConsoleTransportOptions = {}): Transport {\n const level = options.level ?? 'debug';\n const showTimestamp = options.timestamp ?? true;\n const format = options.format ?? 'raw';\n const isNode = typeof window === 'undefined';\n const useAnsi = options.ansi ?? (isNode ? supportsAnsi() : false);\n const resolved = resolveTheme(options.theme);\n const inspectFn: ((v: unknown) => string) | undefined =\n format === 'json' ? (v) => JSON.stringify(v) : options.inspectFn;\n\n return (entry: LogEntry): void => {\n if (!isLevelEnabled(level, entry.level)) return;\n\n const timestamp = showTimestamp ? entry.timestamp.toISOString().slice(11, 23) : '';\n const payload = buildPayload(entry.data, entry.message, inspectFn);\n const method = console[LOG_METHOD[entry.level]] as (...args: unknown[]) => void;\n\n if (isNode) {\n method(buildNodePrefix(resolved, entry.level, entry.namespace, timestamp, useAnsi), ...payload);\n } else {\n const { fmt, parts } = buildBrowserPrefix(resolved, entry.level, entry.namespace, timestamp);\n\n method(fmt, ...parts, ...payload);\n }\n };\n}\n\n/* ─── Group rendering (used by logger.ts wrapGroup) ─── */\n\nexport function renderGroup(collapsed: boolean, label: string, namespace: string, theme: ResolvedTheme): void {\n const fn = collapsed ? console.groupCollapsed : console.group;\n const isNode = typeof window === 'undefined';\n\n if (isNode) {\n const meta = [theme.group.badge, escapeConsoleFormat(label)];\n\n if (namespace) meta.push(`[${escapeConsoleFormat(namespace)}]`);\n\n fn(meta.join(' | '));\n\n return;\n }\n\n let fmt = `${theme.group.badge} %c${escapeConsoleFormat(label)}%c`;\n const parts: string[] = [badgeStyle(theme.group, '; margin-right: 6px; padding: 1px 3px 0'), ''];\n\n if (namespace) {\n fmt += ` %c${escapeConsoleFormat(namespace)}%c`;\n parts.push(badgeStyle(theme.ns, `; ${NS_STYLE}; margin-right: 6px`), '');\n }\n\n fn(fmt, ...parts);\n}\n"],"mappings":"+BA6DA,SAAS,aACP,EACA,EACA,EACW,CACX,IAAM,EAAU,OAAO,KAAK,CAAI,CAAC,CAAC,OAAS,EACrC,EAAqB,GAAa,EAAU,EAAU,CAAI,EAAI,EAAU,EAAO,IAAA,GAQrF,OANI,IAAc,IAAA,IAAa,IAAY,IAAA,GAAkB,CAAC,EAAS,CAAS,EAE5E,IAAc,IAAA,GAEd,IAAY,IAAA,GAET,CAAC,EAF0B,CAAC,CAAO,EAFN,CAAC,CAAS,CAKhD,CAIA,IAAa,EAA+B,CAC1C,MAAO,CAAE,MAAO,KAAM,GAAI,UAAW,OAAQ,UAAW,MAAO,SAAU,EACzE,MAAO,CAAE,MAAO,KAAM,GAAI,UAAW,OAAQ,UAAW,MAAO,MAAO,EACtE,MAAO,CAAE,MAAO,KAAM,GAAI,UAAW,OAAQ,UAAW,MAAO,MAAO,EACtE,MAAO,CAAE,MAAO,KAAM,GAAI,UAAW,OAAQ,UAAW,MAAO,MAAO,EACtE,KAAM,CAAE,MAAO,KAAM,GAAI,UAAW,OAAQ,UAAW,MAAO,MAAO,EACrE,GAAI,CAAE,MAAO,GAAI,GAAI,UAAW,OAAQ,UAAW,MAAO,MAAO,EACjE,KAAM,CAAE,MAAO,KAAM,GAAI,UAAW,OAAQ,UAAW,MAAO,SAAU,CAC1E,EAEM,EAAW,+FAEX,EAAiE,CACrE,MAAO,MACP,MAAO,QACP,MAAO,QACP,KAAM,OACN,KAAM,MACR,EAGA,SAAgB,aAAa,EAAmD,CAC9E,GAAI,CAAC,EAAU,OAAO,EAEtB,IAAM,EAAwB,CAAE,GAAG,CAAc,EAEjD,IAAK,IAAM,KAAO,OAAO,KAAK,CAAQ,EAAsC,CAC1E,IAAM,EAAQ,EAAS,GAEnB,IAAO,EAAO,GAAO,CAAE,GAAG,EAAc,GAAM,GAAG,CAAM,EAC7D,CAEA,OAAO,CACT,CAIA,SAAS,SAAS,EAAuC,CACvD,MAAO,CAAC,SAAS,EAAI,MAAM,EAAG,CAAC,EAAG,EAAE,EAAG,SAAS,EAAI,MAAM,EAAG,CAAC,EAAG,EAAE,EAAG,SAAS,EAAI,MAAM,EAAG,CAAC,EAAG,EAAE,CAAC,CACrG,CAEA,SAAS,UAAU,EAAa,EAAsB,CACpD,GAAM,CAAC,EAAG,EAAG,GAAK,SAAS,CAAG,EAE9B,MAAO,aAAa,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAK,QAC1C,CAEA,SAAS,UAAU,EAAsB,CACvC,MAAO,WAAW,EAAK,QACzB,CAEA,SAAS,cAAwB,CAG/B,OAFI,OAAO,OAAW,IAAoB,GAGvC,WAAwF,SAAS,QAAQ,QAC1G,EAEJ,CAEA,SAAS,WAAW,EAA0B,EAAQ,GAAY,CAChE,MAAO,eAAe,EAAM,GAAG,WAAW,EAAM,MAAM,sBAAsB,EAAM,OAAO,sCAAsC,GACjI,CAEA,SAAS,oBAAoB,EAAmB,CAC9C,OAAO,EAAE,QAAQ,KAAM,IAAI,CAC7B,CAQA,SAAS,gBACP,EACA,EACA,EACA,EACA,EACQ,CACR,IAAM,EAAI,EAAM,GACV,EAAY,oBAAoB,EAAE,KAAK,EAEvC,EAAO,CADK,EAAU,UAAU,EAAE,GAAI,CAAS,EAAI,CAClC,EAEvB,GAAI,EAAW,CACb,IAAM,EAAgB,oBAAoB,CAAS,EAEnD,EAAK,KAAK,EAAU,UAAU,IAAI,EAAc,EAAE,EAAI,IAAI,EAAc,EAAE,CAC5E,CAIA,OAFI,GAAW,EAAK,KAAK,EAAU,UAAU,CAAS,EAAI,CAAS,EAE5D,GAAG,EAAK,KAAK,KAAK,EAAE,GAC7B,CAEA,SAAS,mBACP,EACA,EACA,EACA,EACkC,CAClC,IAAI,EAAM,KAAK,oBAAoB,EAAM,EAAK,CAAC,KAAK,EAAE,IAChD,EAAkB,CAAC,WAAW,EAAM,EAAK,EAAG,EAAE,EAYpD,OAVI,IACF,GAAO,MAAM,oBAAoB,CAAS,EAAE,IAC5C,EAAM,KAAK,WAAW,EAAM,GAAI,KAAK,GAAU,EAAG,EAAE,GAGlD,IACF,GAAO,MAAM,EAAU,IACvB,EAAM,KAAK,cAAe,EAAE,GAGvB,CAAE,MAAK,OAAM,CACtB,CAeA,SAAgB,iBAAiB,EAAmC,CAAC,EAAc,CACjF,IAAM,EAAQ,EAAQ,OAAS,QACzB,EAAgB,EAAQ,WAAa,GACrC,EAAS,EAAQ,QAAU,MAC3B,EAAS,OAAO,OAAW,IAC3B,EAAU,EAAQ,OAAS,EAAS,aAAa,EAAI,IACrD,EAAW,aAAa,EAAQ,KAAK,EACrC,EACJ,IAAW,OAAU,GAAM,KAAK,UAAU,CAAC,EAAI,EAAQ,UAEzD,MAAQ,IAA0B,CAChC,GAAI,CAAC,EAAA,eAAe,EAAO,EAAM,KAAK,EAAG,OAEzC,IAAM,EAAY,EAAgB,EAAM,UAAU,YAAY,CAAC,CAAC,MAAM,GAAI,EAAE,EAAI,GAC1E,EAAU,aAAa,EAAM,KAAM,EAAM,QAAS,CAAS,EAC3D,EAAS,QAAQ,EAAW,EAAM,QAExC,GAAI,EACF,EAAO,gBAAgB,EAAU,EAAM,MAAO,EAAM,UAAW,EAAW,CAAO,EAAG,GAAG,CAAO,MACzF,CACL,GAAM,CAAE,MAAK,SAAU,mBAAmB,EAAU,EAAM,MAAO,EAAM,UAAW,CAAS,EAE3F,EAAO,EAAK,GAAG,EAAO,GAAG,CAAO,CAClC,CACF,CACF,CAIA,SAAgB,YAAY,EAAoB,EAAe,EAAmB,EAA4B,CAC5G,IAAM,EAAK,EAAY,QAAQ,eAAiB,QAAQ,MAGxD,GAFe,OAAO,OAAW,IAErB,CACV,IAAM,EAAO,CAAC,EAAM,MAAM,MAAO,oBAAoB,CAAK,CAAC,EAEvD,GAAW,EAAK,KAAK,IAAI,oBAAoB,CAAS,EAAE,EAAE,EAE9D,EAAG,EAAK,KAAK,KAAK,CAAC,EAEnB,MACF,CAEA,IAAI,EAAM,GAAG,EAAM,MAAM,MAAM,KAAK,oBAAoB,CAAK,EAAE,IACzD,EAAkB,CAAC,WAAW,EAAM,MAAO,yCAAyC,EAAG,EAAE,EAE3F,IACF,GAAO,MAAM,oBAAoB,CAAS,EAAE,IAC5C,EAAM,KAAK,WAAW,EAAM,GAAI,KAAK,EAAS,oBAAoB,EAAG,EAAE,GAGzE,EAAG,EAAK,GAAG,CAAK,CAClB"}
|
|
1
|
+
{"version":3,"file":"console.cjs","names":[],"sources":["../src/console.ts"],"sourcesContent":["import type { Bindings, LogEntry, LogLevel, LogType, Transport } from './types';\n\nimport { isLevelEnabled } from './types';\n\n/* ─── Console theme types ─── */\n\n/**\n * Per-level style definition for the console transport.\n * All fields are optional when providing a level override: unspecified fields fall back to the default theme.\n */\nexport type ConsoleThemeEntry = {\n badge: string;\n bg: string;\n border: string;\n color: string;\n};\n\n/**\n * Partial theme overrides merged on top of the default theme.\n * Each level entry is also partial: only specify the fields you want to change.\n *\n * @example\n * consoleTransport({ theme: { error: { badge: '✖' } } })\n */\nexport type ConsoleTheme = Partial<Record<LogType | 'group' | 'ns', Partial<ConsoleThemeEntry>>>;\n\n/**\n * Fully-resolved console theme where every level and every field is populated.\n */\nexport type ResolvedTheme = Record<LogType | 'group' | 'ns', ConsoleThemeEntry>;\n\n/* ─── ConsoleTransportOptions ─── */\n\nexport type ConsoleTransportOptions = {\n /**\n * Enable ANSI 24-bit color output in Node.js.\n * Default: true when process.stdout.isTTY is true, false otherwise.\n */\n ansi?: boolean;\n /**\n * Object serialization format for Node.js output.\n * - 'json': JSON.stringify (machine-readable, fails on circular refs)\n * - 'raw': pass the object directly to the console method (default)\n * Default: 'raw'.\n */\n format?: 'json' | 'raw';\n /**\n * Custom object inspector function. When provided, the `data` object is\n * passed through this function before being written to the console.\n */\n inspectFn?: (value: unknown) => string;\n /** Minimum level to output. Default: 'debug'. */\n level?: LogLevel;\n /** Partial theme overrides merged on top of the default theme. */\n theme?: ConsoleTheme;\n /** Whether to include timestamp in console output. Default: true. */\n timestamp?: boolean;\n};\n\n/* ─── Payload builder ─── */\n\nfunction buildPayload(\n data: Readonly<Bindings>,\n message: string | undefined,\n inspectFn: ((v: unknown) => string) | undefined,\n): unknown[] {\n const hasData = Object.keys(data).length > 0;\n const formatted: unknown = inspectFn && hasData ? inspectFn(data) : hasData ? data : undefined;\n\n if (formatted !== undefined && message !== undefined) return [message, formatted];\n\n if (formatted !== undefined) return [formatted];\n\n if (message !== undefined) return [message];\n\n return [];\n}\n\n/* ─── Console theme ─── */\n\nexport const DEFAULT_THEME: ResolvedTheme = {\n debug: { badge: '🅳', bg: '#616161', border: '#424242', color: '#e0e0e0' },\n error: { badge: '🅴', bg: '#d32f2f', border: '#c62828', color: '#fff' },\n fatal: { badge: '🅵', bg: '#4a148c', border: '#38006b', color: '#fff' },\n group: { badge: '🅶', bg: '#546e7a', border: '#455a64', color: '#fff' },\n info: { badge: '🅸', bg: '#1976d2', border: '#1565c0', color: '#fff' },\n ns: { badge: '', bg: '#424242', border: '#212121', color: '#fff' },\n warn: { badge: '🆆', bg: '#ffb300', border: '#ffa000', color: '#212121' },\n};\n\nconst NS_STYLE = 'border-radius: 8px; font: italic small-caps bold 12px; font-weight: lighter; padding: 0 4px;';\n\nconst LOG_METHOD: Record<LogType, 'error' | 'info' | 'log' | 'warn'> = {\n debug: 'log',\n error: 'error',\n fatal: 'error',\n info: 'info',\n warn: 'warn',\n};\n\n/** Deep-merges per-level overrides onto the default theme. Only specified fields within each level entry are replaced. */\nexport function resolveTheme(override: ConsoleTheme | undefined): ResolvedTheme {\n if (!override) return DEFAULT_THEME;\n\n const result: ResolvedTheme = { ...DEFAULT_THEME };\n\n for (const key of Object.keys(override) as Array<LogType | 'group' | 'ns'>) {\n const entry = override[key];\n\n if (entry) result[key] = { ...DEFAULT_THEME[key], ...entry };\n }\n\n return result;\n}\n\n/* ─── ANSI helpers (Node) ─── */\n\nfunction hexToRgb(hex: string): [number, number, number] {\n return [parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16)];\n}\n\nfunction ansiColor(hex: string, text: string): string {\n const [r, g, b] = hexToRgb(hex);\n\n return `\\x1b[38;2;${r};${g};${b}m${text}\\x1b[0m`;\n}\n\nfunction ansiMuted(text: string): string {\n return `\\x1b[90m${text}\\x1b[0m`;\n}\n\nfunction supportsAnsi(): boolean {\n if (typeof window !== 'undefined') return false;\n\n return (\n (globalThis as Record<string, unknown> & { process?: { stdout?: { isTTY?: boolean } } }).process?.stdout?.isTTY ===\n true\n );\n}\n\nfunction badgeStyle(entry: ConsoleThemeEntry, extra = ''): string {\n return `background: ${entry.bg}; color: ${entry.color}; border: 1px solid ${entry.border}; border-radius: 4px; padding: 0 1px${extra}`;\n}\n\nfunction escapeConsoleFormat(s: string): string {\n return s.replace(/%/g, '%%');\n}\n\n/**\n * Builds the Node console prefix string, passed as the first argument to `console.log()`/etc.\n * alongside the payload. `namespace` is escaped because Node's `console.*` methods run the first\n * string argument through `util.format`: an unescaped `%s`/`%d`/`%o`/etc. in a caller-controlled\n * namespace would consume and hide the actual payload arguments that follow (log forging).\n */\nfunction buildNodePrefix(\n theme: ResolvedTheme,\n type: LogType,\n namespace: string,\n timestamp: string,\n useAnsi: boolean,\n): string {\n const t = theme[type];\n const safeBadge = escapeConsoleFormat(t.badge);\n const badgeText = useAnsi ? ansiColor(t.bg, safeBadge) : safeBadge;\n const meta = [badgeText];\n\n if (namespace) {\n const safeNamespace = escapeConsoleFormat(namespace);\n\n meta.push(useAnsi ? ansiMuted(`[${safeNamespace}]`) : `[${safeNamespace}]`);\n }\n\n if (timestamp) meta.push(useAnsi ? ansiMuted(timestamp) : timestamp);\n\n return `${meta.join(' | ')} |`;\n}\n\nfunction buildBrowserPrefix(\n theme: ResolvedTheme,\n type: LogType,\n namespace: string,\n timestamp: string,\n): { fmt: string; parts: string[] } {\n let fmt = `%c${escapeConsoleFormat(theme[type].badge)}%c`;\n const parts: string[] = [badgeStyle(theme[type]), ''];\n\n if (namespace) {\n fmt += ` %c${escapeConsoleFormat(namespace)}%c`;\n parts.push(badgeStyle(theme.ns, `; ${NS_STYLE}`), '');\n }\n\n if (timestamp) {\n fmt += ` %c${timestamp}%c`;\n parts.push('color: gray', '');\n }\n\n return { fmt, parts };\n}\n\n/* ─── consoleTransport ─── */\n\n/**\n * Formats and writes log entries to the browser or Node.js console.\n * Uses CSS-styled badges in browsers and plain text in Node.\n * Accepts an optional partial `theme` to override colors and badges per level.\n *\n * @example\n * consoleTransport()\n * consoleTransport({ level: 'warn', timestamp: false })\n * consoleTransport({ theme: { error: { badge: '✖' } } })\n * consoleTransport({ inspectFn: (v) => require('util').inspect(v, { colors: true, depth: 4 }) })\n */\nexport function consoleTransport(options: ConsoleTransportOptions = {}): Transport {\n const level = options.level ?? 'debug';\n const showTimestamp = options.timestamp ?? true;\n const format = options.format ?? 'raw';\n const isNode = typeof window === 'undefined';\n const useAnsi = options.ansi ?? (isNode ? supportsAnsi() : false);\n const resolved = resolveTheme(options.theme);\n const inspectFn: ((v: unknown) => string) | undefined =\n format === 'json' ? (v) => JSON.stringify(v) : options.inspectFn;\n\n return (entry: LogEntry): void => {\n if (!isLevelEnabled(level, entry.level)) return;\n\n const timestamp = showTimestamp ? entry.timestamp.toISOString().slice(11, 23) : '';\n const payload = buildPayload(entry.data, entry.message, inspectFn);\n const method = console[LOG_METHOD[entry.level]] as (...args: unknown[]) => void;\n\n if (isNode) {\n method(buildNodePrefix(resolved, entry.level, entry.namespace, timestamp, useAnsi), ...payload);\n } else {\n const { fmt, parts } = buildBrowserPrefix(resolved, entry.level, entry.namespace, timestamp);\n\n method(fmt, ...parts, ...payload);\n }\n };\n}\n\n/* ─── Group rendering (used by logger.ts wrapGroup) ─── */\n\nexport function renderGroup(collapsed: boolean, label: string, namespace: string, theme: ResolvedTheme): void {\n const fn = collapsed ? console.groupCollapsed : console.group;\n const isNode = typeof window === 'undefined';\n\n if (isNode) {\n const meta = [theme.group.badge, escapeConsoleFormat(label)];\n\n if (namespace) meta.push(`[${escapeConsoleFormat(namespace)}]`);\n\n fn(meta.join(' | '));\n\n return;\n }\n\n let fmt = `${theme.group.badge} %c${escapeConsoleFormat(label)}%c`;\n const parts: string[] = [badgeStyle(theme.group, '; margin-right: 6px; padding: 1px 3px 0'), ''];\n\n if (namespace) {\n fmt += ` %c${escapeConsoleFormat(namespace)}%c`;\n parts.push(badgeStyle(theme.ns, `; ${NS_STYLE}; margin-right: 6px`), '');\n }\n\n fn(fmt, ...parts);\n}\n"],"mappings":"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"}
|
package/dist/console.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { LogLevel, LogType, Transport } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* Per-level style definition for the console transport.
|
|
4
|
-
* All fields are optional when providing a level override
|
|
4
|
+
* All fields are optional when providing a level override: unspecified fields fall back to the default theme.
|
|
5
5
|
*/
|
|
6
6
|
export type ConsoleThemeEntry = {
|
|
7
7
|
badge: string;
|
|
@@ -11,7 +11,7 @@ export type ConsoleThemeEntry = {
|
|
|
11
11
|
};
|
|
12
12
|
/**
|
|
13
13
|
* Partial theme overrides merged on top of the default theme.
|
|
14
|
-
* Each level entry is also partial
|
|
14
|
+
* Each level entry is also partial: only specify the fields you want to change.
|
|
15
15
|
*
|
|
16
16
|
* @example
|
|
17
17
|
* consoleTransport({ theme: { error: { badge: '✖' } } })
|
|
@@ -29,8 +29,8 @@ export type ConsoleTransportOptions = {
|
|
|
29
29
|
ansi?: boolean;
|
|
30
30
|
/**
|
|
31
31
|
* Object serialization format for Node.js output.
|
|
32
|
-
* - 'json'
|
|
33
|
-
* - 'raw'
|
|
32
|
+
* - 'json': JSON.stringify (machine-readable, fails on circular refs)
|
|
33
|
+
* - 'raw': pass the object directly to the console method (default)
|
|
34
34
|
* Default: 'raw'.
|
|
35
35
|
*/
|
|
36
36
|
format?: 'json' | 'raw';
|
package/dist/console.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"console.js","names":[],"sources":["../src/console.ts"],"sourcesContent":["import type { Bindings, LogEntry, LogLevel, LogType, Transport } from './types';\n\nimport { isLevelEnabled } from './types';\n\n/* ─── Console theme types ─── */\n\n/**\n * Per-level style definition for the console transport.\n * All fields are optional when providing a level override — unspecified fields fall back to the default theme.\n */\nexport type ConsoleThemeEntry = {\n badge: string;\n bg: string;\n border: string;\n color: string;\n};\n\n/**\n * Partial theme overrides merged on top of the default theme.\n * Each level entry is also partial — only specify the fields you want to change.\n *\n * @example\n * consoleTransport({ theme: { error: { badge: '✖' } } })\n */\nexport type ConsoleTheme = Partial<Record<LogType | 'group' | 'ns', Partial<ConsoleThemeEntry>>>;\n\n/**\n * Fully-resolved console theme where every level and every field is populated.\n */\nexport type ResolvedTheme = Record<LogType | 'group' | 'ns', ConsoleThemeEntry>;\n\n/* ─── ConsoleTransportOptions ─── */\n\nexport type ConsoleTransportOptions = {\n /**\n * Enable ANSI 24-bit color output in Node.js.\n * Default: true when process.stdout.isTTY is true, false otherwise.\n */\n ansi?: boolean;\n /**\n * Object serialization format for Node.js output.\n * - 'json' — JSON.stringify (machine-readable, fails on circular refs)\n * - 'raw' — pass the object directly to the console method (default)\n * Default: 'raw'.\n */\n format?: 'json' | 'raw';\n /**\n * Custom object inspector function. When provided, the `data` object is\n * passed through this function before being written to the console.\n */\n inspectFn?: (value: unknown) => string;\n /** Minimum level to output. Default: 'debug'. */\n level?: LogLevel;\n /** Partial theme overrides merged on top of the default theme. */\n theme?: ConsoleTheme;\n /** Whether to include timestamp in console output. Default: true. */\n timestamp?: boolean;\n};\n\n/* ─── Payload builder ─── */\n\nfunction buildPayload(\n data: Readonly<Bindings>,\n message: string | undefined,\n inspectFn: ((v: unknown) => string) | undefined,\n): unknown[] {\n const hasData = Object.keys(data).length > 0;\n const formatted: unknown = inspectFn && hasData ? inspectFn(data) : hasData ? data : undefined;\n\n if (formatted !== undefined && message !== undefined) return [message, formatted];\n\n if (formatted !== undefined) return [formatted];\n\n if (message !== undefined) return [message];\n\n return [];\n}\n\n/* ─── Console theme ─── */\n\nexport const DEFAULT_THEME: ResolvedTheme = {\n debug: { badge: '🅳', bg: '#616161', border: '#424242', color: '#e0e0e0' },\n error: { badge: '🅴', bg: '#d32f2f', border: '#c62828', color: '#fff' },\n fatal: { badge: '🅵', bg: '#4a148c', border: '#38006b', color: '#fff' },\n group: { badge: '🅶', bg: '#546e7a', border: '#455a64', color: '#fff' },\n info: { badge: '🅸', bg: '#1976d2', border: '#1565c0', color: '#fff' },\n ns: { badge: '', bg: '#424242', border: '#212121', color: '#fff' },\n warn: { badge: '🆆', bg: '#ffb300', border: '#ffa000', color: '#212121' },\n};\n\nconst NS_STYLE = 'border-radius: 8px; font: italic small-caps bold 12px; font-weight: lighter; padding: 0 4px;';\n\nconst LOG_METHOD: Record<LogType, 'error' | 'info' | 'log' | 'warn'> = {\n debug: 'log',\n error: 'error',\n fatal: 'error',\n info: 'info',\n warn: 'warn',\n};\n\n/** Deep-merges per-level overrides onto the default theme. Only specified fields within each level entry are replaced. */\nexport function resolveTheme(override: ConsoleTheme | undefined): ResolvedTheme {\n if (!override) return DEFAULT_THEME;\n\n const result: ResolvedTheme = { ...DEFAULT_THEME };\n\n for (const key of Object.keys(override) as Array<LogType | 'group' | 'ns'>) {\n const entry = override[key];\n\n if (entry) result[key] = { ...DEFAULT_THEME[key], ...entry };\n }\n\n return result;\n}\n\n/* ─── ANSI helpers (Node) ─── */\n\nfunction hexToRgb(hex: string): [number, number, number] {\n return [parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16)];\n}\n\nfunction ansiColor(hex: string, text: string): string {\n const [r, g, b] = hexToRgb(hex);\n\n return `\\x1b[38;2;${r};${g};${b}m${text}\\x1b[0m`;\n}\n\nfunction ansiMuted(text: string): string {\n return `\\x1b[90m${text}\\x1b[0m`;\n}\n\nfunction supportsAnsi(): boolean {\n if (typeof window !== 'undefined') return false;\n\n return (\n (globalThis as Record<string, unknown> & { process?: { stdout?: { isTTY?: boolean } } }).process?.stdout?.isTTY ===\n true\n );\n}\n\nfunction badgeStyle(entry: ConsoleThemeEntry, extra = ''): string {\n return `background: ${entry.bg}; color: ${entry.color}; border: 1px solid ${entry.border}; border-radius: 4px; padding: 0 1px${extra}`;\n}\n\nfunction escapeConsoleFormat(s: string): string {\n return s.replace(/%/g, '%%');\n}\n\n/**\n * Builds the Node console prefix string, passed as the first argument to `console.log()`/etc.\n * alongside the payload. `namespace` is escaped because Node's `console.*` methods run the first\n * string argument through `util.format` — an unescaped `%s`/`%d`/`%o`/etc. in a caller-controlled\n * namespace would consume and hide the actual payload arguments that follow (log forging).\n */\nfunction buildNodePrefix(\n theme: ResolvedTheme,\n type: LogType,\n namespace: string,\n timestamp: string,\n useAnsi: boolean,\n): string {\n const t = theme[type];\n const safeBadge = escapeConsoleFormat(t.badge);\n const badgeText = useAnsi ? ansiColor(t.bg, safeBadge) : safeBadge;\n const meta = [badgeText];\n\n if (namespace) {\n const safeNamespace = escapeConsoleFormat(namespace);\n\n meta.push(useAnsi ? ansiMuted(`[${safeNamespace}]`) : `[${safeNamespace}]`);\n }\n\n if (timestamp) meta.push(useAnsi ? ansiMuted(timestamp) : timestamp);\n\n return `${meta.join(' | ')} |`;\n}\n\nfunction buildBrowserPrefix(\n theme: ResolvedTheme,\n type: LogType,\n namespace: string,\n timestamp: string,\n): { fmt: string; parts: string[] } {\n let fmt = `%c${escapeConsoleFormat(theme[type].badge)}%c`;\n const parts: string[] = [badgeStyle(theme[type]), ''];\n\n if (namespace) {\n fmt += ` %c${escapeConsoleFormat(namespace)}%c`;\n parts.push(badgeStyle(theme.ns, `; ${NS_STYLE}`), '');\n }\n\n if (timestamp) {\n fmt += ` %c${timestamp}%c`;\n parts.push('color: gray', '');\n }\n\n return { fmt, parts };\n}\n\n/* ─── consoleTransport ─── */\n\n/**\n * Formats and writes log entries to the browser or Node.js console.\n * Uses CSS-styled badges in browsers and plain text in Node.\n * Accepts an optional partial `theme` to override colors and badges per level.\n *\n * @example\n * consoleTransport()\n * consoleTransport({ level: 'warn', timestamp: false })\n * consoleTransport({ theme: { error: { badge: '✖' } } })\n * consoleTransport({ inspectFn: (v) => require('util').inspect(v, { colors: true, depth: 4 }) })\n */\nexport function consoleTransport(options: ConsoleTransportOptions = {}): Transport {\n const level = options.level ?? 'debug';\n const showTimestamp = options.timestamp ?? true;\n const format = options.format ?? 'raw';\n const isNode = typeof window === 'undefined';\n const useAnsi = options.ansi ?? (isNode ? supportsAnsi() : false);\n const resolved = resolveTheme(options.theme);\n const inspectFn: ((v: unknown) => string) | undefined =\n format === 'json' ? (v) => JSON.stringify(v) : options.inspectFn;\n\n return (entry: LogEntry): void => {\n if (!isLevelEnabled(level, entry.level)) return;\n\n const timestamp = showTimestamp ? entry.timestamp.toISOString().slice(11, 23) : '';\n const payload = buildPayload(entry.data, entry.message, inspectFn);\n const method = console[LOG_METHOD[entry.level]] as (...args: unknown[]) => void;\n\n if (isNode) {\n method(buildNodePrefix(resolved, entry.level, entry.namespace, timestamp, useAnsi), ...payload);\n } else {\n const { fmt, parts } = buildBrowserPrefix(resolved, entry.level, entry.namespace, timestamp);\n\n method(fmt, ...parts, ...payload);\n }\n };\n}\n\n/* ─── Group rendering (used by logger.ts wrapGroup) ─── */\n\nexport function renderGroup(collapsed: boolean, label: string, namespace: string, theme: ResolvedTheme): void {\n const fn = collapsed ? console.groupCollapsed : console.group;\n const isNode = typeof window === 'undefined';\n\n if (isNode) {\n const meta = [theme.group.badge, escapeConsoleFormat(label)];\n\n if (namespace) meta.push(`[${escapeConsoleFormat(namespace)}]`);\n\n fn(meta.join(' | '));\n\n return;\n }\n\n let fmt = `${theme.group.badge} %c${escapeConsoleFormat(label)}%c`;\n const parts: string[] = [badgeStyle(theme.group, '; margin-right: 6px; padding: 1px 3px 0'), ''];\n\n if (namespace) {\n fmt += ` %c${escapeConsoleFormat(namespace)}%c`;\n parts.push(badgeStyle(theme.ns, `; ${NS_STYLE}; margin-right: 6px`), '');\n }\n\n fn(fmt, ...parts);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"console.js","names":[],"sources":["../src/console.ts"],"sourcesContent":["import type { Bindings, LogEntry, LogLevel, LogType, Transport } from './types';\n\nimport { isLevelEnabled } from './types';\n\n/* ─── Console theme types ─── */\n\n/**\n * Per-level style definition for the console transport.\n * All fields are optional when providing a level override: unspecified fields fall back to the default theme.\n */\nexport type ConsoleThemeEntry = {\n badge: string;\n bg: string;\n border: string;\n color: string;\n};\n\n/**\n * Partial theme overrides merged on top of the default theme.\n * Each level entry is also partial: only specify the fields you want to change.\n *\n * @example\n * consoleTransport({ theme: { error: { badge: '✖' } } })\n */\nexport type ConsoleTheme = Partial<Record<LogType | 'group' | 'ns', Partial<ConsoleThemeEntry>>>;\n\n/**\n * Fully-resolved console theme where every level and every field is populated.\n */\nexport type ResolvedTheme = Record<LogType | 'group' | 'ns', ConsoleThemeEntry>;\n\n/* ─── ConsoleTransportOptions ─── */\n\nexport type ConsoleTransportOptions = {\n /**\n * Enable ANSI 24-bit color output in Node.js.\n * Default: true when process.stdout.isTTY is true, false otherwise.\n */\n ansi?: boolean;\n /**\n * Object serialization format for Node.js output.\n * - 'json': JSON.stringify (machine-readable, fails on circular refs)\n * - 'raw': pass the object directly to the console method (default)\n * Default: 'raw'.\n */\n format?: 'json' | 'raw';\n /**\n * Custom object inspector function. When provided, the `data` object is\n * passed through this function before being written to the console.\n */\n inspectFn?: (value: unknown) => string;\n /** Minimum level to output. Default: 'debug'. */\n level?: LogLevel;\n /** Partial theme overrides merged on top of the default theme. */\n theme?: ConsoleTheme;\n /** Whether to include timestamp in console output. Default: true. */\n timestamp?: boolean;\n};\n\n/* ─── Payload builder ─── */\n\nfunction buildPayload(\n data: Readonly<Bindings>,\n message: string | undefined,\n inspectFn: ((v: unknown) => string) | undefined,\n): unknown[] {\n const hasData = Object.keys(data).length > 0;\n const formatted: unknown = inspectFn && hasData ? inspectFn(data) : hasData ? data : undefined;\n\n if (formatted !== undefined && message !== undefined) return [message, formatted];\n\n if (formatted !== undefined) return [formatted];\n\n if (message !== undefined) return [message];\n\n return [];\n}\n\n/* ─── Console theme ─── */\n\nexport const DEFAULT_THEME: ResolvedTheme = {\n debug: { badge: '🅳', bg: '#616161', border: '#424242', color: '#e0e0e0' },\n error: { badge: '🅴', bg: '#d32f2f', border: '#c62828', color: '#fff' },\n fatal: { badge: '🅵', bg: '#4a148c', border: '#38006b', color: '#fff' },\n group: { badge: '🅶', bg: '#546e7a', border: '#455a64', color: '#fff' },\n info: { badge: '🅸', bg: '#1976d2', border: '#1565c0', color: '#fff' },\n ns: { badge: '', bg: '#424242', border: '#212121', color: '#fff' },\n warn: { badge: '🆆', bg: '#ffb300', border: '#ffa000', color: '#212121' },\n};\n\nconst NS_STYLE = 'border-radius: 8px; font: italic small-caps bold 12px; font-weight: lighter; padding: 0 4px;';\n\nconst LOG_METHOD: Record<LogType, 'error' | 'info' | 'log' | 'warn'> = {\n debug: 'log',\n error: 'error',\n fatal: 'error',\n info: 'info',\n warn: 'warn',\n};\n\n/** Deep-merges per-level overrides onto the default theme. Only specified fields within each level entry are replaced. */\nexport function resolveTheme(override: ConsoleTheme | undefined): ResolvedTheme {\n if (!override) return DEFAULT_THEME;\n\n const result: ResolvedTheme = { ...DEFAULT_THEME };\n\n for (const key of Object.keys(override) as Array<LogType | 'group' | 'ns'>) {\n const entry = override[key];\n\n if (entry) result[key] = { ...DEFAULT_THEME[key], ...entry };\n }\n\n return result;\n}\n\n/* ─── ANSI helpers (Node) ─── */\n\nfunction hexToRgb(hex: string): [number, number, number] {\n return [parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16)];\n}\n\nfunction ansiColor(hex: string, text: string): string {\n const [r, g, b] = hexToRgb(hex);\n\n return `\\x1b[38;2;${r};${g};${b}m${text}\\x1b[0m`;\n}\n\nfunction ansiMuted(text: string): string {\n return `\\x1b[90m${text}\\x1b[0m`;\n}\n\nfunction supportsAnsi(): boolean {\n if (typeof window !== 'undefined') return false;\n\n return (\n (globalThis as Record<string, unknown> & { process?: { stdout?: { isTTY?: boolean } } }).process?.stdout?.isTTY ===\n true\n );\n}\n\nfunction badgeStyle(entry: ConsoleThemeEntry, extra = ''): string {\n return `background: ${entry.bg}; color: ${entry.color}; border: 1px solid ${entry.border}; border-radius: 4px; padding: 0 1px${extra}`;\n}\n\nfunction escapeConsoleFormat(s: string): string {\n return s.replace(/%/g, '%%');\n}\n\n/**\n * Builds the Node console prefix string, passed as the first argument to `console.log()`/etc.\n * alongside the payload. `namespace` is escaped because Node's `console.*` methods run the first\n * string argument through `util.format`: an unescaped `%s`/`%d`/`%o`/etc. in a caller-controlled\n * namespace would consume and hide the actual payload arguments that follow (log forging).\n */\nfunction buildNodePrefix(\n theme: ResolvedTheme,\n type: LogType,\n namespace: string,\n timestamp: string,\n useAnsi: boolean,\n): string {\n const t = theme[type];\n const safeBadge = escapeConsoleFormat(t.badge);\n const badgeText = useAnsi ? ansiColor(t.bg, safeBadge) : safeBadge;\n const meta = [badgeText];\n\n if (namespace) {\n const safeNamespace = escapeConsoleFormat(namespace);\n\n meta.push(useAnsi ? ansiMuted(`[${safeNamespace}]`) : `[${safeNamespace}]`);\n }\n\n if (timestamp) meta.push(useAnsi ? ansiMuted(timestamp) : timestamp);\n\n return `${meta.join(' | ')} |`;\n}\n\nfunction buildBrowserPrefix(\n theme: ResolvedTheme,\n type: LogType,\n namespace: string,\n timestamp: string,\n): { fmt: string; parts: string[] } {\n let fmt = `%c${escapeConsoleFormat(theme[type].badge)}%c`;\n const parts: string[] = [badgeStyle(theme[type]), ''];\n\n if (namespace) {\n fmt += ` %c${escapeConsoleFormat(namespace)}%c`;\n parts.push(badgeStyle(theme.ns, `; ${NS_STYLE}`), '');\n }\n\n if (timestamp) {\n fmt += ` %c${timestamp}%c`;\n parts.push('color: gray', '');\n }\n\n return { fmt, parts };\n}\n\n/* ─── consoleTransport ─── */\n\n/**\n * Formats and writes log entries to the browser or Node.js console.\n * Uses CSS-styled badges in browsers and plain text in Node.\n * Accepts an optional partial `theme` to override colors and badges per level.\n *\n * @example\n * consoleTransport()\n * consoleTransport({ level: 'warn', timestamp: false })\n * consoleTransport({ theme: { error: { badge: '✖' } } })\n * consoleTransport({ inspectFn: (v) => require('util').inspect(v, { colors: true, depth: 4 }) })\n */\nexport function consoleTransport(options: ConsoleTransportOptions = {}): Transport {\n const level = options.level ?? 'debug';\n const showTimestamp = options.timestamp ?? true;\n const format = options.format ?? 'raw';\n const isNode = typeof window === 'undefined';\n const useAnsi = options.ansi ?? (isNode ? supportsAnsi() : false);\n const resolved = resolveTheme(options.theme);\n const inspectFn: ((v: unknown) => string) | undefined =\n format === 'json' ? (v) => JSON.stringify(v) : options.inspectFn;\n\n return (entry: LogEntry): void => {\n if (!isLevelEnabled(level, entry.level)) return;\n\n const timestamp = showTimestamp ? entry.timestamp.toISOString().slice(11, 23) : '';\n const payload = buildPayload(entry.data, entry.message, inspectFn);\n const method = console[LOG_METHOD[entry.level]] as (...args: unknown[]) => void;\n\n if (isNode) {\n method(buildNodePrefix(resolved, entry.level, entry.namespace, timestamp, useAnsi), ...payload);\n } else {\n const { fmt, parts } = buildBrowserPrefix(resolved, entry.level, entry.namespace, timestamp);\n\n method(fmt, ...parts, ...payload);\n }\n };\n}\n\n/* ─── Group rendering (used by logger.ts wrapGroup) ─── */\n\nexport function renderGroup(collapsed: boolean, label: string, namespace: string, theme: ResolvedTheme): void {\n const fn = collapsed ? console.groupCollapsed : console.group;\n const isNode = typeof window === 'undefined';\n\n if (isNode) {\n const meta = [theme.group.badge, escapeConsoleFormat(label)];\n\n if (namespace) meta.push(`[${escapeConsoleFormat(namespace)}]`);\n\n fn(meta.join(' | '));\n\n return;\n }\n\n let fmt = `${theme.group.badge} %c${escapeConsoleFormat(label)}%c`;\n const parts: string[] = [badgeStyle(theme.group, '; margin-right: 6px; padding: 1px 3px 0'), ''];\n\n if (namespace) {\n fmt += ` %c${escapeConsoleFormat(namespace)}%c`;\n parts.push(badgeStyle(theme.ns, `; ${NS_STYLE}; margin-right: 6px`), '');\n }\n\n fn(fmt, ...parts);\n}\n"],"mappings":"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"}
|
package/dist/lazy.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy.cjs","names":[],"sources":["../src/lazy.ts"],"sourcesContent":["const LAZY_BRAND = Symbol('rune.lazy');\n\n/** A deferred binding value
|
|
1
|
+
{"version":3,"file":"lazy.cjs","names":[],"sources":["../src/lazy.ts"],"sourcesContent":["const LAZY_BRAND = Symbol('rune.lazy');\n\n/** A deferred binding value: evaluated only when an entry is actually emitted. Create via `lazy(fn)`. */\nexport type LazyBinding = { readonly factory: () => unknown; readonly [LAZY_BRAND]: true };\n\n/** @internal */\nexport function isLazy(v: unknown): v is LazyBinding {\n return typeof v === 'object' && v !== null && (v as Record<symbol, unknown>)[LAZY_BRAND] === true;\n}\n\n/**\n * Defer evaluation of an expensive binding value until after the log level check passes.\n * The factory function is only called when an entry is actually emitted.\n *\n * @example\n * const reqLog = log.withBindings({ diagnostics: lazy(() => buildExpensiveDiagnostics()) });\n * reqLog.debug('trace'); // diagnostics() only called when logLevel allows debug\n */\nexport function lazy(fn: () => unknown): LazyBinding {\n return { factory: fn, [LAZY_BRAND]: true } as LazyBinding;\n}\n"],"mappings":"AAAA,IAAM,EAAa,OAAO,WAAW,EAMrC,SAAgB,OAAO,EAA8B,CACnD,OAAO,OAAO,GAAM,YAAY,GAAe,EAA8B,KAAgB,EAC/F,CAUA,SAAgB,KAAK,EAAgC,CACnD,MAAO,CAAE,QAAS,GAAK,GAAa,EAAK,CAC3C"}
|
package/dist/lazy.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
declare const LAZY_BRAND: unique symbol;
|
|
2
|
-
/** A deferred binding value
|
|
2
|
+
/** A deferred binding value: evaluated only when an entry is actually emitted. Create via `lazy(fn)`. */
|
|
3
3
|
export type LazyBinding = {
|
|
4
4
|
readonly factory: () => unknown;
|
|
5
5
|
readonly [LAZY_BRAND]: true;
|
package/dist/lazy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../src/lazy.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,UAAU,eAAsB,CAAC;AAEvC,
|
|
1
|
+
{"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../src/lazy.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,UAAU,eAAsB,CAAC;AAEvC,yGAAyG;AACzG,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC;IAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAO3F;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,OAAO,GAAG,WAAW,CAEnD"}
|
package/dist/lazy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy.js","names":[],"sources":["../src/lazy.ts"],"sourcesContent":["const LAZY_BRAND = Symbol('rune.lazy');\n\n/** A deferred binding value
|
|
1
|
+
{"version":3,"file":"lazy.js","names":[],"sources":["../src/lazy.ts"],"sourcesContent":["const LAZY_BRAND = Symbol('rune.lazy');\n\n/** A deferred binding value: evaluated only when an entry is actually emitted. Create via `lazy(fn)`. */\nexport type LazyBinding = { readonly factory: () => unknown; readonly [LAZY_BRAND]: true };\n\n/** @internal */\nexport function isLazy(v: unknown): v is LazyBinding {\n return typeof v === 'object' && v !== null && (v as Record<symbol, unknown>)[LAZY_BRAND] === true;\n}\n\n/**\n * Defer evaluation of an expensive binding value until after the log level check passes.\n * The factory function is only called when an entry is actually emitted.\n *\n * @example\n * const reqLog = log.withBindings({ diagnostics: lazy(() => buildExpensiveDiagnostics()) });\n * reqLog.debug('trace'); // diagnostics() only called when logLevel allows debug\n */\nexport function lazy(fn: () => unknown): LazyBinding {\n return { factory: fn, [LAZY_BRAND]: true } as LazyBinding;\n}\n"],"mappings":"AAAA,IAAM,EAAa,OAAO,WAAW,EAMrC,SAAgB,OAAO,EAA8B,CACnD,OAAO,OAAO,GAAM,YAAY,GAAe,EAA8B,KAAgB,EAC/F,CAUA,SAAgB,KAAK,EAAgC,CACnD,MAAO,CAAE,QAAS,GAAK,GAAa,EAAK,CAC3C"}
|
package/dist/logger.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.cjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["import { warn } from './_dev';\nimport { isUnsafeObjectKey } from './_prototype';\nimport { consoleTransport, DEFAULT_THEME, renderGroup } from './console';\nimport { isLazy } from './lazy';\nimport type { Bindings, LogEntry, Logger, LogLevel, LogMiddleware, LogType, RuneOptions, Transport } from './types';\nimport { isLevelEnabled } from './types';\n\n/* --- Arg parsing (simplified) --- */\n\nfunction serializeError(err: Error): { message: string; name: string; stack?: string } {\n return { message: err.message, name: err.name, stack: err.stack };\n}\n\n/**\n * Resolve lazy bindings and serialize Errors in a single pass.\n * Always allocates a fresh object — the result is never an alias of the input.\n */\nfunction prepareBindings(bindings: Bindings): Bindings {\n const out: Bindings = {};\n\n for (const [k, v] of Object.entries(bindings)) {\n // Guard against a `__proto__`/`constructor`/`prototype` field name hijacking out's own\n // prototype via the bracket-assignment accessor — see _prototype.ts.\n if (isUnsafeObjectKey(k)) continue;\n\n const resolved = isLazy(v) ? v.factory() : v;\n\n out[k] = resolved instanceof Error ? serializeError(resolved) : resolved;\n }\n\n return out;\n}\n\ntype ParsedArgs = { context: Bindings | undefined; message: string | undefined };\n\nfunction parseArgs(first: unknown, second?: unknown, third?: unknown): ParsedArgs {\n if (typeof first === 'string') {\n return {\n context: second !== null && typeof second === 'object' ? (second as Bindings) : undefined,\n message: first,\n };\n }\n\n if (first instanceof Error) {\n const context = second !== null && typeof second === 'object' ? (second as Bindings) : {};\n const message = third !== undefined ? String(third) : typeof second === 'string' ? second : undefined;\n\n return { context: { err: serializeError(first), ...context }, message };\n }\n\n if (first !== null && typeof first === 'object') {\n return { context: first as Bindings, message: second !== undefined ? String(second) : undefined };\n }\n\n return { context: undefined, message: first === undefined ? undefined : String(first) };\n}\n\n/* --- Namespace joining --- */\n\n/**\n * Joins parent and child namespaces with '.' as separator.\n * Examples:\n * joinNamespace('api', 'auth') → 'api.auth'\n * joinNamespace('', 'api') → 'api'\n * joinNamespace('api', '') → 'api'\n */\nfunction joinNamespace(parent: string, child: string): string {\n if (!parent) return child;\n\n if (!child) return parent;\n\n return `${parent}.${child}`;\n}\n\n/* --- createLogger --- */\n\n/**\n * Creates an isolated logger instance.\n *\n * Accepts two call signatures:\n * - `createLogger()` / `createLogger(options)` — configure via `RuneOptions`\n * - `createLogger('namespace', options?)` — namespace shorthand + optional options\n *\n * Each instance has its own immutable config (logLevel, transports, middleware).\n * To change the log level at runtime, create a new logger or child.\n */\nexport function createLogger(namespace: string, options?: Omit<RuneOptions, 'namespace'>): Logger;\nexport function createLogger(options?: RuneOptions): Logger;\nexport function createLogger(initial: RuneOptions | string = {}, extra?: Omit<RuneOptions, 'namespace'>): Logger {\n const initialOpts: RuneOptions = typeof initial === 'string' ? { namespace: initial, ...extra } : initial;\n\n const logLevel: LogLevel = initialOpts.logLevel ?? 'debug';\n const middleware: LogMiddleware[] = [...(initialOpts.middleware ?? [])];\n const namespace: string = initialOpts.namespace ?? '';\n const transports = [...(initialOpts.transports ?? [consoleTransport()])];\n const ownBindings: Bindings = { ...(initialOpts.bindings ?? {}) };\n\n const disposeController = new AbortController();\n let isDisposed = false;\n\n const passes = (type: LogType): boolean => isLevelEnabled(logLevel, type);\n const namespaceSuffix = (): string => (namespace ? ` (namespace: \"${namespace}\")` : '');\n\n const dispatch = (entry: LogEntry): void => {\n let current = entry;\n\n for (const transform of middleware) {\n try {\n const next = transform(current);\n\n if (next === null || next === undefined) return;\n\n current = next;\n } catch (err) {\n warn(`Middleware threw and dropped this entry${namespaceSuffix()}: ${String(err)}`);\n return;\n }\n }\n\n for (const transport of transports) {\n try {\n transport(current);\n } catch (err) {\n warn(`Transport threw an unhandled error${namespaceSuffix()}: ${String(err)}`);\n }\n }\n };\n\n const emit = (type: LogType, first: unknown, second?: unknown, third?: unknown): void => {\n if (isDisposed) return;\n\n if (!passes(type)) return;\n\n const { context, message } = parseArgs(first, second, third);\n // prepareBindings() always allocates a fresh object, so `data` is never an alias of `ownBindings`.\n const data: Bindings = context\n ? { ...prepareBindings(ownBindings), ...prepareBindings(context) }\n : prepareBindings(ownBindings);\n\n dispatch({\n data,\n level: type,\n message,\n namespace,\n timestamp: new Date(),\n });\n };\n\n const timeImpl = <T>(label: string, fn: () => T, level: LogType = 'debug'): T => {\n const start = performance.now();\n\n const done = (thrownErr?: unknown): void => {\n const duration_ms = Math.round((performance.now() - start) * 100) / 100;\n const ctx: Bindings = { duration_ms };\n\n if (thrownErr !== undefined)\n ctx.err = serializeError(thrownErr instanceof Error ? thrownErr : new Error(String(thrownErr)));\n\n emit(level, ctx, label);\n };\n\n try {\n const result = fn();\n\n if (result instanceof Promise) {\n return result.then(\n (v) => {\n done();\n\n return v;\n },\n (err: unknown) => {\n done(err);\n\n return Promise.reject(err) as never;\n },\n ) as T;\n }\n\n done();\n\n return result;\n } catch (err) {\n done(err);\n throw err;\n }\n };\n\n const wrapGroup = <T>(collapsed: boolean, label: string, fn: () => T, level?: LogType): T => {\n if (isDisposed || logLevel === 'off') return fn();\n\n if (level !== undefined && !passes(level)) {\n return fn();\n }\n\n renderGroup(collapsed, label, namespace, DEFAULT_THEME);\n\n try {\n const result = fn();\n\n if (result instanceof Promise) return result.finally(() => console.groupEnd()) as T;\n\n console.groupEnd();\n\n return result;\n } catch (err) {\n console.groupEnd();\n throw err;\n }\n };\n\n const childLogger = (overrides: RuneOptions = {}): Logger =>\n createLogger({\n bindings: { ...ownBindings, ...(overrides.bindings ?? {}) },\n logLevel: overrides.logLevel ?? logLevel,\n middleware: overrides.middleware ?? middleware,\n namespace: overrides.namespace !== undefined ? joinNamespace(namespace, overrides.namespace) : namespace,\n transports: overrides.transports ?? transports,\n });\n\n const logger: Logger = {\n get bindings(): Readonly<Bindings> {\n return { ...ownBindings };\n },\n\n child: childLogger,\n\n debug: (first: unknown, second?: unknown, third?: unknown) => emit('debug', first, second, third),\n\n get disposalSignal(): AbortSignal {\n return disposeController.signal;\n },\n\n dispose: (): void => {\n if (isDisposed) return;\n\n isDisposed = true;\n disposeController.abort();\n },\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n enabled: (type: LogLevel): boolean => isLevelEnabled(logLevel, type),\n\n error: (first: unknown, second?: unknown, third?: unknown) => emit('error', first, second, third),\n\n fatal: (first: unknown, second?: unknown, third?: unknown) => emit('fatal', first, second, third),\n\n group: (label, fn, level) => wrapGroup(false, label, fn, level),\n\n groupCollapsed: (label, fn, level) => wrapGroup(true, label, fn, level),\n\n info: (first: unknown, second?: unknown, third?: unknown) => emit('info', first, second, third),\n\n get logLevel(): LogLevel {\n return logLevel;\n },\n\n get middleware(): readonly LogMiddleware[] {\n return [...middleware];\n },\n\n get namespace(): string {\n return namespace;\n },\n\n [Symbol.dispose](): void {\n logger.dispose();\n },\n\n time: timeImpl,\n\n get transports(): readonly Transport[] {\n return [...transports];\n },\n\n use: (transform: LogMiddleware): Logger => childLogger({ middleware: [...middleware, transform] }),\n\n warn: (first: unknown, second?: unknown, third?: unknown) => emit('warn', first, second, third),\n\n withBindings: (bindings: Bindings): Logger => childLogger({ bindings }),\n };\n\n return logger;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"logger.cjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["import { warn } from './_dev';\nimport { isUnsafeObjectKey } from './_prototype';\nimport { consoleTransport, DEFAULT_THEME, renderGroup } from './console';\nimport { isLazy } from './lazy';\nimport type { Bindings, LogEntry, Logger, LogLevel, LogMiddleware, LogType, RuneOptions, Transport } from './types';\nimport { isLevelEnabled } from './types';\n\n/* --- Arg parsing (simplified) --- */\n\nfunction serializeError(err: Error): { message: string; name: string; stack?: string } {\n return { message: err.message, name: err.name, stack: err.stack };\n}\n\n/**\n * Resolve lazy bindings and serialize Errors in a single pass.\n * Always allocates a fresh object: the result is never an alias of the input.\n */\nfunction prepareBindings(bindings: Bindings): Bindings {\n const out: Bindings = {};\n\n for (const [k, v] of Object.entries(bindings)) {\n // Guard against a `__proto__`/`constructor`/`prototype` field name hijacking out's own\n // prototype via the bracket-assignment accessor: see _prototype.ts.\n if (isUnsafeObjectKey(k)) continue;\n\n const resolved = isLazy(v) ? v.factory() : v;\n\n out[k] = resolved instanceof Error ? serializeError(resolved) : resolved;\n }\n\n return out;\n}\n\ntype ParsedArgs = { context: Bindings | undefined; message: string | undefined };\n\nfunction parseArgs(first: unknown, second?: unknown, third?: unknown): ParsedArgs {\n if (typeof first === 'string') {\n return {\n context: second !== null && typeof second === 'object' ? (second as Bindings) : undefined,\n message: first,\n };\n }\n\n if (first instanceof Error) {\n const context = second !== null && typeof second === 'object' ? (second as Bindings) : {};\n const message = third !== undefined ? String(third) : typeof second === 'string' ? second : undefined;\n\n return { context: { err: serializeError(first), ...context }, message };\n }\n\n if (first !== null && typeof first === 'object') {\n return { context: first as Bindings, message: second !== undefined ? String(second) : undefined };\n }\n\n return { context: undefined, message: first === undefined ? undefined : String(first) };\n}\n\n/* --- Namespace joining --- */\n\n/**\n * Joins parent and child namespaces with '.' as separator.\n * Examples:\n * joinNamespace('api', 'auth') → 'api.auth'\n * joinNamespace('', 'api') → 'api'\n * joinNamespace('api', '') → 'api'\n */\nfunction joinNamespace(parent: string, child: string): string {\n if (!parent) return child;\n\n if (!child) return parent;\n\n return `${parent}.${child}`;\n}\n\n/* --- createLogger --- */\n\n/**\n * Creates an isolated logger instance.\n *\n * Accepts two call signatures:\n * - `createLogger()` / `createLogger(options)`: configure via `RuneOptions`\n * - `createLogger('namespace', options?)`: namespace shorthand + optional options\n *\n * Each instance has its own immutable config (logLevel, transports, middleware).\n * To change the log level at runtime, create a new logger or child.\n */\nexport function createLogger(namespace: string, options?: Omit<RuneOptions, 'namespace'>): Logger;\nexport function createLogger(options?: RuneOptions): Logger;\nexport function createLogger(initial: RuneOptions | string = {}, extra?: Omit<RuneOptions, 'namespace'>): Logger {\n const initialOpts: RuneOptions = typeof initial === 'string' ? { namespace: initial, ...extra } : initial;\n\n const logLevel: LogLevel = initialOpts.logLevel ?? 'debug';\n const middleware: LogMiddleware[] = [...(initialOpts.middleware ?? [])];\n const namespace: string = initialOpts.namespace ?? '';\n const transports = [...(initialOpts.transports ?? [consoleTransport()])];\n const ownBindings: Bindings = { ...(initialOpts.bindings ?? {}) };\n\n const disposeController = new AbortController();\n let isDisposed = false;\n\n const passes = (type: LogType): boolean => isLevelEnabled(logLevel, type);\n const namespaceSuffix = (): string => (namespace ? ` (namespace: \"${namespace}\")` : '');\n\n const dispatch = (entry: LogEntry): void => {\n let current = entry;\n\n for (const transform of middleware) {\n try {\n const next = transform(current);\n\n if (next === null || next === undefined) return;\n\n current = next;\n } catch (err) {\n warn(`Middleware threw and dropped this entry${namespaceSuffix()}: ${String(err)}`);\n return;\n }\n }\n\n for (const transport of transports) {\n try {\n transport(current);\n } catch (err) {\n warn(`Transport threw an unhandled error${namespaceSuffix()}: ${String(err)}`);\n }\n }\n };\n\n const emit = (type: LogType, first: unknown, second?: unknown, third?: unknown): void => {\n if (isDisposed) return;\n\n if (!passes(type)) return;\n\n const { context, message } = parseArgs(first, second, third);\n // prepareBindings() always allocates a fresh object, so `data` is never an alias of `ownBindings`.\n const data: Bindings = context\n ? { ...prepareBindings(ownBindings), ...prepareBindings(context) }\n : prepareBindings(ownBindings);\n\n dispatch({\n data,\n level: type,\n message,\n namespace,\n timestamp: new Date(),\n });\n };\n\n const timeImpl = <T>(label: string, fn: () => T, level: LogType = 'debug'): T => {\n const start = performance.now();\n\n const done = (thrownErr?: unknown): void => {\n const duration_ms = Math.round((performance.now() - start) * 100) / 100;\n const ctx: Bindings = { duration_ms };\n\n if (thrownErr !== undefined)\n ctx.err = serializeError(thrownErr instanceof Error ? thrownErr : new Error(String(thrownErr)));\n\n emit(level, ctx, label);\n };\n\n try {\n const result = fn();\n\n if (result instanceof Promise) {\n return result.then(\n (v) => {\n done();\n\n return v;\n },\n (err: unknown) => {\n done(err);\n\n return Promise.reject(err) as never;\n },\n ) as T;\n }\n\n done();\n\n return result;\n } catch (err) {\n done(err);\n throw err;\n }\n };\n\n const wrapGroup = <T>(collapsed: boolean, label: string, fn: () => T, level?: LogType): T => {\n if (isDisposed || logLevel === 'off') return fn();\n\n if (level !== undefined && !passes(level)) {\n return fn();\n }\n\n renderGroup(collapsed, label, namespace, DEFAULT_THEME);\n\n try {\n const result = fn();\n\n if (result instanceof Promise) return result.finally(() => console.groupEnd()) as T;\n\n console.groupEnd();\n\n return result;\n } catch (err) {\n console.groupEnd();\n throw err;\n }\n };\n\n const childLogger = (overrides: RuneOptions = {}): Logger =>\n createLogger({\n bindings: { ...ownBindings, ...(overrides.bindings ?? {}) },\n logLevel: overrides.logLevel ?? logLevel,\n middleware: overrides.middleware ?? middleware,\n namespace: overrides.namespace !== undefined ? joinNamespace(namespace, overrides.namespace) : namespace,\n transports: overrides.transports ?? transports,\n });\n\n const logger: Logger = {\n get bindings(): Readonly<Bindings> {\n return { ...ownBindings };\n },\n\n child: childLogger,\n\n debug: (first: unknown, second?: unknown, third?: unknown) => emit('debug', first, second, third),\n\n get disposalSignal(): AbortSignal {\n return disposeController.signal;\n },\n\n dispose: (): void => {\n if (isDisposed) return;\n\n isDisposed = true;\n disposeController.abort();\n },\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n enabled: (type: LogLevel): boolean => isLevelEnabled(logLevel, type),\n\n error: (first: unknown, second?: unknown, third?: unknown) => emit('error', first, second, third),\n\n fatal: (first: unknown, second?: unknown, third?: unknown) => emit('fatal', first, second, third),\n\n group: (label, fn, level) => wrapGroup(false, label, fn, level),\n\n groupCollapsed: (label, fn, level) => wrapGroup(true, label, fn, level),\n\n info: (first: unknown, second?: unknown, third?: unknown) => emit('info', first, second, third),\n\n get logLevel(): LogLevel {\n return logLevel;\n },\n\n get middleware(): readonly LogMiddleware[] {\n return [...middleware];\n },\n\n get namespace(): string {\n return namespace;\n },\n\n [Symbol.dispose](): void {\n logger.dispose();\n },\n\n time: timeImpl,\n\n get transports(): readonly Transport[] {\n return [...transports];\n },\n\n use: (transform: LogMiddleware): Logger => childLogger({ middleware: [...middleware, transform] }),\n\n warn: (first: unknown, second?: unknown, third?: unknown) => emit('warn', first, second, third),\n\n withBindings: (bindings: Bindings): Logger => childLogger({ bindings }),\n };\n\n return logger;\n}\n"],"mappings":"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"}
|
package/dist/logger.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import type { Logger, RuneOptions } from './types';
|
|
|
3
3
|
* Creates an isolated logger instance.
|
|
4
4
|
*
|
|
5
5
|
* Accepts two call signatures:
|
|
6
|
-
* - `createLogger()` / `createLogger(options)
|
|
7
|
-
* - `createLogger('namespace', options?)
|
|
6
|
+
* - `createLogger()` / `createLogger(options)`: configure via `RuneOptions`
|
|
7
|
+
* - `createLogger('namespace', options?)`: namespace shorthand + optional options
|
|
8
8
|
*
|
|
9
9
|
* Each instance has its own immutable config (logLevel, transports, middleware).
|
|
10
10
|
* To change the log level at runtime, create a new logger or child.
|
package/dist/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","names":[],"sources":["../src/logger.ts"],"sourcesContent":["import { warn } from './_dev';\nimport { isUnsafeObjectKey } from './_prototype';\nimport { consoleTransport, DEFAULT_THEME, renderGroup } from './console';\nimport { isLazy } from './lazy';\nimport type { Bindings, LogEntry, Logger, LogLevel, LogMiddleware, LogType, RuneOptions, Transport } from './types';\nimport { isLevelEnabled } from './types';\n\n/* --- Arg parsing (simplified) --- */\n\nfunction serializeError(err: Error): { message: string; name: string; stack?: string } {\n return { message: err.message, name: err.name, stack: err.stack };\n}\n\n/**\n * Resolve lazy bindings and serialize Errors in a single pass.\n * Always allocates a fresh object — the result is never an alias of the input.\n */\nfunction prepareBindings(bindings: Bindings): Bindings {\n const out: Bindings = {};\n\n for (const [k, v] of Object.entries(bindings)) {\n // Guard against a `__proto__`/`constructor`/`prototype` field name hijacking out's own\n // prototype via the bracket-assignment accessor — see _prototype.ts.\n if (isUnsafeObjectKey(k)) continue;\n\n const resolved = isLazy(v) ? v.factory() : v;\n\n out[k] = resolved instanceof Error ? serializeError(resolved) : resolved;\n }\n\n return out;\n}\n\ntype ParsedArgs = { context: Bindings | undefined; message: string | undefined };\n\nfunction parseArgs(first: unknown, second?: unknown, third?: unknown): ParsedArgs {\n if (typeof first === 'string') {\n return {\n context: second !== null && typeof second === 'object' ? (second as Bindings) : undefined,\n message: first,\n };\n }\n\n if (first instanceof Error) {\n const context = second !== null && typeof second === 'object' ? (second as Bindings) : {};\n const message = third !== undefined ? String(third) : typeof second === 'string' ? second : undefined;\n\n return { context: { err: serializeError(first), ...context }, message };\n }\n\n if (first !== null && typeof first === 'object') {\n return { context: first as Bindings, message: second !== undefined ? String(second) : undefined };\n }\n\n return { context: undefined, message: first === undefined ? undefined : String(first) };\n}\n\n/* --- Namespace joining --- */\n\n/**\n * Joins parent and child namespaces with '.' as separator.\n * Examples:\n * joinNamespace('api', 'auth') → 'api.auth'\n * joinNamespace('', 'api') → 'api'\n * joinNamespace('api', '') → 'api'\n */\nfunction joinNamespace(parent: string, child: string): string {\n if (!parent) return child;\n\n if (!child) return parent;\n\n return `${parent}.${child}`;\n}\n\n/* --- createLogger --- */\n\n/**\n * Creates an isolated logger instance.\n *\n * Accepts two call signatures:\n * - `createLogger()` / `createLogger(options)` — configure via `RuneOptions`\n * - `createLogger('namespace', options?)` — namespace shorthand + optional options\n *\n * Each instance has its own immutable config (logLevel, transports, middleware).\n * To change the log level at runtime, create a new logger or child.\n */\nexport function createLogger(namespace: string, options?: Omit<RuneOptions, 'namespace'>): Logger;\nexport function createLogger(options?: RuneOptions): Logger;\nexport function createLogger(initial: RuneOptions | string = {}, extra?: Omit<RuneOptions, 'namespace'>): Logger {\n const initialOpts: RuneOptions = typeof initial === 'string' ? { namespace: initial, ...extra } : initial;\n\n const logLevel: LogLevel = initialOpts.logLevel ?? 'debug';\n const middleware: LogMiddleware[] = [...(initialOpts.middleware ?? [])];\n const namespace: string = initialOpts.namespace ?? '';\n const transports = [...(initialOpts.transports ?? [consoleTransport()])];\n const ownBindings: Bindings = { ...(initialOpts.bindings ?? {}) };\n\n const disposeController = new AbortController();\n let isDisposed = false;\n\n const passes = (type: LogType): boolean => isLevelEnabled(logLevel, type);\n const namespaceSuffix = (): string => (namespace ? ` (namespace: \"${namespace}\")` : '');\n\n const dispatch = (entry: LogEntry): void => {\n let current = entry;\n\n for (const transform of middleware) {\n try {\n const next = transform(current);\n\n if (next === null || next === undefined) return;\n\n current = next;\n } catch (err) {\n warn(`Middleware threw and dropped this entry${namespaceSuffix()}: ${String(err)}`);\n return;\n }\n }\n\n for (const transport of transports) {\n try {\n transport(current);\n } catch (err) {\n warn(`Transport threw an unhandled error${namespaceSuffix()}: ${String(err)}`);\n }\n }\n };\n\n const emit = (type: LogType, first: unknown, second?: unknown, third?: unknown): void => {\n if (isDisposed) return;\n\n if (!passes(type)) return;\n\n const { context, message } = parseArgs(first, second, third);\n // prepareBindings() always allocates a fresh object, so `data` is never an alias of `ownBindings`.\n const data: Bindings = context\n ? { ...prepareBindings(ownBindings), ...prepareBindings(context) }\n : prepareBindings(ownBindings);\n\n dispatch({\n data,\n level: type,\n message,\n namespace,\n timestamp: new Date(),\n });\n };\n\n const timeImpl = <T>(label: string, fn: () => T, level: LogType = 'debug'): T => {\n const start = performance.now();\n\n const done = (thrownErr?: unknown): void => {\n const duration_ms = Math.round((performance.now() - start) * 100) / 100;\n const ctx: Bindings = { duration_ms };\n\n if (thrownErr !== undefined)\n ctx.err = serializeError(thrownErr instanceof Error ? thrownErr : new Error(String(thrownErr)));\n\n emit(level, ctx, label);\n };\n\n try {\n const result = fn();\n\n if (result instanceof Promise) {\n return result.then(\n (v) => {\n done();\n\n return v;\n },\n (err: unknown) => {\n done(err);\n\n return Promise.reject(err) as never;\n },\n ) as T;\n }\n\n done();\n\n return result;\n } catch (err) {\n done(err);\n throw err;\n }\n };\n\n const wrapGroup = <T>(collapsed: boolean, label: string, fn: () => T, level?: LogType): T => {\n if (isDisposed || logLevel === 'off') return fn();\n\n if (level !== undefined && !passes(level)) {\n return fn();\n }\n\n renderGroup(collapsed, label, namespace, DEFAULT_THEME);\n\n try {\n const result = fn();\n\n if (result instanceof Promise) return result.finally(() => console.groupEnd()) as T;\n\n console.groupEnd();\n\n return result;\n } catch (err) {\n console.groupEnd();\n throw err;\n }\n };\n\n const childLogger = (overrides: RuneOptions = {}): Logger =>\n createLogger({\n bindings: { ...ownBindings, ...(overrides.bindings ?? {}) },\n logLevel: overrides.logLevel ?? logLevel,\n middleware: overrides.middleware ?? middleware,\n namespace: overrides.namespace !== undefined ? joinNamespace(namespace, overrides.namespace) : namespace,\n transports: overrides.transports ?? transports,\n });\n\n const logger: Logger = {\n get bindings(): Readonly<Bindings> {\n return { ...ownBindings };\n },\n\n child: childLogger,\n\n debug: (first: unknown, second?: unknown, third?: unknown) => emit('debug', first, second, third),\n\n get disposalSignal(): AbortSignal {\n return disposeController.signal;\n },\n\n dispose: (): void => {\n if (isDisposed) return;\n\n isDisposed = true;\n disposeController.abort();\n },\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n enabled: (type: LogLevel): boolean => isLevelEnabled(logLevel, type),\n\n error: (first: unknown, second?: unknown, third?: unknown) => emit('error', first, second, third),\n\n fatal: (first: unknown, second?: unknown, third?: unknown) => emit('fatal', first, second, third),\n\n group: (label, fn, level) => wrapGroup(false, label, fn, level),\n\n groupCollapsed: (label, fn, level) => wrapGroup(true, label, fn, level),\n\n info: (first: unknown, second?: unknown, third?: unknown) => emit('info', first, second, third),\n\n get logLevel(): LogLevel {\n return logLevel;\n },\n\n get middleware(): readonly LogMiddleware[] {\n return [...middleware];\n },\n\n get namespace(): string {\n return namespace;\n },\n\n [Symbol.dispose](): void {\n logger.dispose();\n },\n\n time: timeImpl,\n\n get transports(): readonly Transport[] {\n return [...transports];\n },\n\n use: (transform: LogMiddleware): Logger => childLogger({ middleware: [...middleware, transform] }),\n\n warn: (first: unknown, second?: unknown, third?: unknown) => emit('warn', first, second, third),\n\n withBindings: (bindings: Bindings): Logger => childLogger({ bindings }),\n };\n\n return logger;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"logger.js","names":[],"sources":["../src/logger.ts"],"sourcesContent":["import { warn } from './_dev';\nimport { isUnsafeObjectKey } from './_prototype';\nimport { consoleTransport, DEFAULT_THEME, renderGroup } from './console';\nimport { isLazy } from './lazy';\nimport type { Bindings, LogEntry, Logger, LogLevel, LogMiddleware, LogType, RuneOptions, Transport } from './types';\nimport { isLevelEnabled } from './types';\n\n/* --- Arg parsing (simplified) --- */\n\nfunction serializeError(err: Error): { message: string; name: string; stack?: string } {\n return { message: err.message, name: err.name, stack: err.stack };\n}\n\n/**\n * Resolve lazy bindings and serialize Errors in a single pass.\n * Always allocates a fresh object: the result is never an alias of the input.\n */\nfunction prepareBindings(bindings: Bindings): Bindings {\n const out: Bindings = {};\n\n for (const [k, v] of Object.entries(bindings)) {\n // Guard against a `__proto__`/`constructor`/`prototype` field name hijacking out's own\n // prototype via the bracket-assignment accessor: see _prototype.ts.\n if (isUnsafeObjectKey(k)) continue;\n\n const resolved = isLazy(v) ? v.factory() : v;\n\n out[k] = resolved instanceof Error ? serializeError(resolved) : resolved;\n }\n\n return out;\n}\n\ntype ParsedArgs = { context: Bindings | undefined; message: string | undefined };\n\nfunction parseArgs(first: unknown, second?: unknown, third?: unknown): ParsedArgs {\n if (typeof first === 'string') {\n return {\n context: second !== null && typeof second === 'object' ? (second as Bindings) : undefined,\n message: first,\n };\n }\n\n if (first instanceof Error) {\n const context = second !== null && typeof second === 'object' ? (second as Bindings) : {};\n const message = third !== undefined ? String(third) : typeof second === 'string' ? second : undefined;\n\n return { context: { err: serializeError(first), ...context }, message };\n }\n\n if (first !== null && typeof first === 'object') {\n return { context: first as Bindings, message: second !== undefined ? String(second) : undefined };\n }\n\n return { context: undefined, message: first === undefined ? undefined : String(first) };\n}\n\n/* --- Namespace joining --- */\n\n/**\n * Joins parent and child namespaces with '.' as separator.\n * Examples:\n * joinNamespace('api', 'auth') → 'api.auth'\n * joinNamespace('', 'api') → 'api'\n * joinNamespace('api', '') → 'api'\n */\nfunction joinNamespace(parent: string, child: string): string {\n if (!parent) return child;\n\n if (!child) return parent;\n\n return `${parent}.${child}`;\n}\n\n/* --- createLogger --- */\n\n/**\n * Creates an isolated logger instance.\n *\n * Accepts two call signatures:\n * - `createLogger()` / `createLogger(options)`: configure via `RuneOptions`\n * - `createLogger('namespace', options?)`: namespace shorthand + optional options\n *\n * Each instance has its own immutable config (logLevel, transports, middleware).\n * To change the log level at runtime, create a new logger or child.\n */\nexport function createLogger(namespace: string, options?: Omit<RuneOptions, 'namespace'>): Logger;\nexport function createLogger(options?: RuneOptions): Logger;\nexport function createLogger(initial: RuneOptions | string = {}, extra?: Omit<RuneOptions, 'namespace'>): Logger {\n const initialOpts: RuneOptions = typeof initial === 'string' ? { namespace: initial, ...extra } : initial;\n\n const logLevel: LogLevel = initialOpts.logLevel ?? 'debug';\n const middleware: LogMiddleware[] = [...(initialOpts.middleware ?? [])];\n const namespace: string = initialOpts.namespace ?? '';\n const transports = [...(initialOpts.transports ?? [consoleTransport()])];\n const ownBindings: Bindings = { ...(initialOpts.bindings ?? {}) };\n\n const disposeController = new AbortController();\n let isDisposed = false;\n\n const passes = (type: LogType): boolean => isLevelEnabled(logLevel, type);\n const namespaceSuffix = (): string => (namespace ? ` (namespace: \"${namespace}\")` : '');\n\n const dispatch = (entry: LogEntry): void => {\n let current = entry;\n\n for (const transform of middleware) {\n try {\n const next = transform(current);\n\n if (next === null || next === undefined) return;\n\n current = next;\n } catch (err) {\n warn(`Middleware threw and dropped this entry${namespaceSuffix()}: ${String(err)}`);\n return;\n }\n }\n\n for (const transport of transports) {\n try {\n transport(current);\n } catch (err) {\n warn(`Transport threw an unhandled error${namespaceSuffix()}: ${String(err)}`);\n }\n }\n };\n\n const emit = (type: LogType, first: unknown, second?: unknown, third?: unknown): void => {\n if (isDisposed) return;\n\n if (!passes(type)) return;\n\n const { context, message } = parseArgs(first, second, third);\n // prepareBindings() always allocates a fresh object, so `data` is never an alias of `ownBindings`.\n const data: Bindings = context\n ? { ...prepareBindings(ownBindings), ...prepareBindings(context) }\n : prepareBindings(ownBindings);\n\n dispatch({\n data,\n level: type,\n message,\n namespace,\n timestamp: new Date(),\n });\n };\n\n const timeImpl = <T>(label: string, fn: () => T, level: LogType = 'debug'): T => {\n const start = performance.now();\n\n const done = (thrownErr?: unknown): void => {\n const duration_ms = Math.round((performance.now() - start) * 100) / 100;\n const ctx: Bindings = { duration_ms };\n\n if (thrownErr !== undefined)\n ctx.err = serializeError(thrownErr instanceof Error ? thrownErr : new Error(String(thrownErr)));\n\n emit(level, ctx, label);\n };\n\n try {\n const result = fn();\n\n if (result instanceof Promise) {\n return result.then(\n (v) => {\n done();\n\n return v;\n },\n (err: unknown) => {\n done(err);\n\n return Promise.reject(err) as never;\n },\n ) as T;\n }\n\n done();\n\n return result;\n } catch (err) {\n done(err);\n throw err;\n }\n };\n\n const wrapGroup = <T>(collapsed: boolean, label: string, fn: () => T, level?: LogType): T => {\n if (isDisposed || logLevel === 'off') return fn();\n\n if (level !== undefined && !passes(level)) {\n return fn();\n }\n\n renderGroup(collapsed, label, namespace, DEFAULT_THEME);\n\n try {\n const result = fn();\n\n if (result instanceof Promise) return result.finally(() => console.groupEnd()) as T;\n\n console.groupEnd();\n\n return result;\n } catch (err) {\n console.groupEnd();\n throw err;\n }\n };\n\n const childLogger = (overrides: RuneOptions = {}): Logger =>\n createLogger({\n bindings: { ...ownBindings, ...(overrides.bindings ?? {}) },\n logLevel: overrides.logLevel ?? logLevel,\n middleware: overrides.middleware ?? middleware,\n namespace: overrides.namespace !== undefined ? joinNamespace(namespace, overrides.namespace) : namespace,\n transports: overrides.transports ?? transports,\n });\n\n const logger: Logger = {\n get bindings(): Readonly<Bindings> {\n return { ...ownBindings };\n },\n\n child: childLogger,\n\n debug: (first: unknown, second?: unknown, third?: unknown) => emit('debug', first, second, third),\n\n get disposalSignal(): AbortSignal {\n return disposeController.signal;\n },\n\n dispose: (): void => {\n if (isDisposed) return;\n\n isDisposed = true;\n disposeController.abort();\n },\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n enabled: (type: LogLevel): boolean => isLevelEnabled(logLevel, type),\n\n error: (first: unknown, second?: unknown, third?: unknown) => emit('error', first, second, third),\n\n fatal: (first: unknown, second?: unknown, third?: unknown) => emit('fatal', first, second, third),\n\n group: (label, fn, level) => wrapGroup(false, label, fn, level),\n\n groupCollapsed: (label, fn, level) => wrapGroup(true, label, fn, level),\n\n info: (first: unknown, second?: unknown, third?: unknown) => emit('info', first, second, third),\n\n get logLevel(): LogLevel {\n return logLevel;\n },\n\n get middleware(): readonly LogMiddleware[] {\n return [...middleware];\n },\n\n get namespace(): string {\n return namespace;\n },\n\n [Symbol.dispose](): void {\n logger.dispose();\n },\n\n time: timeImpl,\n\n get transports(): readonly Transport[] {\n return [...transports];\n },\n\n use: (transform: LogMiddleware): Logger => childLogger({ middleware: [...middleware, transform] }),\n\n warn: (first: unknown, second?: unknown, third?: unknown) => emit('warn', first, second, third),\n\n withBindings: (bindings: Bindings): Logger => childLogger({ bindings }),\n };\n\n return logger;\n}\n"],"mappings":"yOASA,SAAS,eAAe,EAA+D,CACrF,MAAO,CAAE,QAAS,EAAI,QAAS,KAAM,EAAI,KAAM,MAAO,EAAI,KAAM,CAClE,CAMA,SAAS,gBAAgB,EAA8B,CACrD,IAAM,EAAgB,CAAC,EAEvB,IAAK,GAAM,CAAC,EAAG,KAAM,OAAO,QAAQ,CAAQ,EAAG,CAG7C,GAAI,EAAkB,CAAC,EAAG,SAE1B,IAAM,EAAW,EAAO,CAAC,EAAI,EAAE,QAAQ,EAAI,EAE3C,EAAI,GAAK,aAAoB,MAAQ,eAAe,CAAQ,EAAI,CAClE,CAEA,OAAO,CACT,CAIA,SAAS,UAAU,EAAgB,EAAkB,EAA6B,CAChF,GAAI,OAAO,GAAU,SACnB,MAAO,CACL,QAA4B,OAAO,GAAW,UAArC,EAAiD,EAAsB,IAAA,GAChF,QAAS,CACX,EAGF,GAAI,aAAiB,MAAO,CAC1B,IAAM,EAA6B,OAAO,GAAW,UAArC,EAAiD,EAAsB,CAAC,EAClF,EAAU,IAAU,IAAA,GAA4B,OAAO,GAAW,SAAW,EAAS,IAAA,GAAtD,OAAO,CAAK,EAElD,MAAO,CAAE,QAAS,CAAE,IAAK,eAAe,CAAK,EAAG,GAAG,CAAQ,EAAG,SAAQ,CACxE,CAMA,OAJsB,OAAO,GAAU,UAAnC,EACK,CAAE,QAAS,EAAmB,QAAS,IAAW,IAAA,GAA6B,IAAA,GAAjB,OAAO,CAAM,CAAc,EAG3F,CAAE,QAAS,IAAA,GAAW,QAAS,IAAU,IAAA,GAAY,IAAA,GAAY,OAAO,CAAK,CAAE,CACxF,CAWA,SAAS,cAAc,EAAgB,EAAuB,CAK5D,OAJK,EAEA,EAEE,GAAG,EAAO,GAAG,IAFD,EAFC,CAKtB,CAgBA,SAAgB,aAAa,EAAgC,CAAC,EAAG,EAAgD,CAC/G,IAAM,EAA2B,OAAO,GAAY,SAAW,CAAE,UAAW,EAAS,GAAG,CAAM,EAAI,EAE5F,EAAqB,EAAY,UAAY,QAC7C,EAA8B,CAAC,GAAI,EAAY,YAAc,CAAC,CAAE,EAChE,EAAoB,EAAY,WAAa,GAC7C,EAAa,CAAC,GAAI,EAAY,YAAc,CAAC,EAAiB,CAAC,CAAE,EACjE,EAAwB,CAAE,GAAI,EAAY,UAAY,CAAC,CAAG,EAE1D,EAAoB,IAAI,gBAC1B,EAAa,GAEX,OAAU,GAA2B,EAAe,EAAU,CAAI,EAClE,oBAAiC,EAAY,iBAAiB,EAAU,IAAM,GAE9E,SAAY,GAA0B,CAC1C,IAAI,EAAU,EAEd,IAAK,IAAM,KAAa,EACtB,GAAI,CACF,IAAM,EAAO,EAAU,CAAO,EAE9B,GAAI,GAAS,KAA4B,OAEzC,EAAU,CACZ,OAAS,EAAK,CACP,GAA0C,gBAAgB,EAA1D,EAAgE,OAAO,CAAG,EAA1E,EACL,MACF,CAGF,IAAK,IAAM,KAAa,EACtB,GAAI,CACF,EAAU,CAAO,CACnB,OAAS,EAAK,CACP,GAAqC,gBAAgB,EAArD,EAA2D,OAAO,CAAG,EAArE,CACP,CAEJ,EAEM,MAAQ,EAAe,EAAgB,EAAkB,IAA0B,CAGvF,GAFI,GAEA,CAAC,OAAO,CAAI,EAAG,OAEnB,GAAM,CAAE,UAAS,WAAY,UAAU,EAAO,EAAQ,CAAK,EAErD,EAAiB,EACnB,CAAE,GAAG,gBAAgB,CAAW,EAAG,GAAG,gBAAgB,CAAO,CAAE,EAC/D,gBAAgB,CAAW,EAE/B,SAAS,CACP,OACA,MAAO,EACP,UACA,YACA,UAAW,IAAI,IACjB,CAAC,CACH,EAEM,UAAe,EAAe,EAAa,EAAiB,UAAe,CAC/E,IAAM,EAAQ,YAAY,IAAI,EAExB,KAAQ,GAA8B,CAE1C,IAAM,EAAgB,CAAE,YADJ,KAAK,OAAO,YAAY,IAAI,EAAI,GAAS,GAAG,EAAI,GAChC,EAEhC,IAAc,IAAA,KAChB,EAAI,IAAM,eAAe,aAAqB,MAAQ,EAAgB,MAAM,OAAO,CAAS,CAAC,CAAC,GAEhG,KAAK,EAAO,EAAK,CAAK,CACxB,EAEA,GAAI,CACF,IAAM,EAAS,EAAG,EAmBlB,OAjBI,aAAkB,QACb,EAAO,KACX,IACC,KAAK,EAEE,GAER,IACC,KAAK,CAAG,EAED,QAAQ,OAAO,CAAG,EAE7B,GAGF,KAAK,EAEE,EACT,OAAS,EAAK,CAEZ,MADA,KAAK,CAAG,EACF,CACR,CACF,EAEM,WAAgB,EAAoB,EAAe,EAAa,IAAuB,CAG3F,GAFI,GAAc,IAAa,OAE3B,IAAU,IAAA,IAAa,CAAC,OAAO,CAAK,EACtC,OAAO,EAAG,EAGZ,EAAY,EAAW,EAAO,EAAW,CAAa,EAEtD,GAAI,CACF,IAAM,EAAS,EAAG,EAMlB,OAJI,aAAkB,QAAgB,EAAO,YAAc,QAAQ,SAAS,CAAC,GAE7E,QAAQ,SAAS,EAEV,EACT,OAAS,EAAK,CAEZ,MADA,QAAQ,SAAS,EACX,CACR,CACF,EAEM,aAAe,EAAyB,CAAC,IAC7C,aAAa,CACX,SAAU,CAAE,GAAG,EAAa,GAAI,EAAU,UAAY,CAAC,CAAG,EAC1D,SAAU,EAAU,UAAY,EAChC,WAAY,EAAU,YAAc,EACpC,UAAW,EAAU,YAAc,IAAA,GAA4D,EAAhD,cAAc,EAAW,EAAU,SAAS,EAC3F,WAAY,EAAU,YAAc,CACtC,CAAC,EAEG,EAAiB,CACrB,IAAI,UAA+B,CACjC,MAAO,CAAE,GAAG,CAAY,CAC1B,EAEA,MAAO,YAEP,OAAQ,EAAgB,EAAkB,IAAoB,KAAK,QAAS,EAAO,EAAQ,CAAK,EAEhG,IAAI,gBAA8B,CAChC,OAAO,EAAkB,MAC3B,EAEA,YAAqB,CACf,IAEJ,EAAa,GACb,EAAkB,MAAM,EAC1B,EAEA,IAAI,UAAoB,CACtB,OAAO,CACT,EAEA,QAAU,GAA4B,EAAe,EAAU,CAAI,EAEnE,OAAQ,EAAgB,EAAkB,IAAoB,KAAK,QAAS,EAAO,EAAQ,CAAK,EAEhG,OAAQ,EAAgB,EAAkB,IAAoB,KAAK,QAAS,EAAO,EAAQ,CAAK,EAEhG,OAAQ,EAAO,EAAI,IAAU,UAAU,GAAO,EAAO,EAAI,CAAK,EAE9D,gBAAiB,EAAO,EAAI,IAAU,UAAU,GAAM,EAAO,EAAI,CAAK,EAEtE,MAAO,EAAgB,EAAkB,IAAoB,KAAK,OAAQ,EAAO,EAAQ,CAAK,EAE9F,IAAI,UAAqB,CACvB,OAAO,CACT,EAEA,IAAI,YAAuC,CACzC,MAAO,CAAC,GAAG,CAAU,CACvB,EAEA,IAAI,WAAoB,CACtB,OAAO,CACT,EAEA,CAAC,OAAO,UAAiB,CACvB,EAAO,QAAQ,CACjB,EAEA,KAAM,SAEN,IAAI,YAAmC,CACrC,MAAO,CAAC,GAAG,CAAU,CACvB,EAEA,IAAM,GAAqC,YAAY,CAAE,WAAY,CAAC,GAAG,EAAY,CAAS,CAAE,CAAC,EAEjG,MAAO,EAAgB,EAAkB,IAAoB,KAAK,OAAQ,EAAO,EAAQ,CAAK,EAE9F,aAAe,GAA+B,YAAY,CAAE,UAAS,CAAC,CACxE,EAEA,OAAO,CACT"}
|