field-redactor 1.0.0 → 1.2.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
@@ -18,7 +18,7 @@ In many instances, redaction of sensitive data from log output is fairly straigh
18
18
  If this object is placed in a data set with many others, and only some of these objects contain PII, redaction becomes quite troublesome. One could redact all `value` fields from these objects - but this merely renders the log output useless for debugging or tracing, as all values are now redacted. The value of the `name` field determines whether or not the `value` field should be redacted. I often found myself writing custom logic to make this determination, which led to brittle code that was difficult to maintain. In the end I decided to write a new, highly configurable plug-and-play solution that could redact sensitive data in various manners while requiring only minor configuration tweaks. Enter FieldRedactor!
19
19
 
20
20
  ## Basic Usage
21
- Basic usage of the FieldRedactor is straightforward but not recommended. Object redaction can be performed either in-place or return the redacted object:
21
+ Basic usage of the FieldRedactor is straightforward but not recommended. Object redaction can be performed either in-place or return the redacted object. If redactor is given a string, primitive, Date, function, or null/undefined value then it returns the value without modification.
22
22
 
23
23
  ```typescript
24
24
  import { FieldRedactor } from 'field-redactor';
@@ -27,15 +27,19 @@ const fieldRedactor = new FieldRedactor();
27
27
 
28
28
  // return redacted result
29
29
  const result = await fieldRedactor.redact(myJsonObject);
30
+ const primitiveResult = await fieldRedactor.redact("foobar");
30
31
  console.log(myJsonObject); // { foo: "bar", fizz: null }
31
32
  console.log(result); // { foo: "REDACTED", fizz: null }
33
+ console.log(primitiveResult); // "foobar"
32
34
 
33
35
  // redact in place
34
36
  await fieldRedactor.redactInPlace(myJsonObject);
35
37
  console.log(myJsonObject); // { foo: "REDACTED", fizz: null }
36
38
  ```
37
- > **Note:** `null` and `undefined` values are not redacted by default.
38
39
 
40
+ > **Note:** `null`, `undefined`, `string`, `Date`, `Function`, and primitive value inputs are completely ignored.
41
+ >
42
+ > **Note:** `null` and `undefined` values are not redacted by default.
39
43
 
40
44
 
41
45
  ## Customization
@@ -48,6 +52,7 @@ The true power of this tool comes from its customization. FieldRedactor can be c
48
52
  | `secretKeys` | `RegExp[]` | `null` | Specifies which values at any level of the JSON object should be redacted. Objects are not deeply redacted, but primitive values in arrays are. If not specified, all values are considered secret. |
49
53
  | `deepSecretKeys` | `RegExp[]` | `[]` | Specifies keys at any level of the JSON object to be deeply redacted. All values within matching objects are fully redacted unless matching a custom object. |
50
54
  | `fullSecretKeys` | `RegExp[]` | `[]` | Specifies keys at any level of the JSON object to be stringified and fully redacted. Primarily used for objects and arrays. |
55
+ | `deleteSecretKeys` | `RegExp[]` | `[]` | Specifies keys at any level of the JSON object to be completely deleted. |
51
56
  | `customObjects` | `CustomObject[]` | `[]` | Specifies custom objects requiring fine-tuned redaction logic, such as referencing sibling keys. See the "Custom Objects" section for details. |
52
57
  | `ignoreBooleans` | `boolean` | `false` | If `true`, booleans will not be redacted even if secret. |
53
58
  | `ignoreNullOrUndefined` | `boolean` | `true` | If `true`, `null` and `undefined` values will not be redacted. |
