@tallyrow/safesignal 1.0.1-rc.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/LICENSE +21 -0
- package/README.md +345 -0
- package/dist/index.cjs +1240 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +167 -0
- package/dist/index.d.ts +167 -0
- package/dist/index.mjs +1232 -0
- package/dist/index.mjs.map +1 -0
- package/dist/testing.cjs +272 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +97 -0
- package/dist/testing.d.ts +97 -0
- package/dist/testing.mjs +268 -0
- package/dist/testing.mjs.map +1 -0
- package/dist/transport-beacon.cjs +452 -0
- package/dist/transport-beacon.cjs.map +1 -0
- package/dist/transport-beacon.d.cts +68 -0
- package/dist/transport-beacon.d.ts +68 -0
- package/dist/transport-beacon.mjs +450 -0
- package/dist/transport-beacon.mjs.map +1 -0
- package/dist/types-D-xVvmvX.d.cts +227 -0
- package/dist/types-D-xVvmvX.d.ts +227 -0
- package/package.json +79 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1232 @@
|
|
|
1
|
+
// src/context/context-merge.ts
|
|
2
|
+
function mergeContexts(...sources) {
|
|
3
|
+
const merged = {};
|
|
4
|
+
for (const src of sources) {
|
|
5
|
+
if (src === void 0) continue;
|
|
6
|
+
if (src.application !== void 0) {
|
|
7
|
+
merged.application = src.application;
|
|
8
|
+
}
|
|
9
|
+
if (src.module !== void 0) {
|
|
10
|
+
merged.module = src.module;
|
|
11
|
+
}
|
|
12
|
+
if (src.environment !== void 0) {
|
|
13
|
+
merged.environment = src.environment;
|
|
14
|
+
}
|
|
15
|
+
if (src.attributes !== void 0) {
|
|
16
|
+
merged.attributes = deepMergeAttributes(
|
|
17
|
+
merged.attributes ?? {},
|
|
18
|
+
src.attributes
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const out = {};
|
|
23
|
+
if (merged.application !== void 0) out.application = merged.application;
|
|
24
|
+
if (merged.module !== void 0) out.module = merged.module;
|
|
25
|
+
if (merged.environment !== void 0) out.environment = merged.environment;
|
|
26
|
+
if (merged.attributes !== void 0) out.attributes = merged.attributes;
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
function deepMergeAttributes(earlier, later) {
|
|
30
|
+
const result = { ...earlier };
|
|
31
|
+
for (const key of Object.keys(later)) {
|
|
32
|
+
const laterValue = later[key];
|
|
33
|
+
if (laterValue === void 0) continue;
|
|
34
|
+
const earlierValue = result[key];
|
|
35
|
+
if (isPlainAttributeObject(earlierValue) && isPlainAttributeObject(laterValue)) {
|
|
36
|
+
result[key] = deepMergeAttributes(earlierValue, laterValue);
|
|
37
|
+
} else {
|
|
38
|
+
result[key] = laterValue;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
function isPlainAttributeObject(value) {
|
|
44
|
+
return value !== null && value !== void 0 && typeof value === "object" && !Array.isArray(value);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/internal/errors/internal-errors.ts
|
|
48
|
+
var PACKAGE_ERROR_MARKER = /* @__PURE__ */ Symbol("frontend-logging-sdk/package-error");
|
|
49
|
+
var PackageError = class extends Error {
|
|
50
|
+
constructor(code, message, options = {}) {
|
|
51
|
+
super(message);
|
|
52
|
+
this.name = "PackageError";
|
|
53
|
+
this.code = code;
|
|
54
|
+
if (options.cause !== void 0) {
|
|
55
|
+
this.cause = options.cause;
|
|
56
|
+
}
|
|
57
|
+
if (options.transportName !== void 0) {
|
|
58
|
+
this.transportName = options.transportName;
|
|
59
|
+
}
|
|
60
|
+
Object.defineProperty(this, PACKAGE_ERROR_MARKER, {
|
|
61
|
+
value: true,
|
|
62
|
+
enumerable: false,
|
|
63
|
+
writable: false,
|
|
64
|
+
configurable: false
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
function isPackageError(value) {
|
|
69
|
+
if (typeof value !== "object" || value === null) return false;
|
|
70
|
+
return value[PACKAGE_ERROR_MARKER] === true;
|
|
71
|
+
}
|
|
72
|
+
function wrapAsPackageError(code, message, cause, transportName) {
|
|
73
|
+
if (isPackageError(cause)) return cause;
|
|
74
|
+
const options = { cause };
|
|
75
|
+
if (transportName !== void 0) {
|
|
76
|
+
options.transportName = transportName;
|
|
77
|
+
}
|
|
78
|
+
return new PackageError(code, message, options);
|
|
79
|
+
}
|
|
80
|
+
function safeNotify(onInternalError, err) {
|
|
81
|
+
try {
|
|
82
|
+
onInternalError(err);
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/pipeline/control-char-guard.ts
|
|
88
|
+
var CONTROL_CHAR_CLASS = "[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u2028\\u2029]";
|
|
89
|
+
var HAS_CONTROL_CHAR = new RegExp(CONTROL_CHAR_CLASS);
|
|
90
|
+
var CONTROL_CHAR_GLOBAL = new RegExp(CONTROL_CHAR_CLASS, "g");
|
|
91
|
+
function escapeControlChars(value) {
|
|
92
|
+
if (!HAS_CONTROL_CHAR.test(value)) return value;
|
|
93
|
+
return value.replace(CONTROL_CHAR_GLOBAL, (ch) => {
|
|
94
|
+
const code = ch.charCodeAt(0);
|
|
95
|
+
return "\\u" + code.toString(16).padStart(4, "0");
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
var controlCharGuard = (event, _config) => {
|
|
99
|
+
const message = escapeControlChars(event.message);
|
|
100
|
+
const attributes = walkAttributes(event.attributes);
|
|
101
|
+
const context = walkContext(event.context);
|
|
102
|
+
let error;
|
|
103
|
+
if (event.error !== void 0) {
|
|
104
|
+
const escName = escapeControlChars(event.error.name);
|
|
105
|
+
const escMessage = escapeControlChars(event.error.message);
|
|
106
|
+
const stack = event.error.stack;
|
|
107
|
+
const escStack = stack === void 0 ? void 0 : escapeControlChars(stack);
|
|
108
|
+
if (escName === event.error.name && escMessage === event.error.message && escStack === stack) {
|
|
109
|
+
error = event.error;
|
|
110
|
+
} else {
|
|
111
|
+
error = { name: escName, message: escMessage };
|
|
112
|
+
if (escStack !== void 0) error.stack = escStack;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const noChange = message === event.message && attributes === event.attributes && context === event.context && error === event.error;
|
|
116
|
+
if (noChange) return event;
|
|
117
|
+
const next = {
|
|
118
|
+
timestamp: event.timestamp,
|
|
119
|
+
level: event.level,
|
|
120
|
+
message,
|
|
121
|
+
attributes,
|
|
122
|
+
context
|
|
123
|
+
};
|
|
124
|
+
if (error !== void 0) next.error = error;
|
|
125
|
+
return next;
|
|
126
|
+
};
|
|
127
|
+
function walkAttributes(attrs) {
|
|
128
|
+
let changed = false;
|
|
129
|
+
let result = null;
|
|
130
|
+
for (const key of Object.keys(attrs)) {
|
|
131
|
+
const value = attrs[key];
|
|
132
|
+
if (value === void 0) continue;
|
|
133
|
+
const escaped = walkValue(value);
|
|
134
|
+
if (escaped !== value) {
|
|
135
|
+
if (result === null) {
|
|
136
|
+
result = {};
|
|
137
|
+
for (const k of Object.keys(attrs)) {
|
|
138
|
+
const existing = attrs[k];
|
|
139
|
+
if (existing !== void 0) result[k] = existing;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
result[key] = escaped;
|
|
143
|
+
changed = true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return changed && result !== null ? result : attrs;
|
|
147
|
+
}
|
|
148
|
+
function walkValue(value) {
|
|
149
|
+
if (typeof value === "string") return escapeControlChars(value);
|
|
150
|
+
if (Array.isArray(value)) return walkArray(value);
|
|
151
|
+
if (value !== null && typeof value === "object") return walkAttributes(value);
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
function walkArray(arr) {
|
|
155
|
+
let changed = false;
|
|
156
|
+
let result = null;
|
|
157
|
+
for (let i = 0; i < arr.length; i++) {
|
|
158
|
+
const item = arr[i];
|
|
159
|
+
if (item === void 0) continue;
|
|
160
|
+
const escaped = walkValue(item);
|
|
161
|
+
if (escaped !== item) {
|
|
162
|
+
if (result === null) result = arr.slice();
|
|
163
|
+
result[i] = escaped;
|
|
164
|
+
changed = true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return changed && result !== null ? result : arr;
|
|
168
|
+
}
|
|
169
|
+
function walkContext(context) {
|
|
170
|
+
if (context.attributes === void 0) return context;
|
|
171
|
+
const escaped = walkAttributes(context.attributes);
|
|
172
|
+
if (escaped === context.attributes) return context;
|
|
173
|
+
return { ...context, attributes: escaped };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/pipeline/freeze.ts
|
|
177
|
+
var freezeInDev = (event, _config) => {
|
|
178
|
+
deepFreeze(event);
|
|
179
|
+
return event;
|
|
180
|
+
};
|
|
181
|
+
function deepFreeze(value) {
|
|
182
|
+
if (Object.isFrozen(value)) return;
|
|
183
|
+
Object.freeze(value);
|
|
184
|
+
for (const key of Object.keys(value)) {
|
|
185
|
+
const child = value[key];
|
|
186
|
+
if (child !== null && typeof child === "object") {
|
|
187
|
+
deepFreeze(child);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// src/pipeline/redactor.ts
|
|
193
|
+
var DEFAULT_REPLACEMENT = "[REDACTED]";
|
|
194
|
+
var DEFAULT_RULES = [
|
|
195
|
+
// Key rules (immediate-name match, case-insensitive).
|
|
196
|
+
{ key: /^password$|^passwd$/i },
|
|
197
|
+
{ key: /^token$|access[_-]?token|refresh[_-]?token|bearer[_-]?token/i },
|
|
198
|
+
{ key: /^authorization$|^auth$/i },
|
|
199
|
+
{ key: /^cookie$|^set-cookie$/i },
|
|
200
|
+
{ key: /^secret$/i },
|
|
201
|
+
{ key: /api[_-]?key/i },
|
|
202
|
+
{ key: /session[_-]?id|^sid$/i },
|
|
203
|
+
{ key: /^ssn$/i },
|
|
204
|
+
{ key: /credit[_-]?card|^cardNumber$|^cvv$/i },
|
|
205
|
+
// Shape rules (leaf-string match).
|
|
206
|
+
{ shape: /^[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}$/ },
|
|
207
|
+
{ shape: /^Bearer\s+[A-Za-z0-9._-]+$/i }
|
|
208
|
+
];
|
|
209
|
+
function compileRules(rules) {
|
|
210
|
+
const keyRules = [];
|
|
211
|
+
const shapeRules = [];
|
|
212
|
+
for (const rule of rules) {
|
|
213
|
+
const replacement = rule.replacement ?? DEFAULT_REPLACEMENT;
|
|
214
|
+
if (rule.key !== void 0) {
|
|
215
|
+
keyRules.push(makeKeyRule(rule.key, replacement));
|
|
216
|
+
}
|
|
217
|
+
if (rule.shape !== void 0) {
|
|
218
|
+
shapeRules.push({ pattern: rule.shape, replacement });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return { keyRules, shapeRules };
|
|
222
|
+
}
|
|
223
|
+
function makeKeyRule(key, replacement) {
|
|
224
|
+
if (typeof key === "string") {
|
|
225
|
+
const expected = key.toLowerCase();
|
|
226
|
+
return {
|
|
227
|
+
match: (candidate) => candidate.toLowerCase() === expected,
|
|
228
|
+
replacement
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
return { match: (candidate) => key.test(candidate), replacement };
|
|
232
|
+
}
|
|
233
|
+
function createRedactor(rules) {
|
|
234
|
+
const active2 = rules ?? DEFAULT_RULES;
|
|
235
|
+
const compiled = compileRules(active2);
|
|
236
|
+
return function defaultStyleRedactor(event) {
|
|
237
|
+
const attributes = walkObject(event.attributes, compiled);
|
|
238
|
+
const context = walkContext2(event.context, compiled);
|
|
239
|
+
const message = applyShapeRules(event.message, compiled.shapeRules);
|
|
240
|
+
let error = event.error;
|
|
241
|
+
if (event.error !== void 0) {
|
|
242
|
+
const escName = applyShapeRules(event.error.name, compiled.shapeRules);
|
|
243
|
+
const escMessage = applyShapeRules(event.error.message, compiled.shapeRules);
|
|
244
|
+
const stack = event.error.stack;
|
|
245
|
+
const escStack = stack === void 0 ? void 0 : applyShapeRules(stack, compiled.shapeRules);
|
|
246
|
+
const errorChanged = escName !== event.error.name || escMessage !== event.error.message || escStack !== stack;
|
|
247
|
+
if (errorChanged) {
|
|
248
|
+
error = { name: escName, message: escMessage };
|
|
249
|
+
if (escStack !== void 0) error.stack = escStack;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const noChange = attributes === event.attributes && context === event.context && message === event.message && error === event.error;
|
|
253
|
+
if (noChange) return event;
|
|
254
|
+
const next = {
|
|
255
|
+
timestamp: event.timestamp,
|
|
256
|
+
level: event.level,
|
|
257
|
+
message,
|
|
258
|
+
attributes,
|
|
259
|
+
context
|
|
260
|
+
};
|
|
261
|
+
if (error !== void 0) next.error = error;
|
|
262
|
+
return next;
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
var cachedDefaultRedactor = null;
|
|
266
|
+
function getDefaultRedactor() {
|
|
267
|
+
if (cachedDefaultRedactor === null) {
|
|
268
|
+
cachedDefaultRedactor = createRedactor();
|
|
269
|
+
}
|
|
270
|
+
return cachedDefaultRedactor;
|
|
271
|
+
}
|
|
272
|
+
var redact = (event, config) => {
|
|
273
|
+
const redactor = config.redactor ?? getDefaultRedactor();
|
|
274
|
+
const result = redactor(event);
|
|
275
|
+
if (result === null) return null;
|
|
276
|
+
if (!isLogEventShape(result)) {
|
|
277
|
+
throw new PackageError(
|
|
278
|
+
"redactor_failed",
|
|
279
|
+
"Redactor returned a value that is neither a LogEvent nor null; the event is dropped (fail-closed)."
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
return result;
|
|
283
|
+
};
|
|
284
|
+
function walkObject(attrs, rules) {
|
|
285
|
+
let changed = false;
|
|
286
|
+
let result = null;
|
|
287
|
+
for (const key of Object.keys(attrs)) {
|
|
288
|
+
const value = attrs[key];
|
|
289
|
+
if (value === void 0) continue;
|
|
290
|
+
const newValue = redactValueAtKey(value, key, rules);
|
|
291
|
+
if (newValue !== value) {
|
|
292
|
+
if (result === null) {
|
|
293
|
+
result = {};
|
|
294
|
+
for (const k of Object.keys(attrs)) {
|
|
295
|
+
const existing = attrs[k];
|
|
296
|
+
if (existing !== void 0) result[k] = existing;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
result[key] = newValue;
|
|
300
|
+
changed = true;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return changed && result !== null ? result : attrs;
|
|
304
|
+
}
|
|
305
|
+
function walkContext2(context, rules) {
|
|
306
|
+
if (context.attributes === void 0) return context;
|
|
307
|
+
const next = walkObject(context.attributes, rules);
|
|
308
|
+
if (next === context.attributes) return context;
|
|
309
|
+
return { ...context, attributes: next };
|
|
310
|
+
}
|
|
311
|
+
function redactValueAtKey(value, key, rules) {
|
|
312
|
+
for (const rule of rules.keyRules) {
|
|
313
|
+
if (rule.match(key)) return rule.replacement;
|
|
314
|
+
}
|
|
315
|
+
if (typeof value === "string") {
|
|
316
|
+
return applyShapeRules(value, rules.shapeRules);
|
|
317
|
+
}
|
|
318
|
+
if (Array.isArray(value)) {
|
|
319
|
+
return walkArray2(value, rules);
|
|
320
|
+
}
|
|
321
|
+
if (value !== null && typeof value === "object") {
|
|
322
|
+
return walkObject(value, rules);
|
|
323
|
+
}
|
|
324
|
+
return value;
|
|
325
|
+
}
|
|
326
|
+
function walkArray2(arr, rules) {
|
|
327
|
+
let changed = false;
|
|
328
|
+
let result = null;
|
|
329
|
+
for (let i = 0; i < arr.length; i++) {
|
|
330
|
+
const item = arr[i];
|
|
331
|
+
if (item === void 0) continue;
|
|
332
|
+
let newItem;
|
|
333
|
+
if (typeof item === "string") {
|
|
334
|
+
newItem = applyShapeRules(item, rules.shapeRules);
|
|
335
|
+
} else if (Array.isArray(item)) {
|
|
336
|
+
newItem = walkArray2(item, rules);
|
|
337
|
+
} else if (item !== null && typeof item === "object") {
|
|
338
|
+
newItem = walkObject(item, rules);
|
|
339
|
+
} else {
|
|
340
|
+
newItem = item;
|
|
341
|
+
}
|
|
342
|
+
if (newItem !== item) {
|
|
343
|
+
if (result === null) result = arr.slice();
|
|
344
|
+
result[i] = newItem;
|
|
345
|
+
changed = true;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return changed && result !== null ? result : arr;
|
|
349
|
+
}
|
|
350
|
+
function applyShapeRules(value, rules) {
|
|
351
|
+
for (const rule of rules) {
|
|
352
|
+
if (rule.pattern.test(value)) return rule.replacement;
|
|
353
|
+
}
|
|
354
|
+
return value;
|
|
355
|
+
}
|
|
356
|
+
var VALID_LEVELS = /* @__PURE__ */ new Set([
|
|
357
|
+
"debug",
|
|
358
|
+
"info",
|
|
359
|
+
"warn",
|
|
360
|
+
"error"
|
|
361
|
+
]);
|
|
362
|
+
function isLogEventShape(value) {
|
|
363
|
+
if (typeof value !== "object" || /* v8 ignore next */
|
|
364
|
+
value === null) {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
const obj = value;
|
|
368
|
+
if (typeof obj["timestamp"] !== "string") return false;
|
|
369
|
+
if (typeof obj["level"] !== "string") return false;
|
|
370
|
+
if (!VALID_LEVELS.has(obj["level"])) return false;
|
|
371
|
+
if (typeof obj["message"] !== "string") return false;
|
|
372
|
+
if (obj["attributes"] === null || typeof obj["attributes"] !== "object") return false;
|
|
373
|
+
if (obj["context"] === null || typeof obj["context"] !== "object") return false;
|
|
374
|
+
return true;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/pipeline/sanitizer.ts
|
|
378
|
+
var TRUNCATION_MARKER_KEY = "__truncated__";
|
|
379
|
+
var STRING_TRUNCATION_SUFFIX = "...[truncated]";
|
|
380
|
+
var UNSERIALIZABLE_MARKER = "[Unserializable]";
|
|
381
|
+
var sanitize = (event, config) => {
|
|
382
|
+
const ctx = newContext(config);
|
|
383
|
+
const sanitizedAttributes = sanitizeRootObject(event.attributes, ctx);
|
|
384
|
+
const sanitizedContext = sanitizeContext(event.context, ctx);
|
|
385
|
+
const next = {
|
|
386
|
+
timestamp: event.timestamp,
|
|
387
|
+
level: event.level,
|
|
388
|
+
message: truncateString(event.message, ctx.maxStringLength),
|
|
389
|
+
attributes: sanitizedAttributes,
|
|
390
|
+
context: sanitizedContext
|
|
391
|
+
};
|
|
392
|
+
if (event.error !== void 0) {
|
|
393
|
+
next.error = sanitizeErrorInfo(event.error, ctx);
|
|
394
|
+
}
|
|
395
|
+
if (ctx.keysOmitted > 0) {
|
|
396
|
+
next.attributes = withTruncationMarker(next.attributes, ctx.keysOmitted);
|
|
397
|
+
}
|
|
398
|
+
return next;
|
|
399
|
+
};
|
|
400
|
+
function newContext(config) {
|
|
401
|
+
const limits = config.sanitizerLimits;
|
|
402
|
+
return {
|
|
403
|
+
maxDepth: limits.maxDepth,
|
|
404
|
+
maxStringLength: limits.maxStringLength,
|
|
405
|
+
maxArrayLength: limits.maxArrayLength,
|
|
406
|
+
maxAttributeCount: limits.maxAttributeCount,
|
|
407
|
+
keysUsed: 0,
|
|
408
|
+
keysOmitted: 0,
|
|
409
|
+
seen: /* @__PURE__ */ new WeakSet()
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
function sanitizeRootObject(source, ctx) {
|
|
413
|
+
if (source === null || typeof source !== "object" || Array.isArray(source)) {
|
|
414
|
+
return {};
|
|
415
|
+
}
|
|
416
|
+
return sanitizeObject(source, 0, ctx);
|
|
417
|
+
}
|
|
418
|
+
function sanitizeContext(source, ctx) {
|
|
419
|
+
if (source.attributes === void 0) return source;
|
|
420
|
+
const sanitizedAttrs = sanitizeRootObject(source.attributes, ctx);
|
|
421
|
+
return { ...source, attributes: sanitizedAttrs };
|
|
422
|
+
}
|
|
423
|
+
function sanitizeErrorInfo(error, ctx) {
|
|
424
|
+
const info = {
|
|
425
|
+
name: truncateString(error.name, ctx.maxStringLength),
|
|
426
|
+
message: truncateString(error.message, ctx.maxStringLength)
|
|
427
|
+
};
|
|
428
|
+
if (error.stack !== void 0) {
|
|
429
|
+
info.stack = truncateString(error.stack, ctx.maxStringLength);
|
|
430
|
+
}
|
|
431
|
+
return info;
|
|
432
|
+
}
|
|
433
|
+
function withTruncationMarker(attrs, omitted) {
|
|
434
|
+
const tagged = { ...attrs };
|
|
435
|
+
tagged[TRUNCATION_MARKER_KEY] = `[Truncated: ${String(omitted)} keys omitted]`;
|
|
436
|
+
return tagged;
|
|
437
|
+
}
|
|
438
|
+
function truncateString(value, maxLength) {
|
|
439
|
+
if (value.length <= maxLength) return value;
|
|
440
|
+
return value.slice(0, maxLength) + STRING_TRUNCATION_SUFFIX;
|
|
441
|
+
}
|
|
442
|
+
function sanitizeValue(value, depth, ctx) {
|
|
443
|
+
try {
|
|
444
|
+
return sanitizeValueImpl(value, depth, ctx);
|
|
445
|
+
} catch {
|
|
446
|
+
return UNSERIALIZABLE_MARKER;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
function sanitizeValueImpl(value, depth, ctx) {
|
|
450
|
+
if (depth > ctx.maxDepth) return "[MaxDepth]";
|
|
451
|
+
if (value === null) return null;
|
|
452
|
+
const t = typeof value;
|
|
453
|
+
if (t === "string") return truncateString(value, ctx.maxStringLength);
|
|
454
|
+
if (t === "number") {
|
|
455
|
+
const n = value;
|
|
456
|
+
return Number.isFinite(n) ? n : null;
|
|
457
|
+
}
|
|
458
|
+
if (t === "boolean") return value;
|
|
459
|
+
if (t === "bigint") return String(value);
|
|
460
|
+
if (t === "function") return "[Function]";
|
|
461
|
+
if (t === "symbol") return "[Symbol]";
|
|
462
|
+
if (t === "undefined") return null;
|
|
463
|
+
const obj = value;
|
|
464
|
+
if (ctx.seen.has(obj)) return "[Circular]";
|
|
465
|
+
if (Array.isArray(value)) {
|
|
466
|
+
return sanitizeArray(value, depth, ctx);
|
|
467
|
+
}
|
|
468
|
+
if (value instanceof Date) {
|
|
469
|
+
return dateToIso(value);
|
|
470
|
+
}
|
|
471
|
+
if (value instanceof Error) {
|
|
472
|
+
return sanitizeErrorAsAttribute(value, depth, ctx);
|
|
473
|
+
}
|
|
474
|
+
if (typeof Element !== "undefined" && value instanceof Element) {
|
|
475
|
+
return `[Element:${tagNameOf(value)}]`;
|
|
476
|
+
}
|
|
477
|
+
if (typeof Document !== "undefined" && value instanceof Document) {
|
|
478
|
+
return "[Document]";
|
|
479
|
+
}
|
|
480
|
+
if (typeof Window !== "undefined" && value instanceof Window) {
|
|
481
|
+
return "[Window]";
|
|
482
|
+
}
|
|
483
|
+
if (typeof Node !== "undefined" && value instanceof Node) {
|
|
484
|
+
return "[Node]";
|
|
485
|
+
}
|
|
486
|
+
if (typeof Event !== "undefined" && value instanceof Event) {
|
|
487
|
+
return `[Event:${eventTypeOf(value)}]`;
|
|
488
|
+
}
|
|
489
|
+
if (typeof Promise !== "undefined" && value instanceof Promise) {
|
|
490
|
+
return "[Promise]";
|
|
491
|
+
}
|
|
492
|
+
if (typeof Map !== "undefined" && value instanceof Map) {
|
|
493
|
+
return "[Map]";
|
|
494
|
+
}
|
|
495
|
+
if (typeof Set !== "undefined" && value instanceof Set) {
|
|
496
|
+
return "[Set]";
|
|
497
|
+
}
|
|
498
|
+
if (typeof WeakMap !== "undefined" && value instanceof WeakMap) {
|
|
499
|
+
return "[WeakMap]";
|
|
500
|
+
}
|
|
501
|
+
if (typeof WeakSet !== "undefined" && value instanceof WeakSet) {
|
|
502
|
+
return "[WeakSet]";
|
|
503
|
+
}
|
|
504
|
+
if (typeof Request !== "undefined" && value instanceof Request) {
|
|
505
|
+
return "[Request]";
|
|
506
|
+
}
|
|
507
|
+
if (typeof Response !== "undefined" && value instanceof Response) {
|
|
508
|
+
return "[Response]";
|
|
509
|
+
}
|
|
510
|
+
if (typeof Blob !== "undefined" && value instanceof Blob) {
|
|
511
|
+
return "[Blob]";
|
|
512
|
+
}
|
|
513
|
+
if (typeof FormData !== "undefined" && value instanceof FormData) {
|
|
514
|
+
return "[FormData]";
|
|
515
|
+
}
|
|
516
|
+
if (typeof URL !== "undefined" && value instanceof URL) {
|
|
517
|
+
return "[URL]";
|
|
518
|
+
}
|
|
519
|
+
if (isPlainObject(obj)) {
|
|
520
|
+
return sanitizeObject(obj, depth, ctx);
|
|
521
|
+
}
|
|
522
|
+
return `[${getConstructorName(obj)}]`;
|
|
523
|
+
}
|
|
524
|
+
function sanitizeArray(arr, depth, ctx) {
|
|
525
|
+
ctx.seen.add(arr);
|
|
526
|
+
const out = [];
|
|
527
|
+
const len = arr.length;
|
|
528
|
+
const limit = len > ctx.maxArrayLength ? ctx.maxArrayLength : len;
|
|
529
|
+
for (let i = 0; i < limit; i++) {
|
|
530
|
+
out.push(sanitizeValue(arr[i], depth + 1, ctx));
|
|
531
|
+
}
|
|
532
|
+
if (len > ctx.maxArrayLength) {
|
|
533
|
+
const omitted = len - ctx.maxArrayLength;
|
|
534
|
+
out.push(`[Truncated: ${String(omitted)} elements omitted]`);
|
|
535
|
+
}
|
|
536
|
+
ctx.seen.delete(arr);
|
|
537
|
+
return out;
|
|
538
|
+
}
|
|
539
|
+
function sanitizeObject(obj, depth, ctx) {
|
|
540
|
+
ctx.seen.add(obj);
|
|
541
|
+
const result = {};
|
|
542
|
+
const keys = ownEnumerableKeys(obj);
|
|
543
|
+
for (const key of keys) {
|
|
544
|
+
const raw = readProperty(obj, key);
|
|
545
|
+
if (raw === void 0) continue;
|
|
546
|
+
if (ctx.keysUsed >= ctx.maxAttributeCount) {
|
|
547
|
+
ctx.keysOmitted++;
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
ctx.keysUsed++;
|
|
551
|
+
result[key] = sanitizeValue(raw, depth + 1, ctx);
|
|
552
|
+
}
|
|
553
|
+
ctx.seen.delete(obj);
|
|
554
|
+
return result;
|
|
555
|
+
}
|
|
556
|
+
function sanitizeErrorAsAttribute(err, depth, ctx) {
|
|
557
|
+
const reduced = {
|
|
558
|
+
name: safeString(() => err.name, "Error"),
|
|
559
|
+
message: safeString(() => err.message, "")
|
|
560
|
+
};
|
|
561
|
+
const stack = safeOptional(() => err.stack);
|
|
562
|
+
if (stack !== void 0) {
|
|
563
|
+
reduced["stack"] = stack;
|
|
564
|
+
}
|
|
565
|
+
return sanitizeObject(reduced, depth, ctx);
|
|
566
|
+
}
|
|
567
|
+
function ownEnumerableKeys(obj) {
|
|
568
|
+
try {
|
|
569
|
+
return Object.keys(obj);
|
|
570
|
+
} catch {
|
|
571
|
+
return [];
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
function readProperty(obj, key) {
|
|
575
|
+
try {
|
|
576
|
+
return obj[key];
|
|
577
|
+
} catch {
|
|
578
|
+
return UNSERIALIZABLE_MARKER;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
function isPlainObject(obj) {
|
|
582
|
+
const proto = Object.getPrototypeOf(obj);
|
|
583
|
+
return proto === null || proto === Object.prototype;
|
|
584
|
+
}
|
|
585
|
+
function getConstructorName(obj) {
|
|
586
|
+
try {
|
|
587
|
+
const proto = Object.getPrototypeOf(obj);
|
|
588
|
+
const ctor = proto?.constructor;
|
|
589
|
+
const name = ctor?.name;
|
|
590
|
+
if (typeof name === "string" && name.length > 0) return name;
|
|
591
|
+
} catch {
|
|
592
|
+
}
|
|
593
|
+
return "Object";
|
|
594
|
+
}
|
|
595
|
+
function tagNameOf(el) {
|
|
596
|
+
try {
|
|
597
|
+
const t = el.tagName;
|
|
598
|
+
return typeof t === "string" && t.length > 0 ? t.toLowerCase() : "element";
|
|
599
|
+
} catch {
|
|
600
|
+
return "element";
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
function eventTypeOf(ev) {
|
|
604
|
+
try {
|
|
605
|
+
const t = ev.type;
|
|
606
|
+
return typeof t === "string" && t.length > 0 ? t : "event";
|
|
607
|
+
} catch {
|
|
608
|
+
return "event";
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
function dateToIso(d) {
|
|
612
|
+
try {
|
|
613
|
+
return d.toISOString();
|
|
614
|
+
} catch {
|
|
615
|
+
return null;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
function safeString(read, fallback) {
|
|
619
|
+
try {
|
|
620
|
+
const v = read();
|
|
621
|
+
return typeof v === "string" ? v : fallback;
|
|
622
|
+
} catch {
|
|
623
|
+
return fallback;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
function safeOptional(read) {
|
|
627
|
+
try {
|
|
628
|
+
const v = read();
|
|
629
|
+
return typeof v === "string" ? v : void 0;
|
|
630
|
+
} catch {
|
|
631
|
+
return void 0;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// src/pipeline/url-scrubber.ts
|
|
636
|
+
var REDACTED = "[REDACTED]";
|
|
637
|
+
var DEFAULT_PARAM_DENYLIST = [
|
|
638
|
+
/^password$/i,
|
|
639
|
+
/^passwd$/i,
|
|
640
|
+
/^token$/i,
|
|
641
|
+
/access[_-]?token/i,
|
|
642
|
+
/refresh[_-]?token/i,
|
|
643
|
+
/bearer[_-]?token/i,
|
|
644
|
+
/id[_-]?token/i,
|
|
645
|
+
/^authorization$/i,
|
|
646
|
+
/^auth$/i,
|
|
647
|
+
/^cookie$/i,
|
|
648
|
+
/^set-cookie$/i,
|
|
649
|
+
/^secret$/i,
|
|
650
|
+
/client[_-]?secret/i,
|
|
651
|
+
/api[_-]?key/i,
|
|
652
|
+
/session[_-]?id/i,
|
|
653
|
+
/^sid$/i,
|
|
654
|
+
/^ssn$/i,
|
|
655
|
+
/credit[_-]?card/i,
|
|
656
|
+
/^cardnumber$/i,
|
|
657
|
+
/^cvv$/i
|
|
658
|
+
];
|
|
659
|
+
function scrubUrl(url, options) {
|
|
660
|
+
if (typeof url !== "string" || url.length === 0) return url;
|
|
661
|
+
let parsed;
|
|
662
|
+
try {
|
|
663
|
+
parsed = new URL(url);
|
|
664
|
+
} catch {
|
|
665
|
+
return url;
|
|
666
|
+
}
|
|
667
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
668
|
+
return url;
|
|
669
|
+
}
|
|
670
|
+
const extras = options?.extraParams ?? [];
|
|
671
|
+
const scrubFragment = options?.fragment !== false;
|
|
672
|
+
let changed = false;
|
|
673
|
+
changed = scrubSearchParams(parsed, extras) || changed;
|
|
674
|
+
if (scrubFragment) {
|
|
675
|
+
changed = scrubHashFragment(parsed, extras) || changed;
|
|
676
|
+
}
|
|
677
|
+
if (!changed) return url;
|
|
678
|
+
return parsed.toString();
|
|
679
|
+
}
|
|
680
|
+
var urlScrub = (event, _config) => {
|
|
681
|
+
const message = maybeScrubString(event.message);
|
|
682
|
+
const attributes = walkAttributes2(event.attributes);
|
|
683
|
+
const context = walkContext3(event.context);
|
|
684
|
+
let error = void 0;
|
|
685
|
+
if (event.error !== void 0) {
|
|
686
|
+
const scrubbedMessage = maybeScrubString(event.error.message);
|
|
687
|
+
const stack = event.error.stack;
|
|
688
|
+
const scrubbedStack = stack === void 0 ? void 0 : maybeScrubString(stack);
|
|
689
|
+
error = { name: event.error.name, message: scrubbedMessage };
|
|
690
|
+
if (scrubbedStack !== void 0) error.stack = scrubbedStack;
|
|
691
|
+
}
|
|
692
|
+
const noChange = message === event.message && attributes === event.attributes && context === event.context && error === event.error;
|
|
693
|
+
if (noChange) return event;
|
|
694
|
+
const next = {
|
|
695
|
+
timestamp: event.timestamp,
|
|
696
|
+
level: event.level,
|
|
697
|
+
message,
|
|
698
|
+
attributes,
|
|
699
|
+
context
|
|
700
|
+
};
|
|
701
|
+
if (error !== void 0) next.error = error;
|
|
702
|
+
return next;
|
|
703
|
+
};
|
|
704
|
+
function scrubSearchParams(parsed, extras) {
|
|
705
|
+
const entries = [];
|
|
706
|
+
for (const [name, value] of parsed.searchParams.entries()) {
|
|
707
|
+
entries.push([name, value]);
|
|
708
|
+
}
|
|
709
|
+
let changed = false;
|
|
710
|
+
for (let i = 0; i < entries.length; i++) {
|
|
711
|
+
const entry = entries[i];
|
|
712
|
+
if (isDenied(entry[0], extras)) {
|
|
713
|
+
entries[i] = [entry[0], REDACTED];
|
|
714
|
+
changed = true;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
if (!changed) return false;
|
|
718
|
+
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
719
|
+
for (const entry of entries) uniqueKeys.add(entry[0]);
|
|
720
|
+
for (const key of uniqueKeys) parsed.searchParams.delete(key);
|
|
721
|
+
for (const [name, value] of entries) parsed.searchParams.append(name, value);
|
|
722
|
+
return true;
|
|
723
|
+
}
|
|
724
|
+
function scrubHashFragment(parsed, extras) {
|
|
725
|
+
const hash = parsed.hash;
|
|
726
|
+
if (hash.length < 2 || !hash.startsWith("#")) return false;
|
|
727
|
+
const body = hash.slice(1);
|
|
728
|
+
if (!body.includes("=")) return false;
|
|
729
|
+
const parts = body.split("&");
|
|
730
|
+
let changed = false;
|
|
731
|
+
const out = [];
|
|
732
|
+
for (const part of parts) {
|
|
733
|
+
const eq = part.indexOf("=");
|
|
734
|
+
if (eq < 0) {
|
|
735
|
+
out.push(part);
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
const rawKey = part.slice(0, eq);
|
|
739
|
+
const decodedKey = tryDecode(rawKey);
|
|
740
|
+
if (isDenied(decodedKey, extras)) {
|
|
741
|
+
out.push(`${rawKey}=${encodeURIComponent(REDACTED)}`);
|
|
742
|
+
changed = true;
|
|
743
|
+
} else {
|
|
744
|
+
out.push(part);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
if (!changed) return false;
|
|
748
|
+
parsed.hash = "#" + out.join("&");
|
|
749
|
+
return true;
|
|
750
|
+
}
|
|
751
|
+
function isDenied(name, extras) {
|
|
752
|
+
for (const pattern of DEFAULT_PARAM_DENYLIST) {
|
|
753
|
+
if (pattern.test(name)) return true;
|
|
754
|
+
}
|
|
755
|
+
for (const pattern of extras) {
|
|
756
|
+
if (typeof pattern === "string") {
|
|
757
|
+
if (pattern.toLowerCase() === name.toLowerCase()) return true;
|
|
758
|
+
} else if (pattern.test(name)) {
|
|
759
|
+
return true;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
return false;
|
|
763
|
+
}
|
|
764
|
+
function tryDecode(value) {
|
|
765
|
+
try {
|
|
766
|
+
return decodeURIComponent(value);
|
|
767
|
+
} catch {
|
|
768
|
+
return value;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
function maybeScrubString(value) {
|
|
772
|
+
if (value.length < 8) return value;
|
|
773
|
+
if (value.startsWith("http://") || value.startsWith("https://")) {
|
|
774
|
+
return scrubUrl(value);
|
|
775
|
+
}
|
|
776
|
+
return value;
|
|
777
|
+
}
|
|
778
|
+
function walkAttributes2(attrs) {
|
|
779
|
+
let changed = false;
|
|
780
|
+
let result = null;
|
|
781
|
+
for (const key of Object.keys(attrs)) {
|
|
782
|
+
const value = attrs[key];
|
|
783
|
+
if (value === void 0) continue;
|
|
784
|
+
const scrubbed = walkValue2(value);
|
|
785
|
+
if (scrubbed !== value) {
|
|
786
|
+
if (result === null) {
|
|
787
|
+
result = {};
|
|
788
|
+
for (const k of Object.keys(attrs)) {
|
|
789
|
+
const existing = attrs[k];
|
|
790
|
+
if (existing !== void 0) result[k] = existing;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
result[key] = scrubbed;
|
|
794
|
+
changed = true;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return changed && result !== null ? result : attrs;
|
|
798
|
+
}
|
|
799
|
+
function walkValue2(value) {
|
|
800
|
+
if (typeof value === "string") return maybeScrubString(value);
|
|
801
|
+
if (Array.isArray(value)) return walkArray3(value);
|
|
802
|
+
if (value !== null && typeof value === "object") return walkAttributes2(value);
|
|
803
|
+
return value;
|
|
804
|
+
}
|
|
805
|
+
function walkArray3(arr) {
|
|
806
|
+
let changed = false;
|
|
807
|
+
let result = null;
|
|
808
|
+
for (let i = 0; i < arr.length; i++) {
|
|
809
|
+
const item = arr[i];
|
|
810
|
+
if (item === void 0) continue;
|
|
811
|
+
const scrubbed = walkValue2(item);
|
|
812
|
+
if (scrubbed !== item) {
|
|
813
|
+
if (result === null) result = arr.slice();
|
|
814
|
+
result[i] = scrubbed;
|
|
815
|
+
changed = true;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
return changed && result !== null ? result : arr;
|
|
819
|
+
}
|
|
820
|
+
function walkContext3(context) {
|
|
821
|
+
if (context.attributes === void 0) return context;
|
|
822
|
+
const scrubbed = walkAttributes2(context.attributes);
|
|
823
|
+
if (scrubbed === context.attributes) return context;
|
|
824
|
+
return { ...context, attributes: scrubbed };
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// src/pipeline/dispatcher.ts
|
|
828
|
+
function dispatch(event, config) {
|
|
829
|
+
let current;
|
|
830
|
+
try {
|
|
831
|
+
current = sanitize(event, config);
|
|
832
|
+
if (current === null) return;
|
|
833
|
+
current = urlScrub(current, config);
|
|
834
|
+
if (current === null) return;
|
|
835
|
+
current = redact(current, config);
|
|
836
|
+
if (current === null) return;
|
|
837
|
+
current = controlCharGuard(current, config);
|
|
838
|
+
if (current === null) return;
|
|
839
|
+
current = freezeInDev(current, config);
|
|
840
|
+
if (current === null) return;
|
|
841
|
+
} catch (err) {
|
|
842
|
+
safeNotify(
|
|
843
|
+
config.onInternalError,
|
|
844
|
+
wrapAsPackageError(
|
|
845
|
+
"redactor_failed",
|
|
846
|
+
"A pipeline stage threw; the event was dropped (fail-closed).",
|
|
847
|
+
err
|
|
848
|
+
)
|
|
849
|
+
);
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
for (const transport of config.transports) {
|
|
853
|
+
try {
|
|
854
|
+
const result = transport.send(current);
|
|
855
|
+
if (result instanceof Promise) {
|
|
856
|
+
result.then(void 0, () => void 0);
|
|
857
|
+
}
|
|
858
|
+
} catch {
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// src/pipeline/event-builder.ts
|
|
864
|
+
function buildLogEvent(input) {
|
|
865
|
+
const event = {
|
|
866
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
867
|
+
level: input.level,
|
|
868
|
+
message: input.message,
|
|
869
|
+
attributes: input.attributes ?? {},
|
|
870
|
+
context: input.context
|
|
871
|
+
};
|
|
872
|
+
if (input.errorValue !== void 0) {
|
|
873
|
+
event.error = reduceError(input.errorValue);
|
|
874
|
+
}
|
|
875
|
+
return event;
|
|
876
|
+
}
|
|
877
|
+
function reduceError(value) {
|
|
878
|
+
if (value instanceof Error) {
|
|
879
|
+
const info = { name: value.name, message: value.message };
|
|
880
|
+
if (value.stack !== void 0) info.stack = value.stack;
|
|
881
|
+
return info;
|
|
882
|
+
}
|
|
883
|
+
return { name: "NonError", message: String(value) };
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// src/pipeline/level-filter.ts
|
|
887
|
+
var LEVEL_NUMBER = {
|
|
888
|
+
debug: 10,
|
|
889
|
+
info: 20,
|
|
890
|
+
warn: 30,
|
|
891
|
+
error: 40
|
|
892
|
+
};
|
|
893
|
+
function resolveEffectiveLevel(perLoggerLevel, configLevel) {
|
|
894
|
+
return perLoggerLevel ?? configLevel;
|
|
895
|
+
}
|
|
896
|
+
function passesLevelFilter(eventLevel, perLoggerLevel, configLevel) {
|
|
897
|
+
const effective = resolveEffectiveLevel(perLoggerLevel, configLevel);
|
|
898
|
+
return LEVEL_NUMBER[eventLevel] >= LEVEL_NUMBER[effective];
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// src/config/env-defaults.ts
|
|
902
|
+
var DEFAULT_LEVEL_BY_ENVIRONMENT = {
|
|
903
|
+
production: "warn",
|
|
904
|
+
development: "debug",
|
|
905
|
+
test: "warn"
|
|
906
|
+
};
|
|
907
|
+
var FALLBACK_LEVEL = "warn";
|
|
908
|
+
var DEFAULT_SANITIZER_LIMITS = {
|
|
909
|
+
maxDepth: 8,
|
|
910
|
+
maxStringLength: 8192,
|
|
911
|
+
maxArrayLength: 1e3,
|
|
912
|
+
maxAttributeCount: 256
|
|
913
|
+
};
|
|
914
|
+
var SANITIZER_LIMIT_BOUNDS = {
|
|
915
|
+
maxDepth: { min: 1, max: 16 },
|
|
916
|
+
maxStringLength: { min: 64, max: 65536 },
|
|
917
|
+
maxArrayLength: { min: 1, max: 1e4 },
|
|
918
|
+
maxAttributeCount: { min: 1, max: 4096 }
|
|
919
|
+
};
|
|
920
|
+
function defaultLevelForEnvironment(environment) {
|
|
921
|
+
if (environment === void 0) return FALLBACK_LEVEL;
|
|
922
|
+
return DEFAULT_LEVEL_BY_ENVIRONMENT[environment] ?? FALLBACK_LEVEL;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// src/config/config.ts
|
|
926
|
+
var NOOP_ON_INTERNAL_ERROR = () => void 0;
|
|
927
|
+
function normalizeConfig(config) {
|
|
928
|
+
const environment = config.environment;
|
|
929
|
+
const onInternalError = config.onInternalError ?? NOOP_ON_INTERNAL_ERROR;
|
|
930
|
+
const sanitizerLimits = resolveSanitizerLimits(
|
|
931
|
+
config.sanitizerLimits,
|
|
932
|
+
onInternalError
|
|
933
|
+
);
|
|
934
|
+
const level = resolveConfigLevel(config.level, environment);
|
|
935
|
+
const transports = (config.transports ?? []).map(
|
|
936
|
+
(entry) => typeof entry === "function" ? entry() : entry
|
|
937
|
+
);
|
|
938
|
+
return {
|
|
939
|
+
application: config.application,
|
|
940
|
+
module: config.module,
|
|
941
|
+
environment,
|
|
942
|
+
level,
|
|
943
|
+
context: config.context ?? {},
|
|
944
|
+
correlation: config.correlation,
|
|
945
|
+
transports,
|
|
946
|
+
redactor: config.redactor,
|
|
947
|
+
sanitizerLimits,
|
|
948
|
+
onInternalError
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
function resolveConfigLevel(level, environment) {
|
|
952
|
+
if (level === void 0) {
|
|
953
|
+
return defaultLevelForEnvironment(environment);
|
|
954
|
+
}
|
|
955
|
+
if (typeof level === "string") {
|
|
956
|
+
return level;
|
|
957
|
+
}
|
|
958
|
+
if (environment !== void 0) {
|
|
959
|
+
const map = level;
|
|
960
|
+
const mapped = map[environment];
|
|
961
|
+
if (mapped !== void 0) return mapped;
|
|
962
|
+
}
|
|
963
|
+
return defaultLevelForEnvironment(environment);
|
|
964
|
+
}
|
|
965
|
+
function resolveSanitizerLimits(overrides, onInternalError) {
|
|
966
|
+
if (overrides === void 0) {
|
|
967
|
+
return { ...DEFAULT_SANITIZER_LIMITS };
|
|
968
|
+
}
|
|
969
|
+
const limits = { ...DEFAULT_SANITIZER_LIMITS };
|
|
970
|
+
const keys = Object.keys(SANITIZER_LIMIT_BOUNDS);
|
|
971
|
+
for (const key of keys) {
|
|
972
|
+
const requested = overrides[key];
|
|
973
|
+
if (requested === void 0) continue;
|
|
974
|
+
const bounds = SANITIZER_LIMIT_BOUNDS[key];
|
|
975
|
+
if (requested > bounds.max) {
|
|
976
|
+
limits[key] = bounds.max;
|
|
977
|
+
safeNotify(
|
|
978
|
+
onInternalError,
|
|
979
|
+
new PackageError(
|
|
980
|
+
"sanitizer_limit_clamped",
|
|
981
|
+
`sanitizerLimits.${key} value ${String(requested)} exceeds max ${String(bounds.max)}; clamped to ${String(bounds.max)}`
|
|
982
|
+
)
|
|
983
|
+
);
|
|
984
|
+
} else if (requested < bounds.min) {
|
|
985
|
+
limits[key] = bounds.min;
|
|
986
|
+
safeNotify(
|
|
987
|
+
onInternalError,
|
|
988
|
+
new PackageError(
|
|
989
|
+
"sanitizer_limit_clamped",
|
|
990
|
+
`sanitizerLimits.${key} value ${String(requested)} is below min ${String(bounds.min)}; clamped to ${String(bounds.min)}`
|
|
991
|
+
)
|
|
992
|
+
);
|
|
993
|
+
} else {
|
|
994
|
+
limits[key] = requested;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
return limits;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// src/transport/noop-transport.ts
|
|
1001
|
+
var NoopTransport = () => ({
|
|
1002
|
+
name: "noop",
|
|
1003
|
+
send() {
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
// src/transport/safe-transport.ts
|
|
1008
|
+
var SafeTransport = class {
|
|
1009
|
+
constructor(inner, onInternalError) {
|
|
1010
|
+
this.notified = false;
|
|
1011
|
+
this.inner = inner;
|
|
1012
|
+
this.name = inner.name;
|
|
1013
|
+
this.onInternalError = onInternalError;
|
|
1014
|
+
}
|
|
1015
|
+
send(event) {
|
|
1016
|
+
try {
|
|
1017
|
+
const result = this.inner.send(event);
|
|
1018
|
+
if (result instanceof Promise) {
|
|
1019
|
+
result.then(void 0, (reason) => {
|
|
1020
|
+
this.notify(reason, "transport_send_failed");
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
} catch (err) {
|
|
1024
|
+
this.notify(err, "transport_send_failed");
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
async flush() {
|
|
1028
|
+
if (this.inner.flush === void 0) return;
|
|
1029
|
+
try {
|
|
1030
|
+
await this.inner.flush();
|
|
1031
|
+
} catch (err) {
|
|
1032
|
+
this.notify(err, "transport_send_failed");
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
async shutdown() {
|
|
1036
|
+
if (this.inner.shutdown === void 0) return;
|
|
1037
|
+
try {
|
|
1038
|
+
await this.inner.shutdown();
|
|
1039
|
+
} catch (err) {
|
|
1040
|
+
this.notify(err, "transport_shutdown_failed");
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
notify(cause, code) {
|
|
1044
|
+
if (this.notified) return;
|
|
1045
|
+
this.notified = true;
|
|
1046
|
+
safeNotify(
|
|
1047
|
+
this.onInternalError,
|
|
1048
|
+
wrapAsPackageError(
|
|
1049
|
+
code,
|
|
1050
|
+
`Transport '${this.name}' failed: ${describe(cause)}`,
|
|
1051
|
+
cause,
|
|
1052
|
+
this.name
|
|
1053
|
+
)
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1056
|
+
};
|
|
1057
|
+
function describe(value) {
|
|
1058
|
+
if (value instanceof Error) return value.message;
|
|
1059
|
+
if (typeof value === "string") return value;
|
|
1060
|
+
return String(value);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// src/runtime/configured-runtime.ts
|
|
1064
|
+
function buildConfiguredRuntime(config) {
|
|
1065
|
+
const normalized = normalizeConfig(config);
|
|
1066
|
+
const sourceTransports = normalized.transports.length === 0 ? [NoopTransport()] : normalized.transports;
|
|
1067
|
+
const wrapped = sourceTransports.map(
|
|
1068
|
+
(t) => new SafeTransport(t, normalized.onInternalError)
|
|
1069
|
+
);
|
|
1070
|
+
const installedConfig = {
|
|
1071
|
+
...normalized,
|
|
1072
|
+
transports: wrapped
|
|
1073
|
+
};
|
|
1074
|
+
return {
|
|
1075
|
+
config: installedConfig,
|
|
1076
|
+
transports: wrapped,
|
|
1077
|
+
redactor: normalized.redactor,
|
|
1078
|
+
sanitizerLimits: normalized.sanitizerLimits,
|
|
1079
|
+
onInternalError: normalized.onInternalError,
|
|
1080
|
+
correlation: normalized.correlation
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
async function shutdownRuntime(runtime) {
|
|
1084
|
+
for (const transport of runtime.transports) {
|
|
1085
|
+
if (transport.flush !== void 0) {
|
|
1086
|
+
try {
|
|
1087
|
+
await transport.flush();
|
|
1088
|
+
} catch {
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
if (transport.shutdown !== void 0) {
|
|
1092
|
+
try {
|
|
1093
|
+
await transport.shutdown();
|
|
1094
|
+
} catch {
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// src/runtime/runtime-ref.ts
|
|
1101
|
+
var active;
|
|
1102
|
+
function getActiveRuntime() {
|
|
1103
|
+
return active;
|
|
1104
|
+
}
|
|
1105
|
+
function installRuntime(runtime) {
|
|
1106
|
+
const previous = active;
|
|
1107
|
+
active = runtime;
|
|
1108
|
+
return previous;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// src/api/logger.ts
|
|
1112
|
+
var rootLogger;
|
|
1113
|
+
function installState(config) {
|
|
1114
|
+
const runtime = buildConfiguredRuntime(config);
|
|
1115
|
+
const previousRuntime = installRuntime(runtime);
|
|
1116
|
+
if (previousRuntime !== void 0) {
|
|
1117
|
+
void shutdownRuntime(previousRuntime).then(void 0, () => void 0);
|
|
1118
|
+
}
|
|
1119
|
+
return runtime;
|
|
1120
|
+
}
|
|
1121
|
+
function ensureState() {
|
|
1122
|
+
let runtime = getActiveRuntime();
|
|
1123
|
+
if (runtime === void 0) {
|
|
1124
|
+
runtime = installState({});
|
|
1125
|
+
}
|
|
1126
|
+
return runtime;
|
|
1127
|
+
}
|
|
1128
|
+
function configureLogging(config) {
|
|
1129
|
+
installState(config);
|
|
1130
|
+
}
|
|
1131
|
+
function createLogger(options = {}) {
|
|
1132
|
+
return makeLogger(options, []);
|
|
1133
|
+
}
|
|
1134
|
+
function getRootLogger() {
|
|
1135
|
+
if (rootLogger === void 0) {
|
|
1136
|
+
rootLogger = createLogger();
|
|
1137
|
+
}
|
|
1138
|
+
return rootLogger;
|
|
1139
|
+
}
|
|
1140
|
+
function makeLogger(options, chainedContexts) {
|
|
1141
|
+
const loggerContextLayers = [
|
|
1142
|
+
options.context ?? {},
|
|
1143
|
+
options.module !== void 0 ? { module: options.module } : {}
|
|
1144
|
+
];
|
|
1145
|
+
function emit(level, message, attributes, errorValue) {
|
|
1146
|
+
const runtime = ensureState();
|
|
1147
|
+
const cfg = runtime.config;
|
|
1148
|
+
if (!passesLevelFilter(level, options.level, cfg.level)) {
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
const rootIdentity = {};
|
|
1152
|
+
if (cfg.application !== void 0) {
|
|
1153
|
+
rootIdentity.application = cfg.application;
|
|
1154
|
+
}
|
|
1155
|
+
if (cfg.module !== void 0) {
|
|
1156
|
+
rootIdentity.module = cfg.module;
|
|
1157
|
+
}
|
|
1158
|
+
if (cfg.environment !== void 0) {
|
|
1159
|
+
rootIdentity.environment = cfg.environment;
|
|
1160
|
+
}
|
|
1161
|
+
let correlation;
|
|
1162
|
+
if (cfg.correlation !== void 0) {
|
|
1163
|
+
try {
|
|
1164
|
+
correlation = cfg.correlation();
|
|
1165
|
+
} catch (err) {
|
|
1166
|
+
safeNotify(
|
|
1167
|
+
cfg.onInternalError,
|
|
1168
|
+
wrapAsPackageError(
|
|
1169
|
+
"correlation_failed",
|
|
1170
|
+
"correlation() callback threw; its output is dropped for this event.",
|
|
1171
|
+
err
|
|
1172
|
+
)
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
const context = mergeContexts(
|
|
1177
|
+
rootIdentity,
|
|
1178
|
+
cfg.context,
|
|
1179
|
+
...loggerContextLayers,
|
|
1180
|
+
...chainedContexts,
|
|
1181
|
+
correlation
|
|
1182
|
+
);
|
|
1183
|
+
const event = buildLogEvent({
|
|
1184
|
+
level,
|
|
1185
|
+
message,
|
|
1186
|
+
attributes,
|
|
1187
|
+
context,
|
|
1188
|
+
errorValue
|
|
1189
|
+
});
|
|
1190
|
+
dispatch(event, cfg);
|
|
1191
|
+
}
|
|
1192
|
+
return {
|
|
1193
|
+
debug(message, attributes) {
|
|
1194
|
+
emit("debug", message, attributes);
|
|
1195
|
+
},
|
|
1196
|
+
info(message, attributes) {
|
|
1197
|
+
emit("info", message, attributes);
|
|
1198
|
+
},
|
|
1199
|
+
warn(message, attributes) {
|
|
1200
|
+
emit("warn", message, attributes);
|
|
1201
|
+
},
|
|
1202
|
+
error(message, attributes, errorValue) {
|
|
1203
|
+
emit("error", message, attributes, errorValue);
|
|
1204
|
+
},
|
|
1205
|
+
child(context) {
|
|
1206
|
+
return makeLogger(options, [...chainedContexts, context]);
|
|
1207
|
+
},
|
|
1208
|
+
withContext(context) {
|
|
1209
|
+
return makeLogger(options, [...chainedContexts, context]);
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
// src/transport/console-transport.ts
|
|
1215
|
+
function resolveConsoleMethod(level) {
|
|
1216
|
+
const slot = console[level];
|
|
1217
|
+
if (typeof slot === "function") {
|
|
1218
|
+
return slot.bind(console);
|
|
1219
|
+
}
|
|
1220
|
+
return console.log.bind(console);
|
|
1221
|
+
}
|
|
1222
|
+
var ConsoleTransport = () => ({
|
|
1223
|
+
name: "console",
|
|
1224
|
+
send(event) {
|
|
1225
|
+
const log = resolveConsoleMethod(event.level);
|
|
1226
|
+
log(event.message, event);
|
|
1227
|
+
}
|
|
1228
|
+
});
|
|
1229
|
+
|
|
1230
|
+
export { ConsoleTransport, NoopTransport, configureLogging, createLogger, createRedactor, getRootLogger, scrubUrl };
|
|
1231
|
+
//# sourceMappingURL=index.mjs.map
|
|
1232
|
+
//# sourceMappingURL=index.mjs.map
|