@heroku/js-blanket 0.0.0 → 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/README.md +4 -1
- package/dist/cjs/.tsbuildinfo +1 -0
- package/dist/cjs/adapters/logging/generic.js +23 -0
- package/dist/cjs/adapters/logging/generic.js.map +1 -0
- package/dist/cjs/adapters/logging/generic.test.js +432 -0
- package/dist/cjs/adapters/logging/generic.test.js.map +1 -0
- package/dist/cjs/core/patterns.js +17 -0
- package/dist/cjs/core/patterns.js.map +1 -0
- package/dist/cjs/core/presets.js +116 -0
- package/dist/cjs/core/presets.js.map +1 -0
- package/dist/cjs/core/scrubber.js +260 -0
- package/dist/cjs/core/scrubber.js.map +1 -0
- package/dist/cjs/core/scrubber.test.js +392 -0
- package/dist/cjs/core/scrubber.test.js.map +1 -0
- package/dist/cjs/core/types.js +3 -0
- package/dist/cjs/core/types.js.map +1 -0
- package/dist/cjs/core/types.test.js +326 -0
- package/dist/cjs/core/types.test.js.map +1 -0
- package/dist/cjs/index.js +16 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/index.test.js +31 -0
- package/dist/cjs/index.test.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/.tsbuildinfo +1 -0
- package/{src/adapters/logging/generic.ts → dist/esm/adapters/logging/generic.d.ts} +1 -4
- package/dist/esm/adapters/logging/generic.js +20 -0
- package/dist/esm/adapters/logging/generic.js.map +1 -0
- package/dist/esm/adapters/logging/generic.test.d.ts +7 -0
- package/dist/esm/adapters/logging/generic.test.js +430 -0
- package/dist/esm/adapters/logging/generic.test.js.map +1 -0
- package/dist/esm/core/patterns.d.ts +4 -0
- package/dist/esm/core/patterns.js +14 -0
- package/dist/esm/core/patterns.js.map +1 -0
- package/dist/esm/core/presets.d.ts +64 -0
- package/{src/core/presets.ts → dist/esm/core/presets.js} +46 -55
- package/dist/esm/core/presets.js.map +1 -0
- package/dist/esm/core/scrubber.d.ts +131 -0
- package/dist/esm/core/scrubber.js +256 -0
- package/dist/esm/core/scrubber.js.map +1 -0
- package/dist/esm/core/scrubber.test.d.ts +1 -0
- package/dist/esm/core/scrubber.test.js +390 -0
- package/dist/esm/core/scrubber.test.js.map +1 -0
- package/dist/esm/core/types.d.ts +169 -0
- package/dist/esm/core/types.js +2 -0
- package/dist/esm/core/types.js.map +1 -0
- package/dist/esm/core/types.test.d.ts +9 -0
- package/dist/esm/core/types.test.js +324 -0
- package/dist/esm/core/types.test.js.map +1 -0
- package/{src/index.ts → dist/esm/index.d.ts} +0 -3
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/index.test.d.ts +1 -0
- package/dist/esm/index.test.js +29 -0
- package/dist/esm/index.test.js.map +1 -0
- package/package.json +45 -47
- package/.c8rc.json +0 -11
- package/.editorconfig +0 -11
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -41
- package/.github/copilot-instructions.md +0 -117
- package/.github/workflows/ci.yml +0 -25
- package/.husky/pre-commit +0 -1
- package/.lintstagedrc.json +0 -4
- package/.tool-versions +0 -1
- package/CODEOWNERS +0 -8
- package/CODE_OF_CONDUCT.md +0 -111
- package/CONTRIBUTING.md +0 -123
- package/SECURITY.md +0 -8
- package/docs/examples/logging-integration.md +0 -736
- package/eslint.config.mjs +0 -108
- package/prettier.config.mjs +0 -10
- package/scripts/test-setup.mjs +0 -24
- package/src/adapters/logging/generic.test.ts +0 -531
- package/src/core/patterns.ts +0 -22
- package/src/core/scrubber.test.ts +0 -465
- package/src/core/scrubber.ts +0 -284
- package/src/core/types.test.ts +0 -516
- package/src/core/types.ts +0 -176
- package/src/index.test.ts +0 -41
- package/tsconfig.cjs.json +0 -12
- package/tsconfig.esm.json +0 -12
- package/tsconfig.json +0 -32
- package/tsconfig.test.json +0 -9
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type Safety Tests for Core Scrubber
|
|
3
|
+
*
|
|
4
|
+
* These tests validate that TypeScript types are preserved correctly through scrubbing operations.
|
|
5
|
+
* They use compile-time type assertions to ensure type safety without runtime overhead.
|
|
6
|
+
*
|
|
7
|
+
* Run with: pnpm test (type-checked during pretest)
|
|
8
|
+
*/
|
|
9
|
+
import { expect } from 'chai';
|
|
10
|
+
import { Scrubber } from './scrubber.js';
|
|
11
|
+
describe('Type Safety', () => {
|
|
12
|
+
describe('Generic Type Preservation', () => {
|
|
13
|
+
it('preserves simple object types', () => {
|
|
14
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
15
|
+
const user = {
|
|
16
|
+
name: 'John',
|
|
17
|
+
email: 'john@example.com',
|
|
18
|
+
password: 'secret',
|
|
19
|
+
};
|
|
20
|
+
const result = scrubber.scrub(user);
|
|
21
|
+
// Compile-time assertion: result.data should be User type
|
|
22
|
+
const typeCheck = true;
|
|
23
|
+
expect(typeCheck).to.be.true;
|
|
24
|
+
// Runtime validation
|
|
25
|
+
expect(result.data).to.have.property('name');
|
|
26
|
+
expect(result.data).to.have.property('email');
|
|
27
|
+
expect(result.data).to.have.property('password');
|
|
28
|
+
});
|
|
29
|
+
it('preserves nested object types', () => {
|
|
30
|
+
const scrubber = new Scrubber({ fields: ['email'] });
|
|
31
|
+
const profile = {
|
|
32
|
+
user: { name: 'John', email: 'john@example.com' },
|
|
33
|
+
address: { street: '123 Main St', city: 'Springfield', zip: '12345' },
|
|
34
|
+
metadata: { lastLogin: '2024-01-01', loginCount: 42 },
|
|
35
|
+
};
|
|
36
|
+
const _result = scrubber.scrub(profile);
|
|
37
|
+
// Compile-time assertion
|
|
38
|
+
const typeCheck = true;
|
|
39
|
+
expect(typeCheck).to.be.true;
|
|
40
|
+
});
|
|
41
|
+
it('preserves array types', () => {
|
|
42
|
+
const scrubber = new Scrubber({ fields: ['secret'] });
|
|
43
|
+
const items = [
|
|
44
|
+
{ id: 1, name: 'Item 1', secret: 'secret1' },
|
|
45
|
+
{ id: 2, name: 'Item 2', secret: 'secret2' },
|
|
46
|
+
];
|
|
47
|
+
const result = scrubber.scrub(items);
|
|
48
|
+
// Compile-time assertion
|
|
49
|
+
const typeCheck = true;
|
|
50
|
+
expect(typeCheck).to.be.true;
|
|
51
|
+
// Runtime validation
|
|
52
|
+
expect(result.data).to.be.an('array');
|
|
53
|
+
expect(result.data).to.have.lengthOf(2);
|
|
54
|
+
});
|
|
55
|
+
it('preserves union types', () => {
|
|
56
|
+
const scrubber = new Scrubber({ fields: ['email'] });
|
|
57
|
+
const data = {
|
|
58
|
+
type: 'user',
|
|
59
|
+
name: 'John',
|
|
60
|
+
email: 'john@example.com',
|
|
61
|
+
};
|
|
62
|
+
const _result = scrubber.scrub(data);
|
|
63
|
+
// Compile-time assertion
|
|
64
|
+
const typeCheck = true;
|
|
65
|
+
expect(typeCheck).to.be.true;
|
|
66
|
+
});
|
|
67
|
+
it('preserves readonly types', () => {
|
|
68
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
69
|
+
const user = {
|
|
70
|
+
id: 1,
|
|
71
|
+
name: 'John',
|
|
72
|
+
password: 'secret',
|
|
73
|
+
};
|
|
74
|
+
const result = scrubber.scrub(user);
|
|
75
|
+
// Compile-time assertion
|
|
76
|
+
const typeCheck = true;
|
|
77
|
+
expect(typeCheck).to.be.true;
|
|
78
|
+
// Immutability: original should not be modified
|
|
79
|
+
expect(user.password).to.equal('secret');
|
|
80
|
+
expect(result.data.password).to.equal('[SCRUBBED]');
|
|
81
|
+
});
|
|
82
|
+
it('preserves optional property types', () => {
|
|
83
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
84
|
+
const user = {
|
|
85
|
+
name: 'John',
|
|
86
|
+
email: 'john@example.com',
|
|
87
|
+
// phone is omitted
|
|
88
|
+
password: 'secret',
|
|
89
|
+
};
|
|
90
|
+
const _result = scrubber.scrub(user);
|
|
91
|
+
// Compile-time assertion
|
|
92
|
+
const typeCheck = true;
|
|
93
|
+
expect(typeCheck).to.be.true;
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe('ScrubResult Type', () => {
|
|
97
|
+
it('has correct result structure', () => {
|
|
98
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
99
|
+
const data = { user: 'john', password: 'secret' };
|
|
100
|
+
const result = scrubber.scrub(data);
|
|
101
|
+
// Type assertion: result should be ScrubResult
|
|
102
|
+
const typeCheck = true;
|
|
103
|
+
expect(typeCheck).to.be.true;
|
|
104
|
+
// Runtime validation
|
|
105
|
+
expect(result).to.have.property('data');
|
|
106
|
+
expect(result).to.have.property('scrubbed');
|
|
107
|
+
expect(result).to.have.property('scrubbedPaths');
|
|
108
|
+
expect(result.scrubbed).to.be.a('boolean');
|
|
109
|
+
expect(result.scrubbedPaths).to.be.an('array');
|
|
110
|
+
});
|
|
111
|
+
it('preserves input type in result.data', () => {
|
|
112
|
+
const scrubber = new Scrubber({ fields: ['a'] });
|
|
113
|
+
const input = { a: 'test', b: 42, c: true };
|
|
114
|
+
const _result = scrubber.scrub(input);
|
|
115
|
+
// Compile-time assertion
|
|
116
|
+
const typeCheck = true;
|
|
117
|
+
expect(typeCheck).to.be.true;
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe('ScrubConfig Type', () => {
|
|
121
|
+
it('accepts valid configurations', () => {
|
|
122
|
+
const config1 = {
|
|
123
|
+
fields: ['password', 'apiToken'],
|
|
124
|
+
};
|
|
125
|
+
const config2 = {
|
|
126
|
+
fields: ['password', /api[-_]?key/i],
|
|
127
|
+
paths: ['user.email'],
|
|
128
|
+
patterns: [/\d{3}-\d{2}-\d{4}/g],
|
|
129
|
+
replacement: '[REDACTED]',
|
|
130
|
+
};
|
|
131
|
+
const config3 = {
|
|
132
|
+
fields: [],
|
|
133
|
+
paths: [],
|
|
134
|
+
patterns: [],
|
|
135
|
+
recursive: false,
|
|
136
|
+
};
|
|
137
|
+
// All should be valid ScrubConfig types
|
|
138
|
+
expect(config1).to.be.an('object');
|
|
139
|
+
expect(config2).to.be.an('object');
|
|
140
|
+
expect(config3).to.be.an('object');
|
|
141
|
+
});
|
|
142
|
+
it('allows partial configurations', () => {
|
|
143
|
+
const partial1 = {};
|
|
144
|
+
const partial2 = { fields: ['password'] };
|
|
145
|
+
const partial3 = { replacement: '[X]' };
|
|
146
|
+
expect(partial1).to.be.an('object');
|
|
147
|
+
expect(partial2).to.be.an('object');
|
|
148
|
+
expect(partial3).to.be.an('object');
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
describe('Complex Type Scenarios', () => {
|
|
152
|
+
it('handles deeply nested generic types', () => {
|
|
153
|
+
const scrubber = new Scrubber({ fields: ['secret'] });
|
|
154
|
+
const data = {
|
|
155
|
+
level1: {
|
|
156
|
+
level2: {
|
|
157
|
+
level3: {
|
|
158
|
+
level4: {
|
|
159
|
+
value: 42,
|
|
160
|
+
secret: 'hidden',
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
const _result = scrubber.scrub(data);
|
|
167
|
+
// Compile-time assertion
|
|
168
|
+
const typeCheck = true;
|
|
169
|
+
expect(typeCheck).to.be.true;
|
|
170
|
+
});
|
|
171
|
+
it('handles arrays of complex types', () => {
|
|
172
|
+
const scrubber = new Scrubber({ fields: ['email'] });
|
|
173
|
+
const events = [
|
|
174
|
+
{
|
|
175
|
+
id: '1',
|
|
176
|
+
timestamp: new Date(),
|
|
177
|
+
user: { id: 'u1', email: 'user1@example.com' },
|
|
178
|
+
metadata: { key: 'value' },
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
id: '2',
|
|
182
|
+
timestamp: new Date(),
|
|
183
|
+
user: { id: 'u2', email: 'user2@example.com' },
|
|
184
|
+
metadata: { key: 'value' },
|
|
185
|
+
},
|
|
186
|
+
];
|
|
187
|
+
const _result = scrubber.scrub(events);
|
|
188
|
+
// Compile-time assertion
|
|
189
|
+
const typeCheck = true;
|
|
190
|
+
expect(typeCheck).to.be.true;
|
|
191
|
+
});
|
|
192
|
+
it('handles Record types', () => {
|
|
193
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
194
|
+
const users = {
|
|
195
|
+
user1: { name: 'John', password: 'secret1' },
|
|
196
|
+
user2: { name: 'Jane', password: 'secret2' },
|
|
197
|
+
};
|
|
198
|
+
const _result = scrubber.scrub(users);
|
|
199
|
+
// Compile-time assertion
|
|
200
|
+
const typeCheck = true;
|
|
201
|
+
expect(typeCheck).to.be.true;
|
|
202
|
+
});
|
|
203
|
+
it('handles mixed primitive and object types', () => {
|
|
204
|
+
const scrubber = new Scrubber({ fields: ['key'] });
|
|
205
|
+
const data = {
|
|
206
|
+
string: 'text',
|
|
207
|
+
number: 42,
|
|
208
|
+
boolean: true,
|
|
209
|
+
null: null,
|
|
210
|
+
undefined: undefined,
|
|
211
|
+
date: new Date(),
|
|
212
|
+
regex: /test/,
|
|
213
|
+
object: { key: 'value' },
|
|
214
|
+
array: [1, 2, 3],
|
|
215
|
+
};
|
|
216
|
+
const _result = scrubber.scrub(data);
|
|
217
|
+
// Compile-time assertion
|
|
218
|
+
const typeCheck = true;
|
|
219
|
+
expect(typeCheck).to.be.true;
|
|
220
|
+
});
|
|
221
|
+
it('handles tuple types', () => {
|
|
222
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
223
|
+
const tuple = ['John', 30, true, { password: 'secret' }];
|
|
224
|
+
const result = scrubber.scrub(tuple);
|
|
225
|
+
// Note: TypeScript treats tuples as arrays at runtime, so the type is preserved
|
|
226
|
+
// but the specific tuple structure is maintained
|
|
227
|
+
expect(result.data).to.be.an('array');
|
|
228
|
+
expect(result.data).to.have.lengthOf(4);
|
|
229
|
+
});
|
|
230
|
+
it('preserves type safety with unknown types', () => {
|
|
231
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
232
|
+
const data = { user: 'john', password: 'secret' };
|
|
233
|
+
const _result = scrubber.scrub(data);
|
|
234
|
+
// Compile-time assertion: unknown in, unknown out
|
|
235
|
+
const typeCheck = true;
|
|
236
|
+
expect(typeCheck).to.be.true;
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
describe('Type Inference', () => {
|
|
240
|
+
it('infers types from literal objects', () => {
|
|
241
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
242
|
+
// Type should be inferred from the literal
|
|
243
|
+
const result = scrubber.scrub({
|
|
244
|
+
name: 'John',
|
|
245
|
+
email: 'john@example.com',
|
|
246
|
+
password: 'secret',
|
|
247
|
+
});
|
|
248
|
+
// TypeScript infers the exact shape
|
|
249
|
+
expect(result.data).to.have.property('name');
|
|
250
|
+
expect(result.data).to.have.property('email');
|
|
251
|
+
expect(result.data).to.have.property('password');
|
|
252
|
+
});
|
|
253
|
+
it('works with const assertions', () => {
|
|
254
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
255
|
+
const data = {
|
|
256
|
+
name: 'John',
|
|
257
|
+
role: 'admin',
|
|
258
|
+
password: 'secret',
|
|
259
|
+
};
|
|
260
|
+
// Type should preserve readonly properties from const assertion
|
|
261
|
+
const result = scrubber.scrub(data);
|
|
262
|
+
expect(result.data.name).to.equal('John');
|
|
263
|
+
expect(result.data.role).to.equal('admin');
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
describe('Edge Case Types', () => {
|
|
267
|
+
it('handles empty objects', () => {
|
|
268
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
269
|
+
const empty = {};
|
|
270
|
+
const result = scrubber.scrub(empty);
|
|
271
|
+
const typeCheck = true;
|
|
272
|
+
expect(typeCheck).to.be.true;
|
|
273
|
+
expect(result.data).to.deep.equal({});
|
|
274
|
+
});
|
|
275
|
+
it('handles primitives directly', () => {
|
|
276
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
277
|
+
const string = 'test';
|
|
278
|
+
const number = 42;
|
|
279
|
+
const boolean = true;
|
|
280
|
+
const nullVal = null;
|
|
281
|
+
expect(scrubber.scrub(string).data).to.equal(string);
|
|
282
|
+
expect(scrubber.scrub(number).data).to.equal(number);
|
|
283
|
+
expect(scrubber.scrub(boolean).data).to.equal(boolean);
|
|
284
|
+
expect(scrubber.scrub(nullVal).data).to.equal(nullVal);
|
|
285
|
+
});
|
|
286
|
+
it('handles circular references with type preservation', () => {
|
|
287
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
288
|
+
const obj = {
|
|
289
|
+
name: 'test',
|
|
290
|
+
password: 'secret',
|
|
291
|
+
};
|
|
292
|
+
obj.self = obj; // Circular reference
|
|
293
|
+
const result = scrubber.scrub(obj);
|
|
294
|
+
// Type is preserved even with circular reference
|
|
295
|
+
const typeCheck = true;
|
|
296
|
+
expect(typeCheck).to.be.true;
|
|
297
|
+
expect(result.data.name).to.equal('test');
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
describe('Strict TypeScript Compliance', () => {
|
|
301
|
+
it('respects noUncheckedIndexedAccess', () => {
|
|
302
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
303
|
+
const data = {
|
|
304
|
+
user: 'john',
|
|
305
|
+
password: 'secret',
|
|
306
|
+
};
|
|
307
|
+
const result = scrubber.scrub(data);
|
|
308
|
+
// With noUncheckedIndexedAccess, indexed access returns string | undefined
|
|
309
|
+
const value = result.data['nonexistent'];
|
|
310
|
+
expect(value).to.be.undefined;
|
|
311
|
+
});
|
|
312
|
+
it('respects strictNullChecks', () => {
|
|
313
|
+
const scrubber = new Scrubber({ fields: ['value'] });
|
|
314
|
+
const data = {
|
|
315
|
+
value: null,
|
|
316
|
+
};
|
|
317
|
+
const _result = scrubber.scrub(data);
|
|
318
|
+
// Compile-time assertion
|
|
319
|
+
const typeCheck = true;
|
|
320
|
+
expect(typeCheck).to.be.true;
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
//# sourceMappingURL=types.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.test.js","sourceRoot":"","sources":["../../../src/core/types.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
// Core exports
|
|
2
1
|
export { Scrubber } from './core/scrubber.js';
|
|
3
2
|
export type { ScrubConfig, ScrubResult } from './core/types.js';
|
|
4
3
|
export { HEROKU_FIELDS, GDPR_FIELDS, PCI_FIELDS } from './core/presets.js';
|
|
5
4
|
export { PII_PATTERNS } from './core/patterns.js';
|
|
6
|
-
|
|
7
|
-
// Logging adapter
|
|
8
5
|
export { createRedactor } from './adapters/logging/generic.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Core exports
|
|
2
|
+
export { Scrubber } from './core/scrubber.js';
|
|
3
|
+
export { HEROKU_FIELDS, GDPR_FIELDS, PCI_FIELDS } from './core/presets.js';
|
|
4
|
+
export { PII_PATTERNS } from './core/patterns.js';
|
|
5
|
+
// Logging adapter
|
|
6
|
+
export { createRedactor } from './adapters/logging/generic.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,kBAAkB;AAClB,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Integration test to verify the public API works correctly
|
|
2
|
+
import { expect } from 'chai';
|
|
3
|
+
import { Scrubber, createRedactor, HEROKU_FIELDS, PII_PATTERNS, } from './index.js';
|
|
4
|
+
describe('js-blanket', () => {
|
|
5
|
+
it('creates and uses Scrubber instances for field-based scrubbing', () => {
|
|
6
|
+
expect(Scrubber).to.be.a('function');
|
|
7
|
+
const scrubber = new Scrubber({ fields: ['password'] });
|
|
8
|
+
expect(scrubber).to.be.instanceOf(Scrubber);
|
|
9
|
+
});
|
|
10
|
+
it('creates redactor instances that scrub sensitive data', () => {
|
|
11
|
+
expect(createRedactor).to.be.a('function');
|
|
12
|
+
const redactor = createRedactor({ fields: ['password'] });
|
|
13
|
+
const result = redactor.scrub({ password: 'secret' });
|
|
14
|
+
expect(result.data.password).to.equal('[SCRUBBED]');
|
|
15
|
+
});
|
|
16
|
+
it('provides HEROKU_FIELDS preset with standard Heroku sensitive fields', () => {
|
|
17
|
+
expect(HEROKU_FIELDS).to.be.an('array');
|
|
18
|
+
expect(HEROKU_FIELDS).to.include('password');
|
|
19
|
+
// Check for api_key pattern (can be string or regex)
|
|
20
|
+
const hasApiKey = HEROKU_FIELDS.some((field) => field === 'api_key' ||
|
|
21
|
+
(field instanceof RegExp && field.test('api_key')));
|
|
22
|
+
expect(hasApiKey).to.be.true;
|
|
23
|
+
});
|
|
24
|
+
it('provides PII_PATTERNS preset with common PII regex patterns', () => {
|
|
25
|
+
expect(PII_PATTERNS).to.be.an('array');
|
|
26
|
+
expect(PII_PATTERNS.length).to.be.greaterThan(0);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/index.test.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAE5D,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAC9B,OAAO,EACL,QAAQ,EACR,cAAc,EACd,aAAa,EACb,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACxD,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QACtD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC7C,qDAAqD;QACrD,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAClC,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,KAAK,SAAS;YACnB,CAAC,KAAK,YAAY,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CACrD,CAAC;QACF,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;QACvC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,26 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroku/js-blanket",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Framework-agnostic sensitive data scrubbing library for error monitoring and logging",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"pii",
|
|
7
|
-
"scrubbing",
|
|
8
|
-
"security",
|
|
9
|
-
"data-sanitization",
|
|
10
|
-
"error-monitoring",
|
|
11
|
-
"logging"
|
|
12
|
-
],
|
|
13
|
-
"homepage": "https://github.com/heroku/js-blanket#readme",
|
|
14
|
-
"bugs": {
|
|
15
|
-
"url": "https://github.com/heroku/js-blanket/issues"
|
|
16
|
-
},
|
|
17
|
-
"repository": {
|
|
18
|
-
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/heroku/js-blanket.git"
|
|
20
|
-
},
|
|
21
|
-
"license": "Apache-2.0",
|
|
22
|
-
"author": "Heroku",
|
|
23
5
|
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20.0.0"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/cjs/index.js",
|
|
10
|
+
"module": "./dist/esm/index.js",
|
|
11
|
+
"types": "./dist/esm/index.d.ts",
|
|
24
12
|
"exports": {
|
|
25
13
|
".": {
|
|
26
14
|
"import": "./dist/esm/index.js",
|
|
@@ -28,27 +16,6 @@
|
|
|
28
16
|
"types": "./dist/esm/index.d.ts"
|
|
29
17
|
}
|
|
30
18
|
},
|
|
31
|
-
"main": "./dist/cjs/index.js",
|
|
32
|
-
"types": "./dist/esm/index.d.ts",
|
|
33
|
-
"directories": {
|
|
34
|
-
"doc": "docs"
|
|
35
|
-
},
|
|
36
|
-
"scripts": {
|
|
37
|
-
"build:cjs": "rm -rf dist/cjs && tsc -p tsconfig.cjs.json && mkdir -p dist/cjs && echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json",
|
|
38
|
-
"build:esm": "rm -rf dist/esm && tsc -p tsconfig.esm.json",
|
|
39
|
-
"build": "pnpm run build:cjs && pnpm run build:esm",
|
|
40
|
-
"test": "c8 mocha --require ./scripts/test-setup.mjs --forbid-only \"dist/esm/**/*.test.js\"",
|
|
41
|
-
"prepare": "husky",
|
|
42
|
-
"lint": "eslint \"src/**/*.{js,ts}\"",
|
|
43
|
-
"lint:fix": "eslint \"src/**/*.{js,ts}\" --fix",
|
|
44
|
-
"prettier": "prettier . --write",
|
|
45
|
-
"format": "pnpm run prettier && pnpm run lint:fix",
|
|
46
|
-
"pretest": "pnpm run build:cjs && pnpm run build:esm && pnpm run type-check",
|
|
47
|
-
"type-check": "tsc --noEmit -p tsconfig.json",
|
|
48
|
-
"lint-staged": "npx lint-staged",
|
|
49
|
-
"check": "pnpm run format && pnpm run type-check && pnpm test",
|
|
50
|
-
"ci": "pnpm run lint && pnpm run type-check && pnpm test"
|
|
51
|
-
},
|
|
52
19
|
"dependencies": {
|
|
53
20
|
"tslib": "^2.8.1"
|
|
54
21
|
},
|
|
@@ -68,13 +35,44 @@
|
|
|
68
35
|
"prettier": "^3.6.2",
|
|
69
36
|
"typescript": "^5.9.3"
|
|
70
37
|
},
|
|
71
|
-
"engines": {
|
|
72
|
-
"node": ">=20.0.0"
|
|
73
|
-
},
|
|
74
38
|
"publishConfig": {
|
|
75
|
-
"access": "
|
|
39
|
+
"access": "restricted",
|
|
76
40
|
"registry": "https://registry.npmjs.org/"
|
|
77
41
|
},
|
|
78
|
-
"
|
|
79
|
-
|
|
80
|
-
|
|
42
|
+
"files": [
|
|
43
|
+
"/dist"
|
|
44
|
+
],
|
|
45
|
+
"author": "Heroku",
|
|
46
|
+
"license": "Apache-2.0",
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "git+https://github.com/heroku/js-blanket.git"
|
|
50
|
+
},
|
|
51
|
+
"bugs": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "https://github.com/heroku/js-blanket/issues"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"pii",
|
|
57
|
+
"scrubbing",
|
|
58
|
+
"security",
|
|
59
|
+
"data-sanitization",
|
|
60
|
+
"error-monitoring",
|
|
61
|
+
"logging"
|
|
62
|
+
],
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build:cjs": "rm -rf dist/cjs && tsc -p tsconfig.cjs.json && mkdir -p dist/cjs && echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json",
|
|
65
|
+
"build:esm": "rm -rf dist/esm && tsc -p tsconfig.esm.json",
|
|
66
|
+
"build": "pnpm run build:cjs && pnpm run build:esm",
|
|
67
|
+
"test": "c8 mocha --require ./scripts/test-setup.mjs --forbid-only \"dist/esm/**/*.test.js\"",
|
|
68
|
+
"lint": "eslint \"src/**/*.{js,ts}\"",
|
|
69
|
+
"lint:fix": "eslint \"src/**/*.{js,ts}\" --fix",
|
|
70
|
+
"prettier": "prettier . --write",
|
|
71
|
+
"format": "pnpm run prettier && pnpm run lint:fix",
|
|
72
|
+
"pretest": "pnpm run build:cjs && pnpm run build:esm && pnpm run type-check",
|
|
73
|
+
"type-check": "tsc --noEmit -p tsconfig.json",
|
|
74
|
+
"lint-staged": "npx lint-staged",
|
|
75
|
+
"check": "pnpm run format && pnpm run type-check && pnpm test",
|
|
76
|
+
"ci": "pnpm run lint && pnpm run type-check && pnpm test"
|
|
77
|
+
}
|
|
78
|
+
}
|
package/.c8rc.json
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"all": true,
|
|
3
|
-
"include": ["dist/esm/**/*.js"],
|
|
4
|
-
"exclude": ["**/*.test.js", "test/**/*", "node_modules/**/*"],
|
|
5
|
-
"reporter": ["text", "html", "text-summary"],
|
|
6
|
-
"clean": true,
|
|
7
|
-
"temp-directory": "./coverage/tmp",
|
|
8
|
-
"report-dir": "./coverage",
|
|
9
|
-
"src": "src",
|
|
10
|
-
"excludeNodeModules": true
|
|
11
|
-
}
|
package/.editorconfig
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
When creating a PR, be sure to prepend the PR title with the Conventional Commit type (`feat`, `fix`, or `chore`).
|
|
3
|
-
|
|
4
|
-
Examples:
|
|
5
|
-
|
|
6
|
-
`feat: add growl notification to spaces:wait`
|
|
7
|
-
|
|
8
|
-
`fix: handle special characters in app names`
|
|
9
|
-
|
|
10
|
-
`chore: refactor tests`
|
|
11
|
-
|
|
12
|
-
Learn more about [Conventional Commits](https://www.conventionalcommits.org/).
|
|
13
|
-
-->
|
|
14
|
-
|
|
15
|
-
## Summary
|
|
16
|
-
|
|
17
|
-
<!-- Brief description of the changes in this PR. -->
|
|
18
|
-
|
|
19
|
-
## Type of Change
|
|
20
|
-
|
|
21
|
-
- [ ] **fix**: Bug fix or issue (patch semvar update)
|
|
22
|
-
- [ ] **feat**: Introduces a new feature to the codebase (minor semvar update)
|
|
23
|
-
- [ ] **perf**: Performance improvement
|
|
24
|
-
- [ ] **docs**: Documentation only changes
|
|
25
|
-
- [ ] **tests**: Adding missing tests or correcting existing tests
|
|
26
|
-
- [ ] **chore**: Code cleanup tasks, dependency updates, or other changes
|
|
27
|
-
|
|
28
|
-
Note: Add a `!` after your change type to denote a breaking change.
|
|
29
|
-
|
|
30
|
-
## Additional Context
|
|
31
|
-
|
|
32
|
-
<!--
|
|
33
|
-
* For fixes, provide reproduction steps and expected vs actual behavior
|
|
34
|
-
* For features, describe the objective and rationale for this change.
|
|
35
|
-
* If this is a breaking change, describe what functionality is affected and a migration path for existing users
|
|
36
|
-
* Any additional information, links, screenshots, or attachments that help describe the issue
|
|
37
|
-
-->
|
|
38
|
-
|
|
39
|
-
## Related Issue
|
|
40
|
-
|
|
41
|
-
Closes #[Github issue number]
|