@@ -80,16 +85,14 @@ console.log(result);
80
85
  ```
81
86
 
82
87
  ### `secretKeys` Configuration
83
- Used to specify primitive that should be redacted. If none of `secretKeys`, `deepSecretKeys`, or `fullSecretKeys` specified then all values are considered secret. Users should almost always specify at least one of these three fields. Has the lowest precedence of all configurable secret fields.
88
+ * Specifies values which should be redacted.
89
+ * __All values are considered secret if no secrets of any type are specified.__
90
+ * has lowest precedence of all secret specifiers.
84
91
 
85
92
  #### Details
86
93
  - **Type:** `RegExp[]`
87
- - **Default:** All values considered secret
88
- - If `deepSecretKeys` or `fullSecretKeys` specified, defaults to `[]`
89
- - **Effect:** Matches keys in objects or child objects and redacts their values, if primitive. Arrays are processed recursively, with primitives redacted.
90
- - If the value is an object it will be assessed using the same logic, regardless of if its key value is a secret.
91
- - if an array value is an object it will be assessed using the same logic, regardless of if its key value is a secret.
92
- - Has lowest precedence when compared to `deepSecretKeys`, `fullSecretKeys`, and `customObjects` configurations.
94
+ - **Default:** All values considered secret unless a secret field is specified.
95
+ - **Effect:** Matches keys in objects, child objects, or array value primitives. Assessed recursively.
93
96
 
94
97
  #### Example
95
98
  ##### Code
@@ -103,14 +106,11 @@ const myJsonObject = {
103
106
  firstName: "Foo",
104
107
  lastName: "Bar",
105
108
  Salutation: "Mr.",
106
- preference: "email",
107
- lastUpdated: "2024-12-01T22:07:26.448Z"
108
109
  },
109
110
  someSecretData: ["fizz", "buzz", { deep: "is not redacted", name: "foobar" }],
110
- hobbies: ["Basketball", "Baseball", "Tennis"]
111
111
  }
112
112
  const fieldRedactor = new FieldRedactor({
113
- secretKeys: [/email/i, /name/i, /someSecretData/i, /contactInfo/i],
113
+ secretKeys: [/email/i, /name/i, /userid/i, /someSecretData/i],
114
114
  });
115
115
  const result = await fieldRedactor.redact(myJsonObject);
116
116
  console.log(result);
@@ -120,33 +120,31 @@ console.log(result);
120
120
  ```json
121
121
  {
122
122
  "timestamp": "2024-12-01T22:07:26.448Z",
123
- "userId": 271,
123
+ "userId": "REDACTED",
124
124
  "contactInfo": {
125
125
  "email": "REDACTED",
126
126
  "firstName": "REDACTED",
127
127
  "lastName": "REDACTED",
128
128
  "Salutation": "Mr.",
129
- "preference": "email",
130
- "lastUpdated": "2024-12-01T22:07:26.448Z"
131
129
  },
132
- "someSecretData": ["REDACTED", "REDACTED", { "deep": "is not redacted", "name": "REDACTED" }],
133
- "hobbies": ["Basketball", "Baseball", "Tennis"]
130
+ "someSecretData": ["REDACTED", "REDACTED", { "deep": "is not redacted", "name": "REDACTED" }]
134
131
  }
