@geekmidas/logger 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/pino.ts CHANGED
@@ -1,7 +1,173 @@
1
+ /**
2
+ * Pino logger with built-in redaction support for sensitive data.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { createLogger, DEFAULT_REDACT_PATHS } from '@geekmidas/logger/pino';
7
+ *
8
+ * // Enable redaction with sensible defaults
9
+ * const logger = createLogger({ redact: true });
10
+ *
11
+ * // Sensitive data is automatically masked
12
+ * logger.info({ password: 'secret123', user: 'john' }, 'Login');
13
+ * // Output: { password: '[Redacted]', user: 'john' } Login
14
+ *
15
+ * // Add custom paths (merged with defaults)
16
+ * const logger2 = createLogger({ redact: ['user.ssn'] });
17
+ *
18
+ * // Override defaults for full control
19
+ * const logger3 = createLogger({
20
+ * redact: {
21
+ * paths: ['onlyThis'],
22
+ * resolution: 'override',
23
+ * }
24
+ * });
25
+ * ```
26
+ *
27
+ * @module
28
+ */
1
29
  import { pino } from 'pino';
2
- import type { CreateLoggerOptions } from './types';
30
+ import type { CreateLoggerOptions, RedactOptions } from './types';
3
31
 
4
- export function createLogger(options: CreateLoggerOptions) {
32
+ /**
33
+ * Default sensitive field paths for redaction.
34
+ *
35
+ * These paths are automatically used when `redact: true` is set,
36
+ * and merged with custom paths unless `resolution: 'override'` is specified.
37
+ *
38
+ * Includes:
39
+ * - Authentication: password, token, apiKey, authorization, credentials
40
+ * - Headers: authorization, cookie, x-api-key, x-auth-token
41
+ * - Personal data: ssn, creditCard, cvv, pin
42
+ * - Secrets: secret, connectionString, databaseUrl
43
+ * - Wildcards: *.password, *.secret, *.token (catches nested fields)
44
+ */
45
+ export const DEFAULT_REDACT_PATHS: string[] = [
46
+ // Authentication & authorization
47
+ 'password',
48
+ 'pass',
49
+ 'passwd',
50
+ 'secret',
51
+ 'token',
52
+ 'accessToken',
53
+ 'refreshToken',
54
+ 'idToken',
55
+ 'apiKey',
56
+ 'api_key',
57
+ 'apikey',
58
+ 'auth',
59
+ 'authorization',
60
+ 'credential',
61
+ 'credentials',
62
+
63
+ // Common nested patterns (headers, body, etc.)
64
+ '*.password',
65
+ '*.secret',
66
+ '*.token',
67
+ '*.apiKey',
68
+ '*.api_key',
69
+ '*.authorization',
70
+ '*.accessToken',
71
+ '*.refreshToken',
72
+
73
+ // HTTP headers (case variations)
74
+ 'headers.authorization',
75
+ 'headers.Authorization',
76
+ 'headers["authorization"]',
77
+ 'headers["Authorization"]',
78
+ 'headers.cookie',
79
+ 'headers.Cookie',
80
+ 'headers["x-api-key"]',
81
+ 'headers["X-Api-Key"]',
82
+ 'headers["x-auth-token"]',
83
+ 'headers["X-Auth-Token"]',
84
+
85
+ // Common sensitive data fields
86
+ 'ssn',
87
+ 'socialSecurityNumber',
88
+ 'social_security_number',
89
+ 'creditCard',
90
+ 'credit_card',
91
+ 'cardNumber',
92
+ 'card_number',
93
+ 'cvv',
94
+ 'cvc',
95
+ 'pin',
96
+
97
+ // Database & connection strings
98
+ 'connectionString',
99
+ 'connection_string',
100
+ 'databaseUrl',
101
+ 'database_url',
102
+ ];
103
+
104
+ /**
105
+ * Type for the resolved pino redact config (without our custom resolution field).
106
+ */
107
+ type PinoRedactConfig =
108
+ | string[]
109
+ | {
110
+ paths: string[];
111
+ censor?: string | ((value: unknown, path: string[]) => unknown);
112
+ remove?: boolean;
113
+ };
114
+
115
+ /**
116
+ * Resolves redaction configuration from options.
117
+ * Returns undefined if redaction is disabled, or a pino-compatible redact config.
118
+ *
119
+ * By default (resolution: 'merge'), custom paths are merged with DEFAULT_REDACT_PATHS.
120
+ * With resolution: 'override', only the custom paths are used.
121
+ */
122
+ function resolveRedactConfig(
123
+ redact: boolean | RedactOptions | undefined,
124
+ ): PinoRedactConfig | undefined {
125
+ if (redact === undefined || redact === false) {
126
+ return undefined;
127
+ }
128
+
129
+ if (redact === true) {
130
+ return DEFAULT_REDACT_PATHS;
131
+ }
132
+
133
+ // Array syntax - merge with defaults
134
+ if (Array.isArray(redact)) {
135
+ return [...DEFAULT_REDACT_PATHS, ...redact];
136
+ }
137
+
138
+ // Object syntax - check resolution mode
139
+ const { resolution = 'merge', paths, censor, remove } = redact;
140
+
141
+ const resolvedPaths =
142
+ resolution === 'override' ? paths : [...DEFAULT_REDACT_PATHS, ...paths];
143
+
144
+ // Return clean pino config without our resolution field
145
+ const config: PinoRedactConfig = { paths: resolvedPaths };
146
+ if (censor !== undefined) config.censor = censor;
147
+ if (remove !== undefined) config.remove = remove;
148
+
149
+ return config;
150
+ }
151
+
152
+ /**
153
+ * Creates a pino logger instance with optional redaction support.
154
+ *
155
+ * @param options - Logger configuration options
156
+ * @returns A configured pino logger instance
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * // Basic logger
161
+ * const logger = createLogger({ level: 'debug' });
162
+ *
163
+ * // With redaction enabled
164
+ * const secureLogger = createLogger({ redact: true });
165
+ *
166
+ * // Pretty printing in development
167
+ * const devLogger = createLogger({ pretty: true, redact: true });
168
+ * ```
169
+ */
170
+ export function createLogger(options: CreateLoggerOptions = {}) {
5
171
  // @ts-ignore
6
172
  const pretty = options?.pretty && process.NODE_ENV !== 'production';
7
173
  const baseOptions = pretty
@@ -12,8 +178,13 @@ export function createLogger(options: CreateLoggerOptions) {
12
178
  },
13
179
  }
14
180
  : {};
181
+
182
+ const redact = resolveRedactConfig(options.redact);
183
+
15
184
  return pino({
16
185
  ...baseOptions,
186
+ ...(options.level && { level: options.level }),
187
+ ...(redact && { redact }),
17
188
  formatters: {
18
189
  bindings() {
19
190
  return { nodeVersion: process.version };
package/src/types.ts CHANGED
@@ -74,7 +74,94 @@ export enum LogLevel {
74
74
  Silent = 'silent',
75
75
  }
76
76
 
77
+ /**
78
+ * Redaction configuration for masking sensitive data in logs.
79
+ * Uses pino's fast-redact library under the hood.
80
+ *
81
+ * By default, custom paths are merged with the default sensitive paths.
82
+ * Use `resolution: 'override'` to use only your custom paths.
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * // Simple path array (merges with defaults)
87
+ * redact: ['user.ssn', 'custom.field']
88
+ *
89
+ * // Override defaults completely
90
+ * redact: {
91
+ * paths: ['only.these.paths'],
92
+ * resolution: 'override',
93
+ * }
94
+ *
95
+ * // With custom censor
96
+ * redact: {
97
+ * paths: ['extra.secret'],
98
+ * censor: '***',
99
+ * }
100
+ *
101
+ * // Remove fields entirely
102
+ * redact: {
103
+ * paths: ['temporary.data'],
104
+ * remove: true,
105
+ * }
106
+ * ```
107
+ */
108
+ export type RedactOptions =
109
+ | string[]
110
+ | {
111
+ /** Paths to redact using dot notation or bracket notation for special chars */
112
+ paths: string[];
113
+ /** Custom replacement text (default: '[REDACTED]') */
114
+ censor?: string | ((value: unknown, path: string[]) => unknown);
115
+ /** Remove the field entirely instead of replacing (default: false) */
116
+ remove?: boolean;
117
+ /**
118
+ * How to combine custom paths with default sensitive paths.
119
+ * - 'merge': Custom paths are added to default paths (default)
120
+ * - 'override': Only custom paths are used, defaults are ignored
121
+ */
122
+ resolution?: 'merge' | 'override';
123
+ };
124
+
77
125
  export type CreateLoggerOptions = {
126
+ /** Enable pretty printing with colors (disabled in production) */
78
127
  pretty?: boolean;
128
+ /** Minimum log level to output */
79
129
  level?: LogLevel;
130
+ /**
131
+ * Redaction configuration for masking sensitive data.
132
+ *
133
+ * - `true`: Uses default sensitive paths (password, token, secret, etc.)
134
+ * - `false` or `undefined`: No redaction applied
135
+ * - `string[]`: Custom paths merged with defaults
136
+ * - `object`: Advanced config with paths, censor, remove, and resolution options
137
+ *
138
+ * By default, custom paths are **merged** with the default sensitive paths.
139
+ * Use `resolution: 'override'` to disable defaults and use only your paths.
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * // Use defaults only
144
+ * createLogger({ redact: true });
145
+ *
146
+ * // Add custom paths (merged with defaults)
147
+ * createLogger({ redact: ['user.ssn', 'custom.field'] });
148
+ *
149
+ * // Override defaults completely
150
+ * createLogger({
151
+ * redact: {
152
+ * paths: ['only.these.paths'],
153
+ * resolution: 'override',
154
+ * }
155
+ * });
156
+ *
157
+ * // Merge with custom censor
158
+ * createLogger({
159
+ * redact: {
160
+ * paths: ['extra.secret'],
161
+ * censor: '***',
162
+ * }
163
+ * });
164
+ * ```
165
+ */
166
+ redact?: boolean | RedactOptions;
80
167
  };