UNPKG

syntropylog

Version:

An instance manager with observability for Node.js applications

1,367 lines (1,352 loc) 113 kB
import { z } from 'zod'; import { RedisClientType, RedisModules, RedisFunctions, RedisScripts, RedisClusterType } from 'redis'; import { EventEmitter } from 'events'; import chalk from 'chalk'; /** * Internal Types for SyntropyLog Framework * * These types and utilities are for advanced usage and internal framework operations. * Use with caution - they may change between versions. */ /** * Represents any value that can be safely serialized to JSON. * This is a recursive type used to ensure type safety for log metadata. */ type JsonValue = string | number | boolean | null | { [key: string]: JsonValue; } | JsonValue[]; /** * Helper function to convert unknown error to JsonValue * Moved from @syntropylog/types to internal types */ declare function errorToJsonValue(error: unknown): JsonValue; /** * Type for log metadata objects that can be passed to logging methods */ type LogMetadata = Record<string, JsonValue>; /** * Type for log bindings that are attached to logger instances */ type LogBindings = Record<string, JsonValue>; /** * Type for retention rules that can be attached to loggers */ type LogRetentionRules = { ttl?: number; maxSize?: number; maxEntries?: number; archiveAfter?: number; deleteAfter?: number; [key: string]: JsonValue | number | undefined; }; /** * Type for format arguments that can be passed to logging methods */ type LogFormatArg = string | number | boolean | null | undefined; /** * Type for the arguments that can be passed to logging methods * This follows the Pino-like signature: (obj, msg, ...args) or (msg, ...args) */ type LogArguments = [LogMetadata, string?, ...LogFormatArg[]] | [string, ...LogFormatArg[]] | []; /** * Type for values that can be stored in context */ type ContextValue = string | number | boolean | null | undefined | Buffer | JsonValue; /** * Type for context data structure */ type ContextData = Record<string, ContextValue>; /** * Type for context configuration options */ type ContextConfig = { correlationIdHeader?: string; transactionIdHeader?: string; [key: string]: ContextValue; }; /** * Type for context headers used in HTTP requests */ type ContextHeaders = Record<string, string>; /** * Type for context callback functions */ type ContextCallback = () => void | Promise<void>; /** * Type for logging matrix configuration */ type LoggingMatrix = Partial<Record<string, string[]>>; /** * Type for filtered context based on log level */ type FilteredContext = Record<string, unknown>; /** * Type for any object that can be used as metadata */ type MetadataObject = Record<string, JsonValue>; /** * Context object for logging operations */ type LogContext = { correlationId?: string; userId?: string | number; sessionId?: string; requestId?: string; [key: string]: JsonValue | undefined; }; /** * Context for pipeline operations (serialization, sanitization, etc.) */ type PipelineContext = { correlationId?: string; operation?: string; metadata?: Record<string, JsonValue>; timestamp?: number; }; /** * Context for sanitization operations */ type SanitizationContext = { sensitiveFields?: string[]; maskPatterns?: Record<string, string>; depth?: number; maxDepth?: number; }; /** * Type for Redis values - covers all valid Redis data types */ type RedisValue = string | number | boolean | Buffer | null | undefined | RedisValue[] | { [key: string]: RedisValue; }; /** * Type for Redis list elements */ type RedisListElement = string | number | Buffer | null | undefined; /** * Type for Redis set members */ type RedisSetMember = string | number | Buffer; /** * Type for Redis sorted set members with scores */ type RedisSortedSetMember = { score: number; value: RedisValue; }; /** * Type for Redis hash field values */ type RedisHashValue = string | number | Buffer; /** * Type for Redis command options */ type RedisCommandOptions = { [key: string]: JsonValue; }; /** * Type for Redis pipeline operations */ type RedisPipelineOperation = { command: string; args: RedisValue[]; }; /** * Type for Redis connection parameters */ type RedisConnectionParams = { host?: string; port?: number; password?: string; db?: number; [key: string]: unknown; }; /** * Type for serialized data */ type SerializedData = any; /** * Type for serialization context configuration */ type SerializationContextConfig = { depth: number; maxDepth: number; sensitiveFields: string[]; sanitize: boolean; customTimeout?: number; }; /** * Type for sanitization configuration */ type SanitizationConfig = { sensitiveFields: string[]; redactPatterns: RegExp[]; maxStringLength: number; enableDeepSanitization: boolean; }; /** * Type for serialization pipeline context */ type SerializationPipelineContext = { serializationContext: SerializationContextConfig; sanitizeSensitiveData: boolean; sanitizationContext: SanitizationConfig; enableMetrics: boolean; }; /** * Type for step durations in serialization pipeline */ type StepDurations = { serialization?: number; sanitization?: number; timeout?: number; }; /** * Type for serialization metadata */ type SerializationMetadata = { stepDurations?: StepDurations; operationTimeout?: number; complexity?: string; serializer?: string; timeoutStrategy?: string; }; /** * Type for serialization result */ type SerializationResult = { data: SerializedData; serializer: string; duration: number; complexity: string; sanitized: boolean; success: boolean; metadata: SerializationMetadata; error?: string; }; /** * Type for complexity distribution */ type ComplexityDistribution = { low: number; medium: number; high: number; }; /** * Type for serializer distribution */ type SerializerDistribution = Record<string, number>; /** * Type for timeout strategy distribution */ type TimeoutStrategyDistribution = Record<string, number>; /** * Type for serialization metrics */ type SerializationMetrics = { totalSerializations: number; successfulSerializations: number; failedSerializations: number; averageSerializationDuration: number; averageOperationTimeout: number; maxSerializationDuration: number; minSerializationDuration: number; complexityDistribution: ComplexityDistribution; serializerDistribution: SerializerDistribution; timeoutStrategyDistribution: TimeoutStrategyDistribution; }; /** * Type for logger dependencies (internal) */ type LoggerDependencies = { contextManager: unknown; serializerRegistry: unknown; maskingEngine: unknown; syntropyLogInstance: unknown; }; /** * Interface for HTTP request in adapters */ interface AdapterHttpRequest$1 { /** The full URL for the request. */ url: string; /** The HTTP method. */ method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'; /** A record of request headers. */ headers: Record<string, string | number | string[]>; /** The request body, if any. */ body?: unknown; /** A record of URL query parameters. */ queryParams?: Record<string, any>; } /** * Interface for HTTP response in adapters */ interface AdapterHttpResponse$1<T = any> { /** The HTTP status code of the response. */ statusCode: number; /** The response body data. */ data: T; /** A record of response headers. */ headers: Record<string, string | number | string[]>; } /** * Interface for HTTP error in adapters */ interface AdapterHttpError extends Error { /** The original request that caused the error. */ request: AdapterHttpRequest$1; /** The response received, if any. */ response?: AdapterHttpResponse$1; /** A flag to identify this as a normalized adapter error. */ isAdapterError: true; } /** * @file src/logger/levels.ts * @description Defines the available log levels, their names, and their severity weights. */ /** * @description A mapping of log level names to their severity weights. * Higher numbers indicate higher severity. */ declare const LOG_LEVEL_WEIGHTS: { readonly fatal: 60; readonly error: 50; readonly warn: 40; readonly info: 30; readonly debug: 20; readonly trace: 10; readonly silent: 0; }; /** * @description The type representing a valid log level name. */ type LogLevel = keyof typeof LOG_LEVEL_WEIGHTS; /** * SyntropyLog Types - Internal types for the framework * * This file now uses internal types and only contains types specific to this module. */ type LoggerOptions = { level?: LogLevel; serviceName?: string; transports?: unknown[]; bindings?: Record<string, any>; }; type LogEntry = { /** The severity level of the log. */ level: LogLevel; /** The main log message, formatted from the arguments. */ message: string; /** The ISO 8601 timestamp of when the log was created. */ timestamp: string; /** Any other properties are treated as structured metadata. */ [key: string]: any; }; /** * FILE: src/masking/MaskingEngine.ts * DESCRIPTION: Ultra-fast data masking engine using JSON flattening strategy. * * This engine flattens complex nested objects into linear key-value pairs, * applies masking rules, and then reconstructs the original structure. * This approach provides extreme processing speed for any object depth. */ /** * @enum MaskingStrategy * @description Different masking strategies for various data types. */ declare enum MaskingStrategy { CREDIT_CARD = "credit_card", SSN = "ssn", EMAIL = "email", PHONE = "phone", PASSWORD = "password", TOKEN = "token", CUSTOM = "custom" } /** * @interface MaskingRule * @description Configuration for a masking rule. */ interface MaskingRule { /** Regex pattern to match field names */ pattern: string | RegExp; /** Masking strategy to apply */ strategy: MaskingStrategy; /** Custom masking function (for CUSTOM strategy) */ customMask?: (value: string) => string; /** Whether to preserve original length */ preserveLength?: boolean; /** Character to use for masking */ maskChar?: string; /** Compiled regex pattern for performance */ _compiledPattern?: RegExp; } /** * @interface MaskingEngineOptions * @description Options for configuring the MaskingEngine. */ interface MaskingEngineOptions { /** Array of masking rules */ rules?: MaskingRule[]; /** Default mask character */ maskChar?: string; /** Whether to preserve original length by default */ preserveLength?: boolean; /** Enable default rules for common data types */ enableDefaultRules?: boolean; } /** * @class MaskingEngine * Ultra-fast data masking engine using JSON flattening strategy. * * Instead of processing nested objects recursively, we flatten them to a linear * structure for extreme processing speed. This approach provides O(n) performance * regardless of object depth or complexity. */ declare class MaskingEngine { /** @private Array of masking rules */ private rules; /** @private Default mask character */ private readonly maskChar; /** @private Whether to preserve original length by default */ private readonly preserveLength; /** @private Whether the engine is initialized */ private initialized; /** @private Secure regex tester with timeout */ private readonly regexTest; constructor(options?: MaskingEngineOptions); /** * Adds default masking rules for common data types. * @private */ private addDefaultRules; /** * Adds a custom masking rule. * @param rule - The masking rule to add */ addRule(rule: MaskingRule): void; /** * Processes a metadata object and applies the configured masking rules. * Uses JSON flattening strategy for extreme performance. * @param meta - The metadata object to process * @returns A new object with the masked data */ process(meta: Record<string, unknown>): Record<string, unknown>; /** * Applies masking rules to data recursively. * @param data - Data to mask * @returns Masked data * @private */ private applyMaskingRules; /** * Applies specific masking strategy to a value. * @param value - Value to mask * @param rule - Masking rule to apply * @returns Masked value * @private */ private applyStrategy; /** * Masks credit card number. * @param value - Credit card number * @param rule - Masking rule * @returns Masked credit card * @private */ private maskCreditCard; /** * Masks SSN. * @param value - SSN * @param rule - Masking rule * @returns Masked SSN * @private */ private maskSSN; /** * Masks email address. * @param value - Email address * @param rule - Masking rule * @returns Masked email * @private */ private maskEmail; /** * Masks phone number. * @param value - Phone number * @param rule - Masking rule * @returns Masked phone number * @private */ private maskPhone; /** * Masks password. * @param value - Password * @param rule - Masking rule * @returns Masked password * @private */ private maskPassword; /** * Masks token. * @param value - Token * @param rule - Masking rule * @returns Masked token * @private */ private maskToken; /** * Default masking strategy. * @param value - Value to mask * @param rule - Masking rule * @returns Masked value * @private */ private maskDefault; /** * Gets masking engine statistics. * @returns Dictionary with masking statistics */ getStats(): Record<string, any>; /** * Checks if the masking engine is initialized. * @returns True if initialized */ isInitialized(): boolean; /** * Shutdown the masking engine. */ shutdown(): void; } /** * @file src/sanitization/SanitizationEngine.ts * @description Final security layer that sanitizes log entries before they are written by a transport. */ /** * @class SanitizationEngine * A security engine that makes log entries safe for printing by stripping * potentially malicious control characters, such as ANSI escape codes. * This prevents log injection attacks that could exploit terminal vulnerabilities. */ declare class SanitizationEngine { private readonly maskingEngine?; /** @private This regex matches ANSI escape codes used for colors, cursor movement, etc. */ private readonly ansiRegex; /** * @constructor * The engine is currently not configurable, but the constructor is in place for future enhancements. */ constructor(maskingEngine?: MaskingEngine); /** * Processes a log metadata object, sanitizing all its string values. * @param {Record<string, any>} meta - The metadata object to sanitize. * @returns {Record<string, any>} A new, sanitized metadata object. */ process(meta: Record<string, any>): Record<string, any>; /** * @private * Recursively traverses an object or array to sanitize all string values. * @param {any} data - The data to process. * @returns {any} The sanitized data. */ private sanitizeRecursively; } /** * @file src/logger/transports/formatters/LogFormatter.ts * @description Defines the public contract for log entry formatters. */ /** * @interface LogFormatter * @description Defines the interface for a log formatter. * A formatter is responsible for transforming a standard LogEntry object * into a specific structure required by a target destination (e.g., Datadog JSON, Elastic Common Schema). */ interface LogFormatter { /** * Transforms a LogEntry object into a new object with the desired format. * @param {LogEntry} entry - The standard log entry object to be transformed. * @returns {Record<string, JsonValue>} A new object representing the log in the target format. */ format(entry: LogEntry): Record<string, JsonValue>; } /** * @file src/logger/transports/Transport.ts * @description Defines the abstract base class for all log transports. */ /** * @interface TransportOptions * @description Defines the options for configuring a transport. */ interface TransportOptions { /** * The minimum log level this transport will handle. * If not specified, the transport will handle all levels defined by the logger. */ level?: LogLevel; /** * An optional formatter to transform the log entry before output. */ formatter?: LogFormatter; /** * An optional, pre-configured sanitization engine. * If provided, the transport will use it to sanitize logs. This is typically * used by production-safe transports like `ConsoleTransport`. */ sanitizationEngine?: SanitizationEngine; /** * An optional name for the transport, useful for debugging. */ name?: string; } /** * @class Transport * @description The abstract base class for all log transports. A transport is * responsible for the final output of a log entry, whether it's to the console, * a file, or a remote service. */ declare abstract class Transport { level: LogLevel; name: string; /** The formatter instance to transform log entries. */ protected readonly formatter?: LogFormatter; /** The engine used to sanitize sensitive data. */ protected readonly sanitizationEngine?: SanitizationEngine; /** * @constructor * @param {TransportOptions} [options] - The configuration options for this transport. */ constructor(options?: TransportOptions); /** * Determines if the transport should process a log entry based on its log level. * @param level - The level of the log entry to check. * @returns {boolean} - True if the transport is enabled for this level, false otherwise. */ isLevelEnabled(level: LogLevel): boolean; /** * The core method that all concrete transports must implement. This method * handles the actual sending/writing of the log entry. * @param {LogEntry} entry - The final, processed log entry to be outputted. * @returns {Promise<void>} */ abstract log(entry: LogEntry): Promise<void>; /** * A method to ensure all buffered logs are written before the application exits. * Subclasses should override this if they perform I/O buffering. * @returns {Promise<void>} A promise that resolves when flushing is complete. */ flush(): Promise<void>; } /** * @file src/http/adapters/adapter.types.ts * @description Defines the "Universal HTTP Contract" for any HTTP client that * wants to be instrumented by SyntropyLog. These generic interfaces are key * to decoupling the framework from specific implementations like axios or got. */ /** * @interface AdapterHttpRequest * @description Represents a generic, normalized HTTP request that the framework * can understand. The adapter is responsible for converting this to the * specific format of the underlying library (e.g., AxiosRequestConfig). */ interface AdapterHttpRequest { /** The full URL for the request. */ url: string; /** The HTTP method. */ method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'; /** A record of request headers. */ headers: Record<string, string | number | string[]>; /** The request body, if any. */ body?: unknown; /** A record of URL query parameters. */ queryParams?: Record<string, any>; } /** * @interface AdapterHttpResponse * @description Represents a generic, normalized HTTP response. The adapter * will convert the library-specific response into this format. * @template T The expected type of the response body data. */ interface AdapterHttpResponse<T = any> { /** The HTTP status code of the response. */ statusCode: number; /** The response body data. */ data: T; /** A record of response headers. */ headers: Record<string, string | number | string[]>; } /** * @interface IHttpClientAdapter * @description The interface that every HTTP Client Adapter must implement. * This is the "plug" where users will connect their clients. */ interface IHttpClientAdapter { /** * The core method that the SyntropyLog instrumenter needs. It executes an * HTTP request and returns a normalized response, or throws a normalized error. * @template T The expected type of the response body data. * @param {AdapterHttpRequest} request The generic HTTP request to execute. * @returns {Promise<AdapterHttpResponse<T>>} A promise that resolves with the normalized response. */ request<T>(request: AdapterHttpRequest): Promise<AdapterHttpResponse<T>>; } /** * @file src/brokers/adapter.types.ts * @description Defines the "Universal Broker Contract" for any messaging client * that wants to be instrumented by SyntropyLog. These generic interfaces * are key to decoupling the framework from specific implementations like * RabbitMQ or Kafka. */ /** * @interface BrokerMessage * @description Represents a standard message format that the framework understands. * The adapter is responsible for converting the broker-specific message * format to this structure, and vice-versa. */ interface BrokerMessage { /** * The actual content of the message. Using `Buffer` is the most flexible * approach as it supports any type of serialization (JSON, Avro, Protobuf, etc.). */ payload: Buffer; /** * Key-value metadata attached to the message. * This is where SyntropyLog will inject tracing headers like `correlation-id`. */ headers?: Record<string, string | Buffer>; } /** * @interface MessageLifecycleControls * @description Defines the controls for handling a received message's lifecycle. * An instance of this is passed to the user's message handler, allowing them * to confirm or reject the message. */ interface MessageLifecycleControls { /** * Acknowledges that the message has been successfully processed. * This typically removes the message from the queue. * @returns {Promise<void>} */ ack: () => Promise<void>; /** * Negatively acknowledges the message, indicating a processing failure. * @param {boolean} [requeue=false] - If true, asks the broker to re-queue the message * for another attempt. If false (or omitted), the broker might move it to a dead-letter queue * or discard it, depending on its configuration. * @returns {Promise<void>} */ nack: (requeue?: boolean) => Promise<void>; } /** * @type MessageHandler * @description The signature for the user-provided function that will process incoming messages. * @param {BrokerMessage} message - The received message in the framework's standard format. * @param {MessageLifecycleControls} controls - The functions to manage the message's lifecycle (ack/nack). * @returns {Promise<void>} */ type MessageHandler = (message: BrokerMessage, controls: MessageLifecycleControls) => Promise<void>; /** * @interface IBrokerAdapter * @description The interface that every Broker Client Adapter must implement. * This is the "plug" where users will connect their specific messaging clients * (e.g., `amqplib`, `kafkajs`). */ interface IBrokerAdapter { /** * Establishes a connection to the message broker. * @returns {Promise<void>} */ connect(): Promise<void>; /** * Gracefully disconnects from the broker. */ /** * Gracefully disconnects from the message broker. * @returns {Promise<void>} */ disconnect(): Promise<void>; /** * Publishes a message to a specific topic or routing key. * @param {string} topic - The destination for the message (e.g., a topic name, queue name, or routing key). * @param {BrokerMessage} message - The message to be sent, in the framework's standard format. * @returns {Promise<void>} */ publish(topic: string, message: BrokerMessage): Promise<void>; /** * Subscribes to a topic or queue to receive messages. * @param {string} topic - The source of messages to listen to (e.g., a topic name or queue name). * @param {MessageHandler} handler - The user's function that will be called for each incoming message. * @returns {Promise<void>} */ subscribe(topic: string, handler: MessageHandler): Promise<void>; } /** * FILE: src/config.schema.ts * DESCRIPTION: Defines the Zod validation schemas for the entire library's configuration. * These schemas are the single source of truth for the configuration's structure and types. */ /** * @description Schema for a single HTTP client instance. */ declare const httpInstanceConfigSchema: z.ZodObject<{ instanceName: z.ZodString; adapter: z.ZodType<IHttpClientAdapter, z.ZodTypeDef, IHttpClientAdapter>; isDefault: z.ZodOptional<z.ZodBoolean>; propagate: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; propagateFullContext: z.ZodOptional<z.ZodBoolean>; logging: z.ZodOptional<z.ZodObject<{ onSuccess: z.ZodOptional<z.ZodDefault<z.ZodEnum<["trace", "debug", "info"]>>>; onError: z.ZodOptional<z.ZodDefault<z.ZodEnum<["warn", "error", "fatal"]>>>; logSuccessBody: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>; logSuccessHeaders: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>; onRequest: z.ZodOptional<z.ZodDefault<z.ZodEnum<["trace", "debug", "info"]>>>; logRequestBody: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>; logRequestHeaders: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>; }, "strip", z.ZodTypeAny, { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logSuccessBody?: boolean | undefined; logSuccessHeaders?: boolean | undefined; onRequest?: "info" | "debug" | "trace" | undefined; logRequestBody?: boolean | undefined; logRequestHeaders?: boolean | undefined; }, { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logSuccessBody?: boolean | undefined; logSuccessHeaders?: boolean | undefined; onRequest?: "info" | "debug" | "trace" | undefined; logRequestBody?: boolean | undefined; logRequestHeaders?: boolean | undefined; }>>; }, "strip", z.ZodTypeAny, { instanceName: string; adapter: IHttpClientAdapter; logging?: { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logSuccessBody?: boolean | undefined; logSuccessHeaders?: boolean | undefined; onRequest?: "info" | "debug" | "trace" | undefined; logRequestBody?: boolean | undefined; logRequestHeaders?: boolean | undefined; } | undefined; isDefault?: boolean | undefined; propagate?: string[] | undefined; propagateFullContext?: boolean | undefined; }, { instanceName: string; adapter: IHttpClientAdapter; logging?: { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logSuccessBody?: boolean | undefined; logSuccessHeaders?: boolean | undefined; onRequest?: "info" | "debug" | "trace" | undefined; logRequestBody?: boolean | undefined; logRequestHeaders?: boolean | undefined; } | undefined; isDefault?: boolean | undefined; propagate?: string[] | undefined; propagateFullContext?: boolean | undefined; }>; /** * @description Schema for a single message broker client instance. * It validates that a valid `IBrokerAdapter` is provided. * @private */ declare const brokerInstanceConfigSchema: z.ZodObject<{ instanceName: z.ZodString; adapter: z.ZodType<IBrokerAdapter, z.ZodTypeDef, IBrokerAdapter>; /** * An array of context keys to propagate as message headers/properties. * To propagate all keys, provide an array with a single wildcard: `['*']`. * If not provided, only `correlationId` and `transactionId` are propagated by default. */ propagate: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; /** * @deprecated Use `propagate` instead. * If true, propagates the entire asynchronous context map as headers. * If false (default), only propagates `correlationId` and `transactionId`. */ propagateFullContext: z.ZodOptional<z.ZodBoolean>; isDefault: z.ZodOptional<z.ZodBoolean>; }, "strip", z.ZodTypeAny, { instanceName: string; adapter: IBrokerAdapter; isDefault?: boolean | undefined; propagate?: string[] | undefined; propagateFullContext?: boolean | undefined; }, { instanceName: string; adapter: IBrokerAdapter; isDefault?: boolean | undefined; propagate?: string[] | undefined; propagateFullContext?: boolean | undefined; }>; /** * @description The main schema for the entire SyntropyLog configuration. * This is the single source of truth for validating the user's configuration object. */ declare const syntropyLogConfigSchema: z.ZodObject<{ /** Logger-specific configuration. */ logger: z.ZodOptional<z.ZodObject<{ name: z.ZodOptional<z.ZodString>; level: z.ZodOptional<z.ZodEnum<["fatal", "error", "warn", "info", "debug", "trace", "silent"]>>; serviceName: z.ZodOptional<z.ZodString>; /** * An array of transport instances to be used by the logger. */ transports: z.ZodOptional<z.ZodArray<z.ZodType<Transport, z.ZodTypeDef, Transport>, "many">>; /** * A dictionary of custom serializer functions. The key is the field * to look for in the log object, and the value is the function that transforms it. */ serializers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodFunction<z.ZodTuple<[z.ZodAny], z.ZodUnknown>, z.ZodString>>>; /** * The maximum time in milliseconds a custom serializer can run before being timed out. * @default 50 */ serializerTimeoutMs: z.ZodDefault<z.ZodNumber>; /** Configuration for pretty printing logs in development. */ prettyPrint: z.ZodOptional<z.ZodObject<{ enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>; }, "strip", z.ZodTypeAny, { enabled: boolean; }, { enabled?: boolean | undefined; }>>; }, "strip", z.ZodTypeAny, { serializerTimeoutMs: number; name?: string | undefined; level?: "fatal" | "error" | "warn" | "info" | "debug" | "trace" | "silent" | undefined; serviceName?: string | undefined; transports?: Transport[] | undefined; serializers?: Record<string, (args_0: any, ...args: unknown[]) => string> | undefined; prettyPrint?: { enabled: boolean; } | undefined; }, { name?: string | undefined; level?: "fatal" | "error" | "warn" | "info" | "debug" | "trace" | "silent" | undefined; serviceName?: string | undefined; transports?: Transport[] | undefined; serializers?: Record<string, (args_0: any, ...args: unknown[]) => string> | undefined; serializerTimeoutMs?: number | undefined; prettyPrint?: { enabled?: boolean | undefined; } | undefined; }>>; /** Declarative matrix to control context data in logs. */ loggingMatrix: z.ZodOptional<z.ZodObject<{ /** An array of context keys to include in logs by default. Can be overridden by level-specific rules. */ default: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; /** An array of context keys to include for 'trace' level logs. Use `['*']` to include all context properties. */ trace: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; /** An array of context keys to include for 'debug' level logs. Use `['*']` to include all context properties. */ debug: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; /** An array of context keys to include for 'info' level logs. Use `['*']` to include all context properties. */ info: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; /** An array of context keys to include for 'warn' level logs. Use `['*']` to include all context properties. */ warn: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; /** An array of context keys to include for 'error' level logs. Use `['*']` to include all context properties. */ error: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; /** An array of context keys to include for 'fatal' level logs. Use `['*']` to include all context properties. */ fatal: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; }, "strip", z.ZodTypeAny, { fatal?: string[] | undefined; error?: string[] | undefined; warn?: string[] | undefined; info?: string[] | undefined; debug?: string[] | undefined; trace?: string[] | undefined; default?: string[] | undefined; }, { fatal?: string[] | undefined; error?: string[] | undefined; warn?: string[] | undefined; info?: string[] | undefined; debug?: string[] | undefined; trace?: string[] | undefined; default?: string[] | undefined; }>>; /** Redis client configuration. */ redis: z.ZodOptional<z.ZodObject<{ /** An array of Redis instance configurations. */ instances: z.ZodArray<z.ZodDiscriminatedUnion<"mode", [z.ZodObject<{ mode: z.ZodLiteral<"single">; instanceName: z.ZodString; url: z.ZodString; retryOptions: z.ZodOptional<z.ZodObject<{ maxRetries: z.ZodOptional<z.ZodNumber>; retryDelay: z.ZodOptional<z.ZodNumber>; }, "strip", z.ZodTypeAny, { maxRetries?: number | undefined; retryDelay?: number | undefined; }, { maxRetries?: number | undefined; retryDelay?: number | undefined; }>>; logging: z.ZodOptional<z.ZodObject<{ /** Level for successful commands. @default 'debug' */ onSuccess: z.ZodDefault<z.ZodEnum<["trace", "debug", "info"]>>; /** Level for failed commands. @default 'error' */ onError: z.ZodDefault<z.ZodEnum<["warn", "error", "fatal"]>>; /** Whether to log command parameters. @default true */ logCommandValues: z.ZodDefault<z.ZodBoolean>; /** Whether to log the return value of commands. @default false */ logReturnValue: z.ZodDefault<z.ZodBoolean>; }, "strip", z.ZodTypeAny, { onSuccess: "info" | "debug" | "trace"; onError: "fatal" | "error" | "warn"; logCommandValues: boolean; logReturnValue: boolean; }, { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logCommandValues?: boolean | undefined; logReturnValue?: boolean | undefined; }>>; }, "strip", z.ZodTypeAny, { mode: "single"; instanceName: string; url: string; retryOptions?: { maxRetries?: number | undefined; retryDelay?: number | undefined; } | undefined; logging?: { onSuccess: "info" | "debug" | "trace"; onError: "fatal" | "error" | "warn"; logCommandValues: boolean; logReturnValue: boolean; } | undefined; }, { mode: "single"; instanceName: string; url: string; retryOptions?: { maxRetries?: number | undefined; retryDelay?: number | undefined; } | undefined; logging?: { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logCommandValues?: boolean | undefined; logReturnValue?: boolean | undefined; } | undefined; }>, z.ZodObject<{ mode: z.ZodLiteral<"sentinel">; instanceName: z.ZodString; name: z.ZodString; sentinels: z.ZodArray<z.ZodObject<{ host: z.ZodString; port: z.ZodNumber; }, "strip", z.ZodTypeAny, { host: string; port: number; }, { host: string; port: number; }>, "many">; sentinelPassword: z.ZodOptional<z.ZodString>; retryOptions: z.ZodOptional<z.ZodObject<{ maxRetries: z.ZodOptional<z.ZodNumber>; retryDelay: z.ZodOptional<z.ZodNumber>; }, "strip", z.ZodTypeAny, { maxRetries?: number | undefined; retryDelay?: number | undefined; }, { maxRetries?: number | undefined; retryDelay?: number | undefined; }>>; logging: z.ZodOptional<z.ZodObject<{ onSuccess: z.ZodDefault<z.ZodEnum<["trace", "debug", "info"]>>; onError: z.ZodDefault<z.ZodEnum<["warn", "error", "fatal"]>>; logCommandValues: z.ZodDefault<z.ZodBoolean>; logReturnValue: z.ZodDefault<z.ZodBoolean>; }, "strip", z.ZodTypeAny, { onSuccess: "info" | "debug" | "trace"; onError: "fatal" | "error" | "warn"; logCommandValues: boolean; logReturnValue: boolean; }, { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logCommandValues?: boolean | undefined; logReturnValue?: boolean | undefined; }>>; }, "strip", z.ZodTypeAny, { name: string; mode: "sentinel"; instanceName: string; sentinels: { host: string; port: number; }[]; retryOptions?: { maxRetries?: number | undefined; retryDelay?: number | undefined; } | undefined; logging?: { onSuccess: "info" | "debug" | "trace"; onError: "fatal" | "error" | "warn"; logCommandValues: boolean; logReturnValue: boolean; } | undefined; sentinelPassword?: string | undefined; }, { name: string; mode: "sentinel"; instanceName: string; sentinels: { host: string; port: number; }[]; retryOptions?: { maxRetries?: number | undefined; retryDelay?: number | undefined; } | undefined; logging?: { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logCommandValues?: boolean | undefined; logReturnValue?: boolean | undefined; } | undefined; sentinelPassword?: string | undefined; }>, z.ZodObject<{ mode: z.ZodLiteral<"cluster">; instanceName: z.ZodString; rootNodes: z.ZodArray<z.ZodObject<{ host: z.ZodString; port: z.ZodNumber; }, "strip", z.ZodTypeAny, { host: string; port: number; }, { host: string; port: number; }>, "many">; logging: z.ZodOptional<z.ZodObject<{ /** Level for successful commands. @default 'debug' */ onSuccess: z.ZodDefault<z.ZodEnum<["trace", "debug", "info"]>>; /** Level for failed commands. @default 'error' */ onError: z.ZodDefault<z.ZodEnum<["warn", "error", "fatal"]>>; /** Whether to log command parameters. @default true */ logCommandValues: z.ZodDefault<z.ZodBoolean>; /** Whether to log the return value of commands. @default false */ logReturnValue: z.ZodDefault<z.ZodBoolean>; }, "strip", z.ZodTypeAny, { onSuccess: "info" | "debug" | "trace"; onError: "fatal" | "error" | "warn"; logCommandValues: boolean; logReturnValue: boolean; }, { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logCommandValues?: boolean | undefined; logReturnValue?: boolean | undefined; }>>; }, "strip", z.ZodTypeAny, { mode: "cluster"; instanceName: string; rootNodes: { host: string; port: number; }[]; logging?: { onSuccess: "info" | "debug" | "trace"; onError: "fatal" | "error" | "warn"; logCommandValues: boolean; logReturnValue: boolean; } | undefined; }, { mode: "cluster"; instanceName: string; rootNodes: { host: string; port: number; }[]; logging?: { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logCommandValues?: boolean | undefined; logReturnValue?: boolean | undefined; } | undefined; }>]>, "many">; /** The name of the default Redis instance to use when no name is provided to `getInstance()`. */ default: z.ZodOptional<z.ZodString>; }, "strip", z.ZodTypeAny, { instances: ({ mode: "single"; instanceName: string; url: string; retryOptions?: { maxRetries?: number | undefined; retryDelay?: number | undefined; } | undefined; logging?: { onSuccess: "info" | "debug" | "trace"; onError: "fatal" | "error" | "warn"; logCommandValues: boolean; logReturnValue: boolean; } | undefined; } | { name: string; mode: "sentinel"; instanceName: string; sentinels: { host: string; port: number; }[]; retryOptions?: { maxRetries?: number | undefined; retryDelay?: number | undefined; } | undefined; logging?: { onSuccess: "info" | "debug" | "trace"; onError: "fatal" | "error" | "warn"; logCommandValues: boolean; logReturnValue: boolean; } | undefined; sentinelPassword?: string | undefined; } | { mode: "cluster"; instanceName: string; rootNodes: { host: string; port: number; }[]; logging?: { onSuccess: "info" | "debug" | "trace"; onError: "fatal" | "error" | "warn"; logCommandValues: boolean; logReturnValue: boolean; } | undefined; })[]; default?: string | undefined; }, { instances: ({ mode: "single"; instanceName: string; url: string; retryOptions?: { maxRetries?: number | undefined; retryDelay?: number | undefined; } | undefined; logging?: { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logCommandValues?: boolean | undefined; logReturnValue?: boolean | undefined; } | undefined; } | { name: string; mode: "sentinel"; instanceName: string; sentinels: { host: string; port: number; }[]; retryOptions?: { maxRetries?: number | undefined; retryDelay?: number | undefined; } | undefined; logging?: { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logCommandValues?: boolean | undefined; logReturnValue?: boolean | undefined; } | undefined; sentinelPassword?: string | undefined; } | { mode: "cluster"; instanceName: string; rootNodes: { host: string; port: number; }[]; logging?: { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logCommandValues?: boolean | undefined; logReturnValue?: boolean | undefined; } | undefined; })[]; default?: string | undefined; }>>; /** HTTP client configuration. */ http: z.ZodOptional<z.ZodObject<{ /** An array of HTTP client instance configurations. */ instances: z.ZodArray<z.ZodObject<{ instanceName: z.ZodString; adapter: z.ZodType<IHttpClientAdapter, z.ZodTypeDef, IHttpClientAdapter>; isDefault: z.ZodOptional<z.ZodBoolean>; propagate: z.ZodOptional<z.ZodArray<z.ZodString, "many">>; propagateFullContext: z.ZodOptional<z.ZodBoolean>; logging: z.ZodOptional<z.ZodObject<{ onSuccess: z.ZodOptional<z.ZodDefault<z.ZodEnum<["trace", "debug", "info"]>>>; onError: z.ZodOptional<z.ZodDefault<z.ZodEnum<["warn", "error", "fatal"]>>>; logSuccessBody: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>; logSuccessHeaders: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>; onRequest: z.ZodOptional<z.ZodDefault<z.ZodEnum<["trace", "debug", "info"]>>>; logRequestBody: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>; logRequestHeaders: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>; }, "strip", z.ZodTypeAny, { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logSuccessBody?: boolean | undefined; logSuccessHeaders?: boolean | undefined; onRequest?: "info" | "debug" | "trace" | undefined; logRequestBody?: boolean | undefined; logRequestHeaders?: boolean | undefined; }, { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logSuccessBody?: boolean | undefined; logSuccessHeaders?: boolean | undefined; onRequest?: "info" | "debug" | "trace" | undefined; logRequestBody?: boolean | undefined; logRequestHeaders?: boolean | undefined; }>>; }, "strip", z.ZodTypeAny, { instanceName: string; adapter: IHttpClientAdapter; logging?: { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logSuccessBody?: boolean | undefined; logSuccessHeaders?: boolean | undefined; onRequest?: "info" | "debug" | "trace" | undefined; logRequestBody?: boolean | undefined; logRequestHeaders?: boolean | undefined; } | undefined; isDefault?: boolean | undefined; propagate?: string[] | undefined; propagateFullContext?: boolean | undefined; }, { instanceName: string; adapter: IHttpClientAdapter; logging?: { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logSuccessBody?: boolean | undefined; logSuccessHeaders?: boolean | undefined; onRequest?: "info" | "debug" | "trace" | undefined; logRequestBody?: boolean | undefined; logRequestHeaders?: boolean | undefined; } | undefined; isDefault?: boolean | undefined; propagate?: string[] | undefined; propagateFullContext?: boolean | undefined; }>, "many">; /** The name of the default HTTP client instance to use when no name is provided to `getInstance()`. */ default: z.ZodOptional<z.ZodString>; }, "strip", z.ZodTypeAny, { instances: { instanceName: string; adapter: IHttpClientAdapter; logging?: { onSuccess?: "info" | "debug" | "trace" | undefined; onError?: "fatal" | "error" | "warn" | undefined; logSuccessBody?: boolean | undefined; logS