logixia 2.0.11 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/{async-context-BGUCdYAa.mjs → async-context-1YMPGgJZ.mjs} +3 -3
- package/dist/{async-context-BGUCdYAa.mjs.map → async-context-1YMPGgJZ.mjs.map} +1 -1
- package/dist/{async-context-D8um9I5V.js → async-context-CoPhbRG0.js} +4 -4
- package/dist/{async-context-D8um9I5V.js.map → async-context-CoPhbRG0.js.map} +1 -1
- package/dist/{azure-monitor.transport-CTnfwA0F.mjs → azure-monitor.transport-B_dqSV_o.mjs} +4 -4
- package/dist/{azure-monitor.transport-CTnfwA0F.mjs.map → azure-monitor.transport-B_dqSV_o.mjs.map} +1 -1
- package/dist/{azure-monitor.transport-C8KdmsSw.js → azure-monitor.transport-Bl3xVvpN.js} +4 -4
- package/dist/{azure-monitor.transport-C8KdmsSw.js.map → azure-monitor.transport-Bl3xVvpN.js.map} +1 -1
- package/dist/{azure-monitor.transport-CbSHOnNX.d.mts → azure-monitor.transport-C5VjvREZ.d.mts} +2 -2
- package/dist/{azure-monitor.transport-CbSHOnNX.d.mts.map → azure-monitor.transport-C5VjvREZ.d.mts.map} +1 -1
- package/dist/{azure-monitor.transport-Bvf7Xegt.d.ts → azure-monitor.transport-CyHDjHS-.d.ts} +2 -2
- package/dist/{azure-monitor.transport-Bvf7Xegt.d.ts.map → azure-monitor.transport-CyHDjHS-.d.ts.map} +1 -1
- package/dist/azure.d.mts +1 -1
- package/dist/azure.d.ts +1 -1
- package/dist/azure.js +1 -1
- package/dist/azure.mjs +1 -1
- package/dist/{batch-buffer-BJqzpfpT.mjs → batch-buffer-BnmVCCwI.mjs} +2 -2
- package/dist/{batch-buffer-BJqzpfpT.mjs.map → batch-buffer-BnmVCCwI.mjs.map} +1 -1
- package/dist/{batch-buffer-BTQdAXwC.js → batch-buffer-C-ETEX3Y.js} +2 -2
- package/dist/{batch-buffer-BTQdAXwC.js.map → batch-buffer-C-ETEX3Y.js.map} +1 -1
- package/dist/browser.d.mts +2 -0
- package/dist/browser.d.mts.map +1 -1
- package/dist/browser.d.ts +2 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +33 -15
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +33 -15
- package/dist/browser.mjs.map +1 -1
- package/dist/{builder-C6kKEVrU.mjs → builder-CbttbixM.mjs} +158 -279
- package/dist/builder-CbttbixM.mjs.map +1 -0
- package/dist/{builder-Up4YxX7l.js → builder-Ck1tsC5d.js} +160 -305
- package/dist/builder-Ck1tsC5d.js.map +1 -0
- package/dist/cloudwatch.d.mts +1 -1
- package/dist/cloudwatch.d.ts +1 -1
- package/dist/cloudwatch.js +1 -1
- package/dist/cloudwatch.mjs +1 -1
- package/dist/{cloudwatch.transport-Bl1qzdBx.mjs → cloudwatch.transport-Brh5fmRN.mjs} +5 -5
- package/dist/{cloudwatch.transport-Bl1qzdBx.mjs.map → cloudwatch.transport-Brh5fmRN.mjs.map} +1 -1
- package/dist/{cloudwatch.transport-BoCyxNKO.js → cloudwatch.transport-DO9e__Z-.js} +5 -5
- package/dist/{cloudwatch.transport-BoCyxNKO.js.map → cloudwatch.transport-DO9e__Z-.js.map} +1 -1
- package/dist/{cloudwatch.transport-CQyT6U91.d.ts → cloudwatch.transport-DdSjUWvu.d.ts} +2 -2
- package/dist/{cloudwatch.transport-CQyT6U91.d.ts.map → cloudwatch.transport-DdSjUWvu.d.ts.map} +1 -1
- package/dist/{cloudwatch.transport-CjVrI6S4.d.mts → cloudwatch.transport-_hS7Mcc5.d.mts} +2 -2
- package/dist/{cloudwatch.transport-CjVrI6S4.d.mts.map → cloudwatch.transport-_hS7Mcc5.d.mts.map} +1 -1
- package/dist/correlation.js +3 -3
- package/dist/correlation.mjs +3 -3
- package/dist/{entry-fields-CJbeaoBs.js → entry-fields-BSLkzw18.js} +3 -3
- package/dist/{entry-fields-CJbeaoBs.js.map → entry-fields-BSLkzw18.js.map} +1 -1
- package/dist/{entry-fields-D_aNnjg0.mjs → entry-fields-J1OBi24o.mjs} +2 -2
- package/dist/{entry-fields-D_aNnjg0.mjs.map → entry-fields-J1OBi24o.mjs.map} +1 -1
- package/dist/error.utils-B8_CwESF.mjs +189 -0
- package/dist/error.utils-B8_CwESF.mjs.map +1 -0
- package/dist/error.utils-fZkRExam.js +212 -0
- package/dist/error.utils-fZkRExam.js.map +1 -0
- package/dist/fastify.d.mts +89 -0
- package/dist/fastify.d.mts.map +1 -0
- package/dist/fastify.d.ts +89 -0
- package/dist/fastify.d.ts.map +1 -0
- package/dist/fastify.js +265 -0
- package/dist/fastify.js.map +1 -0
- package/dist/fastify.mjs +263 -0
- package/dist/fastify.mjs.map +1 -0
- package/dist/gcp.d.mts +1 -1
- package/dist/gcp.d.ts +1 -1
- package/dist/gcp.js +1 -1
- package/dist/gcp.mjs +1 -1
- package/dist/{gcp.transport-DOH4bpWM.mjs → gcp.transport-BY1Z3cS0.mjs} +5 -5
- package/dist/{gcp.transport-DOH4bpWM.mjs.map → gcp.transport-BY1Z3cS0.mjs.map} +1 -1
- package/dist/{gcp.transport-D9SdLPwP.d.mts → gcp.transport-C8VJiEM7.d.mts} +2 -2
- package/dist/{gcp.transport-D9SdLPwP.d.mts.map → gcp.transport-C8VJiEM7.d.mts.map} +1 -1
- package/dist/{gcp.transport-BCIvdFV-.d.ts → gcp.transport-Ct0BtKFo.d.ts} +2 -2
- package/dist/{gcp.transport-BCIvdFV-.d.ts.map → gcp.transport-Ct0BtKFo.d.ts.map} +1 -1
- package/dist/{gcp.transport-D_NHVZrw.js → gcp.transport-V9R4dwdT.js} +5 -5
- package/dist/{gcp.transport-D_NHVZrw.js.map → gcp.transport-V9R4dwdT.js.map} +1 -1
- package/dist/hono.d.mts +66 -0
- package/dist/hono.d.mts.map +1 -0
- package/dist/hono.d.ts +66 -0
- package/dist/hono.d.ts.map +1 -0
- package/dist/hono.js +512 -0
- package/dist/hono.js.map +1 -0
- package/dist/hono.mjs +511 -0
- package/dist/hono.mjs.map +1 -0
- package/dist/{index-BAkPHp5D.d.mts → index-B3ajtXJd.d.mts} +2 -2
- package/dist/{index-BAkPHp5D.d.mts.map → index-B3ajtXJd.d.mts.map} +1 -1
- package/dist/{index-e7LowmAu.d.ts → index-oqD3WNxf.d.ts} +2 -2
- package/dist/{index-e7LowmAu.d.ts.map → index-oqD3WNxf.d.ts.map} +1 -1
- package/dist/index.d.mts +8 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +11 -9
- package/dist/index.mjs.map +1 -1
- package/dist/{logitron-logger-DVUdgmBY.d.ts → logitron-logger-Csn3e6Qu.d.ts} +2 -2
- package/dist/{logitron-logger-DVUdgmBY.d.ts.map → logitron-logger-Csn3e6Qu.d.ts.map} +1 -1
- package/dist/{logitron-logger-DoWmMjYB.d.mts → logitron-logger-fMOkXr8H.d.mts} +2 -2
- package/dist/{logitron-logger-DoWmMjYB.d.mts.map → logitron-logger-fMOkXr8H.d.mts.map} +1 -1
- package/dist/middleware.d.mts +1 -1
- package/dist/middleware.d.ts +1 -1
- package/dist/middleware.js +6 -5
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +4 -3
- package/dist/middleware.mjs.map +1 -1
- package/dist/nest.d.mts +47 -15
- package/dist/nest.d.mts.map +1 -1
- package/dist/nest.d.ts +47 -15
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js +172 -50
- package/dist/nest.js.map +1 -1
- package/dist/nest.mjs +168 -46
- package/dist/nest.mjs.map +1 -1
- package/dist/{otel-DH6-G6DR.js → otel-BrgvxLDW.js} +319 -66
- package/dist/otel-BrgvxLDW.js.map +1 -0
- package/dist/{otel-DAVxpArV.mjs → otel-C5jBV_l_.mjs} +319 -66
- package/dist/otel-C5jBV_l_.mjs.map +1 -0
- package/dist/own-property-BWkibepN.js +40 -0
- package/dist/own-property-BWkibepN.js.map +1 -0
- package/dist/own-property-CjFw9qwZ.mjs +29 -0
- package/dist/own-property-CjFw9qwZ.mjs.map +1 -0
- package/dist/{request-trace-C7kXMjx5.js → request-trace-6NBSw5lt.js} +14 -3
- package/dist/{request-trace-C7kXMjx5.js.map → request-trace-6NBSw5lt.js.map} +1 -1
- package/dist/{request-trace-Dekcnenb.mjs → request-trace-txUhyyre.mjs} +9 -4
- package/dist/{request-trace-Dekcnenb.mjs.map → request-trace-txUhyyre.mjs.map} +1 -1
- package/dist/{safe-stringify-pZOnzGRJ.mjs → safe-stringify-B5p5ktFe.mjs} +2 -2
- package/dist/{safe-stringify-pZOnzGRJ.mjs.map → safe-stringify-B5p5ktFe.mjs.map} +1 -1
- package/dist/{safe-stringify-CJisLyZ3.js → safe-stringify-J3sh-7YM.js} +5 -5
- package/dist/{safe-stringify-CJisLyZ3.js.map → safe-stringify-J3sh-7YM.js.map} +1 -1
- package/dist/{search-Crf2IEoA.d.mts → search-B-hJe2N-.d.mts} +7 -3
- package/dist/{search-Crf2IEoA.d.mts.map → search-B-hJe2N-.d.mts.map} +1 -1
- package/dist/{search-B4eEzrhM.d.ts → search-BlKBLm5D.d.ts} +7 -3
- package/dist/{search-B4eEzrhM.d.ts.map → search-BlKBLm5D.d.ts.map} +1 -1
- package/dist/{search-CjYl-mo5.mjs → search-CTR4XNHq.mjs} +52 -14
- package/dist/search-CTR4XNHq.mjs.map +1 -0
- package/dist/{search-CJw_xoQl.js → search-_qx4YzRP.js} +52 -14
- package/dist/search-_qx4YzRP.js.map +1 -0
- package/dist/search.d.mts +1 -1
- package/dist/search.d.ts +1 -1
- package/dist/search.js +1 -1
- package/dist/search.mjs +1 -1
- package/dist/{secret-config-D1F4MW69.mjs → secret-config-Cng7XPLx.mjs} +18 -13
- package/dist/secret-config-Cng7XPLx.mjs.map +1 -0
- package/dist/{secret-config-6hdODxBb.js → secret-config-OqmIPmpV.js} +21 -16
- package/dist/secret-config-OqmIPmpV.js.map +1 -0
- package/dist/{sensitive-names-wv27qBQC.mjs → sensitive-names-BiBM6R1X.mjs} +2 -28
- package/dist/sensitive-names-BiBM6R1X.mjs.map +1 -0
- package/dist/{sensitive-names-CNgHaqv9.js → sensitive-names-NiKIRhp5.js} +1 -39
- package/dist/sensitive-names-NiKIRhp5.js.map +1 -0
- package/dist/{slack.transport-C6E0l4kw.d.ts → slack.transport-5OPL7H3u.d.mts} +76 -3
- package/dist/slack.transport-5OPL7H3u.d.mts.map +1 -0
- package/dist/{slack.transport-BDyENuR0.d.mts → slack.transport-BFpBD_Ri.d.ts} +76 -3
- package/dist/slack.transport-BFpBD_Ri.d.ts.map +1 -0
- package/dist/{slack.transport-YvaLJxNv.mjs → slack.transport-C6dzPJHX.mjs} +226 -9
- package/dist/slack.transport-C6dzPJHX.mjs.map +1 -0
- package/dist/{slack.transport-CEYBVzUj.js → slack.transport-Ci0swStG.js} +231 -8
- package/dist/slack.transport-Ci0swStG.js.map +1 -0
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/{transport.types-CzJq4IrF.d.ts → transport.types-B1ejJJP6.d.mts} +6 -1
- package/dist/transport.types-B1ejJJP6.d.mts.map +1 -0
- package/dist/{transport.types-CzJq4IrF.d.mts → transport.types-B1ejJJP6.d.ts} +6 -1
- package/dist/transport.types-B1ejJJP6.d.ts.map +1 -0
- package/dist/transports.d.mts +61 -11
- package/dist/transports.d.mts.map +1 -1
- package/dist/transports.d.ts +61 -11
- package/dist/transports.d.ts.map +1 -1
- package/dist/transports.js +7 -6
- package/dist/transports.mjs +7 -7
- package/dist/worker-entry.js +106 -22
- package/dist/worker.d.mts +1 -1
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +1 -1
- package/dist/worker.mjs +1 -1
- package/dist/{worker.transport-B9mCQSM1.d.ts → worker.transport-B7olL1Uh.d.ts} +12 -2
- package/dist/worker.transport-B7olL1Uh.d.ts.map +1 -0
- package/dist/{worker.transport-CwNpH98o.js → worker.transport-CZOutlxC.js} +40 -2
- package/dist/worker.transport-CZOutlxC.js.map +1 -0
- package/dist/{worker.transport-DgK_ZXlB.mjs → worker.transport-CxFD8mvS.mjs} +40 -2
- package/dist/worker.transport-CxFD8mvS.mjs.map +1 -0
- package/dist/{worker.transport-Bl8lFRck.d.mts → worker.transport-DnU0_9Bd.d.mts} +12 -2
- package/dist/worker.transport-DnU0_9Bd.d.mts.map +1 -0
- package/package.json +37 -2
- package/dist/builder-C6kKEVrU.mjs.map +0 -1
- package/dist/builder-Up4YxX7l.js.map +0 -1
- package/dist/otel-DAVxpArV.mjs.map +0 -1
- package/dist/otel-DH6-G6DR.js.map +0 -1
- package/dist/search-CJw_xoQl.js.map +0 -1
- package/dist/search-CjYl-mo5.mjs.map +0 -1
- package/dist/secret-config-6hdODxBb.js.map +0 -1
- package/dist/secret-config-D1F4MW69.mjs.map +0 -1
- package/dist/sensitive-names-CNgHaqv9.js.map +0 -1
- package/dist/sensitive-names-wv27qBQC.mjs.map +0 -1
- package/dist/slack.transport-BDyENuR0.d.mts.map +0 -1
- package/dist/slack.transport-C6E0l4kw.d.ts.map +0 -1
- package/dist/slack.transport-CEYBVzUj.js.map +0 -1
- package/dist/slack.transport-YvaLJxNv.mjs.map +0 -1
- package/dist/transport.types-CzJq4IrF.d.mts.map +0 -1
- package/dist/transport.types-CzJq4IrF.d.ts.map +0 -1
- package/dist/worker.transport-B9mCQSM1.d.ts.map +0 -1
- package/dist/worker.transport-Bl8lFRck.d.mts.map +0 -1
- package/dist/worker.transport-CwNpH98o.js.map +0 -1
- package/dist/worker.transport-DgK_ZXlB.mjs.map +0 -1
package/dist/hono.js
ADDED
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let node_async_hooks = require("node:async_hooks");
|
|
3
|
+
let node_crypto = require("node:crypto");
|
|
4
|
+
// src/utils/own-property.ts
|
|
5
|
+
/**
|
|
6
|
+
* Copy `value` onto `target[key]` as an own, enumerable data property.
|
|
7
|
+
*
|
|
8
|
+
* Normal keys use a plain assignment, which is the fast path. `__proto__` goes
|
|
9
|
+
* through `Object.defineProperty` so that a key taken from logged or parsed data
|
|
10
|
+
* becomes an own property instead of replacing the object's prototype.
|
|
11
|
+
*/
|
|
12
|
+
function assignOwn(target, key, value) {
|
|
13
|
+
if (key === "__proto__") Object.defineProperty(target, key, {
|
|
14
|
+
value,
|
|
15
|
+
enumerable: true,
|
|
16
|
+
writable: true,
|
|
17
|
+
configurable: true
|
|
18
|
+
});
|
|
19
|
+
else target[key] = value;
|
|
20
|
+
}
|
|
21
|
+
// src/utils/error.utils.ts
|
|
22
|
+
const EXTRA_FIELDS = [
|
|
23
|
+
"code",
|
|
24
|
+
"statusCode",
|
|
25
|
+
"status",
|
|
26
|
+
"errno",
|
|
27
|
+
"syscall",
|
|
28
|
+
"path",
|
|
29
|
+
"address",
|
|
30
|
+
"port",
|
|
31
|
+
"type"
|
|
32
|
+
];
|
|
33
|
+
const SKIPPED_FIELDS = /* @__PURE__ */ new Set([
|
|
34
|
+
"name",
|
|
35
|
+
"message",
|
|
36
|
+
"stack",
|
|
37
|
+
"cause",
|
|
38
|
+
"errors",
|
|
39
|
+
...EXTRA_FIELDS
|
|
40
|
+
]);
|
|
41
|
+
const NO_OPTIONS = Object.freeze({});
|
|
42
|
+
const NO_FIELDS = [];
|
|
43
|
+
/**
|
|
44
|
+
* Serialize an Error into a plain JSON-safe object, including:
|
|
45
|
+
* - `name`, `message`, `stack`
|
|
46
|
+
* - `cause` (recursively serialized, full ES2022 chain)
|
|
47
|
+
* - `errors` (for AggregateError)
|
|
48
|
+
* - standard Node.js error fields (`code`, `statusCode`, `errno`, …)
|
|
49
|
+
* - any other enumerable own properties
|
|
50
|
+
*/
|
|
51
|
+
function serializeError(error, options = NO_OPTIONS) {
|
|
52
|
+
const { includeStack = true, maxDepth = 5, excludeFields = NO_FIELDS } = options;
|
|
53
|
+
return _serializeError(error, includeStack, maxDepth, excludeFields, 0, /* @__PURE__ */ new WeakSet());
|
|
54
|
+
}
|
|
55
|
+
function _serializeError(error, includeStack, maxDepth, excludeFields, depth, seen) {
|
|
56
|
+
if (depth >= maxDepth) return {
|
|
57
|
+
name: error.name,
|
|
58
|
+
message: error.message,
|
|
59
|
+
_truncated: true
|
|
60
|
+
};
|
|
61
|
+
if (seen.has(error)) return {
|
|
62
|
+
name: error.name,
|
|
63
|
+
message: error.message,
|
|
64
|
+
_circular: true
|
|
65
|
+
};
|
|
66
|
+
seen.add(error);
|
|
67
|
+
const serialized = {
|
|
68
|
+
name: error.name,
|
|
69
|
+
message: error.message
|
|
70
|
+
};
|
|
71
|
+
if (includeStack && error.stack) serialized.stack = error.stack;
|
|
72
|
+
const errorWithCause = error;
|
|
73
|
+
if (errorWithCause.cause !== void 0) {
|
|
74
|
+
if (errorWithCause.cause instanceof Error) serialized.cause = _serializeError(errorWithCause.cause, includeStack, maxDepth, excludeFields, depth + 1, seen);
|
|
75
|
+
else serialized.cause = serializeValue(errorWithCause.cause, maxDepth - depth - 1, seen);
|
|
76
|
+
}
|
|
77
|
+
const aggregateError = error;
|
|
78
|
+
if (Array.isArray(aggregateError.errors)) serialized.errors = aggregateError.errors.map((e) => e instanceof Error ? _serializeError(e, includeStack, maxDepth, excludeFields, depth + 1, seen) : serializeValue(e, maxDepth - depth - 1, seen));
|
|
79
|
+
const errorRecord = error;
|
|
80
|
+
for (const field of EXTRA_FIELDS) if (!excludeFields.includes(field) && errorRecord[field] !== void 0) serialized[field] = errorRecord[field];
|
|
81
|
+
const skip = excludeFields.length === 0 ? SKIPPED_FIELDS : /* @__PURE__ */ new Set([...SKIPPED_FIELDS, ...excludeFields]);
|
|
82
|
+
for (const key of Object.getOwnPropertyNames(error)) {
|
|
83
|
+
if (skip.has(key)) continue;
|
|
84
|
+
try {
|
|
85
|
+
assignOwn(serialized, key, serializeValue(errorRecord[key], maxDepth - depth - 1, seen));
|
|
86
|
+
} catch {
|
|
87
|
+
assignOwn(serialized, key, "[Unserializable]");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return serialized;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Recursively serialize an arbitrary value to a JSON-safe representation.
|
|
94
|
+
*
|
|
95
|
+
* The `seen` guard is threaded through (not recreated) so cross-referencing
|
|
96
|
+
* errors nested inside plain objects/arrays are caught by the same circular
|
|
97
|
+
* check that protects the top-level error tree, rather than only relying on the
|
|
98
|
+
* depth limit.
|
|
99
|
+
*/
|
|
100
|
+
function serializeValue(value, remainingDepth, seen) {
|
|
101
|
+
if (remainingDepth <= 0) return "[Max Depth]";
|
|
102
|
+
if (value === null || value === void 0) return value;
|
|
103
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
|
|
104
|
+
if (value instanceof Date) return value.toISOString();
|
|
105
|
+
if (value instanceof Error) {
|
|
106
|
+
if (seen.has(value)) return {
|
|
107
|
+
name: value.name,
|
|
108
|
+
message: value.message,
|
|
109
|
+
_circular: true
|
|
110
|
+
};
|
|
111
|
+
return _serializeError(value, true, remainingDepth, [], 0, seen);
|
|
112
|
+
}
|
|
113
|
+
if (Array.isArray(value)) {
|
|
114
|
+
if (seen.has(value)) return "[Circular]";
|
|
115
|
+
seen.add(value);
|
|
116
|
+
return value.map((item) => serializeValue(item, remainingDepth - 1, seen));
|
|
117
|
+
}
|
|
118
|
+
if (typeof value === "object") {
|
|
119
|
+
if (seen.has(value)) return "[Circular]";
|
|
120
|
+
seen.add(value);
|
|
121
|
+
const out = {};
|
|
122
|
+
for (const [k, v] of Object.entries(value)) try {
|
|
123
|
+
assignOwn(out, k, serializeValue(v, remainingDepth - 1, seen));
|
|
124
|
+
} catch {
|
|
125
|
+
assignOwn(out, k, "[Unserializable]");
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
return String(value);
|
|
130
|
+
}
|
|
131
|
+
// src/utils/internal-log.ts
|
|
132
|
+
/**
|
|
133
|
+
* Internal logging helpers for use within the logixia library itself.
|
|
134
|
+
*
|
|
135
|
+
* These functions write directly to stderr/stdout without going through
|
|
136
|
+
* LogixiaLogger — this avoids circular dependencies and ensures internal
|
|
137
|
+
* diagnostics still surface even when the logger is misconfigured.
|
|
138
|
+
*
|
|
139
|
+
* Library code must NEVER call console.log/warn/error directly. Use these
|
|
140
|
+
* helpers instead so that internal output can be silenced in tests by setting
|
|
141
|
+
* the LOGIXIA_SILENT_INTERNAL=1 environment variable.
|
|
142
|
+
*/
|
|
143
|
+
/**
|
|
144
|
+
* Read the silence flag on each call rather than caching it at import time, so
|
|
145
|
+
* setting LOGIXIA_SILENT_INTERNAL=1 AFTER the module is first imported (e.g. in
|
|
146
|
+
* a test setup file) still takes effect — the documented test-silencing
|
|
147
|
+
* behavior was previously unreliable because the value was frozen at load.
|
|
148
|
+
*/
|
|
149
|
+
function isSilent() {
|
|
150
|
+
var _process$env;
|
|
151
|
+
if (typeof process !== "undefined" && ((_process$env = process.env) === null || _process$env === void 0 ? void 0 : _process$env.LOGIXIA_SILENT_INTERNAL) === "1") return true;
|
|
152
|
+
const flag = globalThis["LOGIXIA_SILENT_INTERNAL"];
|
|
153
|
+
return flag === "1" || flag === 1 || flag === true;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Write a line to stderr, falling back to the matching console method where
|
|
157
|
+
* `process` is unavailable (browsers, Cloudflare Workers, Deno without Node compat).
|
|
158
|
+
*/
|
|
159
|
+
function writeLine(method, line) {
|
|
160
|
+
var _process$stderr;
|
|
161
|
+
if (typeof process !== "undefined" && typeof ((_process$stderr = process.stderr) === null || _process$stderr === void 0 ? void 0 : _process$stderr.write) === "function") process.stderr.write(`${line}\n`);
|
|
162
|
+
else if (typeof console !== "undefined" && typeof console[method] === "function") console[method](line);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Emit an internal error to stderr.
|
|
166
|
+
* Use when a transport write fails or a serious internal error occurs.
|
|
167
|
+
*/
|
|
168
|
+
function internalError(message, error) {
|
|
169
|
+
if (!isSilent()) {
|
|
170
|
+
let errStr = "";
|
|
171
|
+
if (error instanceof Error) errStr = ` — ${error.message}`;
|
|
172
|
+
else if (error != null) errStr = ` — ${String(error)}`;
|
|
173
|
+
writeLine("error", `[logixia:error] ${message}${errStr}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// src/utils/trace.utils.ts
|
|
177
|
+
/**
|
|
178
|
+
* Trace ID utilities for Logitron
|
|
179
|
+
*/
|
|
180
|
+
/** Default key used to store the trace ID in AsyncLocalStorage. */
|
|
181
|
+
const TRACE_CONTEXT_KEY = "traceId";
|
|
182
|
+
/**
|
|
183
|
+
* Singleton that owns the AsyncLocalStorage and the active contextKey.
|
|
184
|
+
*
|
|
185
|
+
* Why a class instead of bare module-level variables?
|
|
186
|
+
* - The contextKey is user-configurable; encapsulating it here means there is
|
|
187
|
+
* exactly one place that reads and writes it.
|
|
188
|
+
* - All helpers (getCurrentTraceId, runWithTraceId, etc.) delegate to this
|
|
189
|
+
* instance, so the key is always in sync without hidden global state.
|
|
190
|
+
* - Easier to test: you can reset the singleton between test cases.
|
|
191
|
+
*
|
|
192
|
+
* Usage (advanced):
|
|
193
|
+
* import { TraceContext } from 'logixia';
|
|
194
|
+
* TraceContext.instance.contextKey // → 'traceId' (or custom)
|
|
195
|
+
* TraceContext.instance.getCurrentTraceId() // same as standalone fn
|
|
196
|
+
*/
|
|
197
|
+
var TraceContext = class TraceContext {
|
|
198
|
+
static _instance = null;
|
|
199
|
+
storage = new node_async_hooks.AsyncLocalStorage();
|
|
200
|
+
_contextKey = TRACE_CONTEXT_KEY;
|
|
201
|
+
constructor() {}
|
|
202
|
+
/** The process-wide singleton. */
|
|
203
|
+
static get instance() {
|
|
204
|
+
if (!TraceContext._instance) TraceContext._instance = new TraceContext();
|
|
205
|
+
return TraceContext._instance;
|
|
206
|
+
}
|
|
207
|
+
/** @internal Reset the singleton (useful in tests). */
|
|
208
|
+
static _reset() {
|
|
209
|
+
TraceContext._instance = null;
|
|
210
|
+
}
|
|
211
|
+
/** The AsyncLocalStorage key that holds the trace ID value. */
|
|
212
|
+
get contextKey() {
|
|
213
|
+
return this._contextKey;
|
|
214
|
+
}
|
|
215
|
+
/** @internal Called by TraceMiddleware when it boots to register the user's key. */
|
|
216
|
+
setContextKey(key) {
|
|
217
|
+
this._contextKey = key;
|
|
218
|
+
}
|
|
219
|
+
/** UUID v4 generator (default). */
|
|
220
|
+
generate() {
|
|
221
|
+
return (0, node_crypto.randomUUID)();
|
|
222
|
+
}
|
|
223
|
+
/** Read the trace ID from the current async context. */
|
|
224
|
+
getCurrentTraceId() {
|
|
225
|
+
var _this$storage$getStor;
|
|
226
|
+
return (_this$storage$getStor = this.storage.getStore()) === null || _this$storage$getStor === void 0 ? void 0 : _this$storage$getStor[this._contextKey];
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Mutate the CURRENT async context in-place.
|
|
230
|
+
*
|
|
231
|
+
* ⚠️ DEPRECATED — unsafe for concurrent requests.
|
|
232
|
+
*
|
|
233
|
+
* Uses `AsyncLocalStorage.enterWith()`, which mutates the current async
|
|
234
|
+
* execution context and every Promise chain spawned from it. In a server
|
|
235
|
+
* processing overlapping requests this can cause a trace ID set for one
|
|
236
|
+
* request to bleed into *other* in-flight requests that share the same
|
|
237
|
+
* async parent (e.g. a module-level setup function or a cached handler).
|
|
238
|
+
*
|
|
239
|
+
* Use {@link run} instead — it scopes the context to a callback so there
|
|
240
|
+
* is no risk of cross-request leakage.
|
|
241
|
+
*
|
|
242
|
+
* @deprecated Use `TraceContext.instance.run(traceId, fn)` — do not call
|
|
243
|
+
* `setTraceId` from request-handling code.
|
|
244
|
+
*/
|
|
245
|
+
setTraceId(traceId, data) {
|
|
246
|
+
const current = this.storage.getStore() ?? {};
|
|
247
|
+
this.storage.enterWith({
|
|
248
|
+
...current,
|
|
249
|
+
[this._contextKey]: traceId,
|
|
250
|
+
...data
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
/** Run `fn` inside a new async context that carries `traceId`. */
|
|
254
|
+
run(traceId, fn, data) {
|
|
255
|
+
return this.storage.run({
|
|
256
|
+
[this._contextKey]: traceId,
|
|
257
|
+
...data
|
|
258
|
+
}, fn);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
TraceContext.instance.storage;
|
|
262
|
+
/** Generate a UUID v4 trace ID. */
|
|
263
|
+
function generateTraceId() {
|
|
264
|
+
return TraceContext.instance.generate();
|
|
265
|
+
}
|
|
266
|
+
/** Run `fn` inside a new async context carrying `traceId`. */
|
|
267
|
+
function runWithTraceId(traceId, fn, data) {
|
|
268
|
+
return TraceContext.instance.run(traceId, fn, data);
|
|
269
|
+
}
|
|
270
|
+
const SAFE_INCOMING_ID = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
271
|
+
/**
|
|
272
|
+
* Validate an externally supplied identifier (trace ID, correlation ID, origin
|
|
273
|
+
* service name, message-queue ID). Accepts only 1-128 characters from
|
|
274
|
+
* `[A-Za-z0-9._:-]`; surrounding whitespace is trimmed first. Arrays use their
|
|
275
|
+
* first element. Returns the cleaned value, or `undefined` when it is unusable
|
|
276
|
+
* so callers can generate a fresh ID instead of passing client text through.
|
|
277
|
+
*/
|
|
278
|
+
function sanitizeIncomingId(value) {
|
|
279
|
+
const first = Array.isArray(value) ? value[0] : value;
|
|
280
|
+
if (typeof first !== "string" || first.length > 256) return void 0;
|
|
281
|
+
const trimmed = first.trim();
|
|
282
|
+
return SAFE_INCOMING_ID.test(trimmed) ? trimmed : void 0;
|
|
283
|
+
}
|
|
284
|
+
/** W3C trace-context: `version-traceId(32hex)-spanId(16hex)-flags(2hex)`. */
|
|
285
|
+
const W3C_TRACEPARENT_RE = /^[\da-f]{2}-([\da-f]{32})-[\da-f]{16}-[\da-f]{2}$/i;
|
|
286
|
+
/**
|
|
287
|
+
* Extract the 32-hex trace-id segment from a W3C `traceparent` header value.
|
|
288
|
+
* Returns the parsed trace ID, or the original value unchanged when it is not a
|
|
289
|
+
* well-formed traceparent (so non-W3C propagation still works).
|
|
290
|
+
*/
|
|
291
|
+
function parseTraceparent(value) {
|
|
292
|
+
const m = W3C_TRACEPARENT_RE.exec(value);
|
|
293
|
+
return m ? m[1] : value;
|
|
294
|
+
}
|
|
295
|
+
/** Extract trace ID from request using configuration (header → query → body → params). */
|
|
296
|
+
function extractTraceId(request, config) {
|
|
297
|
+
const req = request;
|
|
298
|
+
if (config.header) {
|
|
299
|
+
const headers = Array.isArray(config.header) ? config.header : [config.header];
|
|
300
|
+
for (const header of headers) {
|
|
301
|
+
var _req$headers;
|
|
302
|
+
const lower = header.toLowerCase();
|
|
303
|
+
const value = sanitizeIncomingId((_req$headers = req.headers) === null || _req$headers === void 0 ? void 0 : _req$headers[lower]);
|
|
304
|
+
if (value) return lower === "traceparent" ? parseTraceparent(value) : value;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (config.query) {
|
|
308
|
+
const queries = Array.isArray(config.query) ? config.query : [config.query];
|
|
309
|
+
for (const query of queries) {
|
|
310
|
+
var _req$query;
|
|
311
|
+
const value = sanitizeIncomingId((_req$query = req.query) === null || _req$query === void 0 ? void 0 : _req$query[query]);
|
|
312
|
+
if (value) return value;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (config.body) {
|
|
316
|
+
const bodyFields = Array.isArray(config.body) ? config.body : [config.body];
|
|
317
|
+
for (const field of bodyFields) {
|
|
318
|
+
var _req$body;
|
|
319
|
+
const value = sanitizeIncomingId((_req$body = req.body) === null || _req$body === void 0 ? void 0 : _req$body[field]);
|
|
320
|
+
if (value) return value;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (config.params) {
|
|
324
|
+
const paramFields = Array.isArray(config.params) ? config.params : [config.params];
|
|
325
|
+
for (const param of paramFields) {
|
|
326
|
+
var _req$params;
|
|
327
|
+
const value = sanitizeIncomingId((_req$params = req.params) === null || _req$params === void 0 ? void 0 : _req$params[param]);
|
|
328
|
+
if (value) return value;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Default headers checked for incoming trace ID propagation, in priority order:
|
|
334
|
+
* traceparent (W3C/OTel) → x-trace-id → x-request-id → x-correlation-id → trace-id
|
|
335
|
+
*/
|
|
336
|
+
const DEFAULT_TRACE_HEADERS = [
|
|
337
|
+
"traceparent",
|
|
338
|
+
"x-trace-id",
|
|
339
|
+
"x-request-id",
|
|
340
|
+
"x-correlation-id",
|
|
341
|
+
"trace-id"
|
|
342
|
+
];
|
|
343
|
+
// src/utils/request-trace.ts
|
|
344
|
+
/** Header names to read a trace ID from, defaulting to the library-wide list. */
|
|
345
|
+
function resolveTraceHeaders(option) {
|
|
346
|
+
if (option === void 0) return DEFAULT_TRACE_HEADERS;
|
|
347
|
+
return typeof option === "string" ? [option] : option;
|
|
348
|
+
}
|
|
349
|
+
// src/utils/sensitive-names.ts
|
|
350
|
+
/** Query-string parameters whose values are never logged. */
|
|
351
|
+
const DEFAULT_REDACT_QUERY_PARAMS = [
|
|
352
|
+
"token",
|
|
353
|
+
"access_token",
|
|
354
|
+
"refresh_token",
|
|
355
|
+
"code",
|
|
356
|
+
"password",
|
|
357
|
+
"secret",
|
|
358
|
+
"api_key",
|
|
359
|
+
"apikey",
|
|
360
|
+
"key",
|
|
361
|
+
"signature",
|
|
362
|
+
"sig",
|
|
363
|
+
"auth",
|
|
364
|
+
"accesstoken",
|
|
365
|
+
"refreshtoken",
|
|
366
|
+
"id_token",
|
|
367
|
+
"idtoken",
|
|
368
|
+
"client_secret",
|
|
369
|
+
"clientsecret",
|
|
370
|
+
"session",
|
|
371
|
+
"sessionid",
|
|
372
|
+
"session_id",
|
|
373
|
+
"jwt",
|
|
374
|
+
"auth_token",
|
|
375
|
+
"authtoken",
|
|
376
|
+
"api-key",
|
|
377
|
+
"x-api-key",
|
|
378
|
+
"x-amz-signature",
|
|
379
|
+
"x-amz-credential",
|
|
380
|
+
"x-amz-security-token",
|
|
381
|
+
"x-goog-signature",
|
|
382
|
+
"x-goog-credential",
|
|
383
|
+
"access-token",
|
|
384
|
+
"x-access-token",
|
|
385
|
+
"x-auth-token",
|
|
386
|
+
"apitoken",
|
|
387
|
+
"api_token"
|
|
388
|
+
];
|
|
389
|
+
function safeDecode(value) {
|
|
390
|
+
try {
|
|
391
|
+
return decodeURIComponent(value.replace(/\+/g, " "));
|
|
392
|
+
} catch {
|
|
393
|
+
return value;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
/** Replace the values of sensitive query parameters, leaving the rest verbatim. */
|
|
397
|
+
function redactUrlQuery(url, redactParams) {
|
|
398
|
+
const q = url.indexOf("?");
|
|
399
|
+
if (q === -1) return url;
|
|
400
|
+
const hashAt = url.indexOf("#", q);
|
|
401
|
+
const query = url.slice(q + 1, hashAt === -1 ? void 0 : hashAt);
|
|
402
|
+
const hash = hashAt === -1 ? "" : url.slice(hashAt);
|
|
403
|
+
const cleaned = query.split("&").map((pair) => {
|
|
404
|
+
const eq = pair.indexOf("=");
|
|
405
|
+
const rawKey = eq === -1 ? pair : pair.slice(0, eq);
|
|
406
|
+
const decoded = safeDecode(rawKey);
|
|
407
|
+
const bracket = decoded.indexOf("[");
|
|
408
|
+
const name = (bracket === -1 ? decoded : decoded.slice(0, bracket)).toLowerCase();
|
|
409
|
+
return redactParams.has(name) && eq !== -1 ? `${rawKey}=[REDACTED]` : pair;
|
|
410
|
+
}).join("&");
|
|
411
|
+
return `${url.slice(0, q)}?${cleaned}${hash}`;
|
|
412
|
+
}
|
|
413
|
+
/** Lower-cased lookup set of the default names plus any extras. */
|
|
414
|
+
function buildNameSet(defaults, extra) {
|
|
415
|
+
return new Set([...defaults, ...extra ?? []].map((n) => n.toLowerCase()));
|
|
416
|
+
}
|
|
417
|
+
// src/hono/middleware.ts
|
|
418
|
+
/**
|
|
419
|
+
* Hono request logging middleware: trace ID, response header and a completion entry.
|
|
420
|
+
*
|
|
421
|
+
* Only structural types are used, so it works with any Hono version and runs on Node,
|
|
422
|
+
* Bun and Cloudflare Workers (`nodejs_compat`, for `AsyncLocalStorage`).
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* ```ts
|
|
426
|
+
* import { Hono } from 'hono';
|
|
427
|
+
* import { createHonoMiddleware } from 'logixia/hono';
|
|
428
|
+
*
|
|
429
|
+
* const app = new Hono();
|
|
430
|
+
* app.use(createHonoMiddleware(logger));
|
|
431
|
+
* ```
|
|
432
|
+
*/
|
|
433
|
+
/** Fire-and-forget: a failing log call must never fail the request. */
|
|
434
|
+
function emit(logger, level, message, data) {
|
|
435
|
+
try {
|
|
436
|
+
const result = logger[level](message, data);
|
|
437
|
+
if (result && typeof result.catch === "function") result.catch((error) => internalError("hono middleware: log call failed", error));
|
|
438
|
+
} catch (error) {
|
|
439
|
+
internalError("hono middleware: log call failed", error);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
/** Pathname plus the query string with secret parameters redacted, from an absolute or relative URL. */
|
|
443
|
+
function loggedPath(url, params) {
|
|
444
|
+
const schemeEnd = url.indexOf("://");
|
|
445
|
+
const pathStart = schemeEnd === -1 ? 0 : url.indexOf("/", schemeEnd + 3);
|
|
446
|
+
return pathStart === -1 ? "/" : redactUrlQuery(url.slice(pathStart), params);
|
|
447
|
+
}
|
|
448
|
+
function ensureHeader(c, name, value) {
|
|
449
|
+
try {
|
|
450
|
+
if (c.res.headers.get(name) === value) return;
|
|
451
|
+
c.res.headers.set(name, value);
|
|
452
|
+
} catch {
|
|
453
|
+
const copy = new Response(c.res.body, c.res);
|
|
454
|
+
copy.headers.set(name, value);
|
|
455
|
+
c.res = copy;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Create a Hono middleware (`app.use(...)`).
|
|
460
|
+
*
|
|
461
|
+
* Per request it resolves the trace ID from headers, sets it on the response and on
|
|
462
|
+
* `c.var.traceId`, runs the rest of the request inside {@link runWithTraceId} and logs
|
|
463
|
+
* one entry when the request completes: `method`, `path` (query secrets redacted),
|
|
464
|
+
* `status`, `duration` in ms and `traceId`. Responses with status 500 and above, and
|
|
465
|
+
* errors thrown by handlers, are logged at `error`; other thrown errors at `warn`.
|
|
466
|
+
*/
|
|
467
|
+
function createHonoMiddleware(logger, options = {}) {
|
|
468
|
+
const { skip, extraFields, responseHeader = "x-trace-id" } = options;
|
|
469
|
+
const traceHeaders = resolveTraceHeaders(options.traceIdHeader);
|
|
470
|
+
const params = buildNameSet(DEFAULT_REDACT_QUERY_PARAMS, options.redactQueryParams);
|
|
471
|
+
return async function logixiaHonoMiddleware(c, next) {
|
|
472
|
+
if (skip === null || skip === void 0 ? void 0 : skip(c)) return next();
|
|
473
|
+
const headers = {};
|
|
474
|
+
for (const name of traceHeaders) {
|
|
475
|
+
const key = name.toLowerCase();
|
|
476
|
+
headers[key] = c.req.header(key);
|
|
477
|
+
}
|
|
478
|
+
const traceId = extractTraceId({ headers }, { header: [...traceHeaders] }) ?? generateTraceId();
|
|
479
|
+
const start = Date.now();
|
|
480
|
+
c.set("traceId", traceId);
|
|
481
|
+
if (responseHeader) c.header(responseHeader, traceId);
|
|
482
|
+
await runWithTraceId(traceId, async () => {
|
|
483
|
+
let thrown;
|
|
484
|
+
try {
|
|
485
|
+
await next();
|
|
486
|
+
} catch (error) {
|
|
487
|
+
thrown = error;
|
|
488
|
+
}
|
|
489
|
+
const failure = thrown ?? c.error;
|
|
490
|
+
if (responseHeader && thrown === void 0) ensureHeader(c, responseHeader, traceId);
|
|
491
|
+
const status = thrown === void 0 ? c.res.status : 500;
|
|
492
|
+
const entry = {
|
|
493
|
+
traceId,
|
|
494
|
+
method: c.req.method,
|
|
495
|
+
path: loggedPath(c.req.url, params),
|
|
496
|
+
status,
|
|
497
|
+
duration: Date.now() - start,
|
|
498
|
+
...failure === void 0 ? {} : { error: serializeError(toError(failure)) },
|
|
499
|
+
...extraFields === null || extraFields === void 0 ? void 0 : extraFields(c)
|
|
500
|
+
};
|
|
501
|
+
if (failure !== void 0) emit(logger, status >= 500 ? "error" : "warn", "request failed", entry);
|
|
502
|
+
else emit(logger, status >= 500 ? "error" : "info", "request completed", entry);
|
|
503
|
+
if (thrown !== void 0) throw thrown;
|
|
504
|
+
});
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
function toError(value) {
|
|
508
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
509
|
+
}
|
|
510
|
+
exports.createHonoMiddleware = createHonoMiddleware;
|
|
511
|
+
|
|
512
|
+
//# sourceMappingURL=hono.js.map
|
package/dist/hono.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hono.js","names":["AsyncLocalStorage","randomUUID"],"sources":["../src/utils/own-property.ts","../src/utils/error.utils.ts","../src/utils/internal-log.ts","../src/utils/trace.utils.ts","../src/utils/request-trace.ts","../src/utils/sensitive-names.ts","../src/hono/middleware.ts"],"sourcesContent":["/**\n * True for the one key that must never be assigned with `target[key] = value`.\n *\n * Assigning `constructor` or `prototype` on a fresh plain object only creates an\n * own property, which is harmless. Only `__proto__` invokes the prototype setter.\n */\nexport function isProtoKey(key: string): boolean {\n return key === '__proto__';\n}\n\n/**\n * Copy `value` onto `target[key]` as an own, enumerable data property.\n *\n * Normal keys use a plain assignment, which is the fast path. `__proto__` goes\n * through `Object.defineProperty` so that a key taken from logged or parsed data\n * becomes an own property instead of replacing the object's prototype.\n */\nexport function assignOwn(target: object, key: string, value: unknown): void {\n if (key === '__proto__') {\n Object.defineProperty(target, key, {\n value,\n enumerable: true,\n writable: true,\n configurable: true,\n });\n } else {\n (target as Record<string, unknown>)[key] = value;\n }\n}\n","/**\n * Error serialization utilities for Logixia\n *\n * v1.1 improvements:\n * - Full ES2022 `cause` chain serialization (recursive)\n * - AggregateError.errors array serialization\n * - Standard extra fields: code, statusCode, status, errno, syscall, path\n * - Circular-reference safe via a WeakSet seen guard\n */\n\nimport type { ErrorSerializationOptions } from '../types';\nimport { assignOwn } from './own-property';\n\n// Well-known extra fields to always capture when present on an error\nconst EXTRA_FIELDS = [\n 'code',\n 'statusCode',\n 'status',\n 'errno',\n 'syscall',\n 'path',\n 'address',\n 'port',\n 'type',\n] as const;\n\n// Fields the own-property pass skips, built once instead of per error.\nconst SKIPPED_FIELDS = new Set<string>([\n 'name',\n 'message',\n 'stack',\n 'cause',\n 'errors',\n ...EXTRA_FIELDS,\n]);\nconst NO_OPTIONS: ErrorSerializationOptions = Object.freeze({});\nconst NO_FIELDS: string[] = [];\n\n/**\n * Serialize an Error into a plain JSON-safe object, including:\n * - `name`, `message`, `stack`\n * - `cause` (recursively serialized, full ES2022 chain)\n * - `errors` (for AggregateError)\n * - standard Node.js error fields (`code`, `statusCode`, `errno`, …)\n * - any other enumerable own properties\n */\nexport function serializeError(\n error: Error,\n options: ErrorSerializationOptions = NO_OPTIONS\n): Record<string, unknown> {\n const { includeStack = true, maxDepth = 5, excludeFields = NO_FIELDS } = options;\n const seen = new WeakSet<object>();\n return _serializeError(error, includeStack, maxDepth, excludeFields, 0, seen);\n}\n\nfunction _serializeError(\n error: Error,\n includeStack: boolean,\n maxDepth: number,\n excludeFields: string[],\n depth: number,\n seen: WeakSet<object>\n): Record<string, unknown> {\n if (depth >= maxDepth) {\n return { name: error.name, message: error.message, _truncated: true };\n }\n\n if (seen.has(error)) {\n return { name: error.name, message: error.message, _circular: true };\n }\n seen.add(error);\n\n const serialized: Record<string, unknown> = {\n name: error.name,\n message: error.message,\n };\n\n if (includeStack && error.stack) {\n serialized.stack = error.stack;\n }\n\n // ── ES2022 cause chain ──────────────────────────────────────────────────────\n const errorWithCause = error as Error & { cause?: unknown };\n if (errorWithCause.cause !== undefined) {\n if (errorWithCause.cause instanceof Error) {\n serialized.cause = _serializeError(\n errorWithCause.cause,\n includeStack,\n maxDepth,\n excludeFields,\n depth + 1,\n seen\n );\n } else {\n serialized.cause = serializeValue(errorWithCause.cause, maxDepth - depth - 1, seen);\n }\n }\n\n // ── AggregateError.errors ───────────────────────────────────────────────────\n const aggregateError = error as Error & { errors?: unknown[] };\n if (Array.isArray(aggregateError.errors)) {\n serialized.errors = aggregateError.errors.map((e) =>\n e instanceof Error\n ? _serializeError(e, includeStack, maxDepth, excludeFields, depth + 1, seen)\n : serializeValue(e, maxDepth - depth - 1, seen)\n );\n }\n\n // ── Standard Node.js / HTTP error fields ───────────────────────────────────\n const errorRecord = error as unknown as Record<string, unknown>;\n for (const field of EXTRA_FIELDS) {\n if (!excludeFields.includes(field) && errorRecord[field] !== undefined) {\n serialized[field] = errorRecord[field];\n }\n }\n\n // ── All other own enumerable properties ────────────────────────────────────\n const skip =\n excludeFields.length === 0 ? SKIPPED_FIELDS : new Set([...SKIPPED_FIELDS, ...excludeFields]);\n\n for (const key of Object.getOwnPropertyNames(error)) {\n if (skip.has(key)) continue;\n try {\n assignOwn(serialized, key, serializeValue(errorRecord[key], maxDepth - depth - 1, seen));\n } catch {\n assignOwn(serialized, key, '[Unserializable]');\n }\n }\n\n return serialized;\n}\n\n/**\n * Recursively serialize an arbitrary value to a JSON-safe representation.\n *\n * The `seen` guard is threaded through (not recreated) so cross-referencing\n * errors nested inside plain objects/arrays are caught by the same circular\n * check that protects the top-level error tree, rather than only relying on the\n * depth limit.\n */\nfunction serializeValue(value: unknown, remainingDepth: number, seen: WeakSet<object>): unknown {\n if (remainingDepth <= 0) return '[Max Depth]';\n if (value === null || value === undefined) return value;\n\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return value;\n }\n\n if (value instanceof Date) return value.toISOString();\n\n if (value instanceof Error) {\n if (seen.has(value)) {\n return { name: value.name, message: value.message, _circular: true };\n }\n return _serializeError(value, true, remainingDepth, [], 0, seen);\n }\n\n if (Array.isArray(value)) {\n if (seen.has(value)) return '[Circular]';\n seen.add(value);\n return value.map((item) => serializeValue(item, remainingDepth - 1, seen));\n }\n\n if (typeof value === 'object') {\n if (seen.has(value)) return '[Circular]';\n seen.add(value);\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n try {\n assignOwn(out, k, serializeValue(v, remainingDepth - 1, seen));\n } catch {\n assignOwn(out, k, '[Unserializable]');\n }\n }\n return out;\n }\n\n return String(value);\n}\n\n/**\n * Type guard: returns true if the value looks like an Error object.\n */\nexport function isError(value: unknown): value is Error {\n return (\n value instanceof Error ||\n (Boolean(value) &&\n typeof value === 'object' &&\n 'name' in (value as object) &&\n 'message' in (value as object))\n );\n}\n\nconst MAX_ERROR_SEARCH_DEPTH = 3;\nconst MAX_ERROR_SEARCH_NODES = 2000;\n\n/**\n * Replaces real Error instances inside a log payload with their serialized form,\n * because JSON output drops an Error's non-enumerable `message` and `stack`. Runs on\n * every log call, so its work is capped and it copies nothing until it finds one.\n * Duck-typed objects are data, and an Error with its own toJSON has already chosen\n * what to show. The caller's objects are never mutated.\n */\nexport function serializeNestedErrors(data: Record<string, unknown>): Record<string, unknown> {\n // Saved and restored, because a getter read during the walk can log and re-enter.\n const outerBudget = errorSearchBudget;\n errorSearchBudget = MAX_ERROR_SEARCH_NODES;\n try {\n return walkForErrors(data, MAX_ERROR_SEARCH_DEPTH, undefined, undefined) as Record<\n string,\n unknown\n >;\n } finally {\n errorSearchBudget = outerBudget;\n }\n}\n\nlet errorSearchBudget = 0;\nconst hasOwn = Object.prototype.hasOwnProperty;\n\n// Allocates nothing until it finds an Error. With the depth cap, a node has at most\n// two ancestors that can still recurse, so they are passed as arguments for the cycle check.\nfunction walkForErrors(\n value: object,\n depth: number,\n parent?: object,\n grandparent?: object\n): unknown {\n if (value instanceof Error) {\n return typeof (value as { toJSON?: unknown }).toJSON === 'function'\n ? value\n : serializeError(value);\n }\n if (depth === 0 || --errorSearchBudget < 0 || value === parent || value === grandparent) {\n return value;\n }\n\n let copy: unknown;\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const item: unknown = value[i];\n if (item === null || typeof item !== 'object') continue;\n const next = walkForErrors(item, depth - 1, value, parent);\n if (next !== item) {\n copy ??= value.slice();\n (copy as unknown[])[i] = next;\n }\n }\n } else {\n const proto: unknown = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return value;\n const record = value as Record<string, unknown>;\n // for...in avoids the key array that Object.keys allocates on every call.\n for (const key in record) {\n if (!hasOwn.call(record, key)) continue;\n let item: unknown;\n try {\n item = record[key];\n } catch {\n continue;\n }\n if (item === null || typeof item !== 'object') continue;\n const next = walkForErrors(item, depth - 1, record, parent);\n if (next !== item) {\n copy ??= { ...record };\n assignOwn(copy as Record<string, unknown>, key, next);\n }\n }\n }\n return copy ?? value;\n}\n\n/**\n * Coerce any thrown value into a proper Error instance.\n */\nexport function normalizeError(error: unknown): Error {\n if (isError(error)) return error;\n\n if (typeof error === 'string') return new Error(error);\n\n if (typeof error === 'object' && error !== null) {\n const e = error as Record<string, unknown>;\n const err = new Error(typeof e['message'] === 'string' ? e['message'] : 'Unknown error');\n Object.assign(err, error);\n return err;\n }\n\n return new Error(String(error));\n}\n","/**\n * Internal logging helpers for use within the logixia library itself.\n *\n * These functions write directly to stderr/stdout without going through\n * LogixiaLogger — this avoids circular dependencies and ensures internal\n * diagnostics still surface even when the logger is misconfigured.\n *\n * Library code must NEVER call console.log/warn/error directly. Use these\n * helpers instead so that internal output can be silenced in tests by setting\n * the LOGIXIA_SILENT_INTERNAL=1 environment variable.\n */\n\n/**\n * Read the silence flag on each call rather than caching it at import time, so\n * setting LOGIXIA_SILENT_INTERNAL=1 AFTER the module is first imported (e.g. in\n * a test setup file) still takes effect — the documented test-silencing\n * behavior was previously unreliable because the value was frozen at load.\n */\nfunction isSilent(): boolean {\n if (typeof process !== 'undefined' && process.env?.LOGIXIA_SILENT_INTERNAL === '1') return true;\n const flag = (globalThis as Record<string, unknown>)['LOGIXIA_SILENT_INTERNAL'];\n return flag === '1' || flag === 1 || flag === true;\n}\n\ntype ConsoleMethod = 'log' | 'warn' | 'error';\n\n/**\n * Write a line to stderr, falling back to the matching console method where\n * `process` is unavailable (browsers, Cloudflare Workers, Deno without Node compat).\n */\nfunction writeLine(method: ConsoleMethod, line: string): void {\n if (typeof process !== 'undefined' && typeof process.stderr?.write === 'function') {\n process.stderr.write(`${line}\\n`);\n } else if (typeof console !== 'undefined' && typeof console[method] === 'function') {\n console[method](line);\n }\n}\n\n/**\n * Emit an internal debug/info message to stderr.\n * Use for field-enable/disable notifications that a developer might want to see\n * during development but should not appear in production log streams.\n */\nexport function internalLog(message: string): void {\n if (!isSilent()) {\n writeLine('log', `[logixia] ${message}`);\n }\n}\n\n/**\n * Emit an internal warning to stderr.\n * Use when something is misconfigured but logixia can continue operating.\n */\nexport function internalWarn(message: string): void {\n if (!isSilent()) {\n writeLine('warn', `[logixia:warn] ${message}`);\n }\n}\n\n/**\n * Emit an internal error to stderr.\n * Use when a transport write fails or a serious internal error occurs.\n */\nexport function internalError(message: string, error?: unknown): void {\n if (!isSilent()) {\n let errStr = '';\n if (error instanceof Error) {\n errStr = ` — ${error.message}`;\n } else if (error != null) {\n errStr = ` — ${String(error)}`;\n }\n writeLine('error', `[logixia:error] ${message}${errStr}`);\n }\n}\n","/**\n * Trace ID utilities for Logitron\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { randomUUID } from 'node:crypto';\n\nimport type { TraceIdConfig, TraceIdExtractorConfig } from '../types';\n\n/** Default key used to store the trace ID in AsyncLocalStorage. */\nexport const TRACE_CONTEXT_KEY = 'traceId' as const;\n\n// ── TraceContext class ────────────────────────────────────────────────────────\n\n/**\n * Singleton that owns the AsyncLocalStorage and the active contextKey.\n *\n * Why a class instead of bare module-level variables?\n * - The contextKey is user-configurable; encapsulating it here means there is\n * exactly one place that reads and writes it.\n * - All helpers (getCurrentTraceId, runWithTraceId, etc.) delegate to this\n * instance, so the key is always in sync without hidden global state.\n * - Easier to test: you can reset the singleton between test cases.\n *\n * Usage (advanced):\n * import { TraceContext } from 'logixia';\n * TraceContext.instance.contextKey // → 'traceId' (or custom)\n * TraceContext.instance.getCurrentTraceId() // same as standalone fn\n */\nexport class TraceContext {\n private static _instance: TraceContext | null = null;\n\n readonly storage = new AsyncLocalStorage<Record<string, unknown>>();\n private _contextKey: string = TRACE_CONTEXT_KEY;\n\n private constructor() {}\n\n /** The process-wide singleton. */\n static get instance(): TraceContext {\n if (!TraceContext._instance) {\n TraceContext._instance = new TraceContext();\n }\n return TraceContext._instance;\n }\n\n /** @internal Reset the singleton (useful in tests). */\n static _reset(): void {\n TraceContext._instance = null;\n }\n\n // ── Key management ──────────────────────────────────────────────────────────\n\n /** The AsyncLocalStorage key that holds the trace ID value. */\n get contextKey(): string {\n return this._contextKey;\n }\n\n /** @internal Called by TraceMiddleware when it boots to register the user's key. */\n setContextKey(key: string): void {\n this._contextKey = key;\n }\n\n // ── Core operations ─────────────────────────────────────────────────────────\n\n /** UUID v4 generator (default). */\n generate(): string {\n return randomUUID();\n }\n\n /** Read the trace ID from the current async context. */\n getCurrentTraceId(): string | undefined {\n return this.storage.getStore()?.[this._contextKey] as string | undefined;\n }\n\n /**\n * Mutate the CURRENT async context in-place.\n *\n * ⚠️ DEPRECATED — unsafe for concurrent requests.\n *\n * Uses `AsyncLocalStorage.enterWith()`, which mutates the current async\n * execution context and every Promise chain spawned from it. In a server\n * processing overlapping requests this can cause a trace ID set for one\n * request to bleed into *other* in-flight requests that share the same\n * async parent (e.g. a module-level setup function or a cached handler).\n *\n * Use {@link run} instead — it scopes the context to a callback so there\n * is no risk of cross-request leakage.\n *\n * @deprecated Use `TraceContext.instance.run(traceId, fn)` — do not call\n * `setTraceId` from request-handling code.\n */\n setTraceId(traceId: string, data?: Record<string, unknown>): void {\n const current = this.storage.getStore() ?? {};\n this.storage.enterWith({ ...current, [this._contextKey]: traceId, ...data });\n }\n\n /** Run `fn` inside a new async context that carries `traceId`. */\n run<T>(traceId: string, fn: () => T, data?: Record<string, unknown>): T {\n return this.storage.run({ [this._contextKey]: traceId, ...data }, fn);\n }\n}\n\n// ── Module-level aliases (backwards-compatible public API) ────────────────────\n\n/**\n * The shared AsyncLocalStorage instance.\n * @deprecated Prefer `TraceContext.instance.storage` for new code.\n */\nexport const traceStorage = TraceContext.instance.storage;\n\n/** Returns the key currently used to store the trace ID in AsyncLocalStorage. */\nexport function getTraceContextKey(): string {\n return TraceContext.instance.contextKey;\n}\n\n/** @internal Called by TraceMiddleware / traceMiddleware() when they boot. */\nexport function _setActiveContextKey(key: string): void {\n TraceContext.instance.setContextKey(key);\n}\n\n/** Generate a UUID v4 trace ID. */\nexport function generateTraceId(): string {\n return TraceContext.instance.generate();\n}\n\n/**\n * Get the current trace ID from async context.\n * Returns `undefined` when called outside a traced request.\n */\nexport function getCurrentTraceId(): string | undefined {\n return TraceContext.instance.getCurrentTraceId();\n}\n\n/**\n * Set trace ID in the CURRENT async context without starting a new one.\n *\n * ⚠️ DEPRECATED — unsafe for concurrent requests.\n *\n * Uses `AsyncLocalStorage.enterWith()`, which mutates the current async\n * execution context and every Promise chain spawned from it. Under load this\n * can cause a trace ID from one request to bleed into others sharing the same\n * async parent.\n *\n * Use {@link runWithTraceId} instead. Migration patterns:\n *\n * **Express / Fastify middleware — before:**\n * ```ts\n * app.use((req, _res, next) => {\n * setTraceId(req.headers['x-trace-id'] ?? generateTraceId());\n * next();\n * });\n * ```\n * **after:**\n * ```ts\n * app.use((req, _res, next) => {\n * runWithTraceId(req.headers['x-trace-id'] ?? generateTraceId(), () => next());\n * });\n * ```\n *\n * **Kafka / queue consumer — before:**\n * ```ts\n * async function handle(msg) {\n * setTraceId(msg.headers['x-trace-id']);\n * await processMessage(msg);\n * }\n * ```\n * **after:**\n * ```ts\n * async function handle(msg) {\n * await runWithTraceId(msg.headers['x-trace-id'], () => processMessage(msg));\n * }\n * ```\n *\n * **Background job — before:**\n * ```ts\n * setTraceId(generateTraceId(), { jobId: job.id });\n * await job.run();\n * ```\n * **after:**\n * ```ts\n * await runWithTraceId(generateTraceId(), () => job.run(), { jobId: job.id });\n * ```\n *\n * @deprecated Use `runWithTraceId(traceId, fn)` — do not call `setTraceId`\n * from request-handling code.\n */\nexport function setTraceId(traceId: string, data?: Record<string, unknown>): void {\n TraceContext.instance.setTraceId(traceId, data);\n}\n\n/** Run `fn` inside a new async context carrying `traceId`. */\nexport function runWithTraceId<T>(traceId: string, fn: () => T, data?: Record<string, unknown>): T {\n return TraceContext.instance.run(traceId, fn, data);\n}\n\n// ── Request extraction ────────────────────────────────────────────────────────\n\ntype HeaderValue = string | string[] | undefined;\n\n/** Shape that extractTraceId accepts (Express-compatible) */\ninterface RequestLike {\n headers?: Record<string, HeaderValue>;\n query?: Record<string, HeaderValue>;\n body?: Record<string, string | undefined>;\n params?: Record<string, string | undefined>;\n}\n\n/** Maximum accepted length for an incoming trace / correlation / request ID. */\nexport const MAX_INCOMING_ID_LENGTH = 128;\n\nconst SAFE_INCOMING_ID = /^[A-Za-z0-9._:-]{1,128}$/;\n\n/**\n * Validate an externally supplied identifier (trace ID, correlation ID, origin\n * service name, message-queue ID). Accepts only 1-128 characters from\n * `[A-Za-z0-9._:-]`; surrounding whitespace is trimmed first. Arrays use their\n * first element. Returns the cleaned value, or `undefined` when it is unusable\n * so callers can generate a fresh ID instead of passing client text through.\n */\nexport function sanitizeIncomingId(value: unknown): string | undefined {\n const first = Array.isArray(value) ? value[0] : value;\n if (typeof first !== 'string' || first.length > MAX_INCOMING_ID_LENGTH * 2) return undefined;\n const trimmed = first.trim();\n return SAFE_INCOMING_ID.test(trimmed) ? trimmed : undefined;\n}\n\n/** W3C trace-context: `version-traceId(32hex)-spanId(16hex)-flags(2hex)`. */\nconst W3C_TRACEPARENT_RE = /^[\\da-f]{2}-([\\da-f]{32})-[\\da-f]{16}-[\\da-f]{2}$/i;\n\n/**\n * Extract the 32-hex trace-id segment from a W3C `traceparent` header value.\n * Returns the parsed trace ID, or the original value unchanged when it is not a\n * well-formed traceparent (so non-W3C propagation still works).\n */\nfunction parseTraceparent(value: string): string {\n const m = W3C_TRACEPARENT_RE.exec(value);\n return m ? m[1]! : value;\n}\n\n/** Extract trace ID from request using configuration (header → query → body → params). */\nexport function extractTraceId(\n request: unknown,\n config: TraceIdExtractorConfig\n): string | undefined {\n const req = request as RequestLike;\n\n if (config.header) {\n const headers = Array.isArray(config.header) ? config.header : [config.header];\n for (const header of headers) {\n const lower = header.toLowerCase();\n const value = sanitizeIncomingId(req.headers?.[lower]);\n if (value) return lower === 'traceparent' ? parseTraceparent(value) : value;\n }\n }\n\n if (config.query) {\n const queries = Array.isArray(config.query) ? config.query : [config.query];\n for (const query of queries) {\n const value = sanitizeIncomingId(req.query?.[query]);\n if (value) return value;\n }\n }\n\n if (config.body) {\n const bodyFields = Array.isArray(config.body) ? config.body : [config.body];\n for (const field of bodyFields) {\n const value = sanitizeIncomingId(req.body?.[field]);\n if (value) return value;\n }\n }\n\n if (config.params) {\n const paramFields = Array.isArray(config.params) ? config.params : [config.params];\n for (const param of paramFields) {\n const value = sanitizeIncomingId(req.params?.[param]);\n if (value) return value;\n }\n }\n\n return undefined;\n}\n\n/**\n * Default headers checked for incoming trace ID propagation, in priority order:\n * traceparent (W3C/OTel) → x-trace-id → x-request-id → x-correlation-id → trace-id\n */\nexport const DEFAULT_TRACE_HEADERS = [\n 'traceparent',\n 'x-trace-id',\n 'x-request-id',\n 'x-correlation-id',\n 'trace-id',\n];\n\n/**\n * Create trace ID middleware for Express/NestJS\n */\nexport function createTraceMiddleware(config: TraceIdConfig) {\n const defaultExtractor = {\n header: DEFAULT_TRACE_HEADERS,\n query: ['traceId', 'trace_id'],\n };\n const resolvedConfig: TraceIdConfig = {\n ...config,\n extractor: config?.extractor ? { ...defaultExtractor, ...config.extractor } : defaultExtractor,\n };\n\n _setActiveContextKey(resolvedConfig.contextKey ?? TRACE_CONTEXT_KEY);\n\n return (req: unknown, res: unknown, next: () => void) => {\n let traceId: string | undefined;\n\n if (resolvedConfig.extractor) {\n traceId = extractTraceId(req, resolvedConfig.extractor);\n }\n\n if (!traceId) {\n traceId = resolvedConfig.generator ? resolvedConfig.generator() : generateTraceId();\n }\n\n (req as Record<string, unknown>).traceId = traceId;\n // Echo the trace ID back on the response, tolerating different response APIs:\n // Express/Node use res.setHeader(), Fastify replies use reply.header(). Guard\n // both and never let a missing/!function method (or already-sent headers)\n // crash the request — the trace ID is still propagated via async context.\n const resObj = res as {\n setHeader?: (k: string, v: string) => void;\n header?: (k: string, v: string) => void;\n headersSent?: boolean;\n };\n if (!resObj.headersSent) {\n try {\n if (typeof resObj.setHeader === 'function') {\n resObj.setHeader('X-Trace-Id', traceId);\n } else if (typeof resObj.header === 'function') {\n resObj.header('X-Trace-Id', traceId);\n }\n } catch {\n /* response not in a header-settable state — context propagation still works */\n }\n }\n\n runWithTraceId(traceId, () => next());\n };\n}\n","/**\n * Per-request trace ID resolution shared by the HTTP logger middleware and the\n * context helpers. Internal: not re-exported from the package entry points.\n */\n\nimport type { HttpRequestShape } from '../types/http-shapes';\nimport {\n DEFAULT_TRACE_HEADERS,\n extractTraceId,\n generateTraceId,\n sanitizeIncomingId,\n} from './trace.utils';\n\nexport type TraceHeaderOption = string | readonly string[];\n\n/** Minimal structural request shape; Express and Fastify requests satisfy it. */\nexport type ContextRequestLike = HttpRequestShape;\n\n/** Fastify's default `genReqId` output (`req-` + base36 counter), unique only per process. */\nconst FASTIFY_COUNTER_ID = /^req-[\\da-z]+$/;\n\nconst FALLBACK_KEY = '_logixiaFallbackId';\n\n/** A caller-supplied request ID that is safe to use as a trace ID, or `undefined` for a counter ID. */\nexport function usableRequestId(id: unknown): string | undefined {\n const sanitized = sanitizeIncomingId(id);\n return sanitized !== undefined && !FASTIFY_COUNTER_ID.test(sanitized) ? sanitized : undefined;\n}\n\n/** Header names to read a trace ID from, defaulting to the library-wide list. */\nexport function resolveTraceHeaders(option: TraceHeaderOption | undefined): readonly string[] {\n if (option === undefined) return DEFAULT_TRACE_HEADERS;\n return typeof option === 'string' ? [option] : option;\n}\n\n/**\n * Resolve the trace ID for a request: a sanitised incoming header (honouring\n * `traceparent`), then a non-counter `request.id`, then a generated ID. Header\n * and `request.id` are recomputed per call so each caller's own header list is\n * honoured; only the generated fallback is stored on the request so every helper\n * agrees when no ID was sent.\n */\nexport function resolveRequestTraceId(req: ContextRequestLike, headers: readonly string[]): string {\n const fromHeader = extractTraceId(req, { header: [...headers] });\n if (fromHeader !== undefined) return fromHeader;\n\n const fromId = usableRequestId(req.id);\n if (fromId !== undefined) return fromId;\n\n const holder = req as Record<string, unknown>;\n const cached = holder[FALLBACK_KEY];\n if (typeof cached === 'string') return cached;\n const generated = generateTraceId();\n try {\n holder[FALLBACK_KEY] = generated;\n } catch {\n // frozen request object: each caller generates its own\n }\n return generated;\n}\n","/**\n * The one list of sensitive names. Log redaction (redact.utils), the HTTP logger\n * middleware and transport secret handling (transports/secret-config) all read it,\n * so the lists cannot drift. No imports: safe from any module, including browser code.\n */\n\n/** Field names redacted by name, wherever they appear in logged data. */\nexport const SENSITIVE_KEY_NAMES: readonly string[] = [\n 'password',\n 'passwd',\n 'secret',\n 'token',\n 'apiKey',\n 'api_key',\n 'accessToken',\n 'access_token',\n 'refreshToken',\n 'refresh_token',\n 'authorization',\n 'credentials',\n 'privateKey',\n 'private_key',\n 'clientSecret',\n 'client_secret',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n 'session',\n 'proxy-authorization',\n 'x-auth-token',\n 'x-access-token',\n 'aws_secret_access_key',\n 'awsSecretAccessKey',\n 'secretAccessKey',\n];\n\n/**\n * Extra names that only mean \"secret\" inside transport configuration, where\n * short words like `key` or `signature` are credentials, not log fields.\n */\nexport const TRANSPORT_CONFIG_SECRET_NAMES: readonly string[] = [\n 'writeKey',\n 'apiSecret',\n 'connectionString',\n 'sessionToken',\n 'passphrase',\n 'signature',\n 'pwd',\n 'pfx',\n 'cert',\n 'key',\n 'auth',\n];\n\n/** Request headers whose values are never logged. */\nexport const DEFAULT_REDACT_HEADERS: readonly string[] = [\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n 'proxy-authorization',\n 'x-auth-token',\n 'x-access-token',\n 'x-csrf-token',\n 'x-amz-security-token',\n];\n\n/** Query-string parameters whose values are never logged. */\nexport const DEFAULT_REDACT_QUERY_PARAMS: readonly string[] = [\n 'token',\n 'access_token',\n 'refresh_token',\n 'code',\n 'password',\n 'secret',\n 'api_key',\n 'apikey',\n 'key',\n 'signature',\n 'sig',\n 'auth',\n 'accesstoken',\n 'refreshtoken',\n 'id_token',\n 'idtoken',\n 'client_secret',\n 'clientsecret',\n 'session',\n 'sessionid',\n 'session_id',\n 'jwt',\n 'auth_token',\n 'authtoken',\n 'api-key',\n 'x-api-key',\n 'x-amz-signature',\n 'x-amz-credential',\n 'x-amz-security-token',\n 'x-goog-signature',\n 'x-goog-credential',\n 'access-token',\n 'x-access-token',\n 'x-auth-token',\n 'apitoken',\n 'api_token',\n];\n\nfunction safeDecode(value: string): string {\n try {\n return decodeURIComponent(value.replace(/\\+/g, ' '));\n } catch {\n return value;\n }\n}\n\n/** Replace the values of sensitive query parameters, leaving the rest verbatim. */\nexport function redactUrlQuery(url: string, redactParams: ReadonlySet<string>): string {\n const q = url.indexOf('?');\n if (q === -1) return url;\n const hashAt = url.indexOf('#', q);\n const query = url.slice(q + 1, hashAt === -1 ? undefined : hashAt);\n const hash = hashAt === -1 ? '' : url.slice(hashAt);\n const cleaned = query\n .split('&')\n .map((pair) => {\n const eq = pair.indexOf('=');\n const rawKey = eq === -1 ? pair : pair.slice(0, eq);\n const decoded = safeDecode(rawKey);\n const bracket = decoded.indexOf('[');\n const name = (bracket === -1 ? decoded : decoded.slice(0, bracket)).toLowerCase();\n return redactParams.has(name) && eq !== -1 ? `${rawKey}=[REDACTED]` : pair;\n })\n .join('&');\n return `${url.slice(0, q)}?${cleaned}${hash}`;\n}\n\n/** Lower-cased lookup set of the default names plus any extras. */\nexport function buildNameSet(\n defaults: readonly string[],\n extra: readonly string[] | undefined\n): Set<string> {\n return new Set([...defaults, ...(extra ?? [])].map((n) => n.toLowerCase()));\n}\n\nconst REDACTED = '[REDACTED]';\nconst MIN_SCRUB_LENGTH = 3;\n\nfunction queryNameOf(rawKey: string): string {\n const decoded = safeDecode(rawKey);\n const bracket = decoded.indexOf('[');\n return (bracket === -1 ? decoded : decoded.slice(0, bracket)).toLowerCase();\n}\n\n/**\n * Raw and decoded values of sensitive query parameters present in this URL.\n * Values shorter than 3 characters or already `[REDACTED]` are ignored.\n */\nexport function sensitiveQueryValues(url: string, names: ReadonlySet<string>): string[] {\n const q = url.indexOf('?');\n if (q === -1) return [];\n const hashAt = url.indexOf('#', q);\n const query = url.slice(q + 1, hashAt === -1 ? undefined : hashAt);\n const found = new Set<string>();\n for (const pair of query.split('&')) {\n const eq = pair.indexOf('=');\n if (eq === -1 || !names.has(queryNameOf(pair.slice(0, eq)))) continue;\n const raw = pair.slice(eq + 1);\n for (const value of [raw, safeDecode(raw)]) {\n if (value.length >= MIN_SCRUB_LENGTH && value !== REDACTED) found.add(value);\n }\n }\n return [...found];\n}\n\n/** Replace every literal occurrence of `values` in `text` with `[REDACTED]`. */\nexport function scrubValues(text: string, values: readonly string[]): string {\n if (values.length === 0 || text.length === 0) return text;\n let out = text;\n for (const value of [...values].sort((a, b) => b.length - a.length)) {\n if (value.length > 0 && out.includes(value)) out = out.split(value).join(REDACTED);\n }\n return out;\n}\n\nfunction isUrlTerminator(ch: string): boolean {\n return (\n ch === ' ' ||\n ch === '\\n' ||\n ch === '\\r' ||\n ch === '\\t' ||\n ch === '\"' ||\n ch === \"'\" ||\n ch === '`'\n );\n}\n\n/**\n * Redact sensitive query values in every `?query` found inside free text (an\n * error message, a stack line). Scans for `?` and cuts at whitespace or a quote.\n */\nexport function redactUrlsInText(text: string, names: ReadonlySet<string>): string {\n let q = text.indexOf('?');\n if (q === -1) return text;\n let out = '';\n let cursor = 0;\n while (q !== -1) {\n let end = q + 1;\n while (end < text.length && !isUrlTerminator(text.charAt(end))) end++;\n out += text.slice(cursor, q) + redactUrlQuery(text.slice(q, end), names);\n cursor = end;\n q = text.indexOf('?', end);\n }\n return out + text.slice(cursor);\n}\n\n/** Shape-preserving URL redaction plus literal scrubbing of this request's secret values. */\nexport function sanitizeText(\n text: string,\n names: ReadonlySet<string>,\n values: readonly string[]\n): string {\n return scrubValues(redactUrlsInText(text, names), values);\n}\n","/**\n * Hono request logging middleware: trace ID, response header and a completion entry.\n *\n * Only structural types are used, so it works with any Hono version and runs on Node,\n * Bun and Cloudflare Workers (`nodejs_compat`, for `AsyncLocalStorage`).\n *\n * @example\n * ```ts\n * import { Hono } from 'hono';\n * import { createHonoMiddleware } from 'logixia/hono';\n *\n * const app = new Hono();\n * app.use(createHonoMiddleware(logger));\n * ```\n */\n\nimport { serializeError } from '../utils/error.utils';\nimport { internalError } from '../utils/internal-log';\nimport { resolveTraceHeaders } from '../utils/request-trace';\nimport {\n buildNameSet,\n DEFAULT_REDACT_QUERY_PARAMS,\n redactUrlQuery,\n} from '../utils/sensitive-names';\nimport { extractTraceId, generateTraceId, runWithTraceId } from '../utils/trace.utils';\n\n// ── Structural types ─────────────────────────────────────────────────────────\n\ntype LogFn = (message: string, data?: Record<string, unknown>) => unknown;\n\n/** The logger methods used: logixia's `Logger` and `createBrowserLogger()` both fit. */\nexport interface HonoLoggerLike {\n info: LogFn;\n warn: LogFn;\n error: LogFn;\n}\n\n/** The slice of Hono's `Context` the middleware reads and writes. */\nexport interface HonoContextLike {\n req: { method: string; url: string; header(name: string): string | undefined };\n res: Response;\n error?: Error | undefined;\n header(name: string, value: string): unknown;\n set(key: 'traceId', value: string): void;\n}\n\nexport type HonoNext = () => Promise<void>;\n\nexport interface HonoMiddlewareOptions {\n /** Skip logging and tracing for a request, for example health checks. */\n skip?: (c: HonoContextLike) => boolean;\n /**\n * Header name, or list of names tried in order, to read the trace ID from.\n * Default: `DEFAULT_TRACE_HEADERS` (traceparent, x-trace-id, x-request-id,\n * x-correlation-id, trace-id). A generated UUID is used when none is present.\n */\n traceIdHeader?: string | readonly string[];\n /** Response header that carries the trace ID. Default: `'x-trace-id'`. `false` sets none. */\n responseHeader?: string | false;\n /**\n * Extra query-string parameter names redacted from the logged path, merged with the\n * defaults (token, access_token, refresh_token, code, password, secret, api_key, ...).\n */\n redactQueryParams?: string[];\n /** Fields added to every entry. */\n extraFields?: (c: HonoContextLike) => Record<string, unknown>;\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\n/** Fire-and-forget: a failing log call must never fail the request. */\nfunction emit(logger: HonoLoggerLike, level: keyof HonoLoggerLike, message: string, data: object) {\n try {\n const result = logger[level](message, data as Record<string, unknown>);\n if (result && typeof (result as Promise<unknown>).catch === 'function') {\n (result as Promise<unknown>).catch((error: unknown) =>\n internalError('hono middleware: log call failed', error)\n );\n }\n } catch (error) {\n internalError('hono middleware: log call failed', error);\n }\n}\n\n/** Pathname plus the query string with secret parameters redacted, from an absolute or relative URL. */\nfunction loggedPath(url: string, params: ReadonlySet<string>): string {\n const schemeEnd = url.indexOf('://');\n const pathStart = schemeEnd === -1 ? 0 : url.indexOf('/', schemeEnd + 3);\n return pathStart === -1 ? '/' : redactUrlQuery(url.slice(pathStart), params);\n}\n\nfunction ensureHeader(c: HonoContextLike, name: string, value: string): void {\n try {\n if (c.res.headers.get(name) === value) return;\n c.res.headers.set(name, value);\n } catch {\n // Immutable headers (a proxied fetch() response): rebuild the response with a mutable copy.\n const copy = new Response(c.res.body, c.res);\n copy.headers.set(name, value);\n c.res = copy;\n }\n}\n\n/**\n * Create a Hono middleware (`app.use(...)`).\n *\n * Per request it resolves the trace ID from headers, sets it on the response and on\n * `c.var.traceId`, runs the rest of the request inside {@link runWithTraceId} and logs\n * one entry when the request completes: `method`, `path` (query secrets redacted),\n * `status`, `duration` in ms and `traceId`. Responses with status 500 and above, and\n * errors thrown by handlers, are logged at `error`; other thrown errors at `warn`.\n */\nexport function createHonoMiddleware(\n logger: HonoLoggerLike,\n options: HonoMiddlewareOptions = {}\n): (c: HonoContextLike, next: HonoNext) => Promise<void> {\n const { skip, extraFields, responseHeader = 'x-trace-id' } = options;\n const traceHeaders = resolveTraceHeaders(options.traceIdHeader);\n const params = buildNameSet(DEFAULT_REDACT_QUERY_PARAMS, options.redactQueryParams);\n\n return async function logixiaHonoMiddleware(c, next) {\n if (skip?.(c)) return next();\n\n const headers: Record<string, string | undefined> = {};\n for (const name of traceHeaders) {\n const key = name.toLowerCase();\n headers[key] = c.req.header(key);\n }\n const traceId = extractTraceId({ headers }, { header: [...traceHeaders] }) ?? generateTraceId();\n const start = Date.now();\n c.set('traceId', traceId);\n if (responseHeader) c.header(responseHeader, traceId);\n\n await runWithTraceId(traceId, async () => {\n let thrown: unknown;\n try {\n await next();\n } catch (error) {\n thrown = error;\n }\n // Hono hands a handler's error to onError and resolves next(); c.error is how it shows up here.\n const failure = thrown ?? c.error;\n if (responseHeader && thrown === undefined) ensureHeader(c, responseHeader, traceId);\n\n const status = thrown === undefined ? c.res.status : 500;\n const entry = {\n traceId,\n method: c.req.method,\n path: loggedPath(c.req.url, params),\n status,\n duration: Date.now() - start,\n ...(failure === undefined ? {} : { error: serializeError(toError(failure)) }),\n ...extraFields?.(c),\n };\n if (failure !== undefined) {\n emit(logger, status >= 500 ? 'error' : 'warn', 'request failed', entry);\n } else {\n emit(logger, status >= 500 ? 'error' : 'info', 'request completed', entry);\n }\n if (thrown !== undefined) throw thrown;\n });\n };\n}\n\nfunction toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value));\n}\n"],"mappings":"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"}
|