app-tracker 3.0.0 → 3.1.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 +1 -0
- package/app-tracker.service.d.ts +7 -5
- package/app-tracker.service.js +82 -51
- package/log-privacy.d.ts +2 -0
- package/log-privacy.js +63 -0
- package/log.d.ts +2 -7
- package/log.js +0 -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 createCorrelationId;
|
|
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.createCorrelationId();
|
|
61
|
+
}
|
|
59
62
|
}
|
|
60
63
|
addEventListener(apiKey) {
|
|
61
64
|
if (apiKey != '' && !this.isNode && !this.isRunningLocal && !this.eventListenerAdded) {
|
|
@@ -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,12 @@ class AppTrackerService {
|
|
|
180
174
|
}
|
|
181
175
|
sendLogsToServer(type, message, ...optionalParams) {
|
|
182
176
|
var _a, _b;
|
|
183
|
-
const log = { logType: type, message: message, optionalParams: [], createdAt: new Date()
|
|
177
|
+
const log = { logType: type, message: typeof message === 'string' ? log_privacy_1.sanitizeLogText(message) : message, optionalParams: [], createdAt: new Date() };
|
|
184
178
|
optionalParams.forEach((op) => {
|
|
185
179
|
if (Array.isArray(op))
|
|
186
|
-
op.forEach(o => log.optionalParams.push(o));
|
|
180
|
+
op.forEach(o => log.optionalParams.push(log_privacy_1.sanitizeLogValue(o)));
|
|
187
181
|
else
|
|
188
|
-
log.optionalParams.push(op);
|
|
182
|
+
log.optionalParams.push(log_privacy_1.sanitizeLogValue(op));
|
|
189
183
|
});
|
|
190
184
|
this.logs.push(log);
|
|
191
185
|
const sendImmediately = type === log_1.LogType.critical || ((_a = this.sendLogsByTypesImmediately) === null || _a === void 0 ? void 0 : _a.includes(type)) === true;
|
|
@@ -260,7 +254,7 @@ class AppTrackerService {
|
|
|
260
254
|
return true;
|
|
261
255
|
}
|
|
262
256
|
catch (error) {
|
|
263
|
-
console.error(`AppLogger: Could not send logs to server (attempt ${sendTry}/${this.maxSendTries})
|
|
257
|
+
console.error(`AppLogger: Could not send logs to server (attempt ${sendTry}/${this.maxSendTries})`);
|
|
264
258
|
if (sendTry < this.maxSendTries)
|
|
265
259
|
yield new Promise(resolve => setTimeout(resolve, this.retryDelayMs));
|
|
266
260
|
}
|
|
@@ -280,12 +274,13 @@ class AppTrackerService {
|
|
|
280
274
|
serializePayload(logsToSend, includeApiKey = false) {
|
|
281
275
|
const seen = new WeakSet();
|
|
282
276
|
const payload = {
|
|
283
|
-
ident: this.ident,
|
|
284
277
|
logs: logsToSend,
|
|
285
278
|
osType: this.isNode ? 'node' : 'web',
|
|
286
279
|
packageVersion: version_1.APP_TRACKER_VERSION,
|
|
287
|
-
|
|
280
|
+
clientInfo: this.clientInfo
|
|
288
281
|
};
|
|
282
|
+
if (!this.isNode && this.correlationId)
|
|
283
|
+
payload.correlationId = this.correlationId;
|
|
289
284
|
if (includeApiKey)
|
|
290
285
|
payload.apiKey = this.apiKey;
|
|
291
286
|
return JSON.stringify(payload, (_key, value) => {
|
|
@@ -307,26 +302,62 @@ class AppTrackerService {
|
|
|
307
302
|
return value;
|
|
308
303
|
});
|
|
309
304
|
}
|
|
310
|
-
|
|
305
|
+
getBrowserClientInfo(userAgentOrOs) {
|
|
306
|
+
const userAgent = typeof userAgentOrOs === 'string' ? userAgentOrOs : '';
|
|
307
|
+
const browserPatterns = [
|
|
308
|
+
{ name: 'Edge', expression: /Edg\/([0-9]+)/ },
|
|
309
|
+
{ name: 'Firefox', expression: /Firefox\/([0-9]+)/ },
|
|
310
|
+
{ name: 'Chrome', expression: /(?:Chrome|CriOS)\/([0-9]+)/ },
|
|
311
|
+
{ name: 'Safari', expression: /Version\/([0-9]+).*Safari/ },
|
|
312
|
+
];
|
|
313
|
+
const browser = browserPatterns
|
|
314
|
+
.map(item => ({ item, match: userAgent.match(item.expression) }))
|
|
315
|
+
.find(item => item.match !== null);
|
|
316
|
+
const android = userAgent.match(/Android\s+([0-9]+)/i);
|
|
317
|
+
const ios = userAgent.match(/(?:iPhone|iPad).*OS\s+([0-9]+)/i);
|
|
318
|
+
const windows = userAgent.match(/Windows NT\s+([0-9]+)/i);
|
|
319
|
+
const macOs = userAgent.match(/Mac OS X\s+([0-9]+)/i);
|
|
320
|
+
const os = android ? { name: 'Android', version: android[1], platform: '' }
|
|
321
|
+
: ios ? { name: 'iOS', version: ios[1], platform: '' }
|
|
322
|
+
: windows ? { name: 'Windows', version: windows[1], platform: '' }
|
|
323
|
+
: macOs ? { name: 'macOS', version: macOs[1], platform: '' }
|
|
324
|
+
: /Linux/i.test(userAgent) ? { name: 'Linux', version: '', platform: '' } : null;
|
|
325
|
+
return {
|
|
326
|
+
client: browser ? { type: 'browser', name: browser.item.name, version: browser.match[1] } : null,
|
|
327
|
+
os,
|
|
328
|
+
device: { type: /iPad|Tablet/i.test(userAgent) ? 'tablet' : /Mobile|Android|iPhone/i.test(userAgent) ? 'smartphone' : 'desktop' },
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
getNodeClientInfo(os) {
|
|
311
332
|
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()
|
|
333
|
+
const call = (name) => os && typeof os[name] === 'function' ? String(os[name]()) : '';
|
|
334
|
+
return {
|
|
335
|
+
client: { type: 'library', name: 'Node.js', version: this.majorVersion((_a = this.nodeProcess) === null || _a === void 0 ? void 0 : _a.version) },
|
|
336
|
+
os: { name: call('platform') || ((_b = this.nodeProcess) === null || _b === void 0 ? void 0 : _b.platform) || '', version: this.majorVersion(call('release')), platform: call('arch') },
|
|
337
|
+
device: null,
|
|
322
338
|
};
|
|
323
|
-
return JSON.stringify(osInfo);
|
|
324
339
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
340
|
+
majorVersion(value) {
|
|
341
|
+
const match = typeof value === 'string' ? value.match(/\d+/) : null;
|
|
342
|
+
return match ? match[0] : '';
|
|
343
|
+
}
|
|
344
|
+
createCorrelationId() {
|
|
345
|
+
var _a, _b;
|
|
346
|
+
const browserCrypto = typeof globalThis !== 'undefined' ? globalThis.crypto : undefined;
|
|
347
|
+
if (typeof ((_a = browserCrypto) === null || _a === void 0 ? void 0 : _a.randomUUID) === 'function')
|
|
348
|
+
return browserCrypto.randomUUID();
|
|
349
|
+
const bytes = new Uint8Array(16);
|
|
350
|
+
if (typeof ((_b = browserCrypto) === null || _b === void 0 ? void 0 : _b.getRandomValues) === 'function') {
|
|
351
|
+
browserCrypto.getRandomValues(bytes);
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
for (let index = 0; index < bytes.length; index++)
|
|
355
|
+
bytes[index] = Math.floor(Math.random() * 256);
|
|
356
|
+
}
|
|
357
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
358
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
359
|
+
const hex = Array.from(bytes).map(value => (`0${value.toString(16)}`).slice(-2)).join('');
|
|
360
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
330
361
|
}
|
|
331
362
|
}
|
|
332
363
|
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,14 @@ 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 {
|
|
23
19
|
logType: LogType;
|
|
24
20
|
message: any;
|
|
25
21
|
optionalParams: any[];
|
|
26
22
|
createdAt: Date;
|
|
27
|
-
ident: string;
|
|
28
23
|
}
|
|
29
24
|
export declare enum LogType {
|
|
30
25
|
debug = 0,
|
package/log.js
CHANGED
package/package.json
CHANGED
package/version.js
CHANGED