hppx 0.1.10 → 0.2.3
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 -21
- package/README.md +494 -351
- package/dist/index.cjs +197 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.mjs +196 -84
- package/dist/index.mjs.map +1 -1
- package/package.json +97 -88
- package/src/index.d.cts +0 -70
package/dist/index.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
var DEFAULT_SOURCES = ["query", "body", "params"];
|
|
3
3
|
var DEFAULT_STRATEGY = "keepLast";
|
|
4
4
|
var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
5
|
+
var FORBIDDEN_KEY_CHARS = /[\u0000-\u001F\u007F-\u009F\u200E\u200F\u202A-\u202E\u2066-\u2069\uFEFF]/;
|
|
5
6
|
function isPlainObject(value) {
|
|
6
7
|
if (value === null || typeof value !== "object") return false;
|
|
7
8
|
const proto = Object.getPrototypeOf(value);
|
|
@@ -10,23 +11,28 @@ function isPlainObject(value) {
|
|
|
10
11
|
function sanitizeKey(key, maxKeyLength) {
|
|
11
12
|
if (typeof key !== "string") return null;
|
|
12
13
|
if (DANGEROUS_KEYS.has(key)) return null;
|
|
13
|
-
if (
|
|
14
|
+
if (FORBIDDEN_KEY_CHARS.test(key)) return null;
|
|
14
15
|
const maxLen = maxKeyLength ?? 200;
|
|
15
16
|
if (key.length > maxLen) return null;
|
|
16
17
|
if (key.length > 1 && /^[.\[\]]+$/.test(key)) return null;
|
|
17
18
|
return key;
|
|
18
19
|
}
|
|
20
|
+
var PATH_SEGMENT_CACHE_LIMIT = 500;
|
|
19
21
|
var pathSegmentCache = /* @__PURE__ */ new Map();
|
|
20
22
|
function parsePathSegments(key) {
|
|
21
23
|
const cached = pathSegmentCache.get(key);
|
|
22
24
|
if (cached) return cached;
|
|
23
25
|
const dotted = key.replace(/\]/g, "").replace(/\[/g, ".");
|
|
24
26
|
const result = dotted.split(".").filter((s) => s.length > 0);
|
|
25
|
-
if (pathSegmentCache.size
|
|
26
|
-
pathSegmentCache.
|
|
27
|
+
if (pathSegmentCache.size >= PATH_SEGMENT_CACHE_LIMIT) {
|
|
28
|
+
pathSegmentCache.clear();
|
|
27
29
|
}
|
|
30
|
+
pathSegmentCache.set(key, result);
|
|
28
31
|
return result;
|
|
29
32
|
}
|
|
33
|
+
function __resetPathSegmentCache() {
|
|
34
|
+
pathSegmentCache.clear();
|
|
35
|
+
}
|
|
30
36
|
function expandObjectPaths(obj, maxKeyLength, maxDepth = 20, currentDepth = 0, seen) {
|
|
31
37
|
if (currentDepth > maxDepth) {
|
|
32
38
|
throw new Error(`Maximum object depth (${maxDepth}) exceeded`);
|
|
@@ -34,35 +40,36 @@ function expandObjectPaths(obj, maxKeyLength, maxDepth = 20, currentDepth = 0, s
|
|
|
34
40
|
const seenSet = seen ?? /* @__PURE__ */ new WeakSet();
|
|
35
41
|
if (seenSet.has(obj)) return {};
|
|
36
42
|
seenSet.add(obj);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
value
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
try {
|
|
44
|
+
const result = {};
|
|
45
|
+
for (const rawKey of Object.keys(obj)) {
|
|
46
|
+
const safeKey = sanitizeKey(rawKey, maxKeyLength);
|
|
47
|
+
if (!safeKey) continue;
|
|
48
|
+
const value = obj[rawKey];
|
|
49
|
+
const expandedValue = isPlainObject(value) ? expandObjectPaths(
|
|
50
|
+
value,
|
|
51
|
+
maxKeyLength,
|
|
52
|
+
maxDepth,
|
|
53
|
+
currentDepth + 1,
|
|
54
|
+
seenSet
|
|
55
|
+
) : value;
|
|
56
|
+
if (safeKey.includes(".") || safeKey.includes("[")) {
|
|
57
|
+
const segments = parsePathSegments(safeKey);
|
|
58
|
+
if (segments.length > 0) {
|
|
59
|
+
setIn(result, segments, expandedValue);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
54
62
|
}
|
|
63
|
+
result[safeKey] = expandedValue;
|
|
55
64
|
}
|
|
56
|
-
result
|
|
65
|
+
return result;
|
|
66
|
+
} finally {
|
|
67
|
+
seenSet.delete(obj);
|
|
57
68
|
}
|
|
58
|
-
return result;
|
|
59
69
|
}
|
|
60
|
-
function setReqPropertySafe(target, key, value) {
|
|
70
|
+
function setReqPropertySafe(target, key, value, onFailure) {
|
|
61
71
|
try {
|
|
62
72
|
const desc = Object.getOwnPropertyDescriptor(target, key);
|
|
63
|
-
if (desc && desc.configurable === false && desc.writable === false) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
73
|
if (!desc || desc.configurable !== false) {
|
|
67
74
|
Object.defineProperty(target, key, {
|
|
68
75
|
value,
|
|
@@ -70,13 +77,35 @@ function setReqPropertySafe(target, key, value) {
|
|
|
70
77
|
configurable: true,
|
|
71
78
|
enumerable: true
|
|
72
79
|
});
|
|
73
|
-
return;
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
if (desc.writable) {
|
|
83
|
+
target[key] = value;
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
target[key] = value;
|
|
88
|
+
if (target[key] === value) return true;
|
|
89
|
+
} catch (_assignErr) {
|
|
90
|
+
}
|
|
91
|
+
if (onFailure) {
|
|
92
|
+
onFailure(
|
|
93
|
+
`[hppx] Could not write sanitized value to req.${key}: property is non-configurable and non-writable. The original (potentially polluted) value remains on req.${key}.`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
} catch (_definePropErr) {
|
|
98
|
+
try {
|
|
99
|
+
target[key] = value;
|
|
100
|
+
if (target[key] === value) return true;
|
|
101
|
+
} catch (_assignErr) {
|
|
102
|
+
}
|
|
103
|
+
{
|
|
104
|
+
if (onFailure) {
|
|
105
|
+
onFailure(`[hppx] Could not write sanitized value to req.${key}: defineProperty failed.`);
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
74
108
|
}
|
|
75
|
-
} catch (_) {
|
|
76
|
-
}
|
|
77
|
-
try {
|
|
78
|
-
target[key] = value;
|
|
79
|
-
} catch (_) {
|
|
80
109
|
}
|
|
81
110
|
}
|
|
82
111
|
function safeDeepClone(input, maxKeyLength, maxArrayLength, maxDepth = 20, currentDepth = 0, seen) {
|
|
@@ -87,11 +116,15 @@ function safeDeepClone(input, maxKeyLength, maxArrayLength, maxDepth = 20, curre
|
|
|
87
116
|
const seenSet = seen ?? /* @__PURE__ */ new WeakSet();
|
|
88
117
|
if (seenSet.has(input)) return [];
|
|
89
118
|
seenSet.add(input);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
119
|
+
try {
|
|
120
|
+
const limit = maxArrayLength ?? 1e3;
|
|
121
|
+
const limited = input.slice(0, limit);
|
|
122
|
+
return limited.map(
|
|
123
|
+
(v) => safeDeepClone(v, maxKeyLength, maxArrayLength, maxDepth, currentDepth + 1, seenSet)
|
|
124
|
+
);
|
|
125
|
+
} finally {
|
|
126
|
+
seenSet.delete(input);
|
|
127
|
+
}
|
|
95
128
|
}
|
|
96
129
|
if (isPlainObject(input)) {
|
|
97
130
|
if (currentDepth > maxDepth) {
|
|
@@ -100,19 +133,23 @@ function safeDeepClone(input, maxKeyLength, maxArrayLength, maxDepth = 20, curre
|
|
|
100
133
|
const seenSet = seen ?? /* @__PURE__ */ new WeakSet();
|
|
101
134
|
if (seenSet.has(input)) return {};
|
|
102
135
|
seenSet.add(input);
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
136
|
+
try {
|
|
137
|
+
const out = {};
|
|
138
|
+
for (const k of Object.keys(input)) {
|
|
139
|
+
if (!sanitizeKey(k, maxKeyLength)) continue;
|
|
140
|
+
out[k] = safeDeepClone(
|
|
141
|
+
input[k],
|
|
142
|
+
maxKeyLength,
|
|
143
|
+
maxArrayLength,
|
|
144
|
+
maxDepth,
|
|
145
|
+
currentDepth + 1,
|
|
146
|
+
seenSet
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
return out;
|
|
150
|
+
} finally {
|
|
151
|
+
seenSet.delete(input);
|
|
114
152
|
}
|
|
115
|
-
return out;
|
|
116
153
|
}
|
|
117
154
|
return input;
|
|
118
155
|
}
|
|
@@ -128,9 +165,15 @@ function mergeValues(values, strategy) {
|
|
|
128
165
|
else acc.push(v);
|
|
129
166
|
return acc;
|
|
130
167
|
}, []);
|
|
131
|
-
/* istanbul ignore next --
|
|
132
|
-
|
|
133
|
-
|
|
168
|
+
/* istanbul ignore next -- exhaustiveness check unreachable from outside:
|
|
169
|
+
validateSanitizeOptions rejects every non-listed strategy at construction
|
|
170
|
+
time, so the only way to reach this branch is a programmer error (a new
|
|
171
|
+
MergeStrategy union member added without updating this switch). Failing
|
|
172
|
+
loudly here is preferable to a silent fallback. */
|
|
173
|
+
default: {
|
|
174
|
+
const _exhaustive = strategy;
|
|
175
|
+
throw new Error(`Unknown mergeStrategy: ${_exhaustive}`);
|
|
176
|
+
}
|
|
134
177
|
}
|
|
135
178
|
}
|
|
136
179
|
function isUrlEncodedContentType(req) {
|
|
@@ -154,6 +197,7 @@ function normalizeWhitelist(whitelist) {
|
|
|
154
197
|
if (typeof whitelist === "string") return [whitelist];
|
|
155
198
|
return whitelist.filter((w) => typeof w === "string");
|
|
156
199
|
}
|
|
200
|
+
var WHITELIST_PATH_CACHE_LIMIT = 1e3;
|
|
157
201
|
function buildWhitelistHelpers(whitelist) {
|
|
158
202
|
const exact = new Set(whitelist);
|
|
159
203
|
const prefixes = whitelist.filter((w) => w.length > 0);
|
|
@@ -179,9 +223,10 @@ function buildWhitelistHelpers(whitelist) {
|
|
|
179
223
|
}
|
|
180
224
|
}
|
|
181
225
|
}
|
|
182
|
-
if (pathCache.size
|
|
183
|
-
pathCache.
|
|
226
|
+
if (pathCache.size >= WHITELIST_PATH_CACHE_LIMIT) {
|
|
227
|
+
pathCache.clear();
|
|
184
228
|
}
|
|
229
|
+
pathCache.set(full, result);
|
|
185
230
|
return result;
|
|
186
231
|
}
|
|
187
232
|
};
|
|
@@ -229,25 +274,18 @@ function moveWhitelistedFromPolluted(reqPart, polluted, isWhitelisted) {
|
|
|
229
274
|
function detectAndReduce(input, opts) {
|
|
230
275
|
let keyCount = 0;
|
|
231
276
|
const polluted = {};
|
|
232
|
-
const
|
|
233
|
-
|
|
277
|
+
const pollutedKeysSet = /* @__PURE__ */ new Set();
|
|
278
|
+
const cloned = safeDeepClone(input, opts.maxKeyLength, opts.maxArrayLength, opts.maxDepth);
|
|
279
|
+
function processNode(node, path = [], depth = 0, inArray = false) {
|
|
234
280
|
if (node === null) return opts.preserveNull ? null : void 0;
|
|
235
281
|
if (node === void 0) return node;
|
|
236
282
|
if (Array.isArray(node)) {
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
return mergeValues(mapped, "combine");
|
|
283
|
+
const mapped = node.map((v) => processNode(v, path, depth, true));
|
|
284
|
+
if (!inArray) {
|
|
285
|
+
setIn(polluted, path, node);
|
|
286
|
+
pollutedKeysSet.add(path.join("."));
|
|
242
287
|
}
|
|
243
|
-
|
|
244
|
-
polluted,
|
|
245
|
-
path,
|
|
246
|
-
safeDeepClone(limitedNode, opts.maxKeyLength, opts.maxArrayLength, opts.maxDepth)
|
|
247
|
-
);
|
|
248
|
-
pollutedKeys.push(path.join("."));
|
|
249
|
-
const reduced = mergeValues(mapped, opts.mergeStrategy);
|
|
250
|
-
return reduced;
|
|
288
|
+
return mergeValues(mapped, opts.mergeStrategy);
|
|
251
289
|
}
|
|
252
290
|
if (isPlainObject(node)) {
|
|
253
291
|
if (depth > opts.maxDepth)
|
|
@@ -262,7 +300,7 @@ function detectAndReduce(input, opts) {
|
|
|
262
300
|
if (!safeKey) continue;
|
|
263
301
|
const child = node[rawKey];
|
|
264
302
|
const childPath = path.concat([safeKey]);
|
|
265
|
-
let value = processNode(child, childPath, depth + 1);
|
|
303
|
+
let value = processNode(child, childPath, depth + 1, false);
|
|
266
304
|
if (typeof value === "string" && opts.trimValues) value = value.trim();
|
|
267
305
|
out[safeKey] = value;
|
|
268
306
|
}
|
|
@@ -270,9 +308,8 @@ function detectAndReduce(input, opts) {
|
|
|
270
308
|
}
|
|
271
309
|
return node;
|
|
272
310
|
}
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
return { cleaned, pollutedTree: polluted, pollutedKeys };
|
|
311
|
+
const cleaned = processNode(cloned, [], 0, false);
|
|
312
|
+
return { cleaned, pollutedTree: polluted, pollutedKeys: Array.from(pollutedKeysSet) };
|
|
276
313
|
}
|
|
277
314
|
function sanitize(input, options = {}) {
|
|
278
315
|
validateSanitizeOptions(options);
|
|
@@ -317,6 +354,24 @@ function validateSanitizeOptions(options) {
|
|
|
317
354
|
if (options.mergeStrategy !== void 0 && !["keepFirst", "keepLast", "combine"].includes(options.mergeStrategy)) {
|
|
318
355
|
throw new TypeError("mergeStrategy must be 'keepFirst', 'keepLast', or 'combine'");
|
|
319
356
|
}
|
|
357
|
+
if (options.trimValues !== void 0 && typeof options.trimValues !== "boolean") {
|
|
358
|
+
throw new TypeError("trimValues must be a boolean");
|
|
359
|
+
}
|
|
360
|
+
if (options.preserveNull !== void 0 && typeof options.preserveNull !== "boolean") {
|
|
361
|
+
throw new TypeError("preserveNull must be a boolean");
|
|
362
|
+
}
|
|
363
|
+
if (options.whitelist !== void 0) {
|
|
364
|
+
if (typeof options.whitelist !== "string" && !Array.isArray(options.whitelist)) {
|
|
365
|
+
throw new TypeError("whitelist must be a string or an array of strings");
|
|
366
|
+
}
|
|
367
|
+
if (Array.isArray(options.whitelist)) {
|
|
368
|
+
for (const entry of options.whitelist) {
|
|
369
|
+
if (typeof entry !== "string") {
|
|
370
|
+
throw new TypeError("whitelist must be a string or an array of strings");
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
320
375
|
}
|
|
321
376
|
function validateOptions(options) {
|
|
322
377
|
validateSanitizeOptions(options);
|
|
@@ -324,6 +379,9 @@ function validateOptions(options) {
|
|
|
324
379
|
throw new TypeError("sources must be an array");
|
|
325
380
|
}
|
|
326
381
|
if (options.sources !== void 0) {
|
|
382
|
+
if (options.sources.length === 0) {
|
|
383
|
+
throw new TypeError("sources must contain at least one of 'query', 'body', 'params'");
|
|
384
|
+
}
|
|
327
385
|
for (const source of options.sources) {
|
|
328
386
|
if (!["query", "body", "params"].includes(source)) {
|
|
329
387
|
throw new TypeError("sources must only contain 'query', 'body', or 'params'");
|
|
@@ -333,8 +391,15 @@ function validateOptions(options) {
|
|
|
333
391
|
if (options.checkBodyContentType !== void 0 && !["urlencoded", "any", "none"].includes(options.checkBodyContentType)) {
|
|
334
392
|
throw new TypeError("checkBodyContentType must be 'urlencoded', 'any', or 'none'");
|
|
335
393
|
}
|
|
336
|
-
if (options.excludePaths !== void 0
|
|
337
|
-
|
|
394
|
+
if (options.excludePaths !== void 0) {
|
|
395
|
+
if (!Array.isArray(options.excludePaths)) {
|
|
396
|
+
throw new TypeError("excludePaths must be an array");
|
|
397
|
+
}
|
|
398
|
+
for (const entry of options.excludePaths) {
|
|
399
|
+
if (typeof entry !== "string") {
|
|
400
|
+
throw new TypeError("excludePaths must contain only strings");
|
|
401
|
+
}
|
|
402
|
+
}
|
|
338
403
|
}
|
|
339
404
|
if (options.logger !== void 0 && typeof options.logger !== "function") {
|
|
340
405
|
throw new TypeError("logger must be a function");
|
|
@@ -342,6 +407,12 @@ function validateOptions(options) {
|
|
|
342
407
|
if (options.onPollutionDetected !== void 0 && typeof options.onPollutionDetected !== "function") {
|
|
343
408
|
throw new TypeError("onPollutionDetected must be a function");
|
|
344
409
|
}
|
|
410
|
+
if (options.strict !== void 0 && typeof options.strict !== "boolean") {
|
|
411
|
+
throw new TypeError("strict must be a boolean");
|
|
412
|
+
}
|
|
413
|
+
if (options.logPollution !== void 0 && typeof options.logPollution !== "boolean") {
|
|
414
|
+
throw new TypeError("logPollution must be a boolean");
|
|
415
|
+
}
|
|
345
416
|
}
|
|
346
417
|
function hppx(options = {}) {
|
|
347
418
|
validateOptions(options);
|
|
@@ -366,9 +437,39 @@ function hppx(options = {}) {
|
|
|
366
437
|
const { isWhitelistedPath } = buildWhitelistHelpers(whitelistArr);
|
|
367
438
|
return function hppxMiddleware(req, res, next) {
|
|
368
439
|
try {
|
|
369
|
-
|
|
440
|
+
let pathForExclusion;
|
|
441
|
+
try {
|
|
442
|
+
pathForExclusion = req?.path;
|
|
443
|
+
} catch (pathErr) {
|
|
444
|
+
const message = `[hppx] Failed to read req.path during exclusion check; proceeding without path-based exclusion. Underlying error: ${pathErr instanceof Error ? pathErr.message : String(pathErr)}`;
|
|
445
|
+
if (logger) {
|
|
446
|
+
try {
|
|
447
|
+
logger(message);
|
|
448
|
+
} catch (_) {
|
|
449
|
+
console.warn(message);
|
|
450
|
+
}
|
|
451
|
+
} else {
|
|
452
|
+
console.warn(message);
|
|
453
|
+
}
|
|
454
|
+
pathForExclusion = void 0;
|
|
455
|
+
}
|
|
456
|
+
if (shouldExcludePath(pathForExclusion, excludePaths)) return next();
|
|
370
457
|
let anyPollutionDetected = false;
|
|
371
458
|
const allPollutedKeys = [];
|
|
459
|
+
const warned = /* @__PURE__ */ new Set();
|
|
460
|
+
const warn = (message) => {
|
|
461
|
+
if (warned.has(message)) return;
|
|
462
|
+
warned.add(message);
|
|
463
|
+
if (logger) {
|
|
464
|
+
try {
|
|
465
|
+
logger(message);
|
|
466
|
+
} catch (_) {
|
|
467
|
+
console.warn(message);
|
|
468
|
+
}
|
|
469
|
+
} else {
|
|
470
|
+
console.warn(message);
|
|
471
|
+
}
|
|
472
|
+
};
|
|
372
473
|
for (const source of sources) {
|
|
373
474
|
if (!req || typeof req !== "object") break;
|
|
374
475
|
if (req[source] === void 0) continue;
|
|
@@ -381,7 +482,7 @@ function hppx(options = {}) {
|
|
|
381
482
|
const expandedPart = expandObjectPaths(part, maxKeyLength, maxDepth);
|
|
382
483
|
const pollutedKey = `${source}Polluted`;
|
|
383
484
|
const processedKey = `__hppxProcessed_${source}`;
|
|
384
|
-
const hasProcessedBefore =
|
|
485
|
+
const hasProcessedBefore = Object.prototype.hasOwnProperty.call(req, processedKey);
|
|
385
486
|
if (!hasProcessedBefore) {
|
|
386
487
|
const { cleaned, pollutedTree, pollutedKeys } = detectAndReduce(expandedPart, {
|
|
387
488
|
mergeStrategy,
|
|
@@ -392,9 +493,21 @@ function hppx(options = {}) {
|
|
|
392
493
|
trimValues,
|
|
393
494
|
preserveNull
|
|
394
495
|
});
|
|
395
|
-
setReqPropertySafe(req, source, cleaned);
|
|
396
|
-
setReqPropertySafe(req, pollutedKey, pollutedTree);
|
|
397
|
-
|
|
496
|
+
setReqPropertySafe(req, source, cleaned, warn);
|
|
497
|
+
setReqPropertySafe(req, pollutedKey, pollutedTree, warn);
|
|
498
|
+
try {
|
|
499
|
+
Object.defineProperty(req, processedKey, {
|
|
500
|
+
value: true,
|
|
501
|
+
writable: false,
|
|
502
|
+
configurable: false,
|
|
503
|
+
enumerable: false
|
|
504
|
+
});
|
|
505
|
+
} catch (_) {
|
|
506
|
+
try {
|
|
507
|
+
req[processedKey] = true;
|
|
508
|
+
} catch (_assignErr) {
|
|
509
|
+
}
|
|
510
|
+
}
|
|
398
511
|
const sourceData = req[source];
|
|
399
512
|
const pollutedData = req[pollutedKey];
|
|
400
513
|
if (isPlainObject(sourceData) && isPlainObject(pollutedData)) {
|
|
@@ -461,10 +574,8 @@ function hppx(options = {}) {
|
|
|
461
574
|
try {
|
|
462
575
|
logger(error);
|
|
463
576
|
} catch (logErr) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
console.error("[hppx] Original error:", error);
|
|
467
|
-
}
|
|
577
|
+
console.error("[hppx] Logger failed:", logErr);
|
|
578
|
+
console.error("[hppx] Original error:", error);
|
|
468
579
|
}
|
|
469
580
|
}
|
|
470
581
|
return next(error);
|
|
@@ -475,6 +586,7 @@ export {
|
|
|
475
586
|
DANGEROUS_KEYS,
|
|
476
587
|
DEFAULT_SOURCES,
|
|
477
588
|
DEFAULT_STRATEGY,
|
|
589
|
+
__resetPathSegmentCache,
|
|
478
590
|
hppx as default,
|
|
479
591
|
sanitize
|
|
480
592
|
};
|