logixlysia 6.6.0 → 6.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <div align="center">
2
2
  <h1><code>🦊</code> Logixlysia</h1>
3
3
  <strong>Logixlysia is a logging library for ElysiaJS</strong>
4
- <img src="https://github.com/PunGrumpy/logixlysia/blob/main/apps/docs/app/opengraph-image.png?raw=true" alt="Logixlysia" width="100%" height="auto" />
4
+ <img src="https://github.com/PunGrumpy/logixlysia/blob/main/apps/docs/public/opengraph-image.png?raw=true" alt="Logixlysia" width="100%" height="auto" />
5
5
  </div>
6
6
 
7
7
  ## `📩` Installation
package/dist/ai.d.ts CHANGED
@@ -1,10 +1,4 @@
1
1
  import { Logger as PinoLogger } from "pino";
2
- type Pino = PinoLogger<never, boolean>;
3
- type RequestInfo = Request;
4
- type LogLevel = "DEBUG" | "INFO" | "WARNING" | "ERROR";
5
- interface StoreData {
6
- beforeTime: bigint;
7
- }
8
2
  interface Logger {
9
3
  debug: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void;
10
4
  error: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void;
@@ -16,6 +10,12 @@ interface Logger {
16
10
  pino: Pino;
17
11
  warn: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void;
18
12
  }
13
+ type Pino = PinoLogger<never, boolean>;
14
+ type RequestInfo = Request;
15
+ type LogLevel = "DEBUG" | "INFO" | "WARNING" | "ERROR";
16
+ interface StoreData {
17
+ beforeTime: bigint;
18
+ }
19
19
  interface AIMetrics {
20
20
  calls?: number;
21
21
  finishReason?: string;
@@ -34,4 +34,4 @@ interface AIMetrics {
34
34
  * on the final access log (evlog-style `ai` object).
35
35
  */
36
36
  declare const mergeAIMetrics: (logger: Pick<Logger, "mergeContext">, request: Request, metrics: AIMetrics) => void;
37
- export { mergeAIMetrics, mergeAIMetrics as default, AIMetrics };
37
+ export { mergeAIMetrics, AIMetrics };
package/dist/ai.js CHANGED
@@ -1,4 +1,4 @@
1
- var z=(k,w,d)=>{if(Object.keys(d).length===0)return;k.mergeContext(w,{ai:d})};export{z as mergeAIMetrics,z as default};
1
+ var z=(k,w,d)=>{if(Object.keys(d).length===0)return;k.mergeContext(w,{ai:d})};export{z as mergeAIMetrics};
2
2
 
3
- //# debugId=1C3753C5E33BE73A64756E2164756E21
4
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjL2FpLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWwogICAgImltcG9ydCB0eXBlIHsgTG9nZ2VyIH0gZnJvbSAnLi9pbnRlcmZhY2VzJ1xuXG5leHBvcnQgaW50ZXJmYWNlIEFJTWV0cmljcyB7XG4gIGNhbGxzPzogbnVtYmVyXG4gIGZpbmlzaFJlYXNvbj86IHN0cmluZ1xuICBpbnB1dFRva2Vucz86IG51bWJlclxuICBtb2RlbD86IHN0cmluZ1xuICBtc1RvRmluaXNoPzogbnVtYmVyXG4gIG1zVG9GaXJzdENodW5rPzogbnVtYmVyXG4gIG91dHB1dFRva2Vucz86IG51bWJlclxuICBwcm92aWRlcj86IHN0cmluZ1xuICByZWFzb25pbmdUb2tlbnM/OiBudW1iZXJcbiAgdG9rZW5zUGVyU2Vjb25kPzogbnVtYmVyXG4gIHRvdGFsVG9rZW5zPzogbnVtYmVyXG59XG5cbi8qKlxuICogTWVyZ2VzIEFJIFNESyAvIExMTSB1c2FnZSBtZXRyaWNzIGludG8gdGhlIHJlcXVlc3QgY29udGV4dCBiYWcgc28gdGhleSBhcHBlYXJcbiAqIG9uIHRoZSBmaW5hbCBhY2Nlc3MgbG9nIChldmxvZy1zdHlsZSBgYWlgIG9iamVjdCkuXG4gKi9cbmV4cG9ydCBjb25zdCBtZXJnZUFJTWV0cmljcyA9IChcbiAgbG9nZ2VyOiBQaWNrPExvZ2dlciwgJ21lcmdlQ29udGV4dCc+LFxuICByZXF1ZXN0OiBSZXF1ZXN0LFxuICBtZXRyaWNzOiBBSU1ldHJpY3Ncbik6IHZvaWQgPT4ge1xuICBpZiAoT2JqZWN0LmtleXMobWV0cmljcykubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuXG4gIH1cbiAgbG9nZ2VyLm1lcmdlQ29udGV4dChyZXF1ZXN0LCB7IGFpOiBtZXRyaWNzIH0pXG59XG5cbmV4cG9ydCB7IG1lcmdlQUlNZXRyaWNzIGFzIGRlZmF1bHQgfVxuIgogIF0sCiAgIm1hcHBpbmdzIjogIkFBb0JPLElBQU0sRUFBaUIsQ0FDNUIsRUFDQSxFQUNBLElBQ1MsQ0FDVCxHQUFJLE9BQU8sS0FBSyxDQUFPLEVBQUUsU0FBVyxFQUNsQyxPQUVGLEVBQU8sYUFBYSxFQUFTLENBQUUsR0FBSSxDQUFRLENBQUMiLAogICJkZWJ1Z0lkIjogIjFDMzc1M0M1RTMzQkU3M0E2NDc1NkUyMTY0NzU2RTIxIiwKICAibmFtZXMiOiBbXQp9
3
+ //# debugId=2447CBBCE831480664756E2164756E21
4
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjL2FpLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWwogICAgImltcG9ydCB0eXBlIHsgTG9nZ2VyIH0gZnJvbSAnLi9pbnRlcmZhY2VzJ1xuXG5leHBvcnQgaW50ZXJmYWNlIEFJTWV0cmljcyB7XG4gIGNhbGxzPzogbnVtYmVyXG4gIGZpbmlzaFJlYXNvbj86IHN0cmluZ1xuICBpbnB1dFRva2Vucz86IG51bWJlclxuICBtb2RlbD86IHN0cmluZ1xuICBtc1RvRmluaXNoPzogbnVtYmVyXG4gIG1zVG9GaXJzdENodW5rPzogbnVtYmVyXG4gIG91dHB1dFRva2Vucz86IG51bWJlclxuICBwcm92aWRlcj86IHN0cmluZ1xuICByZWFzb25pbmdUb2tlbnM/OiBudW1iZXJcbiAgdG9rZW5zUGVyU2Vjb25kPzogbnVtYmVyXG4gIHRvdGFsVG9rZW5zPzogbnVtYmVyXG59XG5cbi8qKlxuICogTWVyZ2VzIEFJIFNESyAvIExMTSB1c2FnZSBtZXRyaWNzIGludG8gdGhlIHJlcXVlc3QgY29udGV4dCBiYWcgc28gdGhleSBhcHBlYXJcbiAqIG9uIHRoZSBmaW5hbCBhY2Nlc3MgbG9nIChldmxvZy1zdHlsZSBgYWlgIG9iamVjdCkuXG4gKi9cbmV4cG9ydCBjb25zdCBtZXJnZUFJTWV0cmljcyA9IChcbiAgbG9nZ2VyOiBQaWNrPExvZ2dlciwgJ21lcmdlQ29udGV4dCc+LFxuICByZXF1ZXN0OiBSZXF1ZXN0LFxuICBtZXRyaWNzOiBBSU1ldHJpY3Ncbik6IHZvaWQgPT4ge1xuICBpZiAoT2JqZWN0LmtleXMobWV0cmljcykubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuXG4gIH1cbiAgbG9nZ2VyLm1lcmdlQ29udGV4dChyZXF1ZXN0LCB7IGFpOiBtZXRyaWNzIH0pXG59XG4iCiAgXSwKICAibWFwcGluZ3MiOiAiQUFvQk8sSUFBTSxFQUFpQixDQUM1QixFQUNBLEVBQ0EsSUFDUyxDQUNULEdBQUksT0FBTyxLQUFLLENBQU8sRUFBRSxTQUFXLEVBQ2xDLE9BRUYsRUFBTyxhQUFhLEVBQVMsQ0FBRSxHQUFJLENBQVEsQ0FBQyIsCiAgImRlYnVnSWQiOiAiMjQ0N0NCQkNFODMxNDgwNjY0NzU2RTIxNjQ3NTZFMjEiLAogICJuYW1lcyI6IFtdCn0=
package/dist/index.d.ts CHANGED
@@ -1,5 +1,24 @@
1
1
  import { Elysia } from "elysia";
2
- import { Logger as PinoLogger, LoggerOptions as PinoLoggerOptions } from "pino";
2
+ import { LoggerOptions as PinoLoggerOptions } from "pino";
3
+ import { Logger as PinoLogger } from "pino";
4
+ interface Logger {
5
+ debug: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void;
6
+ error: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void;
7
+ getContext: (key: RequestInfo | object) => Readonly<Record<string, unknown>>;
8
+ handleHttpError: (request: RequestInfo, error: unknown, store: StoreData) => void;
9
+ info: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void;
10
+ log: (level: LogLevel, request: RequestInfo, data: Record<string, unknown>, store: StoreData) => void;
11
+ mergeContext: (key: RequestInfo | object, partial: Record<string, unknown>) => void;
12
+ pino: Pino;
13
+ warn: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void;
14
+ }
15
+ interface RequestScopedLogger {
16
+ debug: (message: string, context?: Record<string, unknown>) => void;
17
+ error: (message: string, context?: Record<string, unknown>) => void;
18
+ info: (message: string, context?: Record<string, unknown>) => void;
19
+ mergeContext: (partial: Record<string, unknown>) => void;
20
+ warn: (message: string, context?: Record<string, unknown>) => void;
21
+ }
3
22
  type Pino = PinoLogger<never, boolean>;
4
23
  type RequestInfo = Request;
5
24
  type LogLevel = "DEBUG" | "INFO" | "WARNING" | "ERROR";
@@ -11,6 +30,10 @@ interface LogixlysiaStore {
11
30
  logger: Logger;
12
31
  pino: Pino;
13
32
  }
33
+ interface LogixlysiaContext {
34
+ request: Request;
35
+ store: LogixlysiaStore;
36
+ }
14
37
  interface Transport {
15
38
  log: (level: LogLevel, message: string, meta?: Record<string, unknown>) => void | Promise<void>;
16
39
  }
@@ -18,7 +41,9 @@ interface LogRotationConfig {
18
41
  compress?: boolean;
19
42
  compression?: "gzip";
20
43
  /**
21
- * Rotate at a fixed interval, e.g. '1d', '12h'.
44
+ * Rotate when the live file's age reaches a fixed interval, evaluated on
45
+ * write (an idle process rotates on its next write, not on a timer).
46
+ * Format: number + 'h' | 'd' | 'w', e.g. '12h', '1d', '1w'.
22
47
  */
23
48
  interval?: string;
24
49
  /**
@@ -48,6 +73,11 @@ interface LogFilter {
48
73
  */
49
74
  type PrettyPrintConfig = boolean | Record<string, unknown>;
50
75
  type LogPreset = "dev" | "prod" | "json";
76
+ /** Context passed to {@link Options.config.onError} when a sink fails. */
77
+ interface SinkErrorContext {
78
+ error: unknown;
79
+ sink: "file" | "rotation" | "transport";
80
+ }
51
81
  interface RequestIdConfig {
52
82
  /**
53
83
  * Enable request ID generation.
@@ -65,93 +95,105 @@ interface RequestIdConfig {
65
95
  */
66
96
  header?: string;
67
97
  }
68
- interface Options {
69
- config?: {
70
- showStartupMessage?: boolean;
71
- startupMessageFormat?: "simple" | "banner";
72
- useColors?: boolean;
73
- ip?: boolean;
74
- timestamp?: {
75
- translateTime?: string;
76
- };
77
- customLogFormat?: string;
78
- /** Service name shown in `{service}` token (e.g. evlog-style `[my-app]`). */
79
- service?: string;
80
- /** Duration (ms) below this uses green; default 500. */
81
- slowThreshold?: number;
82
- /** Duration (ms) at or above this uses red + `{speed}` badge; default 1000. */
83
- verySlowThreshold?: number;
84
- /** Render `data.context` as tree lines under the main log line; default true. */
85
- showContextTree?: boolean;
86
- /** How many object nesting levels to expand in the context tree; default 1. */
87
- contextDepth?: number;
88
- /** Include query parameters in the logged URL path; default false. */
89
- logQueryParams?: boolean;
90
- /** Skip automatic WebSocket lifecycle logs from `wrapWs`; default false. */
91
- disableWebSocketLogging?: boolean;
92
- /**
93
- * Enable automatic request ID generation and propagation.
94
- *
95
- * - `true`: Enable with defaults (`X-Request-Id` header, `crypto.randomUUID()` generator).
96
- * - `false` or `undefined`: Disabled (default).
97
- * - `RequestIdConfig` object: Enable with custom header name and/or generator.
98
- *
99
- * When enabled, the plugin will:
100
- * 1. Read `X-Request-Id` (or custom header) from the incoming request — honoring IDs set by upstream proxies.
101
- * 2. Generate a new UUID if no header is present.
102
- * 3. Merge `{ requestId }` into the request context (appears in logs and context tree).
103
- * 4. Set the header on the outgoing response for client-side tracing.
104
- */
105
- requestId?: boolean | RequestIdConfig;
106
- logFilter?: LogFilter;
107
- transports?: Transport[];
108
- useTransportsOnly?: boolean;
109
- disableInternalLogger?: boolean;
110
- disableFileLogging?: boolean;
111
- logFilePath?: string;
112
- logRotation?: LogRotationConfig;
113
- /**
114
- * Automatically redact sensitive information (PII) from logs.
115
- * Masks emails, IP addresses, Luhn-valid payment card numbers, and JWTs in strings and deeply nested objects.
116
- */
117
- autoRedact?: boolean;
118
- pino?: (PinoLoggerOptions & {
119
- prettyPrint?: PrettyPrintConfig;
120
- }) | undefined;
121
- /**
122
- * Enable request-scoped logger propagation via AsyncLocalStorage.
123
- * When enabled, a request-scoped logger `log` is also derived on the Elysia context.
124
- * @default false
125
- */
126
- useAsyncLocalStorage?: boolean;
98
+ interface FormattingConfig {
99
+ /** How many object nesting levels to expand in the context tree; default 1. */
100
+ contextDepth?: number;
101
+ customLogFormat?: string;
102
+ ip?: boolean;
103
+ /** Include query parameters in the logged URL path; default false. */
104
+ logQueryParams?: boolean;
105
+ /** Service name shown in `{service}` token (e.g. evlog-style `[my-app]`). */
106
+ service?: string;
107
+ /** Render `data.context` as tree lines under the main log line; default true. */
108
+ showContextTree?: boolean;
109
+ showStartupMessage?: boolean;
110
+ /** Duration (ms) below this uses green; default 500. */
111
+ slowThreshold?: number;
112
+ startupMessageFormat?: "simple" | "banner";
113
+ timestamp?: {
114
+ translateTime?: string;
127
115
  };
116
+ useColors?: boolean;
117
+ /** Duration (ms) at or above this uses red + `{speed}` badge; default 1000. */
118
+ verySlowThreshold?: number;
119
+ }
120
+ interface OutputConfig {
121
+ disableFileLogging?: boolean;
122
+ disableInternalLogger?: boolean;
123
+ /** Directory mode for created log directories. @default 0o700 */
124
+ logDirMode?: number;
125
+ /** File mode for created log files. @default 0o600 */
126
+ logFileMode?: number;
127
+ logFilePath?: string;
128
+ logRotation?: LogRotationConfig;
128
129
  /**
129
- * Opinionated defaults for common environments.
130
- * Explicit `config` fields override preset values.
130
+ * Called when a sink (transport, file, rotation) fails. Errors thrown by
131
+ * the hook itself are swallowed. When absent, failures go to stderr
132
+ * (rate-limited for transports).
131
133
  */
132
- preset?: LogPreset;
134
+ onError?: (context: SinkErrorContext) => void;
135
+ transports?: Transport[];
136
+ useTransportsOnly?: boolean;
133
137
  }
134
- interface Logger {
135
- debug: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void;
136
- error: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void;
137
- getContext: (key: RequestInfo | object) => Readonly<Record<string, unknown>>;
138
- handleHttpError: (request: RequestInfo, error: unknown, store: StoreData) => void;
139
- info: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void;
140
- log: (level: LogLevel, request: RequestInfo, data: Record<string, unknown>, store: StoreData) => void;
141
- mergeContext: (key: RequestInfo | object, partial: Record<string, unknown>) => void;
142
- pino: Pino;
143
- warn: (request: RequestInfo, message: string, context?: Record<string, unknown>) => void;
138
+ interface RedactionConfig {
139
+ /**
140
+ * Automatically redact sensitive information (PII) from logs.
141
+ * Masks emails, IP addresses, Luhn-valid payment card numbers, and JWTs in strings and deeply nested objects.
142
+ */
143
+ autoRedact?: boolean;
144
+ /**
145
+ * Log the offending payload (`found`/`errors`) from validation errors.
146
+ * Off by default: request bodies routinely contain credentials.
147
+ * @default false
148
+ */
149
+ logErrorPayload?: boolean;
150
+ /**
151
+ * Additional key/header names (case-insensitive; `-`/`_`/camelCase variants
152
+ * are normalized) whose values are redacted when `autoRedact` is enabled.
153
+ * Extends the built-in list (authorization, cookie, x-api-key, password,
154
+ * secret, token, session, …).
155
+ */
156
+ redactKeys?: string[];
144
157
  }
145
- interface RequestScopedLogger {
146
- debug: (message: string, context?: Record<string, unknown>) => void;
147
- error: (message: string, context?: Record<string, unknown>) => void;
148
- info: (message: string, context?: Record<string, unknown>) => void;
149
- mergeContext: (partial: Record<string, unknown>) => void;
150
- warn: (message: string, context?: Record<string, unknown>) => void;
158
+ interface RequestTrackingConfig {
159
+ /** Skip automatic WebSocket lifecycle logs from `wrapWs`; default false. */
160
+ disableWebSocketLogging?: boolean;
161
+ /**
162
+ * Enable automatic request ID generation and propagation.
163
+ *
164
+ * - `true`: Enable with defaults (`X-Request-Id` header, `crypto.randomUUID()` generator).
165
+ * - `false` or `undefined`: Disabled (default).
166
+ * - `RequestIdConfig` object: Enable with custom header name and/or generator.
167
+ *
168
+ * When enabled, the plugin will:
169
+ * 1. Read `X-Request-Id` (or custom header) from the incoming request — honoring IDs set by upstream proxies.
170
+ * 2. Generate a new UUID if no header is present.
171
+ * 3. Merge `{ requestId }` into the request context (appears in logs and context tree).
172
+ * 4. Set the header on the outgoing response for client-side tracing.
173
+ */
174
+ requestId?: boolean | RequestIdConfig;
175
+ /**
176
+ * Enable request-scoped logger propagation via AsyncLocalStorage.
177
+ * When enabled, a request-scoped logger `log` is also derived on the Elysia context.
178
+ * @default false
179
+ */
180
+ useAsyncLocalStorage?: boolean;
151
181
  }
152
- interface LogixlysiaContext {
153
- request: Request;
154
- store: LogixlysiaStore;
182
+ interface PinoConfig {
183
+ pino?: (PinoLoggerOptions & {
184
+ prettyPrint?: PrettyPrintConfig;
185
+ }) | undefined;
186
+ }
187
+ interface LogixlysiaConfig extends FormattingConfig, OutputConfig, RedactionConfig, RequestTrackingConfig, PinoConfig {
188
+ logFilter?: LogFilter;
189
+ }
190
+ interface Options {
191
+ config?: LogixlysiaConfig;
192
+ /**
193
+ * Opinionated defaults for common environments.
194
+ * Explicit `config` fields override preset values.
195
+ */
196
+ preset?: LogPreset;
155
197
  }
156
198
  /** HTTP `Request` or WebSocket instance for accumulated context. */
157
199
  type ContextKey = Request | object;
@@ -159,6 +201,13 @@ interface RequestContextStore {
159
201
  clearContext: (key: ContextKey) => void;
160
202
  getContext: (key: ContextKey) => Readonly<Record<string, unknown>>;
161
203
  mergeContext: (key: ContextKey, partial: Record<string, unknown>) => void;
204
+ /**
205
+ * Non-cloning read of the live context bag. Returns the SAME object stored internally (or a
206
+ * shared frozen empty object) — never hand this to user-facing code, which may retain or
207
+ * mutate it. Only internal, read-only call sites (that immediately spread the result into a
208
+ * new object) may use this; everything else must use {@link RequestContextStore.getContext}.
209
+ */
210
+ peekContext: (key: ContextKey) => Readonly<Record<string, unknown>>;
162
211
  }
163
212
  interface WebSocketLike {
164
213
  readonly data?: {
@@ -204,6 +253,11 @@ declare const resolveRequestIdConfig: (raw?: boolean | RequestIdConfig) => Resol
204
253
  /**
205
254
  * Reads an existing request ID from the incoming request header, or generates a
206
255
  * new one using the configured generator.
256
+ *
257
+ * Inbound values are validated against `VALID_REQUEST_ID` (alphanumeric plus
258
+ * `.`, `_`, `-`, 1-128 chars) before being trusted — request IDs flow into log
259
+ * lines, response headers, and context trees, so malformed or oversized
260
+ * values are replaced with a freshly generated one rather than echoed back.
207
261
  */
208
262
  declare const getOrCreateRequestId: (request: Request, config: ResolvedRequestIdConfig) => string;
209
263
  /**
@@ -230,4 +284,4 @@ type LogixlysiaPlugin = Logixlysia & {
230
284
  wrapWs: ReturnType<typeof createWsHandlerWrapper>;
231
285
  };
232
286
  declare const logixlysia: (rawOptions?: Options) => LogixlysiaPlugin;
233
- export { useLogger, resolveRequestIdConfig, resolveOptions, logixlysia, getOrCreateRequestId, logixlysia as default, createWsHandlerWrapper, createPluginLogger, createLogger, WsHandlerHooks, Transport, StoreData, ResolvedRequestIdConfig, RequestScopedLogger, RequestIdConfig, Pino, Options, LogixlysiaStore, LogixlysiaSingleton, LogixlysiaPlugin, LogixlysiaContext, Logixlysia, Logger, LogPreset, LogLevel, EmptyElysiaSlot };
287
+ export { useLogger, resolveRequestIdConfig, resolveOptions, getOrCreateRequestId, logixlysia as default, createWsHandlerWrapper, createPluginLogger, createLogger, WsHandlerHooks, Transport, StoreData, ResolvedRequestIdConfig, RequestScopedLogger, RequestIdConfig, Pino, Options, LogixlysiaStore, LogixlysiaSingleton, LogixlysiaPlugin, LogixlysiaContext, Logixlysia, Logger, LogPreset, LogLevel, EmptyElysiaSlot };