135
132
  ```
136
133
 
137
- > - contactInfo was not redacted despite being a RegExp match as it is not a primitive.
138
- > - `email`, `firstName`, and `lastName` fields were redacted in contactInfo as they matched RegExes
139
- > - primitives in `someSecretData` array value were redacted
140
- > - object in `someSecretData` was evaluated separate from primitives in the same array
134
+ > - `email` and `name` fields were all redacted
135
+ > - primitives in `someSecretData` array were redacted
136
+ > - object values in `someSecretData` was evaluated and redacted if applicable
141
137
 
142
138
  ### `deepSecretKeys` Configuration
143
- Used to specify secrets which should be deeply redacted. Values which are objects or arrays will have all their values redacted, including child objects and arrays, unless identified as a `fullSecretKey` or `customObject` which take higher precedence.
139
+ * Specifies values which should be deeply redacted
140
+ * Has higher precedence than `secretKeys`
141
+ * All children of the key will have their values redacted unless `fullSecretKey` or `customObject` has precedence.
144
142
 
145
143
  #### Details
146
144
  - **Type:** `RegExp[]`
147
145
  - **Default:** `[]`
148
146
  - **Effect:** Matches keys in objects or child objects and deeply redacts all values, including values in child objects or objects within arrays.
149
- - Has higher precedence than `secretKeys` but lower precedence than `fullSecretKeys` and `customObjects`.
147
+ - _Note: has higher precedence than `secretKeys`._
150
148
 
151
149
  #### Example
152
150
  ##### Code
@@ -160,16 +158,11 @@ const myJsonObject = {
160
158
  firstName: "Foo",
161
159
  lastName: "Bar",
162
160
  Salutation: "Mr.",
163
- preference: "email",
164
- lastUpdated: "2024-12-01T22:07:26.448Z",
165
161
  lastUpdatedBy: {
166
- firstName: "John",
167
- lastName: "Doe",
168
- id: "12345"
162
+ id: 1
169
163
  }
170
164
  },
171
- someSecretData: ["fizz", "buzz", { deep: "FOO", name: "BAR" }],
172
- hobbies: ["Basketball", "Baseball", "Tennis", {contactInfo: "foobar"}]
165
+ someSecretData: ["fizz", "buzz", { deep: "FOO", name: "BAR" }]
173
166
  }
174
167
  const fieldRedactor = new FieldRedactor({
175
168
  deepSecretKeys: [/someSecretData/i, /contactInfo/i]
@@ -188,28 +181,24 @@ console.log(result);
188
181
  "firstName": "REDACTED",
189
182
  "lastName": "REDACTED",
190
183
  "Salutation": "REDACTED",
191
- "preference": "REDACTED",
192
- "lastUpdated": "REDACTED",
193
184
  "lastUpdatedBy": {
194
- "firstName": "REDACTED",
195
- "lastName": "REDACTED",
196
185
  "id": "REDACTED"
197
186
  }
198
187
  },
199
- "someSecretData": ["REDACTED", "REDACTED", { "deep": "REDACTED", "name": "REDACTED" }],
200
- "hobbies": ["Basketball", "Baseball", "Tennis", { "contactInfo": "REDACTED" }]
188
+ "someSecretData": ["REDACTED", "REDACTED", { "deep": "REDACTED", "name": "REDACTED" }]
201
189
  }
202
190
  ```
203
- > - All values in `contactInfo` were redacted, including deep children
204
- > - All values in `someSecretData` were redacted, including object values
191
+ > - All values in `contactInfo` were redacted
192
+ > - All values in `someSecretData` were redacted
205
193
 
206
194
  ### `fullSecretKeys` Configuration
207
- Specifies values which should be stringified and passed to the redactor function. Has higher precedence than other secret types but lower precedence than `customObjects`. However, if value is stringified and contains a child object which is a custom object then it will, by definition, not be noticed.
195
+ * Specifies values which should be stringified and redacted
196
+ * _Note: has higher precedence than `secretKeys` and `deepSecretKeys`_
208
197
 
209
198
  #### Details
210
199
  - **Type:** `RegExp[]`
211
200
  - **Default:** `[]`
212
- - **Effect:** Matches keys in objects or child objects and stringifies and fully redacts their values.
201
+ - **Effect:** Matches keys and stringifies + redacts their values.
213
202
  - Has higher precedence than `secretKeys` and `deepSecretKeys` but lower precedence than `customObjects`.
214
203
 
215
204
  #### Example
@@ -227,12 +216,10 @@ const myJsonObject = {
227
216
  Salutation: "Mr.",
228
217
  preference: "email",
229
218
  lastUpdated: "2024-12-01T22:07:26.448Z"
230
- },
231
- someSecretData: ["fizz", "buzz", { deep: "foo", name: "bar" }],
232
- hobbies: ["Basketball", "Baseball", "Tennis"]
219
+ }
233
220
  }
234
221
  const fieldRedactor = new FieldRedactor({
235
- fullSecretKeys: [/someSecretData/i, /contactInfo/i],
222
+ fullSecretKeys: [/someSecretData/i],
236
223
  });
237
224
  const result = await fieldRedactor.redact(myJsonObject);
238
225
  console.log(result);
@@ -243,26 +230,58 @@ console.log(result);
243
230
  {
244
231
  "timestamp": "2024-12-01T22:07:26.448Z",
245
232
  "userId": 271,
246
- "contactInfo": "REDACTED",
247
- "someSecretData": "REDACTED",
248
- "hobbies": ["Basketball", "Baseball", "Tennis"]
233
+ "contactInfo": "REDACTED"
249
234
  }
