app-tracker 3.0.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/app-tracker.service.d.ts +7 -5
- package/app-tracker.service.js +93 -54
- package/log-privacy.d.ts +2 -0
- package/log-privacy.js +63 -0
- package/log.d.ts +3 -7
- package/log.js +1 -1
- package/package.json +1 -1
- package/version.js +1 -1
package/README.md
CHANGED
|
@@ -56,6 +56,7 @@ tracker.error("An error occurred", errorObj);
|
|
|
56
56
|
- **Batching:** Logs are collected and sent after `maxLogsCount` or immediately for critical errors
|
|
57
57
|
- **Explicit flush:** Call and await `tracker.flush()` before a controlled Node.js shutdown
|
|
58
58
|
- **Environment Awareness:** Automatically adapts for browser/Node.js
|
|
59
|
+
- **Browser correlation:** Generates one in-memory correlation ID per page lifetime and includes it in every browser log batch. Node.js payloads do not include it. Use `tracker.getCorrelationId()` to display the current ID when needed.
|
|
59
60
|
- **Secure Sending:** API key required, retry mechanism on errors
|
|
60
61
|
- **External Dependency:** Uses `cross-fetch` for HTTP requests
|
|
61
62
|
|
package/app-tracker.service.d.ts
CHANGED
|
@@ -11,14 +11,13 @@ export declare class AppTrackerService {
|
|
|
11
11
|
private isSending;
|
|
12
12
|
private activeSend?;
|
|
13
13
|
private maxLogsCount;
|
|
14
|
-
private
|
|
14
|
+
private clientInfo;
|
|
15
|
+
private correlationId?;
|
|
15
16
|
private logLevel;
|
|
16
17
|
private sendLogsByTypesImmediately;
|
|
17
18
|
private isNode;
|
|
18
19
|
private nodeProcess;
|
|
19
|
-
private os;
|
|
20
20
|
private isRunningLocal;
|
|
21
|
-
private ident;
|
|
22
21
|
private eventListenerAdded;
|
|
23
22
|
private _boundBeforeUnloadHandler?;
|
|
24
23
|
init(apiKey: string, config?: AppTrackerConfig): void;
|
|
@@ -27,6 +26,7 @@ export declare class AppTrackerService {
|
|
|
27
26
|
private beforeunloadHandler;
|
|
28
27
|
private setRunningSystem;
|
|
29
28
|
getIdent(): string;
|
|
29
|
+
getCorrelationId(): string;
|
|
30
30
|
debug(message?: string, ...optionalParams: any[]): void;
|
|
31
31
|
info(message?: string, ...optionalParams: any[]): void;
|
|
32
32
|
log(message?: string, ...optionalParams: any[]): void;
|
|
@@ -43,6 +43,8 @@ export declare class AppTrackerService {
|
|
|
43
43
|
private sendLogsToServerCore;
|
|
44
44
|
private getLogsEndpoint;
|
|
45
45
|
private serializePayload;
|
|
46
|
-
private
|
|
47
|
-
private
|
|
46
|
+
private getBrowserClientInfo;
|
|
47
|
+
private getNodeClientInfo;
|
|
48
|
+
private majorVersion;
|
|
49
|
+
private createId;
|
|
48
50
|
}
|
package/app-tracker.service.js
CHANGED
|
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
const log_1 = require("./log");
|
|
13
13
|
const cross_fetch_1 = require("cross-fetch");
|
|
14
14
|
const version_1 = require("./version");
|
|
15
|
+
const log_privacy_1 = require("./log-privacy");
|
|
15
16
|
const safeFetch = typeof window !== 'undefined' ? cross_fetch_1.default.bind(window) : cross_fetch_1.default;
|
|
16
17
|
class AppTrackerService {
|
|
17
18
|
constructor() {
|
|
@@ -25,12 +26,11 @@ class AppTrackerService {
|
|
|
25
26
|
this.requestTimeoutMs = 10000;
|
|
26
27
|
this.isSending = false;
|
|
27
28
|
this.maxLogsCount = 10;
|
|
28
|
-
this.
|
|
29
|
+
this.clientInfo = null;
|
|
29
30
|
this.logLevel = [log_1.LogType.error];
|
|
30
31
|
this.sendLogsByTypesImmediately = [log_1.LogType.error, log_1.LogType.critical];
|
|
31
32
|
this.isNode = false;
|
|
32
33
|
this.isRunningLocal = true;
|
|
33
|
-
this.ident = '';
|
|
34
34
|
this.eventListenerAdded = false;
|
|
35
35
|
}
|
|
36
36
|
init(apiKey, config) {
|
|
@@ -56,6 +56,9 @@ class AppTrackerService {
|
|
|
56
56
|
this.sendLogsByTypesImmediately = config.sendLogsByTypesImmediately;
|
|
57
57
|
}
|
|
58
58
|
this.setRunningSystem(config);
|
|
59
|
+
if (!this.isNode && !this.correlationId) {
|
|
60
|
+
this.correlationId = this.createId();
|
|
61
|
+
}
|
|
59
62
|
}
|
|
60
63
|
addEventListener(apiKey) {
|
|
61
64
|
if (apiKey != '' && !this.isNode && !this.isRunningLocal && !this.eventListenerAdded) {
|
|
@@ -76,7 +79,7 @@ class AppTrackerService {
|
|
|
76
79
|
if (this.logs.length === 0)
|
|
77
80
|
return;
|
|
78
81
|
const logsToSend = this.logs.splice(0);
|
|
79
|
-
const body = this.serializePayload(logsToSend, true);
|
|
82
|
+
const body = this.serializePayload(logsToSend, true, this.createId());
|
|
80
83
|
const url = this.getLogsEndpoint();
|
|
81
84
|
// sendBeacon is specifically designed to survive page termination. The API
|
|
82
85
|
// key is also accepted in the request body by the server's ApiKeyGuard.
|
|
@@ -92,35 +95,24 @@ class AppTrackerService {
|
|
|
92
95
|
this.logs.unshift(...logsToSend);
|
|
93
96
|
void this.flush();
|
|
94
97
|
}
|
|
95
|
-
setRunningSystem(
|
|
98
|
+
setRunningSystem(_config) {
|
|
96
99
|
var _a, _b, _c, _d, _e;
|
|
97
100
|
this.nodeProcess = typeof globalThis !== 'undefined' ? globalThis.process : undefined;
|
|
98
101
|
this.isNode = Object.prototype.toString.call(this.nodeProcess || 0) === '[object process]';
|
|
99
|
-
|
|
100
|
-
this.
|
|
101
|
-
this.
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
this.os = (_b = config) === null || _b === void 0 ? void 0 : _b.userAgentOrOs;
|
|
105
|
-
this.userAgent = this.setUserAgentFromOs();
|
|
106
|
-
}
|
|
102
|
+
this.clientInfo = this.isNode
|
|
103
|
+
? this.getNodeClientInfo((_a = _config) === null || _a === void 0 ? void 0 : _a.userAgentOrOs)
|
|
104
|
+
: this.getBrowserClientInfo((_b = _config) === null || _b === void 0 ? void 0 : _b.userAgentOrOs);
|
|
107
105
|
this.isRunningLocal = this.isNode
|
|
108
106
|
? (_e = (_d = (_c = this.nodeProcess) === null || _c === void 0 ? void 0 : _c.env) === null || _d === void 0 ? void 0 : _d.NODE_ENV, (_e !== null && _e !== void 0 ? _e : '')).indexOf("development") > -1
|
|
109
107
|
: window.location.href.indexOf('localhost') > -1;
|
|
110
108
|
}
|
|
111
109
|
getIdent() {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return ident;
|
|
119
|
-
}
|
|
120
|
-
catch (_) {
|
|
121
|
-
// Storage can be unavailable in sandboxed iframes or privacy modes.
|
|
122
|
-
return this.createUUID();
|
|
123
|
-
}
|
|
110
|
+
// Kept for API compatibility. Stable device identifiers are deliberately
|
|
111
|
+
// no longer created or stored because they allow cross-session tracking.
|
|
112
|
+
return '';
|
|
113
|
+
}
|
|
114
|
+
getCorrelationId() {
|
|
115
|
+
return this.isNode ? '' : this.correlationId || '';
|
|
124
116
|
}
|
|
125
117
|
debug(message, ...optionalParams) {
|
|
126
118
|
this.addLog(log_1.LogType.debug, message, ...optionalParams);
|
|
@@ -155,22 +147,24 @@ class AppTrackerService {
|
|
|
155
147
|
}
|
|
156
148
|
logToConsole(type, message, ...optionalParams) {
|
|
157
149
|
if (this.logInConsole) {
|
|
150
|
+
const safeMessage = typeof message === 'string' ? log_privacy_1.sanitizeLogText(message) : message;
|
|
151
|
+
const safeParams = optionalParams.map(param => log_privacy_1.sanitizeLogValue(param));
|
|
158
152
|
switch (type) {
|
|
159
153
|
case log_1.LogType.debug:
|
|
160
|
-
console.debug(
|
|
154
|
+
console.debug(safeMessage, ...safeParams);
|
|
161
155
|
break;
|
|
162
156
|
case log_1.LogType.critical:
|
|
163
157
|
case log_1.LogType.error:
|
|
164
|
-
console.error(
|
|
158
|
+
console.error(safeMessage, ...safeParams);
|
|
165
159
|
break;
|
|
166
160
|
case log_1.LogType.info:
|
|
167
|
-
console.info(
|
|
161
|
+
console.info(safeMessage, ...safeParams);
|
|
168
162
|
break;
|
|
169
163
|
case log_1.LogType.log:
|
|
170
|
-
console.log(
|
|
164
|
+
console.log(safeMessage, ...safeParams);
|
|
171
165
|
break;
|
|
172
166
|
case log_1.LogType.warn:
|
|
173
|
-
console.warn(
|
|
167
|
+
console.warn(safeMessage, ...safeParams);
|
|
174
168
|
break;
|
|
175
169
|
default:
|
|
176
170
|
console.warn("Unkown LogType: ", type);
|
|
@@ -180,12 +174,18 @@ class AppTrackerService {
|
|
|
180
174
|
}
|
|
181
175
|
sendLogsToServer(type, message, ...optionalParams) {
|
|
182
176
|
var _a, _b;
|
|
183
|
-
const log = {
|
|
177
|
+
const log = {
|
|
178
|
+
eventId: this.createId(),
|
|
179
|
+
logType: type,
|
|
180
|
+
message: typeof message === 'string' ? log_privacy_1.sanitizeLogText(message) : message,
|
|
181
|
+
optionalParams: [],
|
|
182
|
+
createdAt: new Date()
|
|
183
|
+
};
|
|
184
184
|
optionalParams.forEach((op) => {
|
|
185
185
|
if (Array.isArray(op))
|
|
186
|
-
op.forEach(o => log.optionalParams.push(o));
|
|
186
|
+
op.forEach(o => log.optionalParams.push(log_privacy_1.sanitizeLogValue(o)));
|
|
187
187
|
else
|
|
188
|
-
log.optionalParams.push(op);
|
|
188
|
+
log.optionalParams.push(log_privacy_1.sanitizeLogValue(op));
|
|
189
189
|
});
|
|
190
190
|
this.logs.push(log);
|
|
191
191
|
const sendImmediately = type === log_1.LogType.critical || ((_a = this.sendLogsByTypesImmediately) === null || _a === void 0 ? void 0 : _a.includes(type)) === true;
|
|
@@ -238,11 +238,12 @@ class AppTrackerService {
|
|
|
238
238
|
sendLogsToServerCore(logsToSend) {
|
|
239
239
|
var _a;
|
|
240
240
|
return __awaiter(this, void 0, void 0, function* () {
|
|
241
|
+
const batchId = this.createId();
|
|
241
242
|
for (let sendTry = 1; sendTry <= this.maxSendTries; sendTry++) {
|
|
242
243
|
const abortController = typeof AbortController !== 'undefined' ? new AbortController() : undefined;
|
|
243
244
|
const timeout = abortController ? setTimeout(() => abortController.abort(), this.requestTimeoutMs) : undefined;
|
|
244
245
|
try {
|
|
245
|
-
const body = this.serializePayload(logsToSend);
|
|
246
|
+
const body = this.serializePayload(logsToSend, false, batchId);
|
|
246
247
|
const response = yield safeFetch(this.getLogsEndpoint(), {
|
|
247
248
|
method: 'POST',
|
|
248
249
|
headers: {
|
|
@@ -260,7 +261,7 @@ class AppTrackerService {
|
|
|
260
261
|
return true;
|
|
261
262
|
}
|
|
262
263
|
catch (error) {
|
|
263
|
-
console.error(`AppLogger: Could not send logs to server (attempt ${sendTry}/${this.maxSendTries})
|
|
264
|
+
console.error(`AppLogger: Could not send logs to server (attempt ${sendTry}/${this.maxSendTries})`);
|
|
264
265
|
if (sendTry < this.maxSendTries)
|
|
265
266
|
yield new Promise(resolve => setTimeout(resolve, this.retryDelayMs));
|
|
266
267
|
}
|
|
@@ -277,15 +278,17 @@ class AppTrackerService {
|
|
|
277
278
|
const last = this.endpointUrl.charAt(this.endpointUrl.length - 1);
|
|
278
279
|
return `${this.endpointUrl}${last === '/' ? 'logs/createLog' : '/logs/createLog'}`;
|
|
279
280
|
}
|
|
280
|
-
serializePayload(logsToSend, includeApiKey = false) {
|
|
281
|
+
serializePayload(logsToSend, includeApiKey = false, batchId = this.createId()) {
|
|
281
282
|
const seen = new WeakSet();
|
|
282
283
|
const payload = {
|
|
283
|
-
ident: this.ident,
|
|
284
284
|
logs: logsToSend,
|
|
285
|
+
batchId: batchId,
|
|
285
286
|
osType: this.isNode ? 'node' : 'web',
|
|
286
287
|
packageVersion: version_1.APP_TRACKER_VERSION,
|
|
287
|
-
|
|
288
|
+
clientInfo: this.clientInfo
|
|
288
289
|
};
|
|
290
|
+
if (!this.isNode && this.correlationId)
|
|
291
|
+
payload.correlationId = this.correlationId;
|
|
289
292
|
if (includeApiKey)
|
|
290
293
|
payload.apiKey = this.apiKey;
|
|
291
294
|
return JSON.stringify(payload, (_key, value) => {
|
|
@@ -307,26 +310,62 @@ class AppTrackerService {
|
|
|
307
310
|
return value;
|
|
308
311
|
});
|
|
309
312
|
}
|
|
310
|
-
|
|
313
|
+
getBrowserClientInfo(userAgentOrOs) {
|
|
314
|
+
const userAgent = typeof userAgentOrOs === 'string' ? userAgentOrOs : '';
|
|
315
|
+
const browserPatterns = [
|
|
316
|
+
{ name: 'Edge', expression: /Edg\/([0-9]+)/ },
|
|
317
|
+
{ name: 'Firefox', expression: /Firefox\/([0-9]+)/ },
|
|
318
|
+
{ name: 'Chrome', expression: /(?:Chrome|CriOS)\/([0-9]+)/ },
|
|
319
|
+
{ name: 'Safari', expression: /Version\/([0-9]+).*Safari/ },
|
|
320
|
+
];
|
|
321
|
+
const browser = browserPatterns
|
|
322
|
+
.map(item => ({ item, match: userAgent.match(item.expression) }))
|
|
323
|
+
.find(item => item.match !== null);
|
|
324
|
+
const android = userAgent.match(/Android\s+([0-9]+)/i);
|
|
325
|
+
const ios = userAgent.match(/(?:iPhone|iPad).*OS\s+([0-9]+)/i);
|
|
326
|
+
const windows = userAgent.match(/Windows NT\s+([0-9]+)/i);
|
|
327
|
+
const macOs = userAgent.match(/Mac OS X\s+([0-9]+)/i);
|
|
328
|
+
const os = android ? { name: 'Android', version: android[1], platform: '' }
|
|
329
|
+
: ios ? { name: 'iOS', version: ios[1], platform: '' }
|
|
330
|
+
: windows ? { name: 'Windows', version: windows[1], platform: '' }
|
|
331
|
+
: macOs ? { name: 'macOS', version: macOs[1], platform: '' }
|
|
332
|
+
: /Linux/i.test(userAgent) ? { name: 'Linux', version: '', platform: '' } : null;
|
|
333
|
+
return {
|
|
334
|
+
client: browser ? { type: 'browser', name: browser.item.name, version: browser.match[1] } : null,
|
|
335
|
+
os,
|
|
336
|
+
device: { type: /iPad|Tablet/i.test(userAgent) ? 'tablet' : /Mobile|Android|iPhone/i.test(userAgent) ? 'smartphone' : 'desktop' },
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
getNodeClientInfo(os) {
|
|
311
340
|
var _a, _b;
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
platform: this.os.platform(),
|
|
318
|
-
release: this.os.release(),
|
|
319
|
-
type: this.os.type(),
|
|
320
|
-
version: this.os.version(),
|
|
321
|
-
hostname: this.os.hostname()
|
|
341
|
+
const call = (name) => os && typeof os[name] === 'function' ? String(os[name]()) : '';
|
|
342
|
+
return {
|
|
343
|
+
client: { type: 'library', name: 'Node.js', version: this.majorVersion((_a = this.nodeProcess) === null || _a === void 0 ? void 0 : _a.version) },
|
|
344
|
+
os: { name: call('platform') || ((_b = this.nodeProcess) === null || _b === void 0 ? void 0 : _b.platform) || '', version: this.majorVersion(call('release')), platform: call('arch') },
|
|
345
|
+
device: null,
|
|
322
346
|
};
|
|
323
|
-
return JSON.stringify(osInfo);
|
|
324
347
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
348
|
+
majorVersion(value) {
|
|
349
|
+
const match = typeof value === 'string' ? value.match(/\d+/) : null;
|
|
350
|
+
return match ? match[0] : '';
|
|
351
|
+
}
|
|
352
|
+
createId() {
|
|
353
|
+
var _a, _b;
|
|
354
|
+
const browserCrypto = typeof globalThis !== 'undefined' ? globalThis.crypto : undefined;
|
|
355
|
+
if (typeof ((_a = browserCrypto) === null || _a === void 0 ? void 0 : _a.randomUUID) === 'function')
|
|
356
|
+
return browserCrypto.randomUUID();
|
|
357
|
+
const bytes = new Uint8Array(16);
|
|
358
|
+
if (typeof ((_b = browserCrypto) === null || _b === void 0 ? void 0 : _b.getRandomValues) === 'function') {
|
|
359
|
+
browserCrypto.getRandomValues(bytes);
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
for (let index = 0; index < bytes.length; index++)
|
|
363
|
+
bytes[index] = Math.floor(Math.random() * 256);
|
|
364
|
+
}
|
|
365
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
366
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
367
|
+
const hex = Array.from(bytes).map(value => (`0${value.toString(16)}`).slice(-2)).join('');
|
|
368
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
330
369
|
}
|
|
331
370
|
}
|
|
332
371
|
exports.AppTrackerService = AppTrackerService;
|
package/log-privacy.d.ts
ADDED
package/log-privacy.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const REDACTED = '[REDACTED]';
|
|
4
|
+
const SENSITIVE_KEYS = new Set(['authorization', 'cookie', 'password', 'passwd', 'secret', 'token', 'apikey', 'email', 'emailaddress', 'phone', 'mobile', 'firstname', 'lastname', 'fullname', 'address', 'street', 'postcode', 'postalcode', 'ip', 'ipaddress', 'hostname', 'ident', 'userid', 'customerid', 'paymentid', 'sessionid', 'refreshtoken', 'accesstoken', 'recipient', 'recipients', 'username', 'displayname', 'birthdate', 'dateofbirth', 'dob', 'iban', 'bic', 'accountnumber', 'creditcard', 'cardnumber', 'coordinates', 'latitude', 'longitude']);
|
|
5
|
+
const SECRET_KEY_PARTS = ['authorization', 'cookie', 'password', 'passwd', 'secret', 'token', 'apikey', 'credential', 'privatekey'];
|
|
6
|
+
function isSensitiveKey(key) {
|
|
7
|
+
const normalizedKey = key.replace(/[^a-z0-9]/gi, '').toLowerCase();
|
|
8
|
+
return SENSITIVE_KEYS.has(normalizedKey) || SECRET_KEY_PARTS.some(part => normalizedKey.indexOf(part) >= 0);
|
|
9
|
+
}
|
|
10
|
+
function sanitizeLogUrl(value) {
|
|
11
|
+
let sanitizedUrl = '[REDACTED URL]';
|
|
12
|
+
try {
|
|
13
|
+
const url = new URL(value);
|
|
14
|
+
const identityRoutes = new Set(['users', 'customers', 'accounts', 'sessions', 'payments']);
|
|
15
|
+
const segments = url.pathname.split('/').map((segment, index, allSegments) => {
|
|
16
|
+
const followsIdentityRoute = index > 0 && identityRoutes.has(allSegments[index - 1].toLowerCase());
|
|
17
|
+
const isIdentifier = /^[0-9a-f]{24}$/i.test(segment) || /^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(segment) || /^(?:cus|pi|pm|seti|sub|cs|price|in|ch)_[A-Za-z0-9_]+$/.test(segment) || /^\d{6,}$/.test(segment);
|
|
18
|
+
return followsIdentityRoute || isIdentifier ? ':id' : segment;
|
|
19
|
+
});
|
|
20
|
+
sanitizedUrl = `${url.protocol}//${url.host}${segments.join('/')}`;
|
|
21
|
+
}
|
|
22
|
+
catch (_error) {
|
|
23
|
+
// Keep the privacy-safe fallback.
|
|
24
|
+
}
|
|
25
|
+
return sanitizedUrl;
|
|
26
|
+
}
|
|
27
|
+
function sanitizeLogText(value) {
|
|
28
|
+
return value
|
|
29
|
+
.replace(/https?:\/\/[^\s"'<>]+/gi, (url) => sanitizeLogUrl(url))
|
|
30
|
+
.replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, REDACTED)
|
|
31
|
+
.replace(/\b(?:\d{1,3}\.){3}\d{1,3}\b/g, REDACTED)
|
|
32
|
+
.replace(/\b[A-Z]{2}\d{2}[A-Z0-9]{11,30}\b/g, REDACTED)
|
|
33
|
+
.replace(/\+\d[\d\s().-]{7,}\d/g, REDACTED)
|
|
34
|
+
.replace(/[A-Z]:\\Users\\[^\\\s]+/gi, REDACTED)
|
|
35
|
+
.replace(/\/home\/[^/\s]+/g, REDACTED)
|
|
36
|
+
.replace(/\b(?:Bearer|Basic)\s+[A-Za-z0-9._~+\/-]+=*/gi, REDACTED)
|
|
37
|
+
.replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, REDACTED);
|
|
38
|
+
}
|
|
39
|
+
exports.sanitizeLogText = sanitizeLogText;
|
|
40
|
+
function sanitizeLogValue(value, depth = 0, seen = new WeakSet()) {
|
|
41
|
+
if (typeof value === 'string')
|
|
42
|
+
return sanitizeLogText(value);
|
|
43
|
+
if (value === null || typeof value === 'undefined' || typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint')
|
|
44
|
+
return value;
|
|
45
|
+
if (depth >= 6)
|
|
46
|
+
return '[TRUNCATED]';
|
|
47
|
+
if (value instanceof Date)
|
|
48
|
+
return value.toISOString();
|
|
49
|
+
if (value instanceof Error)
|
|
50
|
+
return Object.assign({ name: sanitizeLogText(value.name), message: sanitizeLogText(value.message) }, (typeof value.stack === 'string' ? { stack: sanitizeLogText(value.stack) } : {}));
|
|
51
|
+
if (typeof value === 'object') {
|
|
52
|
+
if (seen.has(value))
|
|
53
|
+
return '[Circular]';
|
|
54
|
+
seen.add(value);
|
|
55
|
+
if (Array.isArray(value))
|
|
56
|
+
return value.map(item => sanitizeLogValue(item, depth + 1, seen));
|
|
57
|
+
const result = {};
|
|
58
|
+
Object.keys(value).forEach(key => result[key] = isSensitiveKey(key) ? REDACTED : sanitizeLogValue(value[key], depth + 1, seen));
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
return `[${typeof value}]`;
|
|
62
|
+
}
|
|
63
|
+
exports.sanitizeLogValue = sanitizeLogValue;
|
package/log.d.ts
CHANGED
|
@@ -12,19 +12,15 @@ export declare class AppTrackerConfig {
|
|
|
12
12
|
/** Defines which log types should be sent to the server */
|
|
13
13
|
logLevel?: LogType[];
|
|
14
14
|
sendLogsByTypesImmediately?: LogType[];
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
* Web -> navigator.userAgent,
|
|
18
|
-
* Node -> os (from require('os'))
|
|
19
|
-
*/
|
|
20
|
-
userAgentOrOs: any;
|
|
15
|
+
/** Used only to derive coarse browser/OS categories; raw values are not transmitted. */
|
|
16
|
+
userAgentOrOs?: any;
|
|
21
17
|
}
|
|
22
18
|
export declare class Log {
|
|
19
|
+
eventId: string;
|
|
23
20
|
logType: LogType;
|
|
24
21
|
message: any;
|
|
25
22
|
optionalParams: any[];
|
|
26
23
|
createdAt: Date;
|
|
27
|
-
ident: string;
|
|
28
24
|
}
|
|
29
25
|
export declare enum LogType {
|
|
30
26
|
debug = 0,
|
package/log.js
CHANGED
|
@@ -13,10 +13,10 @@ class AppTrackerConfig {
|
|
|
13
13
|
exports.AppTrackerConfig = AppTrackerConfig;
|
|
14
14
|
class Log {
|
|
15
15
|
constructor() {
|
|
16
|
+
this.eventId = '';
|
|
16
17
|
this.logType = LogType.log;
|
|
17
18
|
this.optionalParams = [];
|
|
18
19
|
this.createdAt = new Date();
|
|
19
|
-
this.ident = '';
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
exports.Log = Log;
|
package/package.json
CHANGED
package/version.js
CHANGED