@loglayer/shared
Advanced tools
+176
-1
@@ -36,4 +36,179 @@ | ||
| //#endregion | ||
| //#region src/lazy.ts | ||
| /** | ||
| * Symbol used to identify lazy values in context and metadata. | ||
| * Can be used to check if a value is a lazy wrapper: `LAZY_SYMBOL in value`. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} | ||
| */ | ||
| const LAZY_SYMBOL = Symbol.for("loglayer.lazy"); | ||
| /** | ||
| * String constant used as a replacement value when a lazy callback fails during evaluation. | ||
| * Exported so users can programmatically detect lazy evaluation failures in their log output. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation#error-handling | Lazy Evaluation Error Handling Docs} | ||
| */ | ||
| const LAZY_EVAL_ERROR = "[LazyEvalError]"; | ||
| /** | ||
| * Wraps a callback function to defer its evaluation until log time. | ||
| * | ||
| * The callback will only be invoked if the log level is enabled, | ||
| * avoiding unnecessary computation for disabled log levels. | ||
| * | ||
| * Can be used in both `withContext()` and `withMetadata()` at the root level. | ||
| * | ||
| * When the callback returns a `Promise` (i.e., is an async function), the | ||
| * log method will return `Promise<void>` so TypeScript can track that the | ||
| * operation is asynchronous. | ||
| * | ||
| * Adapted from [LogTape's lazy evaluation](https://logtape.org/manual/lazy). | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * import { LogLayer, lazy } from "loglayer"; | ||
| * | ||
| * const log = new LogLayer({ ... }); | ||
| * | ||
| * // Dynamic context - evaluated on each log call | ||
| * log.withContext({ | ||
| * memoryUsage: lazy(() => process.memoryUsage().heapUsed), | ||
| * }); | ||
| * | ||
| * // Dynamic metadata - evaluated only if debug is enabled | ||
| * log.withMetadata({ | ||
| * data: lazy(() => JSON.stringify(largeObject)), | ||
| * }).debug("Processing complete"); | ||
| * ``` | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} | ||
| */ | ||
| function lazy(fn) { | ||
| return { [LAZY_SYMBOL]: fn }; | ||
| } | ||
| /** | ||
| * Checks if a value is a lazy value created by {@link lazy}. | ||
| * @internal | ||
| */ | ||
| function isLazy(value) { | ||
| return value != null && typeof value === "object" && LAZY_SYMBOL in value; | ||
| } | ||
| /** | ||
| * Counts the number of lazy values in a record. | ||
| * @internal | ||
| */ | ||
| function countLazyValues(obj) { | ||
| let count = 0; | ||
| for (const key of Object.keys(obj)) if (isLazy(obj[key])) count++; | ||
| return count; | ||
| } | ||
| /** | ||
| * Resolves any lazy values in a record at the root level. | ||
| * Returns the original object if no lazy values are found (optimization). | ||
| * If a lazy callback throws, the value is replaced with LAZY_EVAL_ERROR | ||
| * and the error is collected in the result. | ||
| * @internal | ||
| */ | ||
| function resolveLazyValues(obj) { | ||
| let hasLazy = false; | ||
| for (const key of Object.keys(obj)) if (isLazy(obj[key])) { | ||
| hasLazy = true; | ||
| break; | ||
| } | ||
| if (!hasLazy) return { | ||
| resolved: obj, | ||
| errors: null | ||
| }; | ||
| const result = {}; | ||
| let errors = null; | ||
| for (const key of Object.keys(obj)) { | ||
| const value = obj[key]; | ||
| if (isLazy(value)) try { | ||
| result[key] = value[LAZY_SYMBOL](); | ||
| } catch (e) { | ||
| result[key] = LAZY_EVAL_ERROR; | ||
| if (!errors) errors = []; | ||
| errors.push({ | ||
| key, | ||
| error: e | ||
| }); | ||
| } | ||
| else result[key] = value; | ||
| } | ||
| return { | ||
| resolved: result, | ||
| errors | ||
| }; | ||
| } | ||
| /** | ||
| * Checks if any values in a record are Promises. | ||
| * @internal | ||
| */ | ||
| function hasPromiseValues(obj) { | ||
| for (const key of Object.keys(obj)) if (obj[key] instanceof Promise) return true; | ||
| return false; | ||
| } | ||
| /** | ||
| * Replaces any Promise values in a record with LAZY_EVAL_ERROR. | ||
| * Used to strip async lazy values from context where only sync lazy is supported. | ||
| * Returns the keys that were replaced. | ||
| * @internal | ||
| */ | ||
| function replacePromiseValues(obj) { | ||
| let asyncKeys = null; | ||
| const result = {}; | ||
| for (const key of Object.keys(obj)) if (obj[key] instanceof Promise) { | ||
| result[key] = LAZY_EVAL_ERROR; | ||
| if (!asyncKeys) asyncKeys = []; | ||
| asyncKeys.push(key); | ||
| } else result[key] = obj[key]; | ||
| if (!asyncKeys) return { | ||
| resolved: obj, | ||
| asyncKeys: null | ||
| }; | ||
| return { | ||
| resolved: result, | ||
| asyncKeys | ||
| }; | ||
| } | ||
| /** | ||
| * Resolves any Promise values in a record using Promise.allSettled. | ||
| * If a Promise rejects, the value is replaced with LAZY_EVAL_ERROR | ||
| * and the error is collected in the result. | ||
| * @internal | ||
| */ | ||
| async function resolvePromiseValues(obj) { | ||
| const keys = Object.keys(obj); | ||
| const settled = await Promise.allSettled(keys.map((key) => Promise.resolve(obj[key]))); | ||
| const result = {}; | ||
| let errors = null; | ||
| for (let i = 0; i < keys.length; i++) { | ||
| const s = settled[i]; | ||
| if (s.status === "fulfilled") result[keys[i]] = s.value; | ||
| else { | ||
| result[keys[i]] = LAZY_EVAL_ERROR; | ||
| if (!errors) errors = []; | ||
| errors.push({ | ||
| key: keys[i], | ||
| error: s.reason | ||
| }); | ||
| } | ||
| } | ||
| return { | ||
| resolved: result, | ||
| errors | ||
| }; | ||
| } | ||
| //#endregion | ||
| exports.LAZY_EVAL_ERROR = LAZY_EVAL_ERROR; | ||
| exports.LAZY_SYMBOL = LAZY_SYMBOL; | ||
| exports.LogLevel = LogLevel; | ||
| exports.LogLevelPriority = LogLevelPriority; | ||
| exports.LogLevelPriorityToNames = LogLevelPriorityToNames; | ||
| exports.LogLevelPriorityToNames = LogLevelPriorityToNames; | ||
| exports.countLazyValues = countLazyValues; | ||
| exports.hasPromiseValues = hasPromiseValues; | ||
| exports.isLazy = isLazy; | ||
| exports.lazy = lazy; | ||
| exports.replacePromiseValues = replacePromiseValues; | ||
| exports.resolveLazyValues = resolveLazyValues; | ||
| exports.resolvePromiseValues = resolvePromiseValues; |
+181
-39
@@ -0,1 +1,120 @@ | ||
| //#region src/lazy.d.ts | ||
| /** | ||
| * Symbol used to identify lazy values in context and metadata. | ||
| * Can be used to check if a value is a lazy wrapper: `LAZY_SYMBOL in value`. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} | ||
| */ | ||
| declare const LAZY_SYMBOL: unique symbol; | ||
| /** | ||
| * String constant used as a replacement value when a lazy callback fails during evaluation. | ||
| * Exported so users can programmatically detect lazy evaluation failures in their log output. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation#error-handling | Lazy Evaluation Error Handling Docs} | ||
| */ | ||
| declare const LAZY_EVAL_ERROR = "[LazyEvalError]"; | ||
| /** | ||
| * Describes a single lazy evaluation failure. | ||
| * @internal | ||
| */ | ||
| interface LazyEvalFailure { | ||
| key: string; | ||
| error: unknown; | ||
| } | ||
| /** | ||
| * Result of resolving lazy values, including any errors that occurred. | ||
| * @internal | ||
| */ | ||
| interface ResolveLazyResult<T> { | ||
| resolved: T; | ||
| errors: LazyEvalFailure[] | null; | ||
| } | ||
| /** | ||
| * Represents a lazy value that defers evaluation until log time. | ||
| * | ||
| * Created by the {@link lazy} function. | ||
| * | ||
| * When the type parameter `T` is a `Promise`, log methods that receive this | ||
| * lazy value in metadata will return `Promise<void>` instead of `void`. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} | ||
| */ | ||
| interface LazyLogValue<T = any> { | ||
| [LAZY_SYMBOL]: () => T; | ||
| } | ||
| /** | ||
| * Wraps a callback function to defer its evaluation until log time. | ||
| * | ||
| * The callback will only be invoked if the log level is enabled, | ||
| * avoiding unnecessary computation for disabled log levels. | ||
| * | ||
| * Can be used in both `withContext()` and `withMetadata()` at the root level. | ||
| * | ||
| * When the callback returns a `Promise` (i.e., is an async function), the | ||
| * log method will return `Promise<void>` so TypeScript can track that the | ||
| * operation is asynchronous. | ||
| * | ||
| * Adapted from [LogTape's lazy evaluation](https://logtape.org/manual/lazy). | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * import { LogLayer, lazy } from "loglayer"; | ||
| * | ||
| * const log = new LogLayer({ ... }); | ||
| * | ||
| * // Dynamic context - evaluated on each log call | ||
| * log.withContext({ | ||
| * memoryUsage: lazy(() => process.memoryUsage().heapUsed), | ||
| * }); | ||
| * | ||
| * // Dynamic metadata - evaluated only if debug is enabled | ||
| * log.withMetadata({ | ||
| * data: lazy(() => JSON.stringify(largeObject)), | ||
| * }).debug("Processing complete"); | ||
| * ``` | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} | ||
| */ | ||
| declare function lazy<T>(fn: () => T): LazyLogValue<T>; | ||
| /** | ||
| * Checks if a value is a lazy value created by {@link lazy}. | ||
| * @internal | ||
| */ | ||
| declare function isLazy(value: unknown): value is LazyLogValue; | ||
| /** | ||
| * Counts the number of lazy values in a record. | ||
| * @internal | ||
| */ | ||
| declare function countLazyValues(obj: Record<string, any>): number; | ||
| /** | ||
| * Resolves any lazy values in a record at the root level. | ||
| * Returns the original object if no lazy values are found (optimization). | ||
| * If a lazy callback throws, the value is replaced with LAZY_EVAL_ERROR | ||
| * and the error is collected in the result. | ||
| * @internal | ||
| */ | ||
| declare function resolveLazyValues<T extends Record<string, any>>(obj: T): ResolveLazyResult<T>; | ||
| /** | ||
| * Checks if any values in a record are Promises. | ||
| * @internal | ||
| */ | ||
| declare function hasPromiseValues(obj: Record<string, any>): boolean; | ||
| /** | ||
| * Replaces any Promise values in a record with LAZY_EVAL_ERROR. | ||
| * Used to strip async lazy values from context where only sync lazy is supported. | ||
| * Returns the keys that were replaced. | ||
| * @internal | ||
| */ | ||
| declare function replacePromiseValues<T extends Record<string, any>>(obj: T): { | ||
| resolved: T; | ||
| asyncKeys: string[] | null; | ||
| }; | ||
| /** | ||
| * Resolves any Promise values in a record using Promise.allSettled. | ||
| * If a Promise rejects, the value is replaced with LAZY_EVAL_ERROR | ||
| * and the error is collected in the result. | ||
| * @internal | ||
| */ | ||
| declare function resolvePromiseValues<T extends Record<string, any>>(obj: T): Promise<ResolveLazyResult<T>>; | ||
| //#endregion | ||
| //#region src/common.types.d.ts | ||
@@ -38,3 +157,3 @@ declare enum LogLevel { | ||
| */ | ||
| logLevel?: LogLevel; | ||
| logLevel?: LogLevelType; | ||
| /** | ||
@@ -63,2 +182,21 @@ * If `true`, copies the `error.message` if available to the transport library's | ||
| interface LogLayerData extends Record<string, any> {} | ||
| /** | ||
| * Type-level helper that checks whether a metadata/context record type | ||
| * contains any {@link LazyLogValue} whose callback returns a `Promise`. | ||
| * | ||
| * Evaluates to `true` if any property is `LazyLogValue<Promise<any>>`, | ||
| * `false` otherwise. Returns `false` for `undefined` or `null` inputs. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} | ||
| */ | ||
| type ContainsAsyncLazy<M> = M extends undefined | null ? false : true extends { [K in keyof M]: M[K] extends LazyLogValue<infer T> ? (T extends Promise<any> ? true : false) : false }[keyof M] ? true : false; | ||
| /** | ||
| * Helper type that resolves the return type of log methods based on whether | ||
| * async lazy values are present. | ||
| * | ||
| * - `true` → `Promise<void>` (async lazy values detected) | ||
| * - `false` → `void` (no async lazy values) | ||
| * - `boolean` → `void | Promise<void>` (indeterminate, used by implementation classes) | ||
| */ | ||
| type LogReturnType<IsAsync extends boolean> = IsAsync extends true ? Promise<void> : IsAsync extends false ? void : void | Promise<void>; | ||
| interface LogLayerCommonDataParams { | ||
@@ -477,41 +615,48 @@ /** | ||
| * Interface for implementing a LogLayer builder instance. | ||
| * | ||
| * @typeParam This - The concrete builder type for polymorphic chaining. | ||
| * @typeParam IsAsync - Whether the builder contains async lazy metadata. | ||
| * When `true`, log methods return `Promise<void>`. When `false`, they return `void`. | ||
| * When `boolean` (indeterminate), they return `void | Promise<void>`. | ||
| * | ||
| * @see {@link https://loglayer.dev | LogLayer Documentation} | ||
| */ | ||
| interface ILogBuilder<This = ILogBuilder<any>> { | ||
| interface ILogBuilder<This = ILogBuilder<any, any>, IsAsync extends boolean = false> { | ||
| /** | ||
| * Sends a log message to the logging library under an info log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| */ | ||
| info(...messages: MessageDataType[]): void | Promise<void>; | ||
| info(...messages: MessageDataType[]): LogReturnType<IsAsync>; | ||
| /** | ||
| * Sends a log message to the logging library under the warn log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| */ | ||
| warn(...messages: MessageDataType[]): void | Promise<void>; | ||
| warn(...messages: MessageDataType[]): LogReturnType<IsAsync>; | ||
| /** | ||
| * Sends a log message to the logging library under the error log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| */ | ||
| error(...messages: MessageDataType[]): void | Promise<void>; | ||
| error(...messages: MessageDataType[]): LogReturnType<IsAsync>; | ||
| /** | ||
| * Sends a log message to the logging library under the debug log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| */ | ||
| debug(...messages: MessageDataType[]): void | Promise<void>; | ||
| debug(...messages: MessageDataType[]): LogReturnType<IsAsync>; | ||
| /** | ||
| * Sends a log message to the logging library under the trace log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| */ | ||
| trace(...messages: MessageDataType[]): void | Promise<void>; | ||
| trace(...messages: MessageDataType[]): LogReturnType<IsAsync>; | ||
| /** | ||
| * Sends a log message to the logging library under the fatal log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| */ | ||
| fatal(...messages: MessageDataType[]): void | Promise<void>; | ||
| fatal(...messages: MessageDataType[]): LogReturnType<IsAsync>; | ||
| /** | ||
| * Specifies metadata to include with the log message | ||
| * Specifies metadata to include with the log message. | ||
| * If the metadata contains async lazy values, subsequent log methods will return `Promise<void>`. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/metadata.html | Metadata Docs} | ||
| */ | ||
| withMetadata(metadata?: LogLayerMetadata): This; | ||
| withMetadata<M extends LogLayerMetadata>(metadata?: M): ILogBuilder<This, ContainsAsyncLazy<NonNullable<M>> extends true ? true : IsAsync>; | ||
| /** | ||
@@ -522,3 +667,3 @@ * Specifies an Error to include with the log message | ||
| */ | ||
| withError(error: any): This; | ||
| withError(error: any): ILogBuilder<This, IsAsync>; | ||
| /** | ||
@@ -529,3 +674,3 @@ * Enable sending logs to the logging library. | ||
| */ | ||
| enableLogging(): This; | ||
| enableLogging(): ILogBuilder<This, IsAsync>; | ||
| /** | ||
@@ -536,3 +681,3 @@ * All logging inputs are dropped and stops sending logs to the logging library. | ||
| */ | ||
| disableLogging(): This; | ||
| disableLogging(): ILogBuilder<This, IsAsync>; | ||
| } | ||
@@ -546,36 +691,31 @@ /** | ||
| * Sends a log message to the logging library under an info log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| */ | ||
| info(...messages: MessageDataType[]): void | Promise<void>; | ||
| info(...messages: MessageDataType[]): void; | ||
| /** | ||
| * Sends a log message to the logging library under the warn log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| */ | ||
| warn(...messages: MessageDataType[]): void | Promise<void>; | ||
| warn(...messages: MessageDataType[]): void; | ||
| /** | ||
| * Sends a log message to the logging library under the error log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| */ | ||
| error(...messages: MessageDataType[]): void | Promise<void>; | ||
| error(...messages: MessageDataType[]): void; | ||
| /** | ||
| * Sends a log message to the logging library under the debug log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| */ | ||
| debug(...messages: MessageDataType[]): void | Promise<void>; | ||
| debug(...messages: MessageDataType[]): void; | ||
| /** | ||
| * Sends a log message to the logging library under the trace log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| */ | ||
| trace(...messages: MessageDataType[]): void | Promise<void>; | ||
| trace(...messages: MessageDataType[]): void; | ||
| /** | ||
| * Sends a log message to the logging library under the fatal log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| */ | ||
| fatal(...messages: MessageDataType[]): void | Promise<void>; | ||
| fatal(...messages: MessageDataType[]): void; | ||
| /** | ||
| * Specifies metadata to include with the log message | ||
| * Specifies metadata to include with the log message. | ||
| * If the metadata contains async lazy values, the builder's log methods will return `Promise<void>`. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/metadata.html | Metadata Docs} | ||
| */ | ||
| withMetadata(metadata?: LogLayerMetadata): ILogBuilder<any>; | ||
| withMetadata<M extends LogLayerMetadata>(metadata?: M): ILogBuilder<any, ContainsAsyncLazy<NonNullable<M>>>; | ||
| /** | ||
@@ -586,3 +726,3 @@ * Specifies an Error to include with the log message | ||
| */ | ||
| withError(error: any): ILogBuilder<any>; | ||
| withError(error: any): ILogBuilder<any, false>; | ||
| /** | ||
@@ -629,9 +769,10 @@ * Enable sending logs to the logging library. | ||
| */ | ||
| errorOnly(error: any, opts?: ErrorOnlyOpts): void | Promise<void>; | ||
| errorOnly(error: any, opts?: ErrorOnlyOpts): void; | ||
| /** | ||
| * Logs only metadata without a log message | ||
| * Logs only metadata without a log message. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/metadata.html | Metadata Docs} | ||
| */ | ||
| metadataOnly(metadata?: LogLayerMetadata, logLevel?: LogLevelType): void | Promise<void>; | ||
| metadataOnly<M extends LogLayerMetadata>(metadata?: M, logLevel?: LogLevelType): LogReturnType<ContainsAsyncLazy<NonNullable<M>>>; | ||
| /** | ||
@@ -820,8 +961,9 @@ * Returns the context used. | ||
| * The raw entry will still go through all LogLayer processing. | ||
| * Returns a Promise when async lazy values are present in the entry's metadata. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/basic-logging.html | Basic Logging Docs} | ||
| */ | ||
| raw(rawEntry: RawLogEntry): void | Promise<void>; | ||
| raw<R extends RawLogEntry>(rawEntry: R): LogReturnType<ContainsAsyncLazy<NonNullable<R["metadata"]>>>; | ||
| } | ||
| //#endregion | ||
| export { ErrorOnlyOpts, IContextManager, ILogBuilder, ILogLayer, ILogLevelManager, LogLayerCommonDataParams, LogLayerContext, LogLayerData, LogLayerMetadata, LogLayerPlugin, LogLayerPluginParams, LogLayerTransport, LogLayerTransportParams, LogLevel, LogLevelPriority, LogLevelPriorityToNames, LogLevelType, MessageDataType, OnChildLogLevelManagerCreatedParams, OnChildLoggerCreatedParams, PluginBeforeDataOutParams, PluginBeforeMessageOutParams, PluginShouldSendToLoggerParams, PluginTransformLogLevelParams, RawLogEntry }; | ||
| export { ContainsAsyncLazy, ErrorOnlyOpts, IContextManager, ILogBuilder, ILogLayer, ILogLevelManager, LAZY_EVAL_ERROR, LAZY_SYMBOL, LazyEvalFailure, LazyLogValue, LogLayerCommonDataParams, LogLayerContext, LogLayerData, LogLayerMetadata, LogLayerPlugin, LogLayerPluginParams, LogLayerTransport, LogLayerTransportParams, LogLevel, LogLevelPriority, LogLevelPriorityToNames, LogLevelType, LogReturnType, MessageDataType, OnChildLogLevelManagerCreatedParams, OnChildLoggerCreatedParams, PluginBeforeDataOutParams, PluginBeforeMessageOutParams, PluginShouldSendToLoggerParams, PluginTransformLogLevelParams, RawLogEntry, ResolveLazyResult, countLazyValues, hasPromiseValues, isLazy, lazy, replacePromiseValues, resolveLazyValues, resolvePromiseValues }; |
+181
-39
@@ -0,1 +1,120 @@ | ||
| //#region src/lazy.d.ts | ||
| /** | ||
| * Symbol used to identify lazy values in context and metadata. | ||
| * Can be used to check if a value is a lazy wrapper: `LAZY_SYMBOL in value`. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} | ||
| */ | ||
| declare const LAZY_SYMBOL: unique symbol; | ||
| /** | ||
| * String constant used as a replacement value when a lazy callback fails during evaluation. | ||
| * Exported so users can programmatically detect lazy evaluation failures in their log output. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation#error-handling | Lazy Evaluation Error Handling Docs} | ||
| */ | ||
| declare const LAZY_EVAL_ERROR = "[LazyEvalError]"; | ||
| /** | ||
| * Describes a single lazy evaluation failure. | ||
| * @internal | ||
| */ | ||
| interface LazyEvalFailure { | ||
| key: string; | ||
| error: unknown; | ||
| } | ||
| /** | ||
| * Result of resolving lazy values, including any errors that occurred. | ||
| * @internal | ||
| */ | ||
| interface ResolveLazyResult<T> { | ||
| resolved: T; | ||
| errors: LazyEvalFailure[] | null; | ||
| } | ||
| /** | ||
| * Represents a lazy value that defers evaluation until log time. | ||
| * | ||
| * Created by the {@link lazy} function. | ||
| * | ||
| * When the type parameter `T` is a `Promise`, log methods that receive this | ||
| * lazy value in metadata will return `Promise<void>` instead of `void`. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} | ||
| */ | ||
| interface LazyLogValue<T = any> { | ||
| [LAZY_SYMBOL]: () => T; | ||
| } | ||
| /** | ||
| * Wraps a callback function to defer its evaluation until log time. | ||
| * | ||
| * The callback will only be invoked if the log level is enabled, | ||
| * avoiding unnecessary computation for disabled log levels. | ||
| * | ||
| * Can be used in both `withContext()` and `withMetadata()` at the root level. | ||
| * | ||
| * When the callback returns a `Promise` (i.e., is an async function), the | ||
| * log method will return `Promise<void>` so TypeScript can track that the | ||
| * operation is asynchronous. | ||
| * | ||
| * Adapted from [LogTape's lazy evaluation](https://logtape.org/manual/lazy). | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * import { LogLayer, lazy } from "loglayer"; | ||
| * | ||
| * const log = new LogLayer({ ... }); | ||
| * | ||
| * // Dynamic context - evaluated on each log call | ||
| * log.withContext({ | ||
| * memoryUsage: lazy(() => process.memoryUsage().heapUsed), | ||
| * }); | ||
| * | ||
| * // Dynamic metadata - evaluated only if debug is enabled | ||
| * log.withMetadata({ | ||
| * data: lazy(() => JSON.stringify(largeObject)), | ||
| * }).debug("Processing complete"); | ||
| * ``` | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} | ||
| */ | ||
| declare function lazy<T>(fn: () => T): LazyLogValue<T>; | ||
| /** | ||
| * Checks if a value is a lazy value created by {@link lazy}. | ||
| * @internal | ||
| */ | ||
| declare function isLazy(value: unknown): value is LazyLogValue; | ||
| /** | ||
| * Counts the number of lazy values in a record. | ||
| * @internal | ||
| */ | ||
| declare function countLazyValues(obj: Record<string, any>): number; | ||
| /** | ||
| * Resolves any lazy values in a record at the root level. | ||
| * Returns the original object if no lazy values are found (optimization). | ||
| * If a lazy callback throws, the value is replaced with LAZY_EVAL_ERROR | ||
| * and the error is collected in the result. | ||
| * @internal | ||
| */ | ||
| declare function resolveLazyValues<T extends Record<string, any>>(obj: T): ResolveLazyResult<T>; | ||
| /** | ||
| * Checks if any values in a record are Promises. | ||
| * @internal | ||
| */ | ||
| declare function hasPromiseValues(obj: Record<string, any>): boolean; | ||
| /** | ||
| * Replaces any Promise values in a record with LAZY_EVAL_ERROR. | ||
| * Used to strip async lazy values from context where only sync lazy is supported. | ||
| * Returns the keys that were replaced. | ||
| * @internal | ||
| */ | ||
| declare function replacePromiseValues<T extends Record<string, any>>(obj: T): { | ||
| resolved: T; | ||
| asyncKeys: string[] | null; | ||
| }; | ||
| /** | ||
| * Resolves any Promise values in a record using Promise.allSettled. | ||
| * If a Promise rejects, the value is replaced with LAZY_EVAL_ERROR | ||
| * and the error is collected in the result. | ||
| * @internal | ||
| */ | ||
| declare function resolvePromiseValues<T extends Record<string, any>>(obj: T): Promise<ResolveLazyResult<T>>; | ||
| //#endregion | ||
| //#region src/common.types.d.ts | ||
@@ -38,3 +157,3 @@ declare enum LogLevel { | ||
| */ | ||
| logLevel?: LogLevel; | ||
| logLevel?: LogLevelType; | ||
| /** | ||
@@ -63,2 +182,21 @@ * If `true`, copies the `error.message` if available to the transport library's | ||
| interface LogLayerData extends Record<string, any> {} | ||
| /** | ||
| * Type-level helper that checks whether a metadata/context record type | ||
| * contains any {@link LazyLogValue} whose callback returns a `Promise`. | ||
| * | ||
| * Evaluates to `true` if any property is `LazyLogValue<Promise<any>>`, | ||
| * `false` otherwise. Returns `false` for `undefined` or `null` inputs. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} | ||
| */ | ||
| type ContainsAsyncLazy<M> = M extends undefined | null ? false : true extends { [K in keyof M]: M[K] extends LazyLogValue<infer T> ? (T extends Promise<any> ? true : false) : false }[keyof M] ? true : false; | ||
| /** | ||
| * Helper type that resolves the return type of log methods based on whether | ||
| * async lazy values are present. | ||
| * | ||
| * - `true` → `Promise<void>` (async lazy values detected) | ||
| * - `false` → `void` (no async lazy values) | ||
| * - `boolean` → `void | Promise<void>` (indeterminate, used by implementation classes) | ||
| */ | ||
| type LogReturnType<IsAsync extends boolean> = IsAsync extends true ? Promise<void> : IsAsync extends false ? void : void | Promise<void>; | ||
| interface LogLayerCommonDataParams { | ||
@@ -477,41 +615,48 @@ /** | ||
| * Interface for implementing a LogLayer builder instance. | ||
| * | ||
| * @typeParam This - The concrete builder type for polymorphic chaining. | ||
| * @typeParam IsAsync - Whether the builder contains async lazy metadata. | ||
| * When `true`, log methods return `Promise<void>`. When `false`, they return `void`. | ||
| * When `boolean` (indeterminate), they return `void | Promise<void>`. | ||
| * | ||
| * @see {@link https://loglayer.dev | LogLayer Documentation} | ||
| */ | ||
| interface ILogBuilder<This = ILogBuilder<any>> { | ||
| interface ILogBuilder<This = ILogBuilder<any, any>, IsAsync extends boolean = false> { | ||
| /** | ||
| * Sends a log message to the logging library under an info log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| */ | ||
| info(...messages: MessageDataType[]): void | Promise<void>; | ||
| info(...messages: MessageDataType[]): LogReturnType<IsAsync>; | ||
| /** | ||
| * Sends a log message to the logging library under the warn log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| */ | ||
| warn(...messages: MessageDataType[]): void | Promise<void>; | ||
| warn(...messages: MessageDataType[]): LogReturnType<IsAsync>; | ||
| /** | ||
| * Sends a log message to the logging library under the error log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| */ | ||
| error(...messages: MessageDataType[]): void | Promise<void>; | ||
| error(...messages: MessageDataType[]): LogReturnType<IsAsync>; | ||
| /** | ||
| * Sends a log message to the logging library under the debug log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| */ | ||
| debug(...messages: MessageDataType[]): void | Promise<void>; | ||
| debug(...messages: MessageDataType[]): LogReturnType<IsAsync>; | ||
| /** | ||
| * Sends a log message to the logging library under the trace log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| */ | ||
| trace(...messages: MessageDataType[]): void | Promise<void>; | ||
| trace(...messages: MessageDataType[]): LogReturnType<IsAsync>; | ||
| /** | ||
| * Sends a log message to the logging library under the fatal log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| */ | ||
| fatal(...messages: MessageDataType[]): void | Promise<void>; | ||
| fatal(...messages: MessageDataType[]): LogReturnType<IsAsync>; | ||
| /** | ||
| * Specifies metadata to include with the log message | ||
| * Specifies metadata to include with the log message. | ||
| * If the metadata contains async lazy values, subsequent log methods will return `Promise<void>`. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/metadata.html | Metadata Docs} | ||
| */ | ||
| withMetadata(metadata?: LogLayerMetadata): This; | ||
| withMetadata<M extends LogLayerMetadata>(metadata?: M): ILogBuilder<This, ContainsAsyncLazy<NonNullable<M>> extends true ? true : IsAsync>; | ||
| /** | ||
@@ -522,3 +667,3 @@ * Specifies an Error to include with the log message | ||
| */ | ||
| withError(error: any): This; | ||
| withError(error: any): ILogBuilder<This, IsAsync>; | ||
| /** | ||
@@ -529,3 +674,3 @@ * Enable sending logs to the logging library. | ||
| */ | ||
| enableLogging(): This; | ||
| enableLogging(): ILogBuilder<This, IsAsync>; | ||
| /** | ||
@@ -536,3 +681,3 @@ * All logging inputs are dropped and stops sending logs to the logging library. | ||
| */ | ||
| disableLogging(): This; | ||
| disableLogging(): ILogBuilder<This, IsAsync>; | ||
| } | ||
@@ -546,36 +691,31 @@ /** | ||
| * Sends a log message to the logging library under an info log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| */ | ||
| info(...messages: MessageDataType[]): void | Promise<void>; | ||
| info(...messages: MessageDataType[]): void; | ||
| /** | ||
| * Sends a log message to the logging library under the warn log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| */ | ||
| warn(...messages: MessageDataType[]): void | Promise<void>; | ||
| warn(...messages: MessageDataType[]): void; | ||
| /** | ||
| * Sends a log message to the logging library under the error log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| */ | ||
| error(...messages: MessageDataType[]): void | Promise<void>; | ||
| error(...messages: MessageDataType[]): void; | ||
| /** | ||
| * Sends a log message to the logging library under the debug log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| */ | ||
| debug(...messages: MessageDataType[]): void | Promise<void>; | ||
| debug(...messages: MessageDataType[]): void; | ||
| /** | ||
| * Sends a log message to the logging library under the trace log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| */ | ||
| trace(...messages: MessageDataType[]): void | Promise<void>; | ||
| trace(...messages: MessageDataType[]): void; | ||
| /** | ||
| * Sends a log message to the logging library under the fatal log level. | ||
| * Returns a Promise when async lazy values are present in context or metadata. | ||
| */ | ||
| fatal(...messages: MessageDataType[]): void | Promise<void>; | ||
| fatal(...messages: MessageDataType[]): void; | ||
| /** | ||
| * Specifies metadata to include with the log message | ||
| * Specifies metadata to include with the log message. | ||
| * If the metadata contains async lazy values, the builder's log methods will return `Promise<void>`. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/metadata.html | Metadata Docs} | ||
| */ | ||
| withMetadata(metadata?: LogLayerMetadata): ILogBuilder<any>; | ||
| withMetadata<M extends LogLayerMetadata>(metadata?: M): ILogBuilder<any, ContainsAsyncLazy<NonNullable<M>>>; | ||
| /** | ||
@@ -586,3 +726,3 @@ * Specifies an Error to include with the log message | ||
| */ | ||
| withError(error: any): ILogBuilder<any>; | ||
| withError(error: any): ILogBuilder<any, false>; | ||
| /** | ||
@@ -629,9 +769,10 @@ * Enable sending logs to the logging library. | ||
| */ | ||
| errorOnly(error: any, opts?: ErrorOnlyOpts): void | Promise<void>; | ||
| errorOnly(error: any, opts?: ErrorOnlyOpts): void; | ||
| /** | ||
| * Logs only metadata without a log message | ||
| * Logs only metadata without a log message. | ||
| * Returns a Promise when async lazy values are present in metadata. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/metadata.html | Metadata Docs} | ||
| */ | ||
| metadataOnly(metadata?: LogLayerMetadata, logLevel?: LogLevelType): void | Promise<void>; | ||
| metadataOnly<M extends LogLayerMetadata>(metadata?: M, logLevel?: LogLevelType): LogReturnType<ContainsAsyncLazy<NonNullable<M>>>; | ||
| /** | ||
@@ -820,8 +961,9 @@ * Returns the context used. | ||
| * The raw entry will still go through all LogLayer processing. | ||
| * Returns a Promise when async lazy values are present in the entry's metadata. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/basic-logging.html | Basic Logging Docs} | ||
| */ | ||
| raw(rawEntry: RawLogEntry): void | Promise<void>; | ||
| raw<R extends RawLogEntry>(rawEntry: R): LogReturnType<ContainsAsyncLazy<NonNullable<R["metadata"]>>>; | ||
| } | ||
| //#endregion | ||
| export { ErrorOnlyOpts, IContextManager, ILogBuilder, ILogLayer, ILogLevelManager, LogLayerCommonDataParams, LogLayerContext, LogLayerData, LogLayerMetadata, LogLayerPlugin, LogLayerPluginParams, LogLayerTransport, LogLayerTransportParams, LogLevel, LogLevelPriority, LogLevelPriorityToNames, LogLevelType, MessageDataType, OnChildLogLevelManagerCreatedParams, OnChildLoggerCreatedParams, PluginBeforeDataOutParams, PluginBeforeMessageOutParams, PluginShouldSendToLoggerParams, PluginTransformLogLevelParams, RawLogEntry }; | ||
| export { ContainsAsyncLazy, ErrorOnlyOpts, IContextManager, ILogBuilder, ILogLayer, ILogLevelManager, LAZY_EVAL_ERROR, LAZY_SYMBOL, LazyEvalFailure, LazyLogValue, LogLayerCommonDataParams, LogLayerContext, LogLayerData, LogLayerMetadata, LogLayerPlugin, LogLayerPluginParams, LogLayerTransport, LogLayerTransportParams, LogLevel, LogLevelPriority, LogLevelPriorityToNames, LogLevelType, LogReturnType, MessageDataType, OnChildLogLevelManagerCreatedParams, OnChildLoggerCreatedParams, PluginBeforeDataOutParams, PluginBeforeMessageOutParams, PluginShouldSendToLoggerParams, PluginTransformLogLevelParams, RawLogEntry, ResolveLazyResult, countLazyValues, hasPromiseValues, isLazy, lazy, replacePromiseValues, resolveLazyValues, resolvePromiseValues }; |
+167
-1
@@ -35,2 +35,168 @@ //#region src/common.types.ts | ||
| //#endregion | ||
| export { LogLevel, LogLevelPriority, LogLevelPriorityToNames }; | ||
| //#region src/lazy.ts | ||
| /** | ||
| * Symbol used to identify lazy values in context and metadata. | ||
| * Can be used to check if a value is a lazy wrapper: `LAZY_SYMBOL in value`. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} | ||
| */ | ||
| const LAZY_SYMBOL = Symbol.for("loglayer.lazy"); | ||
| /** | ||
| * String constant used as a replacement value when a lazy callback fails during evaluation. | ||
| * Exported so users can programmatically detect lazy evaluation failures in their log output. | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation#error-handling | Lazy Evaluation Error Handling Docs} | ||
| */ | ||
| const LAZY_EVAL_ERROR = "[LazyEvalError]"; | ||
| /** | ||
| * Wraps a callback function to defer its evaluation until log time. | ||
| * | ||
| * The callback will only be invoked if the log level is enabled, | ||
| * avoiding unnecessary computation for disabled log levels. | ||
| * | ||
| * Can be used in both `withContext()` and `withMetadata()` at the root level. | ||
| * | ||
| * When the callback returns a `Promise` (i.e., is an async function), the | ||
| * log method will return `Promise<void>` so TypeScript can track that the | ||
| * operation is asynchronous. | ||
| * | ||
| * Adapted from [LogTape's lazy evaluation](https://logtape.org/manual/lazy). | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * import { LogLayer, lazy } from "loglayer"; | ||
| * | ||
| * const log = new LogLayer({ ... }); | ||
| * | ||
| * // Dynamic context - evaluated on each log call | ||
| * log.withContext({ | ||
| * memoryUsage: lazy(() => process.memoryUsage().heapUsed), | ||
| * }); | ||
| * | ||
| * // Dynamic metadata - evaluated only if debug is enabled | ||
| * log.withMetadata({ | ||
| * data: lazy(() => JSON.stringify(largeObject)), | ||
| * }).debug("Processing complete"); | ||
| * ``` | ||
| * | ||
| * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} | ||
| */ | ||
| function lazy(fn) { | ||
| return { [LAZY_SYMBOL]: fn }; | ||
| } | ||
| /** | ||
| * Checks if a value is a lazy value created by {@link lazy}. | ||
| * @internal | ||
| */ | ||
| function isLazy(value) { | ||
| return value != null && typeof value === "object" && LAZY_SYMBOL in value; | ||
| } | ||
| /** | ||
| * Counts the number of lazy values in a record. | ||
| * @internal | ||
| */ | ||
| function countLazyValues(obj) { | ||
| let count = 0; | ||
| for (const key of Object.keys(obj)) if (isLazy(obj[key])) count++; | ||
| return count; | ||
| } | ||
| /** | ||
| * Resolves any lazy values in a record at the root level. | ||
| * Returns the original object if no lazy values are found (optimization). | ||
| * If a lazy callback throws, the value is replaced with LAZY_EVAL_ERROR | ||
| * and the error is collected in the result. | ||
| * @internal | ||
| */ | ||
| function resolveLazyValues(obj) { | ||
| let hasLazy = false; | ||
| for (const key of Object.keys(obj)) if (isLazy(obj[key])) { | ||
| hasLazy = true; | ||
| break; | ||
| } | ||
| if (!hasLazy) return { | ||
| resolved: obj, | ||
| errors: null | ||
| }; | ||
| const result = {}; | ||
| let errors = null; | ||
| for (const key of Object.keys(obj)) { | ||
| const value = obj[key]; | ||
| if (isLazy(value)) try { | ||
| result[key] = value[LAZY_SYMBOL](); | ||
| } catch (e) { | ||
| result[key] = LAZY_EVAL_ERROR; | ||
| if (!errors) errors = []; | ||
| errors.push({ | ||
| key, | ||
| error: e | ||
| }); | ||
| } | ||
| else result[key] = value; | ||
| } | ||
| return { | ||
| resolved: result, | ||
| errors | ||
| }; | ||
| } | ||
| /** | ||
| * Checks if any values in a record are Promises. | ||
| * @internal | ||
| */ | ||
| function hasPromiseValues(obj) { | ||
| for (const key of Object.keys(obj)) if (obj[key] instanceof Promise) return true; | ||
| return false; | ||
| } | ||
| /** | ||
| * Replaces any Promise values in a record with LAZY_EVAL_ERROR. | ||
| * Used to strip async lazy values from context where only sync lazy is supported. | ||
| * Returns the keys that were replaced. | ||
| * @internal | ||
| */ | ||
| function replacePromiseValues(obj) { | ||
| let asyncKeys = null; | ||
| const result = {}; | ||
| for (const key of Object.keys(obj)) if (obj[key] instanceof Promise) { | ||
| result[key] = LAZY_EVAL_ERROR; | ||
| if (!asyncKeys) asyncKeys = []; | ||
| asyncKeys.push(key); | ||
| } else result[key] = obj[key]; | ||
| if (!asyncKeys) return { | ||
| resolved: obj, | ||
| asyncKeys: null | ||
| }; | ||
| return { | ||
| resolved: result, | ||
| asyncKeys | ||
| }; | ||
| } | ||
| /** | ||
| * Resolves any Promise values in a record using Promise.allSettled. | ||
| * If a Promise rejects, the value is replaced with LAZY_EVAL_ERROR | ||
| * and the error is collected in the result. | ||
| * @internal | ||
| */ | ||
| async function resolvePromiseValues(obj) { | ||
| const keys = Object.keys(obj); | ||
| const settled = await Promise.allSettled(keys.map((key) => Promise.resolve(obj[key]))); | ||
| const result = {}; | ||
| let errors = null; | ||
| for (let i = 0; i < keys.length; i++) { | ||
| const s = settled[i]; | ||
| if (s.status === "fulfilled") result[keys[i]] = s.value; | ||
| else { | ||
| result[keys[i]] = LAZY_EVAL_ERROR; | ||
| if (!errors) errors = []; | ||
| errors.push({ | ||
| key: keys[i], | ||
| error: s.reason | ||
| }); | ||
| } | ||
| } | ||
| return { | ||
| resolved: result, | ||
| errors | ||
| }; | ||
| } | ||
| //#endregion | ||
| export { LAZY_EVAL_ERROR, LAZY_SYMBOL, LogLevel, LogLevelPriority, LogLevelPriorityToNames, countLazyValues, hasPromiseValues, isLazy, lazy, replacePromiseValues, resolveLazyValues, resolvePromiseValues }; |
+1
-1
| { | ||
| "name": "@loglayer/shared", | ||
| "description": "Shared utilities and types for loglayer packages.", | ||
| "version": "4.0.0", | ||
| "version": "4.0.1", | ||
| "type": "module", | ||
@@ -6,0 +6,0 @@ "main": "./dist/index.cjs", |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
89042
30.62%1366
54.35%7
-22.22%