250
235
  ```
251
236
  > - Entirity of `contactInfo` was redacted.
252
- > - Entirity of `someSecretData` was redacted.
237
+
238
+ ### `deleteSecretKeys` Configuration
239
+ * Specifies values which should be completely deleted.
240
+
241
+ #### Details
242
+ - **Type:** `RegExp[]`
243
+ - **Default:** `[]`
244
+ - **Effect:** Matches keys and deletes them from output.
245
+ - Has lower precedence than `customObjects`
246
+
247
+ #### Example
248
+ ##### Code
249
+ ```typescript
250
+ import { FieldRedactor } from 'field-redactor';
251
+
252
+ const myJsonObject = {
253
+ timestamp: "2024-12-01T22:07:26.448Z",
254
+ userId: 271,
255
+ appAuthKey: "12345-67890"
256
+ }
257
+ const fieldRedactor = new FieldRedactor({
258
+ deleteSecretKeys: [/authKey/i],
259
+ });
260
+ const result = await fieldRedactor.redact(myJsonObject);
261
+ console.log(result);
262
+ ```
263
+
264
+ ##### Output
265
+ ```json
266
+ {
267
+ "timestamp": "2024-12-01T22:07:26.448Z",
268
+ "userId": 271
269
+ }
270
+ ```
271
+ > - `appAuthKey` was deleted
253
272
 
254
273
  ### `customObjects` Configuration
255
- **One of the most powerful features of this library and why it was written in the first place.** Combining `secretKeys`, `deepSecretKeys`, `fullSecretKeys`, and `customObjects` yields a powerful and highly customizable redaction tool capable of conditionally redacting a broad variety of input JSON objects correctly according to a single schema configuration.
274
+ * **One of the most powerful features of this library and why it was written in the first place.**
275
+ * Combining CustomObjects with secrets yields a powerful and highly customizable redaction tool capable of conditionally redacting a broad variety of input JSON objects correctly according to a user-specified schema.
256
276
 
257
277
  #### Details
258
278
  - **Type:** `CustomObject` (See `CustomObject` Schema Section)
259
279
  - **Default:** `[]`
260
- - **Effect:** Any object that matches the schema will be considered a custom object and redacted based on the schema configuration.
261
- - Priority supercedes all others. If a `CustomObject` is nested inside a `deepSecretKey` value then the `CustomObject` configuration takes precedence.
262
- - If a `CustomObject` is found inside another `CustomObject` then the new `CustomObject` takes precedence.
280
+ - **Effect:** Any object that matches the schema will be redacted based on its schema.
281
+ - _Note: has highest precedence_
282
+ - -_Note: If a custom object is nested inside another, the child takes precedence_
263
283
 
264
284
  #### `CustomObject` Schema
265
- A custom object takes the following format:
266
285
  ```typescript
