@darksheep/logger 1.3.1 → 1.4.1

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +35 -13
  3. package/package.json +7 -5
  4. package/src/create-logger.js +4 -4
  5. package/src/formatters/formatter-console/stack.js +1 -1
  6. package/src/formatters/formatter-console.js +2 -2
  7. package/src/index.js +2 -2
  8. package/src/replacer.js +18 -23
  9. package/src/replacers/index.js +1 -1
  10. package/src/replacers/secrets.js +100 -11
  11. package/src/utilities/environment.js +25 -3
  12. package/src/utilities/legacy-secrets.js +36 -0
  13. package/src/utilities/parse-filters.js +2 -2
  14. package/src/utilities/resource-usage.js +9 -6
  15. package/types/create-logger.d.ts +2 -2
  16. package/types/formatter.d.ts +2 -2
  17. package/types/formatters/formatter-console/stack.d.ts +15 -11
  18. package/types/formatters/formatter-console.d.ts +2 -2
  19. package/types/formatters/formatter-json.d.ts +1 -1
  20. package/types/index.d.ts +26 -11
  21. package/types/logger.d.ts +119 -33
  22. package/types/replacer.d.ts +15 -15
  23. package/types/replacers/buffers.d.ts +5 -2
  24. package/types/replacers/error.d.ts +13 -13
  25. package/types/replacers/http-client-request.d.ts +6 -3
  26. package/types/replacers/http-incoming-message.d.ts +8 -4
  27. package/types/replacers/http-server-response.d.ts +6 -3
  28. package/types/replacers/index.d.ts +8 -8
  29. package/types/replacers/long-strings.d.ts +5 -2
  30. package/types/replacers/net-socket.d.ts +6 -3
  31. package/types/replacers/secrets.d.ts +6 -3
  32. package/types/stdout-write.d.ts +1 -1
  33. package/types/utilities/colour.d.ts +30 -30
  34. package/types/utilities/environment.d.ts +14 -22
  35. package/types/utilities/json-path.d.ts +1 -1
  36. package/types/utilities/last-callsite.d.ts +1 -1
  37. package/types/utilities/legacy-secrets.d.ts +33 -0
  38. package/types/utilities/log-filters.d.ts +2 -2
  39. package/types/utilities/log-types.d.ts +30 -4
  40. package/types/utilities/parse-filters.d.ts +1 -1
  41. package/types/utilities/parse-log-level.d.ts +5 -2
  42. package/types/utilities/resource-usage.d.ts +2 -2
  43. package/types/utilities/stacktrace.d.ts +15 -15
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.4.1](https://github.com/DarkSheepSoftware/node-packages/compare/logger-v1.4.0...logger-v1.4.1) (2026-09-21)
4
+
5
+
6
+ ### 🔨 Code Refactoring
7
+
8
+ * JSDoc for resolveSecretFilters parameters ([#1009](https://github.com/DarkSheepSoftware/node-packages/issues/1009)) ([3be00f0](https://github.com/DarkSheepSoftware/node-packages/commit/3be00f02249831795518b436e6a874744654825e))
9
+
10
+ ## [1.4.0](https://github.com/DarkSheepSoftware/node-packages/compare/logger-v1.3.1...logger-v1.4.0) (2026-09-20)
11
+
12
+
13
+ ### 🌟 Features
14
+
15
+ * split logger secrets into redact and remove ([#845](https://github.com/DarkSheepSoftware/node-packages/issues/845)) ([924c6d5](https://github.com/DarkSheepSoftware/node-packages/commit/924c6d589e105c22048d3f05fd7151f03a2513dd))
16
+ * **traverse:** add @darksheep/traverse deep object traversal package ([#874](https://github.com/DarkSheepSoftware/node-packages/issues/874)) ([981bea0](https://github.com/DarkSheepSoftware/node-packages/commit/981bea0a3fa08c78152713108feb02dc0ccbdc37))
17
+
18
+
19
+ ### 📦 Dependencies
20
+
21
+ * **pkg:** update dependency deepmerge-ts to v7.1.6 ([#938](https://github.com/DarkSheepSoftware/node-packages/issues/938)) ([194912b](https://github.com/DarkSheepSoftware/node-packages/commit/194912bd6af5f4a83c101080c4d5ea76047511c5))
22
+ * **pkg:** update dependency deepmerge-ts to v8 [security] ([ca3b39a](https://github.com/DarkSheepSoftware/node-packages/commit/ca3b39a53603b522d6f89a3230fa2836e02d532c))
23
+ * **pkg:** update dependency deepmerge-ts to v8.0.1 ([#949](https://github.com/DarkSheepSoftware/node-packages/issues/949)) ([0099631](https://github.com/DarkSheepSoftware/node-packages/commit/0099631ca6a8a6f437f75d83d63bb45c8383cead))
24
+ * **pkg:** update dependency deepmerge-ts to v8.0.2 ([#957](https://github.com/DarkSheepSoftware/node-packages/issues/957)) ([4c78b29](https://github.com/DarkSheepSoftware/node-packages/commit/4c78b296fee9d8d73abec141eb2151e6e4903fcf))
25
+
3
26
  ## [1.3.1](https://github.com/DarkSheepSoftware/node-packages/compare/logger-v1.3.0...logger-v1.3.1) (2026-04-17)
4
27
 
5
28
 
package/README.md CHANGED
@@ -56,7 +56,8 @@ app.get('/', (request, response) => {
56
56
  | `NODE_ENV` | The deployment location |
57
57
  | `LOG_LEVEL` | Overrides the log level set by the detected environment |
58
58
  | `LOG_FILTERS` | This allows you to allow/block specific channels |
59
- | `LOG_SECRETS` | This allows you to hide or remove secrets in an object |
59
+ | `LOG_SECRET_REDACT` | This allows you to obscure secrets in an object |
60
+ | `LOG_SECRET_REMOVE` | This allows you to remove secrets from an object |
60
61
  | `LOG_CALLSITES` | Include the callsite of the log |
61
62
 
62
63
  #### `NODE_ENV`
@@ -108,18 +109,17 @@ The following filter means that ONLY `router` gets logged, except for the `route
108
109
  LOG_FILTERS="router,-router.ok"
109
110
  ```
110
111
 
111
- #### `LOG_SECRETS`
112
+ #### `LOG_SECRET_REDACT`
112
113
 
113
- Secrets also use a filter, if you use a standard filter the secret key is displayed, if you use a negate the key and value are deleted.
114
+ Comma-separated list of key patterns. Matched keys have their values replaced with `[secret ...]`. Prefix a pattern with `-` to exempt it from redacting.
114
115
 
115
- The following means that `password` is deleted, and `token` is obscured.
116
+ Wild cards are permitted.
116
117
 
117
118
  ```js
118
- // LOG_SECRETS="-password,token"
119
+ // LOG_SECRET_REDACT="token"
119
120
 
120
121
  // Given the following context
121
122
  const context = {
122
- password: '1234',
123
123
  token: 'asdf',
124
124
  };
125
125
 
@@ -129,12 +129,8 @@ const output = {
129
129
  };
130
130
  ```
131
131
 
132
- Wild cards are also permitted.
133
-
134
- For example, using a positive (obscure) wildcard
135
-
136
132
  ```js
137
- // LOG_SECRETS="*.token"
133
+ // LOG_SECRET_REDACT="*.token"
138
134
 
139
135
  // Given the following context
140
136
  const context = {
@@ -161,9 +157,35 @@ const output = {
161
157
  };
162
158
  ```
163
159
 
164
- For example, using a negative (delete) wildcard:
160
+ #### `LOG_SECRET_REMOVE`
161
+
162
+ Comma-separated list of key patterns. Matched keys and their values are deleted entirely. Prefix a pattern with `-` to exempt a specific path from removal.
163
+
164
+ Wild cards are permitted.
165
+
166
+ ```js
167
+ // LOG_SECRET_REMOVE="response,-response.statusMessage"
168
+
169
+ // Given the following context
170
+ const context = {
171
+ status: 200,
172
+ response: {
173
+ statusMessage: 'OK',
174
+ body: '...',
175
+ },
176
+ };
177
+
178
+ // Then the following will be logged
179
+ const output = {
180
+ status: 200,
181
+ response: {
182
+ statusMessage: 'OK',
183
+ },
184
+ };
185
+ ```
186
+
165
187
  ```js
166
- // LOG_SECRETS="-*.token"
188
+ // LOG_SECRET_REMOVE="*.token"
167
189
 
168
190
  // Given the following context
169
191
  const context = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darksheep/logger",
3
- "version": "1.3.1",
3
+ "version": "1.4.1",
4
4
  "description": "Logging your stuff to where ever you want it",
5
5
  "license": "UNLICENCED",
6
6
  "type": "module",
@@ -22,15 +22,17 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@darksheep/environment": "3.2.0",
25
- "deepmerge-ts": "7.1.5",
26
- "stacktrace-parser": "0.1.11",
27
- "traverse": "0.6.11"
25
+ "@darksheep/traverse": "1.0.0",
26
+ "deepmerge-ts": "8.0.2",
27
+ "stacktrace-parser": "0.1.11"
28
28
  },
29
29
  "devDependencies": {
30
- "@types/traverse": "~0.6.33",
31
30
  "nock": "~14.0.0"
32
31
  },
33
32
  "engines": {
34
33
  "node": "^20.13.1 || >=22.2.0"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
35
37
  }
36
38
  }
@@ -7,8 +7,8 @@ import {
7
7
  HttpServerResponseReplacer,
8
8
  LongStringReplacer,
9
9
  NetSocketReplacer,
10
- SecretDelete,
11
- SecretObscure,
10
+ SecretRedact,
11
+ SecretRemove,
12
12
  } from './replacers/index.js';
13
13
 
14
14
  /**
@@ -20,8 +20,8 @@ export function createLogger(channel) {
20
20
  typeof channel === 'string' ? { channel } : {},
21
21
  { replacers: [
22
22
  // Always run the secret replacer first.
23
- SecretDelete,
24
- SecretObscure,
23
+ SecretRemove,
24
+ SecretRedact,
25
25
 
26
26
  ErrorReplacer,
27
27
  HttpClientRequestReplacer,
@@ -85,7 +85,7 @@ function highlightNumber(number, options, colon = ':') {
85
85
  return '';
86
86
  }
87
87
 
88
- return `${colon}${colourString(`${number}`, options)}`;
88
+ return `${colon}${colourString(String(number), options)}`;
89
89
  }
90
90
 
91
91
  /**
@@ -28,7 +28,7 @@ function flattenChannelLevel(channel, level) {
28
28
  }
29
29
 
30
30
  if (level != null && LogNames[level] != null) {
31
- output += `${LogNames[level].toUpperCase()}`;
31
+ output += LogNames[level].toUpperCase();
32
32
  }
33
33
 
34
34
  output += ': ';
@@ -77,7 +77,7 @@ function formatError(error, indent = 0) {
77
77
  error.message,
78
78
  { foreground: 'red', effects: [ 'bold' ] },
79
79
  )
80
- : `${error.message}`;
80
+ : error.message;
81
81
 
82
82
  const stack = formatStack(error.stack, indent);
83
83
  if (stack.trim().length > 0) {
package/src/index.js CHANGED
@@ -28,8 +28,8 @@ export {
28
28
  HttpServerResponseReplacer,
29
29
  LongStringReplacer,
30
30
  NetSocketReplacer,
31
- SecretDelete,
32
- SecretObscure,
31
+ SecretRedact,
32
+ SecretRemove,
33
33
  } from './replacers/index.js';
34
34
  export { environment } from './utilities/environment.js';
35
35
  export { LogLevels } from './utilities/log-types.js';
package/src/replacer.js CHANGED
@@ -1,7 +1,4 @@
1
- /**
2
- * @import { TraverseContext } from 'traverse';
3
- */
4
- import Traverse from 'traverse';
1
+ import { createTraverse } from '@darksheep/traverse';
5
2
 
6
3
  import { nodesToPath } from './utilities/json-path.js';
7
4
 
@@ -21,34 +18,30 @@ import { nodesToPath } from './utilities/json-path.js';
21
18
  * @returns {unknown}
22
19
  */
23
20
  export function replace(object, replacers = []) {
24
- // eslint-disable-next-line unicorn/no-array-for-each -- This is not an array
25
- return Traverse(object).forEach(
26
- /**
27
- * @param {unknown} value - Current property in the traversed object.
28
- * @returns {void}
29
- * @this {TraverseContext}
30
- */
31
- function (value) {
21
+ const walk = createTraverse(
22
+ (context) => {
23
+ const value = context.node;
24
+
32
25
  if (value == null) {
33
- this.remove();
26
+ context.remove();
34
27
  return;
35
28
  }
36
29
 
37
- if (this.circular != null) {
38
- this.update({ $ref: nodesToPath(this.circular.path) });
30
+ if (context.circular != null) {
31
+ context.update({ $ref: nodesToPath(context.circular.path) });
39
32
  return;
40
33
  }
41
34
 
42
35
  for (const replacer of replacers) {
43
- if (replacer.shouldReplace(value, this.path)) {
44
- const replaced = replacer.replace(value, this.path);
36
+ if (replacer.shouldReplace(value, context.path)) {
37
+ const replaced = replacer.replace(value, context.path);
45
38
 
46
39
  if (replaced == null) {
47
- this.remove(replacer.stopHere);
40
+ context.remove();
48
41
  return;
49
42
  }
50
43
 
51
- this.update(replaced, replacer.stopHere);
44
+ context.update(replaced, replacer.stopHere);
52
45
  return;
53
46
  }
54
47
  }
@@ -59,7 +52,7 @@ export function replace(object, replacers = []) {
59
52
  typeof value.toJSON === 'function'
60
53
  ) {
61
54
  try {
62
- this.update(value.toJSON());
55
+ context.update(value.toJSON());
63
56
  return;
64
57
  } catch { }
65
58
  }
@@ -69,20 +62,22 @@ export function replace(object, replacers = []) {
69
62
  Object.getPrototypeOf(value) !== Object.getPrototypeOf({}) &&
70
63
  Object.getPrototypeOf(value) !== Object.getPrototypeOf([])
71
64
  ) {
72
- this.update({ $class: value.constructor.name });
65
+ context.update({ $class: value.constructor.name });
73
66
  return;
74
67
  }
75
68
 
76
69
  if (Object.getPrototypeOf(value)?.constructor === Object) {
77
- this.update({ ...value });
70
+ context.update({ ...value });
78
71
  }
79
72
 
80
73
  if (
81
74
  Array.isArray(value) &&
82
75
  Object.getPrototypeOf(value).constructor === Array
83
76
  ) {
84
- this.update([ ...value ]);
77
+ context.update([ ...value ]);
85
78
  }
86
79
  },
87
80
  );
81
+
82
+ return walk(object);
88
83
  }
@@ -5,4 +5,4 @@ export { HttpIncomingMessageReplacer } from './http-incoming-message.js';
5
5
  export { HttpServerResponseReplacer } from './http-server-response.js';
6
6
  export { LongStringReplacer } from './long-strings.js';
7
7
  export { NetSocketReplacer } from './net-socket.js';
8
- export { SecretDelete, SecretObscure } from './secrets.js';
8
+ export { SecretRedact, SecretRemove } from './secrets.js';
@@ -5,30 +5,106 @@
5
5
  import { environment } from '../utilities/environment.js';
6
6
  import { nodesToPath } from '../utilities/json-path.js';
7
7
 
8
+ /**
9
+ * Whether the subtree at `value` actually contains a node whose path is
10
+ * exempted from removal. Used to decide whether to descend into a node we
11
+ * would otherwise remove wholesale: we only keep the container when a real
12
+ * exempted descendant lives beneath it, so no empty container is left behind.
13
+ *
14
+ * Descendant paths are tested against the compiled exemption patterns, so
15
+ * wildcards behave exactly as they do elsewhere.
16
+ *
17
+ * @param {unknown} value - The node whose descendants to inspect.
18
+ * @param {string} path - The dotted path of `value`.
19
+ * @param {RegExp[]} blocked - The compiled exemption patterns.
20
+ * @param {WeakSet<object>} [seen] - Guards against circular references.
21
+ * @returns {boolean}
22
+ */
23
+ function hasExemptedDescendant(value, path, blocked, seen = new WeakSet()) {
24
+ if (value === null || typeof value !== 'object' || seen.has(value)) {
25
+ return false;
26
+ }
27
+ seen.add(value);
28
+
29
+ const record = /** @type {Record<string, unknown>} */ (value);
30
+ for (const [ key, child ] of Object.entries(record)) {
31
+ const childPath = path === '' ? key : `${path}.${key}`;
32
+
33
+ for (const filter of blocked) {
34
+ if (filter.test(childPath)) {
35
+ return true;
36
+ }
37
+ }
38
+
39
+ if (hasExemptedDescendant(child, childPath, blocked, seen)) {
40
+ return true;
41
+ }
42
+ }
43
+
44
+ return false;
45
+ }
46
+
8
47
  /** @type {Replacer} */
9
- export const SecretDelete = {
10
- name: 'SecretDelete',
48
+ export const SecretRemove = {
49
+ name: 'SecretRemove',
11
50
  stopHere: true,
12
- shouldReplace: (_, original) => {
51
+ shouldReplace: (value, original) => {
13
52
  if (original == null) {
14
53
  return false;
15
54
  }
16
55
 
17
56
  const path = original.join('.');
18
- for (const filter of environment.secretFilters.blocked) {
57
+
58
+ let directlyRemoved = false;
59
+ for (const filter of environment.removeFilters.allowed) {
19
60
  if (filter.test(path)) {
20
- return true;
61
+ directlyRemoved = true;
62
+ break;
21
63
  }
22
64
  }
23
65
 
24
- return false;
66
+ let ancestorRemoved = false;
67
+ if (directlyRemoved === false) {
68
+ for (let i = 1; i < original.length; i++) {
69
+ const ancestorPath = original.slice(0, i).join('.');
70
+ for (const filter of environment.removeFilters.allowed) {
71
+ if (filter.test(ancestorPath)) {
72
+ ancestorRemoved = true;
73
+ break;
74
+ }
75
+ }
76
+ if (ancestorRemoved === true) {
77
+ break;
78
+ }
79
+ }
80
+ }
81
+
82
+ if (directlyRemoved === false && ancestorRemoved === false) {
83
+ return false;
84
+ }
85
+
86
+ for (const filter of environment.removeFilters.blocked) {
87
+ if (filter.test(path)) {
88
+ return false;
89
+ }
90
+ }
91
+
92
+ // This node is slated for removal (directly or via an ancestor). Only keep
93
+ // it when a real exempted descendant lives beneath it, so traversal
94
+ // continues into its children; otherwise remove the whole subtree without
95
+ // leaving an empty container behind.
96
+ if (hasExemptedDescendant(value, path, environment.removeFilters.blocked)) {
97
+ return false;
98
+ }
99
+
100
+ return true;
25
101
  },
26
102
  replace: () => null,
27
103
  };
28
104
 
29
105
  /** @type {Replacer} */
30
- export const SecretObscure = {
31
- name: 'SecretObscure',
106
+ export const SecretRedact = {
107
+ name: 'SecretRedact',
32
108
  stopHere: true,
33
109
  shouldReplace: (_, original) => {
34
110
  if (original == null) {
@@ -36,13 +112,26 @@ export const SecretObscure = {
36
112
  }
37
113
 
38
114
  const path = original.join('.');
39
- for (const filter of environment.secretFilters.allowed) {
115
+
116
+ let matched = false;
117
+ for (const filter of environment.redactFilters.allowed) {
40
118
  if (filter.test(path)) {
41
- return true;
119
+ matched = true;
120
+ break;
42
121
  }
43
122
  }
44
123
 
45
- return false;
124
+ if (matched === false) {
125
+ return false;
126
+ }
127
+
128
+ for (const filter of environment.redactFilters.blocked) {
129
+ if (filter.test(path)) {
130
+ return false;
131
+ }
132
+ }
133
+
134
+ return true;
46
135
  },
47
136
  replace: (_, path) => {
48
137
  if (path == null) {
@@ -1,5 +1,6 @@
1
1
  import { getTypedEnv } from '@darksheep/environment';
2
2
 
3
+ import { resolveSecretFilters } from './legacy-secrets.js';
3
4
  import { parseFilters } from './parse-filters.js';
4
5
  import { parseLogLevel } from './parse-log-level.js';
5
6
 
@@ -10,8 +11,10 @@ const {
10
11
  LOG_LEVEL,
11
12
  LOG_MAX_LENGTH = 1024,
12
13
  LOG_MEMORY = false,
13
- LOG_SECRETS,
14
14
  LOG_RELATIVE_TO,
15
+ LOG_SECRETS,
16
+ LOG_SECRET_REDACT,
17
+ LOG_SECRET_REMOVE,
15
18
  NODE_ENV = 'production',
16
19
  } = getTypedEnv({
17
20
  LOG_CALLSITES: '?boolean',
@@ -20,11 +23,29 @@ const {
20
23
  LOG_LEVEL: '?string',
21
24
  LOG_MAX_LENGTH: '?number',
22
25
  LOG_MEMORY: '?boolean',
23
- LOG_SECRETS: '?string',
24
26
  LOG_RELATIVE_TO: '?string',
27
+ LOG_SECRETS: '?string',
28
+ LOG_SECRET_REDACT: '?string',
29
+ LOG_SECRET_REMOVE: '?string',
25
30
  NODE_ENV: '?string',
26
31
  });
27
32
 
33
+ // `LOG_SECRETS` is the pre-split control; map it onto the redact/remove vars
34
+ // so existing configs keep working. The split vars win when set.
35
+ if (LOG_SECRETS != null) {
36
+ process.emitWarning(
37
+ 'LOG_SECRETS is deprecated; use LOG_SECRET_REDACT (obscure values) and ' +
38
+ 'LOG_SECRET_REMOVE (delete keys) instead.',
39
+ { code: 'DEP_LOG_SECRETS', type: 'DeprecationWarning' },
40
+ );
41
+ }
42
+
43
+ const secretFilters = resolveSecretFilters({
44
+ secrets: LOG_SECRETS,
45
+ redact: LOG_SECRET_REDACT,
46
+ remove: LOG_SECRET_REMOVE,
47
+ });
48
+
28
49
  export const environment = {
29
50
  includeCallsite: LOG_CALLSITES,
30
51
  includeCpuUsage: LOG_CPU,
@@ -34,7 +55,8 @@ export const environment = {
34
55
  isTesting: NODE_ENV === 'test',
35
56
  logFilters: parseFilters(LOG_FILTERS, [ /.*/u ]),
36
57
  logLevel: parseLogLevel(LOG_LEVEL, NODE_ENV),
37
- secretFilters: parseFilters(LOG_SECRETS),
58
+ redactFilters: secretFilters.redactFilters,
38
59
  relativeTo: LOG_RELATIVE_TO,
60
+ removeFilters: secretFilters.removeFilters,
39
61
  stringMaxLength: LOG_MAX_LENGTH,
40
62
  };
@@ -0,0 +1,36 @@
1
+ import { parseFilters } from './parse-filters.js';
2
+
3
+ /**
4
+ * @typedef {{ allowed: RegExp[], blocked: RegExp[] }} Filters
5
+ */
6
+
7
+ /**
8
+ * Resolves the redact and remove filters, mapping the legacy `LOG_SECRETS`
9
+ * control onto them when the split vars are not set.
10
+ *
11
+ * In `LOG_SECRETS` a bare pattern obscured (redacted) the value and a
12
+ * `-`-prefixed pattern removed the key -- which is exactly the `allowed` /
13
+ * `blocked` split that `parseFilters` already produces. So the legacy
14
+ * `allowed` patterns become the redact set and the legacy `blocked` patterns
15
+ * become the remove set (neither carried exemptions). Whenever the matching
16
+ * split var is set it wins and the legacy value is ignored for that half.
17
+ *
18
+ * @param {{
19
+ * secrets?: string | undefined;
20
+ * redact?: string | undefined;
21
+ * remove?: string | undefined;
22
+ * }} options - The raw environment values.
23
+ * @returns {{ redactFilters: Filters, removeFilters: Filters }}
24
+ */
25
+ export function resolveSecretFilters({ secrets, redact, remove }) {
26
+ const legacy = parseFilters(secrets);
27
+
28
+ return {
29
+ redactFilters: redact == null
30
+ ? { allowed: legacy.allowed, blocked: [] }
31
+ : parseFilters(redact),
32
+ removeFilters: remove == null
33
+ ? { allowed: legacy.blocked, blocked: [] }
34
+ : parseFilters(remove),
35
+ };
36
+ }
@@ -29,8 +29,8 @@ export function parseFilters(filter = '', fallback = []) {
29
29
 
30
30
  let regex = channel
31
31
  .replaceAll(/[\s#$()*+,\-.?[\\\]^{|}]/gu, String.raw`\$&`)
32
- .replaceAll(String.raw`\*`, multiLevelWildcard.source)
33
- .replaceAll(String.raw`\+`, oneLevelWildcard.source);
32
+ .replaceAll(String.raw`\*`, () => multiLevelWildcard.source)
33
+ .replaceAll(String.raw`\+`, () => oneLevelWildcard.source);
34
34
 
35
35
  // Allow for multi level wildcards at the start of a filter
36
36
  if (regex.startsWith(String.raw`.*\.`)) {
@@ -14,8 +14,11 @@ export function getMemoryUsage() {
14
14
  };
15
15
  }
16
16
 
17
- let lastCalled = performance.now();
18
- let lastValue = process.cpuUsage();
17
+ /** Previous sample, kept on one object so `getCPUUsage` mutates no bindings. */
18
+ const last = {
19
+ called: performance.now(),
20
+ value: process.cpuUsage(),
21
+ };
19
22
 
20
23
  /**
21
24
  * Get the callsite that we think is outside the package.
@@ -30,12 +33,12 @@ export function getCPUUsage() {
30
33
  /**
31
34
  * Time difference in microseconds.
32
35
  */
33
- const elapsed = Math.floor(1000 * (currentCalled - lastCalled));
36
+ const elapsed = Math.floor(1000 * (currentCalled - last.called));
34
37
 
35
- lastCalled = currentCalled;
36
- lastValue = process.cpuUsage(lastValue);
38
+ last.called = currentCalled;
39
+ last.value = process.cpuUsage(last.value);
37
40
 
38
- const { system, user } = lastValue;
41
+ const { system, user } = last.value;
39
42
  const total = system + user;
40
43
 
41
44
  return { elapsed, total, system, user };
@@ -1,6 +1,6 @@
1
+ import { Logger } from './logger.js';
1
2
  /**
2
3
  * @param {string} [channel] - The logging channel.
3
4
  * @returns {Logger}
4
5
  */
5
- export function createLogger(channel?: string): Logger;
6
- import { Logger } from './logger.js';
6
+ export declare function createLogger(channel?: string): Logger;
@@ -1,6 +1,6 @@
1
+ export type Formatter = (logEntry: import('./utilities/log-types.js').LogEntry) => string;
1
2
  /**
2
3
  * @typedef {(logEntry: import('./utilities/log-types.js').LogEntry) => string} Formatter
3
4
  */
4
5
  /** @type {Formatter} */
5
- export const formatter: Formatter;
6
- export type Formatter = (logEntry: import("./utilities/log-types.js").LogEntry) => string;
6
+ export declare const formatter: Formatter;
@@ -1,18 +1,22 @@
1
1
  /**
2
- * @param {Callsite[] | string | undefined} stack - The stack trace to format.
3
- * @param {number} indent - The indent to render from.
4
- * @returns {string}
2
+ * @import { ColourOptions } from '../../utilities/colour.js';
3
+ * @import { Callsite } from '../../utilities/log-types.js';
5
4
  */
6
- export function formatStack(stack: Callsite[] | string | undefined, indent: number): string;
5
+ import type { ColourOptions } from '../../utilities/colour.js';
6
+ import type { Callsite } from '../../utilities/log-types.js';
7
7
  export type HideOption = {
8
8
  hide?: boolean;
9
9
  };
10
10
  export type LineOptions = (HideOption & {
11
- Line?: Omit<ColourOptions, "reset">;
12
- FunctionName?: Omit<ColourOptions, "reset"> & HideOption;
13
- FilePath?: Omit<ColourOptions, "reset">;
14
- LineNumber?: Omit<ColourOptions, "reset"> & HideOption;
15
- ColumnNumber?: Omit<ColourOptions, "reset"> & HideOption;
11
+ Line?: Omit<ColourOptions, 'reset'>;
12
+ FunctionName?: Omit<ColourOptions, 'reset'> & HideOption;
13
+ FilePath?: Omit<ColourOptions, 'reset'>;
14
+ LineNumber?: Omit<ColourOptions, 'reset'> & HideOption;
15
+ ColumnNumber?: Omit<ColourOptions, 'reset'> & HideOption;
16
16
  });
17
- import type { Callsite } from '../../utilities/log-types.js';
18
- import type { ColourOptions } from '../../utilities/colour.js';
17
+ /**
18
+ * @param {Callsite[] | string | undefined} stack - The stack trace to format.
19
+ * @param {number} indent - The indent to render from.
20
+ * @returns {string}
21
+ */
22
+ export declare function formatStack(stack: Callsite[] | string | undefined, indent: number): string;
@@ -1,6 +1,6 @@
1
+ import type { LogEntry } from '../utilities/log-types.js';
1
2
  /**
2
3
  * @param {LogEntry} logEntry - The Log entry which we're going to convert to a splatted string.
3
4
  * @returns {string}
4
5
  */
5
- export function formatterConsole(logEntry: LogEntry): string;
6
- import type { LogEntry } from '../utilities/log-types.js';
6
+ export declare function formatterConsole(logEntry: LogEntry): string;
@@ -2,4 +2,4 @@
2
2
  * @param {import('../utilities/log-types.js').LogEntry} logEntry - The Log entry which we're going to convert to JSON.
3
3
  * @returns {string}
4
4
  */
5
- export function formatterJson(logEntry: import("../utilities/log-types.js").LogEntry): string;
5
+ export declare function formatterJson(logEntry: import('../utilities/log-types.js').LogEntry): string;