@maestro-js/log 1.0.0-alpha.1 → 1.0.0-alpha.11

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/dist/index.d.ts CHANGED
@@ -24,6 +24,11 @@ interface LogFunctions<LogMessageData extends any[] = any[]> {
24
24
  error(...data: LogMessageData): void;
25
25
  emergency(...data: LogMessageData): void;
26
26
  }
27
+ interface WithRedactionsOptions {
28
+ redact?: (string | RegExp)[];
29
+ replacement?: string;
30
+ redactor?: (key: string, value: unknown) => unknown;
31
+ }
27
32
 
28
33
  declare function ConsoleTransport<LogMessageData extends any[] = any[]>(options?: {
29
34
  filter?: LogMessageFilter<LogMessageData>;
@@ -80,6 +85,8 @@ declare function StubTransport<LogMessageData extends any[] = any[]>(options?: {
80
85
  listMessages(): LogMessage<LogMessageData>[];
81
86
  };
82
87
 
88
+ declare function withRedactions<T extends LogTransport<D>, D extends any[] = any[]>(transport: T, options: WithRedactionsOptions): T;
89
+
83
90
  /**
84
91
  * Creates a new logger. By default loggers have no transports
85
92
  */
@@ -192,6 +199,8 @@ declare namespace Log {
192
199
  type MessageFilter<LogMessageData extends any[] = any[]> = LogMessageFilter<LogMessageData>;
193
200
  /** Destination that receives {@link Log.Message messages} from a logger. */
194
201
  type Transport<LogMessageData extends any[] = any[]> = LogTransport<LogMessageData>;
202
+ /** Options for {@link Log.withRedactions}. */
203
+ type WithRedactionsOptions = WithRedactionsOptions;
195
204
  }
196
205
  /**
197
206
  * Structured logging with pluggable transports.
@@ -208,6 +217,8 @@ declare const Log: {
208
217
  addTransport: (...transport: Log.Transport<any>[]) => void;
209
218
  removeTransport: (...transport: Log.Transport<any>[]) => void;
210
219
  channel: <ChannelMessageData extends any = any>(channel: LogChannel) => Log.LogFunctions<ChannelMessageData>;
220
+ withRedactions: typeof withRedactions;
221
+ commonSensitiveKeys: readonly ["password", "secret", "token", "accessToken", "refreshToken", "apiKey", "apiSecret", "authorization", "cookie", "creditCard", "ssn", "socialSecurityNumber"];
211
222
  transports: {
212
223
  console: typeof ConsoleTransport;
213
224
  file: typeof FileTransport;
package/dist/index.js CHANGED
@@ -188,6 +188,118 @@ function StubTransport(options) {
188
188
  };
189
189
  }
190
190
 
191
+ // src/with-redactions.ts
192
+ var commonSensitiveKeys = [
193
+ "password",
194
+ "secret",
195
+ "token",
196
+ "accessToken",
197
+ "refreshToken",
198
+ "apiKey",
199
+ "apiSecret",
200
+ "authorization",
201
+ "cookie",
202
+ "creditCard",
203
+ "ssn",
204
+ "socialSecurityNumber"
205
+ ];
206
+ function withRedactions(transport, options) {
207
+ const { replacement = "[REDACTED]", redact = [], redactor } = options;
208
+ const stringMatchers = /* @__PURE__ */ new Set();
209
+ const regexMatchers = [];
210
+ for (const matcher of redact) {
211
+ if (typeof matcher === "string") {
212
+ stringMatchers.add(matcher.toLowerCase());
213
+ } else {
214
+ regexMatchers.push(matcher);
215
+ }
216
+ }
217
+ function keyMatches(key) {
218
+ if (stringMatchers.has(key.toLowerCase())) return true;
219
+ for (const re of regexMatchers) {
220
+ if (re.test(key)) return true;
221
+ }
222
+ return false;
223
+ }
224
+ function redactMessage(message) {
225
+ if (stringMatchers.size === 0 && regexMatchers.length === 0 && !redactor) return message;
226
+ const seen = /* @__PURE__ */ new WeakSet();
227
+ const newData = redactData(message.data, seen);
228
+ return newData === message.data ? message : { ...message, data: newData };
229
+ }
230
+ function redactData(data, seen) {
231
+ let changed = false;
232
+ const result = data.map((item) => {
233
+ const redacted = redactValue(item, seen);
234
+ if (redacted !== item) changed = true;
235
+ return redacted;
236
+ });
237
+ return changed ? result : data;
238
+ }
239
+ function redactValue(value, seen) {
240
+ if (value === null || value === void 0 || typeof value !== "object") return value;
241
+ const obj = value;
242
+ if (seen.has(obj)) return "[CIRCULAR]";
243
+ if (obj instanceof Date || obj instanceof RegExp || obj instanceof Map || obj instanceof Set || Buffer.isBuffer(obj)) {
244
+ return obj;
245
+ }
246
+ seen.add(obj);
247
+ if (Array.isArray(obj)) return redactArray(obj, seen);
248
+ if (obj instanceof Error) return redactError(obj, seen);
249
+ const proto = Object.getPrototypeOf(obj);
250
+ if (proto === Object.prototype || proto === null) return redactPlainObject(obj, seen);
251
+ return obj;
252
+ }
253
+ function redactArray(arr, seen) {
254
+ let changed = false;
255
+ const result = arr.map((item) => {
256
+ const redacted = redactValue(item, seen);
257
+ if (redacted !== item) changed = true;
258
+ return redacted;
259
+ });
260
+ return changed ? result : arr;
261
+ }
262
+ function redactError(err, seen) {
263
+ const plain = {
264
+ name: err.name,
265
+ message: err.message,
266
+ stack: err.stack
267
+ };
268
+ if (err.cause !== void 0) {
269
+ plain.cause = redactValue(err.cause, seen);
270
+ }
271
+ for (const key of Object.keys(err)) {
272
+ plain[key] = redactKeyValue(key, err[key], seen);
273
+ }
274
+ return plain;
275
+ }
276
+ function redactPlainObject(obj, seen) {
277
+ let changed = false;
278
+ const result = {};
279
+ for (const key of Object.keys(obj)) {
280
+ const original = obj[key];
281
+ const redacted = redactKeyValue(key, original, seen);
282
+ if (redacted !== original) changed = true;
283
+ result[key] = redacted;
284
+ }
285
+ return changed ? result : obj;
286
+ }
287
+ function redactKeyValue(key, value, seen) {
288
+ if (redactor) {
289
+ const custom = redactor(key, value);
290
+ if (custom !== value) return custom;
291
+ }
292
+ if (keyMatches(key)) return replacement;
293
+ return redactValue(value, seen);
294
+ }
295
+ return {
296
+ ...transport,
297
+ write(message) {
298
+ transport.write(redactMessage(message));
299
+ }
300
+ };
301
+ }
302
+
191
303
  // src/index.ts
192
304
  var defaultConsoleTransport = ConsoleTransport();
193
305
  function create(config) {
@@ -320,6 +432,8 @@ var Log = {
320
432
  addTransport: defaultLogger.addTransport,
321
433
  removeTransport: defaultLogger.removeTransport,
322
434
  channel: defaultLogger.channel,
435
+ withRedactions,
436
+ commonSensitiveKeys,
323
437
  transports: {
324
438
  console: ConsoleTransport,
325
439
  file: FileTransport,
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "@sentry/types": "^8.30.0",
17
17
  "@types/node": "^22.19.11"
18
18
  },
19
- "version": "1.0.0-alpha.1",
19
+ "version": "1.0.0-alpha.11",
20
20
  "publishConfig": {
21
21
  "access": "restricted"
22
22
  },