@hackylabs/deep-redact 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Benjamin Green (https://bengreen.dev)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # Deep Redact
2
+
3
+ Faster than fast-redact <sup>1</sup> as well as being safer and more configurable than many other redaction libraries,
4
+ Deep Redact is a zero-dependency tool that redacts sensitive information from strings and objects. It is designed to be
5
+ used in a production environment where sensitive information needs to be redacted from logs, error messages, files,
6
+ and other outputs.
7
+
8
+ Circular references and other unsupported are handled gracefully, and the library is designed to be as fast as possible
9
+ while still being configurable.
10
+
11
+ Supporting both CommonJS and ESM, with named and default exports, Deep Redact is designed to be versatile and easy to
12
+ use in any modern JavaScript or TypeScript project in Node or the browser.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @hackylabs/deep-redact
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ <h4 style="color: red">In order to maintain a consistent usage throughout your project, it is not advised to call this
23
+ library outside of your global logging/error-reporting libraries.</h4>
24
+
25
+ ```typescript
26
+ // ./src/example.ts
27
+ import {DeepRedact} from 'deep-redact'; // If you're using CommonJS, import with require('deep-redact') instead. Both CommonJS and ESM support named and default imports.
28
+
29
+ const redaction = new DeepRedact({
30
+ replacement: '*',
31
+ replaceStringByLength: true,
32
+ blacklistedKeys: ['password'],
33
+ stringTests: [
34
+ /^[\d]{13,16}$/, // payment card number
35
+ /^[\d]{3,4}$/ // CVV
36
+ ],
37
+ });
38
+
39
+ const obj = {
40
+ password: '<h1><strong>Password</strong></h1>',
41
+ cardNumber: '1234567812345678',
42
+ cvv: '123',
43
+ };
44
+
45
+ redaction.redact(obj) // { password: '**********************************', cardNumber: '****************', cvv: '***' }
46
+ ```
47
+
48
+ ## Configuration
49
+
50
+ ### Main Options
51
+
52
+ | key | description | type | options | default | required |
53
+ | --- | --- | --- | --- | --- | --- |
54
+ | blacklistedKeys | Deeply compare names of these keys against the keys in your object. | array | Array<string│BlacklistKeyConfig> | [] | N |
55
+ | stringTests | Array of regular expressions to perform against string values, whether that value is a flat string or nested within an object. | array | RegExp[] | [] | N |
56
+ | fuzzyKeyMatch | Loosely compare key names by checking if the key name of your unredacted object is included anywhere within the name of your blacklisted key. For example, is "pass" (your key) included in "password" (from config). | boolean | | false | N |
57
+ | caseSensitiveKeyMatch | Loosely compare key names by normalising the strings. This involves removing non-word characters and transforms the string to lowercase. This means you never have to worry having to list duplicate keys in different formats such as snake_case, camelCase, PascalCase or any other case. | boolean | | true | N |
58
+ | remove | Determines whether or not to remove the key from the object when it is redacted. | boolean | | false | N |
59
+ | retainStructure | Determines whether or not keep all nested values of a key that is going to be redacted. Circular references are always removed. | boolean | | false | N |
60
+ | replacement | When a value is going to be redacted, what would you like to replace it with? | string | | [REDACTED] | N |
61
+ | replaceStringByLength | When a string value is going to be replaced, optionally replace it by repeating the `replacement` to match the length of the value. For example, if `replaceStringByLength` were set to `true` and `replacement` was set to "x", then redacting "secret" would return "xxxxxx". This is sometimes useful for debugging purposes, although it may be less secure as it could give hints to the original value. | boolean | | false | N |
62
+ | types | JS types (values of `typeof` keyword). Only values with a typeof equal to `string`, `number`, `bigint`, `boolean` or `object` may be redacted. The other types are only listed as options to keep TypeScript happy, so you never need to list them. | array | Array<'string'│'number'│'bigint'│'boolean'│'symbol'│'undefined'│'object'│'function'> | ['string'] | N |
63
+ | serialise | Determines whether or not to serialise the object after redacting. Typical use cases for this are when you want to send it over the network or save to a file, both of which are common use cases for redacting sensitive information. | boolean | | true | N |
64
+ | unsupportedTransformer | When an unsafe value is encountered or a value that cannot be serialised. By default, this function will transform an unsupported value `Unsupported` object. BigInt values are converted a string. Dates are returned using their own `toISOString` method. Regular expressions are returned as objects with their `source` and `flags` values. Errors are converted objects. This is useful when you have a custom class that you would like to redact. For safety reasons, you should always transform a BigInt to avoid JSON.stringify throwing an error. | (value: unknown) => unknown | | DeepRedact.transformUnsupported | N |
65
+
66
+ ### BlacklistKeyConfig
67
+
68
+ | key | type | default | required |
69
+ | --- | --- | --- | --- |
70
+ | key | string│RegExp | | Y |
71
+ | fuzzyKeyMatch | boolean | Main options `fuzzyKeyMatch` | N |
72
+ | caseSensitiveKeyMatch | boolean | Main options `caseSensitiveKeyMatch` | N |
73
+ | remove | boolean | Main options `remove` | N |
74
+ | retainStructure | boolean | Main options `retainStructure` | N |
75
+
76
+ ### Benchmark
77
+ Comparisons are made against JSON.stringify and fast-redact as well as different configurations of deep-redact, using
78
+ [this test object](./test/setup/dummyUser.ts). The benchmark is run on a 2021 iMac with an M1 chip with 16GB memory
79
+ running Sonoma 14.5.
80
+
81
+ JSON.stringify is included as a benchmark because it is the fastest way to deeply iterate over an object although it
82
+ doesn't redact any sensitive information. Fast-redact is included as a benchmark because it's the next fastest redaction
83
+ library available. Neither JSON.stringify nor fast-redact offer the same level of configurability as deep-redact.
84
+
85
+ ![Benchmark](./benchmark.png)
86
+
87
+ | scenario | ops / sec | op duration (ms) | margin of error | sample count |
88
+ | --- | --- | --- | --- | --- |
89
+ | JSON.stringify, tiny object | 3878848.93 | 0.0002578084 | 0 | 1939425 |
90
+ | DeepRedact, default config, tiny object | 1530332.28 | 0.0006534529 | 0.00001 | 765167 |
91
+ | JSON.stringify, large object | 295526.11 | 0.0033837958 | 0.00001 | 147764 |
92
+ | fast redact, tiny object | 228053.93 | 0.0043849277 | 0.00002 | 114027 |
93
+ | DeepRedact, default config, large object | 92714.28 | 0.0107858256 | 0.00006 | 46358 |
94
+ | DeepRedact, remove item, single object | 92349.45 | 0.0108284349 | 0.00005 | 46175 |
95
+ | DeepRedact, fuzzy matching, single object | 89414.82 | 0.0111838282 | 0.00007 | 44708 |
96
+ | DeepRedact, fuzzy and case insensitive matching, single object | 87852.36 | 0.0113827334 | 0.00006 | 43927 |
97
+ | DeepRedact, case insensitive matching, single object | 86797.23 | 0.0115211045 | 0.00006 | 43399 |
98
+ | DeepRedact, replace string by length, single object | 84150.95 | 0.011883407 | 0.00006 | 42076 |
99
+ | DeepRedact, config per key, single object | 71236.85 | 0.0140376786 | 0.00009 | 35619 |
100
+ | DeepRedact, retain structure, single object | 69738.86 | 0.0143392076 | 0.00007 | 34870 |
101
+ | fast redact, large object | 19480.95 | 0.0513321865 | 0.00038 | 9741 |
102
+ | JSON.stringify, 1000 tiny objects | 16003.16 | 0.0624876526 | 0.00017 | 8002 |
103
+ | DeepRedact, default config, 1000 tiny objects | 15827.22 | 0.0631822932 | 0.00043 | 7914 |
104
+ | DeepRedact, default config, 1000 large objects | 13705.52 | 0.072963285 | 0.00054 | 6853 |
105
+ | fast redact, 1000 tiny objects | 7430.88 | 0.1345735164 | 0.00067 | 3716 |
106
+ | JSON.stringify, 1000 large objects | 423.52 | 2.3611880519 | 0.00982 | 212 |
107
+ | fast redact, 1000 large objects | 77.32 | 12.9327971026 | 0.25939 | 39 |
@@ -0,0 +1,34 @@
1
+ export type Types = 'string' | 'number' | 'bigint' | 'boolean' | 'object' | 'function';
2
+ export interface BlacklistKeyConfig {
3
+ fuzzyKeyMatch?: boolean;
4
+ caseSensitiveKeyMatch?: boolean;
5
+ retainStructure?: boolean;
6
+ remove?: boolean;
7
+ key: string | RegExp;
8
+ }
9
+ export interface DeepRedactConfig {
10
+ blacklistedKeys?: Array<string | BlacklistKeyConfig>;
11
+ stringTests?: RegExp[];
12
+ fuzzyKeyMatch?: boolean;
13
+ caseSensitiveKeyMatch?: boolean;
14
+ retainStructure?: boolean;
15
+ replaceStringByLength?: boolean;
16
+ replacement?: string;
17
+ remove?: boolean;
18
+ types?: Types[];
19
+ serialise?: boolean;
20
+ unsupportedTransformer?: (value: unknown) => unknown;
21
+ }
22
+ declare class DeepRedact {
23
+ private circularReference;
24
+ private readonly config;
25
+ constructor(config: DeepRedactConfig);
26
+ private static unsupportedTransformer;
27
+ private removeCircular;
28
+ private redactString;
29
+ private static complexShouldRedact;
30
+ private shouldRedactObjectValue;
31
+ private deepRedact;
32
+ redact: (value: unknown) => unknown;
33
+ }
34
+ export { DeepRedact as default, DeepRedact };
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DeepRedact = exports.default = void 0;
4
+ const normaliseString = (key) => key.toLowerCase().replace(/\W/g, '');
5
+ class DeepRedact {
6
+ constructor(config) {
7
+ var _a, _b;
8
+ this.circularReference = new WeakSet();
9
+ this.config = {
10
+ blacklistedKeys: [],
11
+ stringTests: [],
12
+ fuzzyKeyMatch: false,
13
+ caseSensitiveKeyMatch: true,
14
+ retainStructure: false,
15
+ remove: false,
16
+ replaceStringByLength: false,
17
+ replacement: '[REDACTED]',
18
+ types: ['string'],
19
+ serialise: true,
20
+ unsupportedTransformer: DeepRedact.unsupportedTransformer,
21
+ };
22
+ this.removeCircular = (value) => {
23
+ var _a, _b;
24
+ if (!(value instanceof Object))
25
+ return value;
26
+ if (!((_a = this.circularReference) === null || _a === void 0 ? void 0 : _a.has(value))) {
27
+ (_b = this.circularReference) === null || _b === void 0 ? void 0 : _b.add(value);
28
+ return value;
29
+ }
30
+ return '__circular__';
31
+ };
32
+ this.redactString = (value, parentShouldRedact = false) => {
33
+ if (!this.config.stringTests.some((test) => test.test(value)) && !parentShouldRedact)
34
+ return value;
35
+ if (this.config.replaceStringByLength)
36
+ return this.config.replacement.repeat(value.length);
37
+ return this.config.remove ? undefined : this.config.replacement;
38
+ };
39
+ this.shouldRedactObjectValue = (key) => {
40
+ return this.config.blacklistedKeys.some((redactableKey) => (typeof redactableKey === 'string'
41
+ ? key === redactableKey
42
+ : DeepRedact.complexShouldRedact(key, redactableKey)));
43
+ };
44
+ this.deepRedact = (value, parentShouldRedact = false) => {
45
+ if (value === undefined || value === null)
46
+ return value;
47
+ let safeValue = this.removeCircular(value);
48
+ safeValue = this.config.unsupportedTransformer(safeValue);
49
+ if (!(safeValue instanceof Object)) {
50
+ // @ts-expect-error - we already know that safeValue is not a function, symbol, undefined, null, or an object
51
+ if (!this.config.types.includes(typeof safeValue))
52
+ return safeValue;
53
+ if (typeof safeValue === 'string')
54
+ return this.redactString(safeValue, parentShouldRedact);
55
+ if (!parentShouldRedact)
56
+ return safeValue;
57
+ return this.config.remove
58
+ ? undefined
59
+ : this.config.replacement;
60
+ }
61
+ if (parentShouldRedact && (!this.config.retainStructure || this.config.remove)) {
62
+ return this.config.remove ? undefined : this.config.replacement;
63
+ }
64
+ if (Array.isArray(safeValue))
65
+ return safeValue.map((val) => this.deepRedact(val, parentShouldRedact));
66
+ return Object.fromEntries(Object.entries(safeValue).map(([key, val]) => {
67
+ const shouldRedact = parentShouldRedact || this.shouldRedactObjectValue(key);
68
+ return [key, this.deepRedact(val, shouldRedact)];
69
+ }));
70
+ };
71
+ this.redact = (value) => {
72
+ this.circularReference = new WeakSet();
73
+ const redacted = this.deepRedact(value);
74
+ this.circularReference = null;
75
+ return this.config.serialise ? JSON.stringify(redacted) : redacted;
76
+ };
77
+ this.config = Object.assign(Object.assign(Object.assign({}, this.config), config), { blacklistedKeys: (_b = (_a = config.blacklistedKeys) === null || _a === void 0 ? void 0 : _a.map((key) => {
78
+ if (typeof key === 'string')
79
+ return key;
80
+ return Object.assign({ fuzzyKeyMatch: this.config.fuzzyKeyMatch, caseSensitiveKeyMatch: this.config.caseSensitiveKeyMatch, retainStructure: this.config.retainStructure, remove: this.config.remove }, key);
81
+ })) !== null && _b !== void 0 ? _b : [] });
82
+ }
83
+ }
84
+ exports.default = DeepRedact;
85
+ exports.DeepRedact = DeepRedact;
86
+ DeepRedact.unsupportedTransformer = (value) => {
87
+ if (typeof value === 'bigint') {
88
+ return {
89
+ __unsupported: {
90
+ type: 'bigint',
91
+ value: value.toString(),
92
+ radix: 10,
93
+ },
94
+ };
95
+ }
96
+ if (value instanceof Error) {
97
+ return {
98
+ __unsupported: {
99
+ type: 'error',
100
+ name: value.name,
101
+ message: value.message,
102
+ stack: value.stack,
103
+ },
104
+ };
105
+ }
106
+ if (value instanceof RegExp) {
107
+ return {
108
+ __unsupported: {
109
+ type: 'regexp',
110
+ source: value.source,
111
+ flags: value.flags,
112
+ },
113
+ };
114
+ }
115
+ if (value instanceof Date)
116
+ return value.toISOString();
117
+ return value;
118
+ };
119
+ DeepRedact.complexShouldRedact = (key, config) => {
120
+ if (config.key instanceof RegExp)
121
+ return config.key.test(key);
122
+ if (config.fuzzyKeyMatch && config.caseSensitiveKeyMatch)
123
+ return key.includes(config.key);
124
+ if (config.fuzzyKeyMatch && !config.caseSensitiveKeyMatch)
125
+ return normaliseString(key).includes(normaliseString(config.key));
126
+ if (!config.fuzzyKeyMatch && config.caseSensitiveKeyMatch)
127
+ return key === config.key;
128
+ return normaliseString(config.key) === normaliseString(key);
129
+ };
@@ -0,0 +1,34 @@
1
+ export type Types = 'string' | 'number' | 'bigint' | 'boolean' | 'object' | 'function';
2
+ export interface BlacklistKeyConfig {
3
+ fuzzyKeyMatch?: boolean;
4
+ caseSensitiveKeyMatch?: boolean;
5
+ retainStructure?: boolean;
6
+ remove?: boolean;
7
+ key: string | RegExp;
8
+ }
9
+ export interface DeepRedactConfig {
10
+ blacklistedKeys?: Array<string | BlacklistKeyConfig>;
11
+ stringTests?: RegExp[];
12
+ fuzzyKeyMatch?: boolean;
13
+ caseSensitiveKeyMatch?: boolean;
14
+ retainStructure?: boolean;
15
+ replaceStringByLength?: boolean;
16
+ replacement?: string;
17
+ remove?: boolean;
18
+ types?: Types[];
19
+ serialise?: boolean;
20
+ unsupportedTransformer?: (value: unknown) => unknown;
21
+ }
22
+ declare class DeepRedact {
23
+ private circularReference;
24
+ private readonly config;
25
+ constructor(config: DeepRedactConfig);
26
+ private static unsupportedTransformer;
27
+ private removeCircular;
28
+ private redactString;
29
+ private static complexShouldRedact;
30
+ private shouldRedactObjectValue;
31
+ private deepRedact;
32
+ redact: (value: unknown) => unknown;
33
+ }
34
+ export { DeepRedact as default, DeepRedact };
@@ -0,0 +1,125 @@
1
+ const normaliseString = (key) => key.toLowerCase().replace(/\W/g, '');
2
+ class DeepRedact {
3
+ constructor(config) {
4
+ var _a, _b;
5
+ this.circularReference = new WeakSet();
6
+ this.config = {
7
+ blacklistedKeys: [],
8
+ stringTests: [],
9
+ fuzzyKeyMatch: false,
10
+ caseSensitiveKeyMatch: true,
11
+ retainStructure: false,
12
+ remove: false,
13
+ replaceStringByLength: false,
14
+ replacement: '[REDACTED]',
15
+ types: ['string'],
16
+ serialise: true,
17
+ unsupportedTransformer: DeepRedact.unsupportedTransformer,
18
+ };
19
+ this.removeCircular = (value) => {
20
+ var _a, _b;
21
+ if (!(value instanceof Object))
22
+ return value;
23
+ if (!((_a = this.circularReference) === null || _a === void 0 ? void 0 : _a.has(value))) {
24
+ (_b = this.circularReference) === null || _b === void 0 ? void 0 : _b.add(value);
25
+ return value;
26
+ }
27
+ return '__circular__';
28
+ };
29
+ this.redactString = (value, parentShouldRedact = false) => {
30
+ if (!this.config.stringTests.some((test) => test.test(value)) && !parentShouldRedact)
31
+ return value;
32
+ if (this.config.replaceStringByLength)
33
+ return this.config.replacement.repeat(value.length);
34
+ return this.config.remove ? undefined : this.config.replacement;
35
+ };
36
+ this.shouldRedactObjectValue = (key) => {
37
+ return this.config.blacklistedKeys.some((redactableKey) => (typeof redactableKey === 'string'
38
+ ? key === redactableKey
39
+ : DeepRedact.complexShouldRedact(key, redactableKey)));
40
+ };
41
+ this.deepRedact = (value, parentShouldRedact = false) => {
42
+ if (value === undefined || value === null)
43
+ return value;
44
+ let safeValue = this.removeCircular(value);
45
+ safeValue = this.config.unsupportedTransformer(safeValue);
46
+ if (!(safeValue instanceof Object)) {
47
+ // @ts-expect-error - we already know that safeValue is not a function, symbol, undefined, null, or an object
48
+ if (!this.config.types.includes(typeof safeValue))
49
+ return safeValue;
50
+ if (typeof safeValue === 'string')
51
+ return this.redactString(safeValue, parentShouldRedact);
52
+ if (!parentShouldRedact)
53
+ return safeValue;
54
+ return this.config.remove
55
+ ? undefined
56
+ : this.config.replacement;
57
+ }
58
+ if (parentShouldRedact && (!this.config.retainStructure || this.config.remove)) {
59
+ return this.config.remove ? undefined : this.config.replacement;
60
+ }
61
+ if (Array.isArray(safeValue))
62
+ return safeValue.map((val) => this.deepRedact(val, parentShouldRedact));
63
+ return Object.fromEntries(Object.entries(safeValue).map(([key, val]) => {
64
+ const shouldRedact = parentShouldRedact || this.shouldRedactObjectValue(key);
65
+ return [key, this.deepRedact(val, shouldRedact)];
66
+ }));
67
+ };
68
+ this.redact = (value) => {
69
+ this.circularReference = new WeakSet();
70
+ const redacted = this.deepRedact(value);
71
+ this.circularReference = null;
72
+ return this.config.serialise ? JSON.stringify(redacted) : redacted;
73
+ };
74
+ this.config = Object.assign(Object.assign(Object.assign({}, this.config), config), { blacklistedKeys: (_b = (_a = config.blacklistedKeys) === null || _a === void 0 ? void 0 : _a.map((key) => {
75
+ if (typeof key === 'string')
76
+ return key;
77
+ return Object.assign({ fuzzyKeyMatch: this.config.fuzzyKeyMatch, caseSensitiveKeyMatch: this.config.caseSensitiveKeyMatch, retainStructure: this.config.retainStructure, remove: this.config.remove }, key);
78
+ })) !== null && _b !== void 0 ? _b : [] });
79
+ }
80
+ }
81
+ DeepRedact.unsupportedTransformer = (value) => {
82
+ if (typeof value === 'bigint') {
83
+ return {
84
+ __unsupported: {
85
+ type: 'bigint',
86
+ value: value.toString(),
87
+ radix: 10,
88
+ },
89
+ };
90
+ }
91
+ if (value instanceof Error) {
92
+ return {
93
+ __unsupported: {
94
+ type: 'error',
95
+ name: value.name,
96
+ message: value.message,
97
+ stack: value.stack,
98
+ },
99
+ };
100
+ }
101
+ if (value instanceof RegExp) {
102
+ return {
103
+ __unsupported: {
104
+ type: 'regexp',
105
+ source: value.source,
106
+ flags: value.flags,
107
+ },
108
+ };
109
+ }
110
+ if (value instanceof Date)
111
+ return value.toISOString();
112
+ return value;
113
+ };
114
+ DeepRedact.complexShouldRedact = (key, config) => {
115
+ if (config.key instanceof RegExp)
116
+ return config.key.test(key);
117
+ if (config.fuzzyKeyMatch && config.caseSensitiveKeyMatch)
118
+ return key.includes(config.key);
119
+ if (config.fuzzyKeyMatch && !config.caseSensitiveKeyMatch)
120
+ return normaliseString(key).includes(normaliseString(config.key));
121
+ if (!config.fuzzyKeyMatch && config.caseSensitiveKeyMatch)
122
+ return key === config.key;
123
+ return normaliseString(config.key) === normaliseString(key);
124
+ };
125
+ export { DeepRedact as default, DeepRedact };
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@hackylabs/deep-redact",
3
+ "version": "1.0.0",
4
+ "description": "A fast, safe and configurable zero-dependency library for redacting strings or deeply redacting arrays and objects.",
5
+ "private": false,
6
+ "license": "MIT",
7
+ "author": "Benjamin Green (https://bengreen.dev)",
8
+ "keywords": [
9
+ "redact",
10
+ "redaction",
11
+ "redactor",
12
+ "redacting",
13
+ "redacted",
14
+ "secrets",
15
+ "sensitive data",
16
+ "sensitive information",
17
+ "personal data",
18
+ "personally identifiable information",
19
+ "general data protection regulation",
20
+ "data protection",
21
+ "data security",
22
+ "GDPR",
23
+ "PII"
24
+ ],
25
+ "exports": {
26
+ ".": {
27
+ "import": "./dist/esm/index.js",
28
+ "require": "./dist/cjs/index.js",
29
+ "types": "./dist/esm/index.d.ts"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist"
34
+ ],
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/hackylabs/deep-redact"
38
+ },
39
+ "scripts": {
40
+ "lint": "eslint",
41
+ "build": "npm run lint && npm run test && npm run bench && npm run build:esm && npm run build:cjs && npm run update-readme && npm run update-license",
42
+ "build:esm": "tsc --project tsconfig.esm.json",
43
+ "build:cjs": "tsc --project tsconfig.cjs.json",
44
+ "bench": "npx vitest bench --watch=false",
45
+ "bench:dev": "npx vitest bench",
46
+ "test:dev": "npx vitest",
47
+ "test": "npx vitest run",
48
+ "update-readme": "npx ts-node ./scripts/update-readme.ts",
49
+ "update-license": "npx ts-node ./scripts/update-license.ts"
50
+ },
51
+ "//": [
52
+ "fast-redact installed only as a benchmark comparison and is not used in the library",
53
+ "all dependencies are for development purposes only"
54
+ ],
55
+ "devDependencies": {
56
+ "@memlab/core": "1.1.34",
57
+ "@types/fast-redact": "3.0.4",
58
+ "@types/node": "20.14.12",
59
+ "@typescript-eslint/eslint-plugin": "7.14.1",
60
+ "@typescript-eslint/parser": "7.14.1",
61
+ "@vitest/coverage-v8": "2.0.4",
62
+ "eslint": "8.57.0",
63
+ "eslint-config-airbnb-base": "15.0.0",
64
+ "eslint-config-airbnb-typescript": "18.0.0",
65
+ "eslint-plugin-import": "2.29.1",
66
+ "eslint-plugin-n": "17.9.0",
67
+ "eslint-plugin-promise": "7.0.0",
68
+ "fast-redact": "3.5.0",
69
+ "image-charts": "6.1.19",
70
+ "typescript": "5.5.4",
71
+ "vitest": "2.0.4"
72
+ }
73
+ }