sachii-safe-logger 1.1.6 → 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 +132 -71
- package/dist/autoMask.d.ts +36 -0
- package/dist/autoMask.js +194 -0
- package/dist/globalMask.d.ts +20 -0
- package/dist/globalMask.js +88 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +17 -1
- package/dist/patterns.d.ts +38 -0
- package/dist/patterns.js +124 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,114 +1,175 @@
|
|
|
1
1
|
# sachii-safe-logger
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-

|
|
5
|
-

|
|
6
|
-

|
|
3
|
+
A lightweight TypeScript library to automatically detect and mask sensitive data (emails, credit cards, phone numbers, API tokens, SSN, passwords, etc.) in logs for security and compliance.
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
## Installation
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npm install sachii-safe-logger
|
|
9
|
+
```
|
|
11
10
|
|
|
12
|
-
##
|
|
11
|
+
## 🚀 Quick Start - Auto-Mask All Console Logs
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
- Mask **email addresses** partially.
|
|
16
|
-
- Mask **credit card numbers** leaving only the last 4 digits.
|
|
17
|
-
- Mask **tokens or API keys** securely.
|
|
18
|
-
- Written in **TypeScript**, with types included.
|
|
19
|
-
- Lightweight, dependency-free, and easy to use.
|
|
13
|
+
Just add **ONE line** at the top of your app and all `console.log` calls will automatically mask sensitive data!
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
```javascript
|
|
16
|
+
// At the very top of your app entry point (index.js, app.js, server.js)
|
|
17
|
+
require('sachii-safe-logger').enableGlobalMasking();
|
|
24
18
|
|
|
25
|
-
|
|
19
|
+
// That's it! Now ALL console.log calls anywhere in your app auto-mask sensitive data!
|
|
20
|
+
console.log("User email: john@example.com"); // → "User email: j***@example.com"
|
|
21
|
+
console.log("Card: 4111111111111111"); // → "Card: ************1111"
|
|
22
|
+
console.log("Call 555-123-4567"); // → "Call *******4567"
|
|
23
|
+
console.log("SSN: 123-45-6789"); // → "SSN: ***-**-6789"
|
|
24
|
+
console.log({ password: "secret123" }); // → { password: "sec****123" }
|
|
25
|
+
```
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
## What Gets Auto-Detected & Masked
|
|
28
|
+
|
|
29
|
+
| Data Type | Example Input | Masked Output |
|
|
30
|
+
|-----------|---------------|---------------|
|
|
31
|
+
| **Email** | `john@example.com` | `j***@example.com` |
|
|
32
|
+
| **Credit Card** | `4111111111111111` | `************1111` |
|
|
33
|
+
| **Phone** | `555-123-4567` | `*******4567` |
|
|
34
|
+
| **SSN** | `123-45-6789` | `***-**-6789` |
|
|
35
|
+
| **JWT Tokens** | `eyJhbGci...` | `eyJh****...` |
|
|
36
|
+
| **Passwords** | `password=secret` | `password=******` |
|
|
37
|
+
| **IP Addresses** | `192.168.1.100` | `192.***.***100` |
|
|
38
|
+
| **AWS Keys** | `AKIAIOSFODNN7EXAMPLE` | `AKIA****MPLE` |
|
|
39
|
+
| **Basic Auth** | `Basic dXNlcjpwYXNz` | `Basic [REDACTED]` |
|
|
40
|
+
| **URLs with creds** | `https://user:pass@host.com` | `https://user:********@host.com` |
|
|
41
|
+
|
|
42
|
+
## API Reference
|
|
43
|
+
|
|
44
|
+
### `enableGlobalMasking(options?)`
|
|
45
|
+
|
|
46
|
+
Enable auto-masking for all console methods globally. Call once at app startup.
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
const { enableGlobalMasking } = require('sachii-safe-logger');
|
|
50
|
+
|
|
51
|
+
// Enable with default options (masks everything)
|
|
52
|
+
enableGlobalMasking();
|
|
53
|
+
|
|
54
|
+
// Or customize what to mask
|
|
55
|
+
enableGlobalMasking({
|
|
56
|
+
maskEmail: true, // default: true
|
|
57
|
+
maskPhone: true, // default: true
|
|
58
|
+
maskCreditCard: true, // default: true
|
|
59
|
+
maskSSN: true, // default: true
|
|
60
|
+
maskIP: true, // default: true
|
|
61
|
+
maskJWT: true, // default: true
|
|
62
|
+
maskPasswords: true, // default: true
|
|
63
|
+
maskMAC: false, // default: false
|
|
64
|
+
});
|
|
65
|
+
```
|
|
29
66
|
|
|
30
|
-
|
|
31
|
-
import { maskPhone, maskEmail, maskCreditCard, maskToken } from "sachii-safe-logger";
|
|
67
|
+
### `disableGlobalMasking()`
|
|
32
68
|
|
|
33
|
-
|
|
34
|
-
const phone = "9876543210";
|
|
35
|
-
console.log(maskPhone(phone));
|
|
36
|
-
// Output: *******210
|
|
69
|
+
Restore original console behavior.
|
|
37
70
|
|
|
71
|
+
```javascript
|
|
72
|
+
const { disableGlobalMasking } = require('sachii-safe-logger');
|
|
73
|
+
disableGlobalMasking();
|
|
74
|
+
```
|
|
38
75
|
|
|
76
|
+
### `autoMask(input, options?)`
|
|
39
77
|
|
|
40
|
-
|
|
41
|
-
console.log(maskEmail(email));
|
|
42
|
-
// Output: e*****@example.com
|
|
78
|
+
Mask sensitive data in a single string.
|
|
43
79
|
|
|
80
|
+
```javascript
|
|
81
|
+
const { autoMask } = require('sachii-safe-logger');
|
|
44
82
|
|
|
83
|
+
const text = "Contact john@example.com or 555-123-4567";
|
|
84
|
+
console.log(autoMask(text));
|
|
85
|
+
// Output: "Contact j***@example.com or *******4567"
|
|
86
|
+
```
|
|
45
87
|
|
|
46
|
-
|
|
47
|
-
console.log(maskCreditCard(creditCard));
|
|
48
|
-
// Output: ************3456
|
|
88
|
+
### `autoMaskObject(obj, options?)`
|
|
49
89
|
|
|
90
|
+
Deep-traverse and mask sensitive data in objects.
|
|
50
91
|
|
|
92
|
+
```javascript
|
|
93
|
+
const { autoMaskObject } = require('sachii-safe-logger');
|
|
51
94
|
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
95
|
+
const user = {
|
|
96
|
+
email: "john@example.com",
|
|
97
|
+
password: "secret123",
|
|
98
|
+
payment: { cardNumber: "4111111111111111" }
|
|
99
|
+
};
|
|
55
100
|
|
|
101
|
+
console.log(autoMaskObject(user));
|
|
102
|
+
// Output: { email: "j***@example.com", password: "sec****123", payment: { cardNumber: "************1111" }}
|
|
56
103
|
```
|
|
57
104
|
|
|
105
|
+
### `createSafeLogger(logger?, options?)`
|
|
106
|
+
|
|
107
|
+
Wrap any logger (console, winston, pino, bunyan) with auto-masking.
|
|
58
108
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
| `maskPhone()` | Masks phone except last 3 digits | `"*******210"` |
|
|
63
|
-
| `maskCreditCard()` | Masks all except last 4 digits | `"************1111"` |
|
|
64
|
-
| `maskToken()` | Masks API tokens except first 4 & last 4 chars | `"abcd********5678"` |
|
|
109
|
+
```javascript
|
|
110
|
+
const { createSafeLogger } = require('sachii-safe-logger');
|
|
111
|
+
const winston = require('winston');
|
|
65
112
|
|
|
66
|
-
|
|
113
|
+
const safeLogger = createSafeLogger(winston);
|
|
114
|
+
safeLogger.info("User email: john@example.com"); // Auto-masked!
|
|
115
|
+
```
|
|
67
116
|
|
|
68
|
-
|
|
117
|
+
### Individual Maskers
|
|
69
118
|
|
|
70
|
-
|
|
119
|
+
```javascript
|
|
120
|
+
const { maskEmail, maskPhone, maskCreditCard, maskToken } = require('sachii-safe-logger');
|
|
71
121
|
|
|
72
|
-
|
|
122
|
+
maskEmail("john@example.com"); // "j***@example.com"
|
|
123
|
+
maskPhone("555-123-4567"); // "*******4567"
|
|
124
|
+
maskCreditCard("4111111111111111"); // "************1111"
|
|
125
|
+
maskToken("sk_live_abc123xyz789"); // "sk_l****9789"
|
|
126
|
+
```
|
|
73
127
|
|
|
128
|
+
### Access Regex Patterns
|
|
74
129
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
│ ├─ maskers/
|
|
78
|
-
│ │ ├─ creditCard.js
|
|
79
|
-
│ │ ├─ email.js
|
|
80
|
-
│ │ ├─ phone.js
|
|
81
|
-
│ │ └─ tokens.js
|
|
82
|
-
│ └─ utils.js
|
|
83
|
-
├─ tests/
|
|
84
|
-
│ ├─ phone.test.ts
|
|
85
|
-
│ ├─ email.test.ts
|
|
86
|
-
│ ├─ creditCard.test.ts
|
|
87
|
-
│ └─ token.test.ts
|
|
88
|
-
├─ package.json
|
|
89
|
-
├─ README.md
|
|
90
|
-
└─ LICENSE
|
|
130
|
+
```javascript
|
|
131
|
+
const { PATTERNS } = require('sachii-safe-logger');
|
|
91
132
|
|
|
133
|
+
// Use patterns for your own validation/detection
|
|
134
|
+
PATTERNS.EMAIL // Email regex
|
|
135
|
+
PATTERNS.CREDIT_CARD // Credit card regex
|
|
136
|
+
PATTERNS.SSN // SSN regex
|
|
137
|
+
PATTERNS.JWT // JWT regex
|
|
138
|
+
// ... and more
|
|
92
139
|
```
|
|
93
140
|
|
|
94
|
-
|
|
141
|
+
## Custom Patterns
|
|
95
142
|
|
|
96
|
-
|
|
97
|
-
[Full API docs](https://sachiinandan.github.io/sachii-safe-logger)
|
|
143
|
+
Add your own regex patterns:
|
|
98
144
|
|
|
145
|
+
```javascript
|
|
146
|
+
enableGlobalMasking({
|
|
147
|
+
customPatterns: [
|
|
148
|
+
{ name: 'employeeId', pattern: /EMP-\d{6}/g },
|
|
149
|
+
{ name: 'internalCode', pattern: /INT-[A-Z]{3}-\d{4}/g }
|
|
150
|
+
]
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## TypeScript Support
|
|
99
155
|
|
|
100
|
-
|
|
156
|
+
Full TypeScript support with type definitions included.
|
|
101
157
|
|
|
102
|
-
|
|
158
|
+
```typescript
|
|
159
|
+
import { enableGlobalMasking, autoMask, AutoMaskOptions } from 'sachii-safe-logger';
|
|
103
160
|
|
|
104
|
-
|
|
161
|
+
const options: AutoMaskOptions = {
|
|
162
|
+
maskEmail: true,
|
|
163
|
+
maskPhone: false
|
|
164
|
+
};
|
|
105
165
|
|
|
106
|
-
|
|
166
|
+
enableGlobalMasking(options);
|
|
167
|
+
```
|
|
107
168
|
|
|
108
|
-
|
|
169
|
+
## License
|
|
109
170
|
|
|
110
|
-
|
|
171
|
+
MIT
|
|
111
172
|
|
|
112
|
-
##
|
|
173
|
+
## Author
|
|
113
174
|
|
|
114
|
-
|
|
175
|
+
Sachinandan <sachinandan.priv05@gmail.com>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface CustomPattern {
|
|
2
|
+
name: string;
|
|
3
|
+
pattern: RegExp;
|
|
4
|
+
}
|
|
5
|
+
export interface AutoMaskOptions {
|
|
6
|
+
maskEmail?: boolean;
|
|
7
|
+
maskPhone?: boolean;
|
|
8
|
+
maskCreditCard?: boolean;
|
|
9
|
+
maskSSN?: boolean;
|
|
10
|
+
maskIP?: boolean;
|
|
11
|
+
maskJWT?: boolean;
|
|
12
|
+
maskBearerToken?: boolean;
|
|
13
|
+
maskAWSKeys?: boolean;
|
|
14
|
+
maskPrivateKeys?: boolean;
|
|
15
|
+
maskPasswords?: boolean;
|
|
16
|
+
maskBasicAuth?: boolean;
|
|
17
|
+
maskURLCredentials?: boolean;
|
|
18
|
+
maskMAC?: boolean;
|
|
19
|
+
customPatterns?: CustomPattern[];
|
|
20
|
+
preserveLength?: boolean;
|
|
21
|
+
maskChar?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface SafeLogger {
|
|
24
|
+
log: (...args: any[]) => void;
|
|
25
|
+
info: (...args: any[]) => void;
|
|
26
|
+
warn: (...args: any[]) => void;
|
|
27
|
+
error: (...args: any[]) => void;
|
|
28
|
+
debug: (...args: any[]) => void;
|
|
29
|
+
trace: (...args: any[]) => void;
|
|
30
|
+
_original: any;
|
|
31
|
+
setOptions: (newOptions: Partial<AutoMaskOptions>) => void;
|
|
32
|
+
}
|
|
33
|
+
export declare function maskMatch(match: string, type: string, options?: Partial<AutoMaskOptions>): string;
|
|
34
|
+
export declare function autoMask(input: string, options?: AutoMaskOptions): string;
|
|
35
|
+
export declare function autoMaskObject<T>(obj: T, options?: AutoMaskOptions): T;
|
|
36
|
+
export declare function createSafeLogger(logger?: any, options?: AutoMaskOptions): SafeLogger;
|
package/dist/autoMask.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.maskMatch = maskMatch;
|
|
4
|
+
exports.autoMask = autoMask;
|
|
5
|
+
exports.autoMaskObject = autoMaskObject;
|
|
6
|
+
exports.createSafeLogger = createSafeLogger;
|
|
7
|
+
const patterns_1 = require("./patterns");
|
|
8
|
+
const email_1 = require("./maskers/email");
|
|
9
|
+
const phone_1 = require("./maskers/phone");
|
|
10
|
+
const creditCard_1 = require("./maskers/creditCard");
|
|
11
|
+
const tokens_1 = require("./maskers/tokens");
|
|
12
|
+
const DEFAULT_OPTIONS = {
|
|
13
|
+
maskEmail: true,
|
|
14
|
+
maskPhone: true,
|
|
15
|
+
maskCreditCard: true,
|
|
16
|
+
maskSSN: true,
|
|
17
|
+
maskIP: true,
|
|
18
|
+
maskJWT: true,
|
|
19
|
+
maskBearerToken: true,
|
|
20
|
+
maskAWSKeys: true,
|
|
21
|
+
maskPrivateKeys: true,
|
|
22
|
+
maskPasswords: true,
|
|
23
|
+
maskBasicAuth: true,
|
|
24
|
+
maskURLCredentials: true,
|
|
25
|
+
maskMAC: false,
|
|
26
|
+
customPatterns: [],
|
|
27
|
+
preserveLength: true,
|
|
28
|
+
maskChar: '*'
|
|
29
|
+
};
|
|
30
|
+
function maskMatch(match, type, options = {}) {
|
|
31
|
+
const { preserveLength = true, maskChar = '*' } = options;
|
|
32
|
+
switch (type) {
|
|
33
|
+
case 'email':
|
|
34
|
+
return (0, email_1.maskEmail)(match);
|
|
35
|
+
case 'phone':
|
|
36
|
+
return (0, phone_1.maskPhone)(match);
|
|
37
|
+
case 'creditCard':
|
|
38
|
+
case 'creditCardFormatted':
|
|
39
|
+
if (match.includes('-') || match.includes(' ')) {
|
|
40
|
+
const cleaned = match.replace(/[-\s]/g, '');
|
|
41
|
+
const masked = (0, creditCard_1.maskCreditCard)(cleaned);
|
|
42
|
+
let result = '';
|
|
43
|
+
let maskIndex = 0;
|
|
44
|
+
for (let i = 0; i < match.length; i++) {
|
|
45
|
+
if (match[i] === '-' || match[i] === ' ') {
|
|
46
|
+
result += match[i];
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
result += masked[maskIndex++];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
return (0, creditCard_1.maskCreditCard)(match);
|
|
55
|
+
case 'ssn':
|
|
56
|
+
const ssnClean = match.replace(/[-\s]/g, '');
|
|
57
|
+
if (match.includes('-')) {
|
|
58
|
+
return `${maskChar.repeat(3)}-${maskChar.repeat(2)}-${ssnClean.slice(-4)}`;
|
|
59
|
+
}
|
|
60
|
+
return maskChar.repeat(5) + ssnClean.slice(-4);
|
|
61
|
+
case 'ipv4':
|
|
62
|
+
const octets = match.split('.');
|
|
63
|
+
return `${octets[0]}.${maskChar.repeat(3)}.${maskChar.repeat(3)}.${octets[3]}`;
|
|
64
|
+
case 'jwt':
|
|
65
|
+
case 'bearerToken':
|
|
66
|
+
case 'awsAccessKey':
|
|
67
|
+
return (0, tokens_1.maskToken)(match);
|
|
68
|
+
case 'privateKey':
|
|
69
|
+
return `-----BEGIN PRIVATE KEY-----\n[REDACTED]\n-----END PRIVATE KEY-----`;
|
|
70
|
+
case 'password':
|
|
71
|
+
const pwdMatch = match.match(/^(password|passwd|pwd|secret|credential)[=:\s]["']?/i);
|
|
72
|
+
if (pwdMatch) {
|
|
73
|
+
const prefix = pwdMatch[0];
|
|
74
|
+
const value = match.slice(prefix.length).replace(/["']$/, '');
|
|
75
|
+
return prefix + maskChar.repeat(value.length);
|
|
76
|
+
}
|
|
77
|
+
return maskChar.repeat(match.length);
|
|
78
|
+
case 'basicAuth':
|
|
79
|
+
return 'Basic [REDACTED]';
|
|
80
|
+
case 'urlWithCredentials':
|
|
81
|
+
return match.replace(/\/\/([^:]+):([^@]+)@/, `//$1:${maskChar.repeat(8)}@`);
|
|
82
|
+
case 'macAddress':
|
|
83
|
+
const macParts = match.split(/[:-]/);
|
|
84
|
+
const separator = match.includes(':') ? ':' : '-';
|
|
85
|
+
return `${macParts[0]}${separator}${maskChar.repeat(2)}${separator}${maskChar.repeat(2)}${separator}${maskChar.repeat(2)}${separator}${maskChar.repeat(2)}${separator}${macParts[5]}`;
|
|
86
|
+
default:
|
|
87
|
+
if (preserveLength) {
|
|
88
|
+
return maskChar.repeat(match.length);
|
|
89
|
+
}
|
|
90
|
+
return '[REDACTED]';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function autoMask(input, options = {}) {
|
|
94
|
+
if (!input || typeof input !== 'string') {
|
|
95
|
+
return input || '';
|
|
96
|
+
}
|
|
97
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
98
|
+
let result = input;
|
|
99
|
+
const patternsToApply = [];
|
|
100
|
+
if (opts.maskEmail)
|
|
101
|
+
patternsToApply.push({ type: 'email', pattern: patterns_1.PATTERNS.EMAIL });
|
|
102
|
+
if (opts.maskPhone)
|
|
103
|
+
patternsToApply.push({ type: 'phone', pattern: patterns_1.PATTERNS.PHONE });
|
|
104
|
+
if (opts.maskCreditCard) {
|
|
105
|
+
patternsToApply.push({ type: 'creditCard', pattern: patterns_1.PATTERNS.CREDIT_CARD });
|
|
106
|
+
patternsToApply.push({ type: 'creditCardFormatted', pattern: patterns_1.PATTERNS.CREDIT_CARD_FORMATTED });
|
|
107
|
+
}
|
|
108
|
+
if (opts.maskSSN)
|
|
109
|
+
patternsToApply.push({ type: 'ssn', pattern: patterns_1.PATTERNS.SSN });
|
|
110
|
+
if (opts.maskIP)
|
|
111
|
+
patternsToApply.push({ type: 'ipv4', pattern: patterns_1.PATTERNS.IPV4 });
|
|
112
|
+
if (opts.maskJWT)
|
|
113
|
+
patternsToApply.push({ type: 'jwt', pattern: patterns_1.PATTERNS.JWT });
|
|
114
|
+
if (opts.maskBearerToken)
|
|
115
|
+
patternsToApply.push({ type: 'bearerToken', pattern: patterns_1.PATTERNS.BEARER_TOKEN });
|
|
116
|
+
if (opts.maskAWSKeys)
|
|
117
|
+
patternsToApply.push({ type: 'awsAccessKey', pattern: patterns_1.PATTERNS.AWS_ACCESS_KEY });
|
|
118
|
+
if (opts.maskPrivateKeys)
|
|
119
|
+
patternsToApply.push({ type: 'privateKey', pattern: patterns_1.PATTERNS.PRIVATE_KEY });
|
|
120
|
+
if (opts.maskPasswords)
|
|
121
|
+
patternsToApply.push({ type: 'password', pattern: patterns_1.PATTERNS.PASSWORD_FIELD });
|
|
122
|
+
if (opts.maskBasicAuth)
|
|
123
|
+
patternsToApply.push({ type: 'basicAuth', pattern: patterns_1.PATTERNS.BASIC_AUTH });
|
|
124
|
+
if (opts.maskURLCredentials)
|
|
125
|
+
patternsToApply.push({ type: 'urlWithCredentials', pattern: patterns_1.PATTERNS.URL_WITH_CREDENTIALS });
|
|
126
|
+
if (opts.maskMAC)
|
|
127
|
+
patternsToApply.push({ type: 'macAddress', pattern: patterns_1.PATTERNS.MAC_ADDRESS });
|
|
128
|
+
if (opts.customPatterns && opts.customPatterns.length > 0) {
|
|
129
|
+
for (const custom of opts.customPatterns) {
|
|
130
|
+
patternsToApply.push({ type: custom.name || 'custom', pattern: custom.pattern });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
for (const { type, pattern } of patternsToApply) {
|
|
134
|
+
const regex = new RegExp(pattern.source, pattern.flags);
|
|
135
|
+
result = result.replace(regex, (match) => maskMatch(match, type, opts));
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
function autoMaskObject(obj, options = {}) {
|
|
140
|
+
if (obj === null || obj === undefined) {
|
|
141
|
+
return obj;
|
|
142
|
+
}
|
|
143
|
+
if (typeof obj === 'string') {
|
|
144
|
+
return autoMask(obj, options);
|
|
145
|
+
}
|
|
146
|
+
if (Array.isArray(obj)) {
|
|
147
|
+
return obj.map(item => autoMaskObject(item, options));
|
|
148
|
+
}
|
|
149
|
+
if (typeof obj === 'object') {
|
|
150
|
+
const result = {};
|
|
151
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
152
|
+
const sensitiveKeys = ['password', 'passwd', 'pwd', 'secret', 'token', 'apikey',
|
|
153
|
+
'api_key', 'apiKey', 'auth', 'authorization', 'credential', 'private',
|
|
154
|
+
'ssn', 'creditcard', 'credit_card', 'creditCard', 'cardNumber', 'card_number',
|
|
155
|
+
'cvv', 'pin', 'accessToken', 'access_token', 'refreshToken', 'refresh_token',
|
|
156
|
+
'bearer', 'jwt', 'sessionId', 'session_id'];
|
|
157
|
+
const lowerKey = key.toLowerCase();
|
|
158
|
+
const isSensitiveKey = sensitiveKeys.some(sk => lowerKey.includes(sk.toLowerCase()));
|
|
159
|
+
if (isSensitiveKey && typeof value === 'string') {
|
|
160
|
+
result[key] = (0, tokens_1.maskToken)(value);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
result[key] = autoMaskObject(value, options);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
return obj;
|
|
169
|
+
}
|
|
170
|
+
function createSafeLogger(logger = console, options = {}) {
|
|
171
|
+
const processArgs = (args) => {
|
|
172
|
+
return args.map(arg => {
|
|
173
|
+
if (typeof arg === 'string') {
|
|
174
|
+
return autoMask(arg, options);
|
|
175
|
+
}
|
|
176
|
+
if (typeof arg === 'object' && arg !== null) {
|
|
177
|
+
return autoMaskObject(arg, options);
|
|
178
|
+
}
|
|
179
|
+
return arg;
|
|
180
|
+
});
|
|
181
|
+
};
|
|
182
|
+
return {
|
|
183
|
+
log: (...args) => logger.log(...processArgs(args)),
|
|
184
|
+
info: (...args) => logger.info(...processArgs(args)),
|
|
185
|
+
warn: (...args) => logger.warn(...processArgs(args)),
|
|
186
|
+
error: (...args) => logger.error(...processArgs(args)),
|
|
187
|
+
debug: (...args) => logger.debug ? logger.debug(...processArgs(args)) : logger.log(...processArgs(args)),
|
|
188
|
+
trace: (...args) => logger.trace ? logger.trace(...processArgs(args)) : logger.log(...processArgs(args)),
|
|
189
|
+
_original: logger,
|
|
190
|
+
setOptions: (newOptions) => {
|
|
191
|
+
Object.assign(options, newOptions);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AutoMaskOptions } from "./autoMask";
|
|
2
|
+
/**
|
|
3
|
+
* Enable global console masking - all console.log, console.info, etc. will auto-mask sensitive data
|
|
4
|
+
* @param options - Masking options (same as autoMask options)
|
|
5
|
+
* @example
|
|
6
|
+
* require('sachii-safe-logger').enableGlobalMasking();
|
|
7
|
+
*
|
|
8
|
+
* // Now all console.log calls will auto-mask!
|
|
9
|
+
* console.log("Email: john@example.com"); // Output: "Email: j***@example.com"
|
|
10
|
+
* console.log("Card: 4111111111111111"); // Output: "Card: ************1111"
|
|
11
|
+
*/
|
|
12
|
+
export declare function enableGlobalMasking(options?: AutoMaskOptions): void;
|
|
13
|
+
/**
|
|
14
|
+
* Disable global console masking and restore original console methods
|
|
15
|
+
*/
|
|
16
|
+
export declare function disableGlobalMasking(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Check if global masking is currently enabled
|
|
19
|
+
*/
|
|
20
|
+
export declare function isGlobalMaskingEnabled(): boolean;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.enableGlobalMasking = enableGlobalMasking;
|
|
4
|
+
exports.disableGlobalMasking = disableGlobalMasking;
|
|
5
|
+
exports.isGlobalMaskingEnabled = isGlobalMaskingEnabled;
|
|
6
|
+
const autoMask_1 = require("./autoMask");
|
|
7
|
+
const originalConsole = {
|
|
8
|
+
log: console.log.bind(console),
|
|
9
|
+
info: console.info.bind(console),
|
|
10
|
+
warn: console.warn.bind(console),
|
|
11
|
+
error: console.error.bind(console),
|
|
12
|
+
debug: console.debug.bind(console),
|
|
13
|
+
trace: console.trace.bind(console)
|
|
14
|
+
};
|
|
15
|
+
let isEnabled = false;
|
|
16
|
+
let globalOptions = {};
|
|
17
|
+
function processArgs(args) {
|
|
18
|
+
return args.map(arg => {
|
|
19
|
+
if (typeof arg === 'string') {
|
|
20
|
+
return (0, autoMask_1.autoMask)(arg, globalOptions);
|
|
21
|
+
}
|
|
22
|
+
if (typeof arg === 'object' && arg !== null) {
|
|
23
|
+
try {
|
|
24
|
+
return (0, autoMask_1.autoMaskObject)(JSON.parse(JSON.stringify(arg)), globalOptions);
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
return arg;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return arg;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Enable global console masking - all console.log, console.info, etc. will auto-mask sensitive data
|
|
35
|
+
* @param options - Masking options (same as autoMask options)
|
|
36
|
+
* @example
|
|
37
|
+
* require('sachii-safe-logger').enableGlobalMasking();
|
|
38
|
+
*
|
|
39
|
+
* // Now all console.log calls will auto-mask!
|
|
40
|
+
* console.log("Email: john@example.com"); // Output: "Email: j***@example.com"
|
|
41
|
+
* console.log("Card: 4111111111111111"); // Output: "Card: ************1111"
|
|
42
|
+
*/
|
|
43
|
+
function enableGlobalMasking(options = {}) {
|
|
44
|
+
if (isEnabled) {
|
|
45
|
+
globalOptions = { ...globalOptions, ...options };
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
globalOptions = options;
|
|
49
|
+
isEnabled = true;
|
|
50
|
+
console.log = function (...args) {
|
|
51
|
+
originalConsole.log(...processArgs(args));
|
|
52
|
+
};
|
|
53
|
+
console.info = function (...args) {
|
|
54
|
+
originalConsole.info(...processArgs(args));
|
|
55
|
+
};
|
|
56
|
+
console.warn = function (...args) {
|
|
57
|
+
originalConsole.warn(...processArgs(args));
|
|
58
|
+
};
|
|
59
|
+
console.error = function (...args) {
|
|
60
|
+
originalConsole.error(...processArgs(args));
|
|
61
|
+
};
|
|
62
|
+
console.debug = function (...args) {
|
|
63
|
+
originalConsole.debug(...processArgs(args));
|
|
64
|
+
};
|
|
65
|
+
console.trace = function (...args) {
|
|
66
|
+
originalConsole.trace(...processArgs(args));
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Disable global console masking and restore original console methods
|
|
71
|
+
*/
|
|
72
|
+
function disableGlobalMasking() {
|
|
73
|
+
if (!isEnabled)
|
|
74
|
+
return;
|
|
75
|
+
isEnabled = false;
|
|
76
|
+
console.log = originalConsole.log;
|
|
77
|
+
console.info = originalConsole.info;
|
|
78
|
+
console.warn = originalConsole.warn;
|
|
79
|
+
console.error = originalConsole.error;
|
|
80
|
+
console.debug = originalConsole.debug;
|
|
81
|
+
console.trace = originalConsole.trace;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check if global masking is currently enabled
|
|
85
|
+
*/
|
|
86
|
+
function isGlobalMaskingEnabled() {
|
|
87
|
+
return isEnabled;
|
|
88
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,3 +2,6 @@ export { maskEmail } from "./maskers/email";
|
|
|
2
2
|
export { maskPhone } from "./maskers/phone";
|
|
3
3
|
export { maskCreditCard } from "./maskers/creditCard";
|
|
4
4
|
export { maskToken } from "./maskers/tokens";
|
|
5
|
+
export { autoMask, autoMaskObject, createSafeLogger, maskMatch, AutoMaskOptions, CustomPattern, SafeLogger } from "./autoMask";
|
|
6
|
+
export { PATTERNS, SENSITIVE_PATTERNS, SensitivePattern } from "./patterns";
|
|
7
|
+
export { enableGlobalMasking, disableGlobalMasking, isGlobalMaskingEnabled } from "./globalMask";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.maskToken = exports.maskCreditCard = exports.maskPhone = exports.maskEmail = void 0;
|
|
3
|
+
exports.isGlobalMaskingEnabled = exports.disableGlobalMasking = exports.enableGlobalMasking = exports.SENSITIVE_PATTERNS = exports.PATTERNS = exports.maskMatch = exports.createSafeLogger = exports.autoMaskObject = exports.autoMask = exports.maskToken = exports.maskCreditCard = exports.maskPhone = exports.maskEmail = void 0;
|
|
4
|
+
// Individual maskers
|
|
4
5
|
var email_1 = require("./maskers/email");
|
|
5
6
|
Object.defineProperty(exports, "maskEmail", { enumerable: true, get: function () { return email_1.maskEmail; } });
|
|
6
7
|
var phone_1 = require("./maskers/phone");
|
|
@@ -9,3 +10,18 @@ var creditCard_1 = require("./maskers/creditCard");
|
|
|
9
10
|
Object.defineProperty(exports, "maskCreditCard", { enumerable: true, get: function () { return creditCard_1.maskCreditCard; } });
|
|
10
11
|
var tokens_1 = require("./maskers/tokens");
|
|
11
12
|
Object.defineProperty(exports, "maskToken", { enumerable: true, get: function () { return tokens_1.maskToken; } });
|
|
13
|
+
// Auto-detection and masking
|
|
14
|
+
var autoMask_1 = require("./autoMask");
|
|
15
|
+
Object.defineProperty(exports, "autoMask", { enumerable: true, get: function () { return autoMask_1.autoMask; } });
|
|
16
|
+
Object.defineProperty(exports, "autoMaskObject", { enumerable: true, get: function () { return autoMask_1.autoMaskObject; } });
|
|
17
|
+
Object.defineProperty(exports, "createSafeLogger", { enumerable: true, get: function () { return autoMask_1.createSafeLogger; } });
|
|
18
|
+
Object.defineProperty(exports, "maskMatch", { enumerable: true, get: function () { return autoMask_1.maskMatch; } });
|
|
19
|
+
// Patterns for custom usage
|
|
20
|
+
var patterns_1 = require("./patterns");
|
|
21
|
+
Object.defineProperty(exports, "PATTERNS", { enumerable: true, get: function () { return patterns_1.PATTERNS; } });
|
|
22
|
+
Object.defineProperty(exports, "SENSITIVE_PATTERNS", { enumerable: true, get: function () { return patterns_1.SENSITIVE_PATTERNS; } });
|
|
23
|
+
// Global console masking
|
|
24
|
+
var globalMask_1 = require("./globalMask");
|
|
25
|
+
Object.defineProperty(exports, "enableGlobalMasking", { enumerable: true, get: function () { return globalMask_1.enableGlobalMasking; } });
|
|
26
|
+
Object.defineProperty(exports, "disableGlobalMasking", { enumerable: true, get: function () { return globalMask_1.disableGlobalMasking; } });
|
|
27
|
+
Object.defineProperty(exports, "isGlobalMaskingEnabled", { enumerable: true, get: function () { return globalMask_1.isGlobalMaskingEnabled; } });
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comprehensive regex patterns for detecting sensitive data
|
|
3
|
+
*/
|
|
4
|
+
export declare const PATTERNS: {
|
|
5
|
+
EMAIL: RegExp;
|
|
6
|
+
PHONE: RegExp;
|
|
7
|
+
PHONE_INTERNATIONAL: RegExp;
|
|
8
|
+
CREDIT_CARD: RegExp;
|
|
9
|
+
CREDIT_CARD_FORMATTED: RegExp;
|
|
10
|
+
SSN: RegExp;
|
|
11
|
+
IPV4: RegExp;
|
|
12
|
+
IPV6: RegExp;
|
|
13
|
+
API_KEY: RegExp;
|
|
14
|
+
BEARER_TOKEN: RegExp;
|
|
15
|
+
JWT: RegExp;
|
|
16
|
+
GENERIC_TOKEN: RegExp;
|
|
17
|
+
HEX_TOKEN: RegExp;
|
|
18
|
+
AWS_ACCESS_KEY: RegExp;
|
|
19
|
+
AWS_SECRET_KEY: RegExp;
|
|
20
|
+
PRIVATE_KEY: RegExp;
|
|
21
|
+
PASSWORD_FIELD: RegExp;
|
|
22
|
+
BANK_ACCOUNT: RegExp;
|
|
23
|
+
PASSPORT: RegExp;
|
|
24
|
+
DOB: RegExp;
|
|
25
|
+
MAC_ADDRESS: RegExp;
|
|
26
|
+
URL_WITH_CREDENTIALS: RegExp;
|
|
27
|
+
BASIC_AUTH: RegExp;
|
|
28
|
+
DRIVERS_LICENSE: RegExp;
|
|
29
|
+
};
|
|
30
|
+
export interface SensitivePattern {
|
|
31
|
+
pattern: RegExp;
|
|
32
|
+
priority: number;
|
|
33
|
+
description: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Sensitive data types with their patterns and masking strategies
|
|
37
|
+
*/
|
|
38
|
+
export declare const SENSITIVE_PATTERNS: Record<string, SensitivePattern>;
|
package/dist/patterns.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SENSITIVE_PATTERNS = exports.PATTERNS = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Comprehensive regex patterns for detecting sensitive data
|
|
6
|
+
*/
|
|
7
|
+
exports.PATTERNS = {
|
|
8
|
+
// Email addresses
|
|
9
|
+
EMAIL: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
|
|
10
|
+
// Phone numbers (various formats)
|
|
11
|
+
PHONE: /\b(?:\+?1[-.\s]?)?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}\b/g,
|
|
12
|
+
PHONE_INTERNATIONAL: /\b\+?[1-9]\d{1,14}\b/g,
|
|
13
|
+
// Credit card numbers (Visa, MasterCard, Amex, Discover, etc.)
|
|
14
|
+
CREDIT_CARD: /\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|6(?:011|5[0-9]{2})[0-9]{12}|3(?:0[0-5]|[68][0-9])[0-9]{11})\b/g,
|
|
15
|
+
CREDIT_CARD_FORMATTED: /\b(?:\d{4}[-\s]?){3}\d{4}\b/g,
|
|
16
|
+
// Social Security Numbers (US)
|
|
17
|
+
SSN: /\b(?!000|666|9\d{2})\d{3}[-\s]?(?!00)\d{2}[-\s]?(?!0000)\d{4}\b/g,
|
|
18
|
+
// IP Addresses
|
|
19
|
+
IPV4: /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/g,
|
|
20
|
+
IPV6: /\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b/g,
|
|
21
|
+
// API Keys and Tokens (common patterns)
|
|
22
|
+
API_KEY: /\b(?:api[_-]?key|apikey|api[_-]?token)[=:\s]["']?([a-zA-Z0-9_-]{20,})/gi,
|
|
23
|
+
BEARER_TOKEN: /\bBearer\s+[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+/gi,
|
|
24
|
+
JWT: /\beyJ[A-Za-z0-9_-]*\.eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*/g,
|
|
25
|
+
// Generic long tokens/secrets (base64, hex)
|
|
26
|
+
GENERIC_TOKEN: /\b[A-Za-z0-9+/]{40,}={0,2}\b/g,
|
|
27
|
+
HEX_TOKEN: /\b[a-fA-F0-9]{32,}\b/g,
|
|
28
|
+
// AWS Keys
|
|
29
|
+
AWS_ACCESS_KEY: /\b(?:AKIA|ABIA|ACCA|ASIA)[0-9A-Z]{16}\b/g,
|
|
30
|
+
AWS_SECRET_KEY: /\b[A-Za-z0-9/+=]{40}\b/g,
|
|
31
|
+
// Private Keys
|
|
32
|
+
PRIVATE_KEY: /-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----[\s\S]*?-----END\s+(?:RSA\s+)?PRIVATE\s+KEY-----/g,
|
|
33
|
+
// Passwords in common log formats
|
|
34
|
+
PASSWORD_FIELD: /(?:password|passwd|pwd|secret|credential)[=:\s]["']?([^\s"'&]+)/gi,
|
|
35
|
+
// Bank Account Numbers (basic pattern)
|
|
36
|
+
BANK_ACCOUNT: /\b\d{9,18}\b/g,
|
|
37
|
+
// Passport Numbers (various countries - basic)
|
|
38
|
+
PASSPORT: /\b[A-Z]{1,2}[0-9]{6,9}\b/g,
|
|
39
|
+
// Date of Birth patterns
|
|
40
|
+
DOB: /\b(?:0?[1-9]|1[0-2])[-/](?:0?[1-9]|[12]\d|3[01])[-/](?:19|20)\d{2}\b/g,
|
|
41
|
+
// MAC Addresses
|
|
42
|
+
MAC_ADDRESS: /\b(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\b/g,
|
|
43
|
+
// URLs with credentials
|
|
44
|
+
URL_WITH_CREDENTIALS: /\b(?:https?|ftp):\/\/[^:@\s]+:[^:@\s]+@[^\s]+/g,
|
|
45
|
+
// Basic Auth headers
|
|
46
|
+
BASIC_AUTH: /\bBasic\s+[A-Za-z0-9+/]+=*\b/gi,
|
|
47
|
+
// Driver's License (US - varies by state, basic pattern)
|
|
48
|
+
DRIVERS_LICENSE: /\b[A-Z]{1,2}[0-9]{5,8}\b/g,
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Sensitive data types with their patterns and masking strategies
|
|
52
|
+
*/
|
|
53
|
+
exports.SENSITIVE_PATTERNS = {
|
|
54
|
+
email: {
|
|
55
|
+
pattern: exports.PATTERNS.EMAIL,
|
|
56
|
+
priority: 1,
|
|
57
|
+
description: "Email addresses"
|
|
58
|
+
},
|
|
59
|
+
phone: {
|
|
60
|
+
pattern: exports.PATTERNS.PHONE,
|
|
61
|
+
priority: 2,
|
|
62
|
+
description: "Phone numbers"
|
|
63
|
+
},
|
|
64
|
+
creditCard: {
|
|
65
|
+
pattern: exports.PATTERNS.CREDIT_CARD,
|
|
66
|
+
priority: 1,
|
|
67
|
+
description: "Credit card numbers"
|
|
68
|
+
},
|
|
69
|
+
creditCardFormatted: {
|
|
70
|
+
pattern: exports.PATTERNS.CREDIT_CARD_FORMATTED,
|
|
71
|
+
priority: 1,
|
|
72
|
+
description: "Formatted credit card numbers"
|
|
73
|
+
},
|
|
74
|
+
ssn: {
|
|
75
|
+
pattern: exports.PATTERNS.SSN,
|
|
76
|
+
priority: 1,
|
|
77
|
+
description: "Social Security Numbers"
|
|
78
|
+
},
|
|
79
|
+
ipv4: {
|
|
80
|
+
pattern: exports.PATTERNS.IPV4,
|
|
81
|
+
priority: 3,
|
|
82
|
+
description: "IPv4 addresses"
|
|
83
|
+
},
|
|
84
|
+
jwt: {
|
|
85
|
+
pattern: exports.PATTERNS.JWT,
|
|
86
|
+
priority: 1,
|
|
87
|
+
description: "JWT tokens"
|
|
88
|
+
},
|
|
89
|
+
bearerToken: {
|
|
90
|
+
pattern: exports.PATTERNS.BEARER_TOKEN,
|
|
91
|
+
priority: 1,
|
|
92
|
+
description: "Bearer tokens"
|
|
93
|
+
},
|
|
94
|
+
awsAccessKey: {
|
|
95
|
+
pattern: exports.PATTERNS.AWS_ACCESS_KEY,
|
|
96
|
+
priority: 1,
|
|
97
|
+
description: "AWS Access Keys"
|
|
98
|
+
},
|
|
99
|
+
privateKey: {
|
|
100
|
+
pattern: exports.PATTERNS.PRIVATE_KEY,
|
|
101
|
+
priority: 1,
|
|
102
|
+
description: "Private keys"
|
|
103
|
+
},
|
|
104
|
+
password: {
|
|
105
|
+
pattern: exports.PATTERNS.PASSWORD_FIELD,
|
|
106
|
+
priority: 1,
|
|
107
|
+
description: "Passwords in log strings"
|
|
108
|
+
},
|
|
109
|
+
basicAuth: {
|
|
110
|
+
pattern: exports.PATTERNS.BASIC_AUTH,
|
|
111
|
+
priority: 1,
|
|
112
|
+
description: "Basic auth headers"
|
|
113
|
+
},
|
|
114
|
+
urlWithCredentials: {
|
|
115
|
+
pattern: exports.PATTERNS.URL_WITH_CREDENTIALS,
|
|
116
|
+
priority: 1,
|
|
117
|
+
description: "URLs containing credentials"
|
|
118
|
+
},
|
|
119
|
+
macAddress: {
|
|
120
|
+
pattern: exports.PATTERNS.MAC_ADDRESS,
|
|
121
|
+
priority: 3,
|
|
122
|
+
description: "MAC addresses"
|
|
123
|
+
}
|
|
124
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sachii-safe-logger",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A lightweight TypeScript library to mask sensitive data (emails, credit cards, phone numbers, API tokens) in logs for security and compliance.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|