267
286
  {
268
287
  [key]: CustomObjectMatchType | string
@@ -271,91 +290,98 @@ A custom object takes the following format:
271
290
 
272
291
  - `key`
273
292
  - **Type:** `string`
274
- - **Effect:** Specifies the key for a custom object
293
+ - **Effect:** Specifies the key to match on.
275
294
  - `value`:
276
295
  - **Type:** `CustomObjectMatchType | string`
277
296
  - **Effect:** Specifies how the value should be redacted
278
- - `string` - checks if the sibling key with this name has a value which is a `secretKey`, `deepSecretKey`, or `fullSecretKey` and redacts accordingly
279
- - `CustomObjectMatchType` - Redacts according to the match type. See `CustomObjectMatchType` Enum Section.
297
+ - `string` - checks if a sibling key with this name exists and contains a secret value. If so, redacts according to the secret specifier.
298
+ - `CustomObjectMatchType` - Redacts according to the match type.
280
299
 
281
300
 
282
301
  #### `CustomObjectMatchType` Enum
302
+ Specifies how a value should be redacted in a CustomObject if not using a `string` sibling specifier.
303
+
283
304
  | Key | Description |
284
305
  | --- | ----------- |
285
- | `Full` | Stringify value and redact. Functions identical to `fullSecretKeys`. |
286
- | `Deep` | Redact if primitive, deeply redact all values and children if object or array. Functions identical to `deepSecretKeys`. |
287
- | `Shallow` | Redact if primitive or array of primitives and revery to normal evaluation if object or array contains object. Functions identical to `secretKeys`. |
288
- | `Pass` | Do not redact if primitive value and revert to normal rules if an object. |
289
- | `Ignore` | Do not redact if primitive and skip evaluation entirely if object or array. |
306
+ | `Delete` | Delete the value from the result. |
307
+ | `Full` | Stringify value and redact. |
308
+ | `Deep` | Redact if primitive and deeply redact if object or array. |
309
+ | `Shallow` | Redact if primitive or array of primitives and revert to normal rules otherwise, including objects in arrays. |
310
+ | `Pass` | Do not redact, but revert to normal rules for child objects or objects in arrays. |
311
+ | `Ignore` | Skip evaluation entirely. |
290
312
 
291
313
  #### Example
292
314
  ```typescript
293
- import { FieldRedactor } from 'field-redactor';
315
+ import { FieldRedactor, CustomObjectMatchType } from 'field-redactor';
294
316
 
295
- const myCustomObject = {
296
- name: CustomObjectMatchType.Ignore,
297
- type: CustomObjectMatchType.Ignore,
298
- significance: CustomObjectMatchType.Ignore,
299
- shallowValue: "name",
300
- deepValue: "type",
301
- fullValue: "significance"
317
+ const myCustomObject1 = {
302
318
  shallow: CustomObjectMatchType.Shallow,
303
319
  deep: CustomObjectMatchType.Deep,
304
320
  full: CustomObjectMatchType.Full,
321
+ delete: CustomObjectMatchType.Delete
305
322
  pass: CustomObjectMatchType.Pass,
306
323
  ignore: CustomObjectMatchType.Ignore
307
324
  };
308
325
 
326
+ const myCustomObject2 = {
327
+ name: CustomObjectMatchType.Ignore,
328
+ type: CustomObjectMatchType.Ignore,
329
+ shallowValue: "name",
330
+ deepValue: "type",
331
+ }
332
+
309
333
  const myJsonObject = {
310
334
  timestamp: "2024-12-01T22:07:26.448Z",
311
335
  userId: 271,
312
336
  data: [
313
337
  {
314
- name: "email",
315
- type: "Secure",
316
- significance: "meta"
317
- shallowValue: "foo.bar@example.com",
318
- deepValue: "foobar",
319
- fullValue: "hello",
320
338
  shallow: "hello",
321
339
  deep: "hello",
322
340
  full: "hello",
341
+ delete: "hello",
323
342
  pass: "hello",
324
343
  ignore: "hello"
325
344
  },
326
345
  {
327
346
  name: "email",
328
347
  type: "Secure",
329
- significance: "meta",
330
- shallowValue: {
348
+ shallowValue: "foo.bar@example.com",
349
+ deepValue: "foobar",
350
+ },
351
+ {
352
+ shallow: {
331
353
  hello: "world",
332
354
  email: "foobar"
333
355
  },
334
- deepValue: {
356
+ deep: {
335
357
  hello: "world",
336
358
  email: "foobar"
337
359
  },
338
- deepValue: {
360
+ full: {
339
361
  hello: "world",
340
362
  email: "foobar"
341
363
  },
342
- shallow: {
364
+ delete: {
343
365
  hello: "world",
344
366
  email: "foobar"
345
367
  },
346
- deep: {
368
+ pass: {
347
369
  hello: "world",
348
370
  email: "foobar"
349
371
  },
350
- full: {
372
+ ignore: {
351
373
  hello: "world",
352
374
  email: "foobar"
353
- },
354
- pass: {
375
+ }
376
+ }
377
+ {
378
+ name: "email",
379
+ type: "Secure",
380
+ shallowValue: {
355
381
  hello: "world",
356
382
  email: "foobar"
357
383
  },
358
- ignore: {
384
+ deepValue: {
359
385
  hello: "world",
360
386
  email: "foobar"
361
387
  }
@@ -366,7 +392,7 @@ const fieldRedactor = new FieldRedactor({
366
392
  secretKeys: [/email/],
367
393
  deepSecretKeys: [/secure/i],
368
394
  fullSecretKeys: [/meta/i],
369
- customObjects: [myCustomObject]
395
+ customObjects: [myCustomObject1, myCustomObject2]
370
396
  });
371
397
  const result = await fieldRedactor.redact(myJsonObject);
372
398
  console.log(result);
@@ -379,11 +405,6 @@ console.log(result);
379
405
  "userId": 271,
380
406
  "data": [
381
407
  {
382
- "name": "email",
383
- "type": "Secure",
384
- "shallowValue": "REDACTED",
385
- "deepValue": "REDACTED",
386
- "fullValue": "REDACTED",
387
408
  "shallow": "REDACTED",
388
409
  "deep": "REDACTED",
389
410
  "full": "REDACTED",
@@ -393,15 +414,10 @@ console.log(result);
393
414
  {
394
415
  "name": "email",
395
416
  "type": "Secure",
396
- "shallowValue": {
397
- "hello": "world",
398
- "email": "REDACTED"
399
- },
400
- "deepValue": {
401
- "hello": "REDACTED",
402
- "email": "REDACTED"
403
- },
404
- "fullValue": "REDACTED",
417
+ "shallowValue": "REDACTED",
418
+ "deepValue": "REDACTED"
419
+ },
420
+ {
405
421
  "shallow": {
406
422
  "hello": "world",
407
423
  "email": "REDACTED"
@@ -420,14 +436,22 @@ console.log(result);
420
436
  "email": "foobar"
421
437
  }
422
438
  }
439
+ {
440
+ "name": "email",
441
+ "type": "Secure",
442
+ "shallowValue": {
443
+ "hello": "world",
444
+ "email": "REDACTED"
445
+ },
446
+ "deepValue": {
447
+ "hello": "REDACTED",
448
+ "email": "REDACTED"
449
+ }
450
+ }
423
451
  ]
424
- };
452
+ }
425
453
  ```
426
- > - Both objects in the data array matched the custom object and were redacted accordingly
427
- > - The first object contains only primitives whereas the second contains objects to highlight the differences
428
- > - `name` and `type` field were never redacted in either object because `CustomObjectMatchType` was `Ignore`
429
- > - `shallowValue`, `deepValue`, and `fullValue` had string key specifiers which matched a `shallowKey`, `deepSecretKey`, and `fullSecretKey`, respectively, and were redacted according to those rules.
430
- > - `shallow`, `deep`, `full`, `pass`, and `ignore` fields were redacted according to their `CustomObjectMatchType` value specified in the schema.
454
+ > - Example shows both primitives and objects to highlight differences
431
455
 
432
456
  ### `ignoreBooleans` Configuration
433
457
  - **Type:** `boolean`
@@ -517,6 +541,7 @@ const fieldRedactor: FieldRedactor = new FieldRedactor({
517
541
  redactor: myRedactor,
518
542
  secretKeys: [/email/, /name/i, /someSecretData/, /children/],
519
543
  deepSecretKeys: [/accountInfo/i, /someDeepSecretData/i, /privateInfo/i],
544
+ deleteSecretKeys: [/authKey/i],
520
545
  customObjects: [metadataCustomObject, actionsCustomObject],
521
546
  ignoreNullOrUndefined: false
522
547
  });
@@ -524,6 +549,7 @@ const fieldRedactor: FieldRedactor = new FieldRedactor({
524
549
  const myJsonObjectToRedact = {
525
550
  timestamp: "2024-12-01T22:07:26.448Z",
526
551
  userId: 271,
552
+ authKey: 12345,
527
553
  contactInfo: {
528
554
  email: "foo.bar@example.com",
529
555
  salutation: "Mr.",
@@ -2,7 +2,7 @@ import { CustomObject } from './types';
2
2
  /**
3
3
  * Utility for determining if a given object matches a CustomObject schema.
4
4
  */
5
- export declare class CustomObjectChecker {
5
+ export declare class CustomObjectManager {
6
6
  private customObjects;
7
7
  /**
8
8
  * Creates a CustomObjectChecker with the specified CustomObjects.
@@ -16,7 +16,7 @@ export declare class CustomObjectChecker {
16
16
  */
17
17
  getMatchingCustomObject(value: any): CustomObject | undefined;
18
18
  private isCustomObject;
19
- private customObjectDoesNotHaveExtraKeys;
19
+ private objectHasExtraKeys;
20
20
  private validateCustomObjects;
21
21
  }
22
- //# sourceMappingURL=customObjectChecker.d.ts.map
22
+ //# sourceMappingURL=customObjectManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customObjectManager.d.ts","sourceRoot":"","sources":["../src/customObjectManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,aAAa,CAAsB;IAE3C;;;OAGG;gBACS,aAAa,CAAC,EAAE,YAAY,EAAE;IAK1C;;;;OAIG;IACI,uBAAuB,CAAC,KAAK,EAAE,GAAG,GAAG,YAAY,GAAG,SAAS;IASpE,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;CAoB9B"}
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CustomObjectChecker = void 0;
3
+ exports.CustomObjectManager = void 0;
4
4
  const errors_1 = require("./errors");
5
5
  /**
6
6
  * Utility for determining if a given object matches a CustomObject schema.
7
7
  */
8
- class CustomObjectChecker {
8
+ class CustomObjectManager {
9
9
  /**
10
10
  * Creates a CustomObjectChecker with the specified CustomObjects.
11
11
  * @param customObjects The CustomObjects to check against.
@@ -32,23 +32,10 @@ class CustomObjectChecker {
32
32
  if (typeof value !== 'object' || !value || Array.isArray(value)) {
33
33
  return false;
34
34
  }
35
- if (!this.customObjectDoesNotHaveExtraKeys(value, customObject)) {
36
- return false;
37
- }
38
- for (const key of Object.keys(value)) {
39
- if (!customObject.hasOwnProperty(key)) {
40
- return false;
41
- }
42
- }
43
- return true;
35
+ return !this.objectHasExtraKeys(customObject, value) && !this.objectHasExtraKeys(value, customObject);
44
36
  }
45
- customObjectDoesNotHaveExtraKeys(value, customObject) {
46
- for (const key of Object.keys(customObject)) {
47
- if (!value.hasOwnProperty(key)) {
48
- return false;
49
- }
50
- }
51
- return true;
37
+ objectHasExtraKeys(object, objectToCompareTo) {
38
+ return Object.keys(object).some((key) => !objectToCompareTo.hasOwnProperty(key));
52
39
  }
53
40
  validateCustomObjects(customObjects) {
54
41
  if (!customObjects || customObjects.length <= 1) {
@@ -68,5 +55,5 @@ class CustomObjectChecker {
68
55
  }
69
56
  }
70
57
  }
71
- exports.CustomObjectChecker = CustomObjectChecker;
72
- //# sourceMappingURL=customObjectChecker.js.map
58
+ exports.CustomObjectManager = CustomObjectManager;
59
+ //# sourceMappingURL=customObjectManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customObjectManager.js","sourceRoot":"","sources":["../src/customObjectManager.ts"],"names":[],"mappings":";;;AAAA,qCAA2D;AAG3D;;GAEG;AACH,MAAa,mBAAmB;IAG9B;;;OAGG;IACH,YAAY,aAA8B;QANlC,kBAAa,GAAmB,EAAE,CAAC;QAOzC,IAAI,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC;QAC1C,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,CAAC;IAED;;;;OAIG;IACI,uBAAuB,CAAC,KAAU;QACvC,KAAK,MAAM,YAAY,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9C,IAAI,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE,CAAC;gBAC7C,OAAO,YAAY,CAAC;YACtB,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAEO,cAAc,CAAC,KAAU,EAAE,YAA0B;QAC3D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAChE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IACxG,CAAC;IAEO,kBAAkB,CAAC,MAAW,EAAE,iBAAsB;QAC5D,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;IACnF,CAAC;IAEO,qBAAqB,CAAC,aAA8B;QAC1D,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YAChD,OAAO;QACT,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,MAAM,OAAO,GAAiB,aAAa,CAAC,CAAC,CAAC,CAAC;YAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAClD,MAAM,KAAK,GAAiB,aAAa,CAAC,CAAC,CAAC,CAAC;gBAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACrC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;gBACjE,IAAI,UAAU,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;oBAChF,MAAM,IAAI,wCAA+B,CACvC,6BAA6B,CAAC,QAAQ,CAAC,gCAAgC,UAAU,EAAE,CACpF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA1DD,kDA0DC"}
package/dist/errors.d.ts CHANGED
@@ -11,10 +11,4 @@ export declare class FieldRedactorError extends Error {
11
11
  export declare class FieldRedactorConfigurationError extends FieldRedactorError {
12
12
  constructor(message: string);
13
13
  }
14
- /**
15
- * Error thrown when the input value to the FieldRedactor fails validation, such as not being a JSON object.
16
- */
17
- export declare class FieldRedactorValidationError extends FieldRedactorError {
18
- constructor(message: string);
19
- }
20
14
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,qBAAa,+BAAgC,SAAQ,kBAAkB;gBACzD,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,4BAA6B,SAAQ,kBAAkB;gBACtD,OAAO,EAAE,MAAM;CAI5B"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,qBAAa,+BAAgC,SAAQ,kBAAkB;gBACzD,OAAO,EAAE,MAAM;CAI5B"}
package/dist/errors.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FieldRedactorValidationError = exports.FieldRedactorConfigurationError = exports.FieldRedactorError = void 0;
3
+ exports.FieldRedactorConfigurationError = exports.FieldRedactorError = void 0;
4
4
  /**
5
5
  * Top-Level Field Redactor error thrown when there is an error redacting a JSON object.
6
6
  */
@@ -22,14 +22,4 @@ class FieldRedactorConfigurationError extends FieldRedactorError {
22
22
  }
23
23
  }
24
24
  exports.FieldRedactorConfigurationError = FieldRedactorConfigurationError;
25
- /**
26
- * Error thrown when the input value to the FieldRedactor fails validation, such as not being a JSON object.
27
- */
28
- class FieldRedactorValidationError extends FieldRedactorError {
29
- constructor(message) {
30
- super(message);
31
- this.name = 'FieldRedactorValidationError';
32
- }
33
- }
34
- exports.FieldRedactorValidationError = FieldRedactorValidationError;
35
25
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AALD,gDAKC;AAED;;;GAGG;AACH,MAAa,+BAAgC,SAAQ,kBAAkB;IACrE,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iCAAiC,CAAC;IAChD,CAAC;CACF;AALD,0EAKC;AAED;;GAEG;AACH,MAAa,4BAA6B,SAAQ,kBAAkB;IAClE,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;IAC7C,CAAC;CACF;AALD,oEAKC"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AALD,gDAKC;AAED;;;GAGG;AACH,MAAa,+BAAgC,SAAQ,kBAAkB;IACrE,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iCAAiC,CAAC;IAChD,CAAC;CACF;AALD,0EAKC"}
@@ -11,15 +11,18 @@ export declare class FieldRedactor {
11
11
  /**
12
12
  * Conditionally redacts fields in the JSON object based on the configuration provided in the constructor and returns the
13
13
  * redacted result.
14
- * @param value The JSON value to redact.
14
+ * If the value is a primitive, undefined, or date, returns the value as-is.
15
+ * @param value The JSON value to redact. If primitive it will be resolved as-is.
15
16
  * @returns The redacted JSON object.
16
17
  */
17
18
  redact(value: any): Promise<any>;
18
19
  /**
19
20
  * Conditionally redacts fields in the JSON object in place based on the configuration provided in the constructor.
20
- * @param value The JSON value to redact in place.
21
+ * If the value is a primitive, undefined, or date, returns the value as-is.
22
+ * @param value The JSON value to redact in place. If primitive it will be resolved as-is.
23
+ * @returns The redacted JSON object.
21
24
  */
22
25
  redactInPlace(value: any): Promise<void>;
23
- private validateInput;
26
+ private isPrimitiveOrUndefined;
24
27
  }
25
28
  //# sourceMappingURL=fieldRedactor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fieldRedactor.d.ts","sourceRoot":"","sources":["../src/fieldRedactor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAO9C;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAwC;IACxD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;gBACpC,MAAM,CAAC,EAAE,mBAAmB;IA4BxC;;;;;OAKG;IACU,MAAM,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAK7C;;;OAGG;IACU,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IASrD,OAAO,CAAC,aAAa;CAKtB"}
1
+ {"version":3,"file":"fieldRedactor.d.ts","sourceRoot":"","sources":["../src/fieldRedactor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAO9C;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAwC;IACxD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;gBACpC,MAAM,CAAC,EAAE,mBAAmB;IAyBxC;;;;;;OAMG;IACU,MAAM,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAK7C;;;;;OAKG;IACU,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAYrD,OAAO,CAAC,sBAAsB;CAG/B"}