evlog 2.14.1 → 2.16.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/LICENSE +21 -0
- package/README.md +4 -4
- package/dist/adapters/axiom.d.mts +18 -27
- package/dist/adapters/axiom.d.mts.map +1 -1
- package/dist/adapters/axiom.mjs +40 -30
- package/dist/adapters/axiom.mjs.map +1 -1
- package/dist/adapters/better-stack.d.mts +11 -24
- package/dist/adapters/better-stack.d.mts.map +1 -1
- package/dist/adapters/better-stack.mjs +34 -29
- package/dist/adapters/better-stack.mjs.map +1 -1
- package/dist/adapters/datadog.d.mts +1 -1
- package/dist/adapters/datadog.d.mts.map +1 -1
- package/dist/adapters/datadog.mjs +10 -4
- package/dist/adapters/datadog.mjs.map +1 -1
- package/dist/adapters/fs.d.mts +2 -2
- package/dist/adapters/fs.d.mts.map +1 -1
- package/dist/adapters/fs.mjs +19 -7
- package/dist/adapters/fs.mjs.map +1 -1
- package/dist/adapters/hyperdx.d.mts +1 -1
- package/dist/adapters/hyperdx.mjs +1 -2
- package/dist/adapters/hyperdx.mjs.map +1 -1
- package/dist/adapters/otlp.d.mts +1 -1
- package/dist/adapters/otlp.d.mts.map +1 -1
- package/dist/adapters/otlp.mjs +36 -31
- package/dist/adapters/otlp.mjs.map +1 -1
- package/dist/adapters/posthog.d.mts +50 -70
- package/dist/adapters/posthog.d.mts.map +1 -1
- package/dist/adapters/posthog.mjs +50 -85
- package/dist/adapters/posthog.mjs.map +1 -1
- package/dist/adapters/sentry.d.mts +1 -1
- package/dist/adapters/sentry.d.mts.map +1 -1
- package/dist/adapters/sentry.mjs +15 -5
- package/dist/adapters/sentry.mjs.map +1 -1
- package/dist/ai/index.d.mts +15 -1
- package/dist/ai/index.d.mts.map +1 -1
- package/dist/ai/index.mjs +48 -16
- package/dist/ai/index.mjs.map +1 -1
- package/dist/{audit-CTIviX3P.d.mts → audit-X1uUukm3.d.mts} +145 -2
- package/dist/audit-X1uUukm3.d.mts.map +1 -0
- package/dist/{audit-DQoBo7Dl.mjs → audit-pV5aLGP0.mjs} +153 -13
- package/dist/audit-pV5aLGP0.mjs.map +1 -0
- package/dist/better-auth/index.d.mts +1 -1
- package/dist/browser.d.mts +1 -1
- package/dist/define-CuXOqecD.d.mts +57 -0
- package/dist/define-CuXOqecD.d.mts.map +1 -0
- package/dist/define-D6OJdSUH.mjs +63 -0
- package/dist/define-D6OJdSUH.mjs.map +1 -0
- package/dist/{dist-Do8P4zWd.mjs → dist-BIlS38vi.mjs} +1 -1
- package/dist/dist-BIlS38vi.mjs.map +1 -0
- package/dist/drain-ByWUeOQC.mjs +160 -0
- package/dist/drain-ByWUeOQC.mjs.map +1 -0
- package/dist/elysia/index.d.mts +25 -2
- package/dist/elysia/index.d.mts.map +1 -1
- package/dist/elysia/index.mjs +53 -20
- package/dist/elysia/index.mjs.map +1 -1
- package/dist/enricher-DYTr9I16.d.mts +42 -0
- package/dist/enricher-DYTr9I16.d.mts.map +1 -0
- package/dist/enricher-Dy06T17G.mjs +95 -0
- package/dist/enricher-Dy06T17G.mjs.map +1 -0
- package/dist/enrichers.d.mts +16 -9
- package/dist/enrichers.d.mts.map +1 -1
- package/dist/enrichers.mjs +81 -64
- package/dist/enrichers.mjs.map +1 -1
- package/dist/{error-C7gSQVqk.d.mts → error-Cpc7RVz6.d.mts} +7 -2
- package/dist/error-Cpc7RVz6.d.mts.map +1 -0
- package/dist/error.d.mts +1 -1
- package/dist/error.mjs +8 -1
- package/dist/error.mjs.map +1 -1
- package/dist/{errors-BJRXUfMg.mjs → errors-BQgyQ9xe.mjs} +1 -1
- package/dist/{errors-BJRXUfMg.mjs.map → errors-BQgyQ9xe.mjs.map} +1 -1
- package/dist/{errors-4MPmTzjY.d.mts → errors-prnQ3kES.d.mts} +2 -2
- package/dist/{errors-4MPmTzjY.d.mts.map → errors-prnQ3kES.d.mts.map} +1 -1
- package/dist/event-DcHmEm3O.mjs +55 -0
- package/dist/event-DcHmEm3O.mjs.map +1 -0
- package/dist/express/index.d.mts +2 -2
- package/dist/express/index.d.mts.map +1 -1
- package/dist/express/index.mjs +17 -15
- package/dist/express/index.mjs.map +1 -1
- package/dist/fastify/index.d.mts +2 -2
- package/dist/fastify/index.d.mts.map +1 -1
- package/dist/fastify/index.mjs +19 -20
- package/dist/fastify/index.mjs.map +1 -1
- package/dist/fork-DPN8aL8O.mjs +227 -0
- package/dist/fork-DPN8aL8O.mjs.map +1 -0
- package/dist/{headers-D74M0wsg.mjs → headers-CU-QqnYg.mjs} +19 -2
- package/dist/headers-CU-QqnYg.mjs.map +1 -0
- package/dist/hono/index.d.mts +2 -2
- package/dist/hono/index.d.mts.map +1 -1
- package/dist/hono/index.mjs +14 -10
- package/dist/hono/index.mjs.map +1 -1
- package/dist/http.d.mts +1 -1
- package/dist/index.d.mts +8 -7
- package/dist/index.mjs +3 -2
- package/dist/integration-DSZPbI9N.mjs +75 -0
- package/dist/integration-DSZPbI9N.mjs.map +1 -0
- package/dist/{logger-DttRJRGa.d.mts → logger-U8lgdc9x.d.mts} +9 -3
- package/dist/logger-U8lgdc9x.d.mts.map +1 -0
- package/dist/logger.d.mts +2 -2
- package/dist/logger.mjs +2 -2
- package/dist/middleware-CAQHJRN1.d.mts +72 -0
- package/dist/middleware-CAQHJRN1.d.mts.map +1 -0
- package/dist/nestjs/index.d.mts +2 -2
- package/dist/nestjs/index.mjs +3 -4
- package/dist/nestjs/index.mjs.map +1 -1
- package/dist/next/client.d.mts +1 -1
- package/dist/next/index.d.mts +4 -4
- package/dist/next/index.mjs +3 -3
- package/dist/next/instrumentation.d.mts +1 -1
- package/dist/next/instrumentation.mjs +1 -1
- package/dist/nitro/errorHandler.mjs +2 -2
- package/dist/nitro/module.d.mts +2 -2
- package/dist/nitro/plugin.mjs +21 -11
- package/dist/nitro/plugin.mjs.map +1 -1
- package/dist/nitro/v3/errorHandler.mjs +3 -3
- package/dist/nitro/v3/index.d.mts +2 -2
- package/dist/nitro/v3/module.d.mts +1 -1
- package/dist/nitro/v3/plugin.mjs +29 -17
- package/dist/nitro/v3/plugin.mjs.map +1 -1
- package/dist/nitro/v3/useLogger.d.mts +1 -1
- package/dist/{nitro-CPPRCPbG.d.mts → nitro-C6Bd682U.d.mts} +2 -2
- package/dist/{nitro-CPPRCPbG.d.mts.map → nitro-C6Bd682U.d.mts.map} +1 -1
- package/dist/{nitro-OmT_M4Pb.mjs → nitro-DavLelNz.mjs} +2 -2
- package/dist/nitro-DavLelNz.mjs.map +1 -0
- package/dist/{nitroConfigBridge-C37lXaNm.mjs → nitroConfigBridge-aZ1e5upQ.mjs} +1 -1
- package/dist/nitroConfigBridge-aZ1e5upQ.mjs.map +1 -0
- package/dist/nuxt/module.d.mts +1 -1
- package/dist/nuxt/module.mjs +2 -2
- package/dist/{parseError-o1GpZEOR.d.mts → parseError-B-dKF6Fd.d.mts} +2 -2
- package/dist/parseError-B-dKF6Fd.d.mts.map +1 -0
- package/dist/react-router/index.d.mts +2 -2
- package/dist/react-router/index.mjs +3 -4
- package/dist/react-router/index.mjs.map +1 -1
- package/dist/{routes-CGPmbzCZ.mjs → routes-B48wm7Pb.mjs} +1 -1
- package/dist/{routes-CGPmbzCZ.mjs.map → routes-B48wm7Pb.mjs.map} +1 -1
- package/dist/runtime/client/log.d.mts +1 -1
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs +21 -10
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs.map +1 -1
- package/dist/runtime/server/useLogger.d.mts +1 -1
- package/dist/runtime/utils/parseError.d.mts +2 -2
- package/dist/runtime/utils/parseError.mjs +9 -1
- package/dist/runtime/utils/parseError.mjs.map +1 -1
- package/dist/{_severity-CQijvfhU.mjs → severity-BYWZ96Sb.mjs} +6 -2
- package/dist/severity-BYWZ96Sb.mjs.map +1 -0
- package/dist/{source-location-DRvDDqfq.mjs → source-location-Dco0cRTz.mjs} +3 -3
- package/dist/source-location-Dco0cRTz.mjs.map +1 -0
- package/dist/storage-BT-3fT1-.mjs +27 -0
- package/dist/storage-BT-3fT1-.mjs.map +1 -0
- package/dist/sveltekit/index.d.mts +2 -2
- package/dist/sveltekit/index.mjs +5 -6
- package/dist/sveltekit/index.mjs.map +1 -1
- package/dist/toolkit.d.mts +288 -12
- package/dist/toolkit.d.mts.map +1 -1
- package/dist/toolkit.mjs +13 -7
- package/dist/types.d.mts +1 -1
- package/dist/{useLogger-CyPP1sVB.d.mts → useLogger-CoNgTjp5.d.mts} +2 -2
- package/dist/{useLogger-CyPP1sVB.d.mts.map → useLogger-CoNgTjp5.d.mts.map} +1 -1
- package/dist/{utils-Dmin7wVL.d.mts → utils-Db4qhBWn.d.mts} +2 -2
- package/dist/{utils-Dmin7wVL.d.mts.map → utils-Db4qhBWn.d.mts.map} +1 -1
- package/dist/utils.d.mts +1 -1
- package/dist/vite/index.d.mts +1 -1
- package/dist/vite/index.mjs +1 -1
- package/dist/workers.d.mts +1 -1
- package/dist/workers.mjs +1 -1
- package/package.json +22 -19
- package/dist/_drain-CmCtsuF6.mjs +0 -23
- package/dist/_drain-CmCtsuF6.mjs.map +0 -1
- package/dist/_http-BY1e9pwC.mjs +0 -78
- package/dist/_http-BY1e9pwC.mjs.map +0 -1
- package/dist/_severity-CQijvfhU.mjs.map +0 -1
- package/dist/audit-CTIviX3P.d.mts.map +0 -1
- package/dist/audit-DQoBo7Dl.mjs.map +0 -1
- package/dist/dist-Do8P4zWd.mjs.map +0 -1
- package/dist/error-C7gSQVqk.d.mts.map +0 -1
- package/dist/fork-D1j1Fuzy.mjs +0 -72
- package/dist/fork-D1j1Fuzy.mjs.map +0 -1
- package/dist/headers-D74M0wsg.mjs.map +0 -1
- package/dist/logger-DttRJRGa.d.mts.map +0 -1
- package/dist/middleware-CTnDsST-.d.mts +0 -93
- package/dist/middleware-CTnDsST-.d.mts.map +0 -1
- package/dist/middleware-oAccqyPp.mjs +0 -123
- package/dist/middleware-oAccqyPp.mjs.map +0 -1
- package/dist/nitro-OmT_M4Pb.mjs.map +0 -1
- package/dist/nitroConfigBridge-C37lXaNm.mjs.map +0 -1
- package/dist/parseError-o1GpZEOR.d.mts.map +0 -1
- package/dist/source-location-DRvDDqfq.mjs.map +0 -1
- package/dist/storage-CFGTn37X.mjs +0 -46
- package/dist/storage-CFGTn37X.mjs.map +0 -1
package/dist/enrichers.mjs
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
+
import { i as normalizeNumber, r as getHeader } from "./headers-CU-QqnYg.mjs";
|
|
2
|
+
import { r as composeEnrichers, t as defineEnricher } from "./enricher-Dy06T17G.mjs";
|
|
1
3
|
//#region src/enrichers/index.ts
|
|
2
|
-
function getHeader(headers, name) {
|
|
3
|
-
if (!headers) return void 0;
|
|
4
|
-
if (headers[name] !== void 0) return headers[name];
|
|
5
|
-
const lowerName = name.toLowerCase();
|
|
6
|
-
if (headers[lowerName] !== void 0) return headers[lowerName];
|
|
7
|
-
for (const [key, value] of Object.entries(headers)) if (key.toLowerCase() === lowerName) return value;
|
|
8
|
-
}
|
|
9
4
|
function parseUserAgent(ua) {
|
|
10
5
|
const lower = ua.toLowerCase();
|
|
11
6
|
let deviceType = { type: "unknown" };
|
|
@@ -75,29 +70,19 @@ function parseTraceparent(traceparent) {
|
|
|
75
70
|
spanId: match[2]
|
|
76
71
|
};
|
|
77
72
|
}
|
|
78
|
-
function mergeEventField(existing, computed, overwrite) {
|
|
79
|
-
if (overwrite || existing === void 0 || existing === null || typeof existing !== "object") return computed;
|
|
80
|
-
return {
|
|
81
|
-
...computed,
|
|
82
|
-
...existing
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
function normalizeNumber(value) {
|
|
86
|
-
if (!value) return void 0;
|
|
87
|
-
const parsed = Number(value);
|
|
88
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
89
|
-
}
|
|
90
73
|
/**
|
|
91
74
|
* Enrich events with parsed user agent data.
|
|
92
75
|
* Sets `event.userAgent` with `UserAgentInfo` shape: `{ raw, browser?, os?, device? }`.
|
|
93
76
|
*/
|
|
94
77
|
function createUserAgentEnricher(options = {}) {
|
|
95
|
-
return (
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
78
|
+
return defineEnricher({
|
|
79
|
+
name: "userAgent",
|
|
80
|
+
field: "userAgent",
|
|
81
|
+
compute: ({ headers }) => {
|
|
82
|
+
const ua = getHeader(headers, "user-agent");
|
|
83
|
+
return ua ? parseUserAgent(ua) : void 0;
|
|
84
|
+
}
|
|
85
|
+
}, options);
|
|
101
86
|
}
|
|
102
87
|
/**
|
|
103
88
|
* Enrich events with geo data from platform headers.
|
|
@@ -112,36 +97,41 @@ function createUserAgentEnricher(options = {}) {
|
|
|
112
97
|
* or use a Workers middleware to copy `cf` properties into custom headers.
|
|
113
98
|
*/
|
|
114
99
|
function createGeoEnricher(options = {}) {
|
|
115
|
-
return (
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
100
|
+
return defineEnricher({
|
|
101
|
+
name: "geo",
|
|
102
|
+
field: "geo",
|
|
103
|
+
compute: ({ headers }) => {
|
|
104
|
+
if (!headers) return void 0;
|
|
105
|
+
const geo = {
|
|
106
|
+
country: getHeader(headers, "x-vercel-ip-country") ?? getHeader(headers, "cf-ipcountry"),
|
|
107
|
+
region: getHeader(headers, "x-vercel-ip-country-region") ?? getHeader(headers, "cf-region"),
|
|
108
|
+
regionCode: getHeader(headers, "x-vercel-ip-country-region-code") ?? getHeader(headers, "cf-region-code"),
|
|
109
|
+
city: getHeader(headers, "x-vercel-ip-city") ?? getHeader(headers, "cf-city"),
|
|
110
|
+
latitude: normalizeNumber(getHeader(headers, "x-vercel-ip-latitude") ?? getHeader(headers, "cf-latitude")),
|
|
111
|
+
longitude: normalizeNumber(getHeader(headers, "x-vercel-ip-longitude") ?? getHeader(headers, "cf-longitude"))
|
|
112
|
+
};
|
|
113
|
+
return Object.values(geo).every((value) => value === void 0) ? void 0 : geo;
|
|
114
|
+
}
|
|
115
|
+
}, options);
|
|
129
116
|
}
|
|
130
117
|
/**
|
|
131
118
|
* Enrich events with request/response payload sizes.
|
|
132
119
|
* Sets `event.requestSize` with `RequestSizeInfo` shape: `{ requestBytes?, responseBytes? }`.
|
|
133
120
|
*/
|
|
134
121
|
function createRequestSizeEnricher(options = {}) {
|
|
135
|
-
return (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
requestBytes,
|
|
140
|
-
responseBytes
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
122
|
+
return defineEnricher({
|
|
123
|
+
name: "requestSize",
|
|
124
|
+
field: "requestSize",
|
|
125
|
+
compute: ({ headers, response }) => {
|
|
126
|
+
const requestBytes = normalizeNumber(getHeader(headers, "content-length"));
|
|
127
|
+
const responseBytes = normalizeNumber(getHeader(response?.headers, "content-length"));
|
|
128
|
+
if (requestBytes === void 0 && responseBytes === void 0) return void 0;
|
|
129
|
+
return {
|
|
130
|
+
requestBytes,
|
|
131
|
+
responseBytes
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}, options);
|
|
145
135
|
}
|
|
146
136
|
/**
|
|
147
137
|
* Enrich events with W3C trace context data.
|
|
@@ -149,24 +139,51 @@ function createRequestSizeEnricher(options = {}) {
|
|
|
149
139
|
* Also sets `event.traceId` and `event.spanId` at the top level.
|
|
150
140
|
*/
|
|
151
141
|
function createTraceContextEnricher(options = {}) {
|
|
142
|
+
const enricher = defineEnricher({
|
|
143
|
+
name: "traceContext",
|
|
144
|
+
field: "traceContext",
|
|
145
|
+
compute: ({ event, headers }) => {
|
|
146
|
+
const traceparent = getHeader(headers, "traceparent");
|
|
147
|
+
const tracestate = getHeader(headers, "tracestate");
|
|
148
|
+
if (!traceparent && !tracestate) return void 0;
|
|
149
|
+
const parsed = traceparent ? parseTraceparent(traceparent) : void 0;
|
|
150
|
+
return {
|
|
151
|
+
traceparent,
|
|
152
|
+
tracestate,
|
|
153
|
+
traceId: parsed?.traceId ?? event.traceId,
|
|
154
|
+
spanId: parsed?.spanId ?? event.spanId
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}, options);
|
|
152
158
|
return (ctx) => {
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
if (!
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
traceparent,
|
|
159
|
-
tracestate,
|
|
160
|
-
traceId: parsed?.traceId ?? ctx.event.traceId,
|
|
161
|
-
spanId: parsed?.spanId ?? ctx.event.spanId
|
|
162
|
-
};
|
|
163
|
-
const mergedTraceContext = mergeEventField(ctx.event.traceContext, incomingTraceContext, options.overwrite);
|
|
164
|
-
ctx.event.traceContext = mergedTraceContext;
|
|
165
|
-
if (mergedTraceContext.traceId && (options.overwrite || ctx.event.traceId === void 0)) ctx.event.traceId = mergedTraceContext.traceId;
|
|
166
|
-
if (mergedTraceContext.spanId && (options.overwrite || ctx.event.spanId === void 0)) ctx.event.spanId = mergedTraceContext.spanId;
|
|
159
|
+
enricher(ctx);
|
|
160
|
+
const merged = ctx.event.traceContext;
|
|
161
|
+
if (!merged) return;
|
|
162
|
+
if (merged.traceId && (options.overwrite || ctx.event.traceId === void 0)) ctx.event.traceId = merged.traceId;
|
|
163
|
+
if (merged.spanId && (options.overwrite || ctx.event.spanId === void 0)) ctx.event.spanId = merged.spanId;
|
|
167
164
|
};
|
|
168
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Compose every built-in enricher into a single async enricher, in the order
|
|
168
|
+
* `userAgent → geo → requestSize → traceContext`.
|
|
169
|
+
*
|
|
170
|
+
* Drop-in shorthand for the most common middleware setup:
|
|
171
|
+
*
|
|
172
|
+
* ```ts
|
|
173
|
+
* import { createDefaultEnrichers } from 'evlog/enrichers'
|
|
174
|
+
*
|
|
175
|
+
* app.use(evlog({ enrich: createDefaultEnrichers() }))
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
function createDefaultEnrichers(options = {}) {
|
|
179
|
+
return composeEnrichers([
|
|
180
|
+
createUserAgentEnricher(options),
|
|
181
|
+
createGeoEnricher(options),
|
|
182
|
+
createRequestSizeEnricher(options),
|
|
183
|
+
createTraceContextEnricher(options)
|
|
184
|
+
], { name: "default-enrichers" });
|
|
185
|
+
}
|
|
169
186
|
//#endregion
|
|
170
|
-
export { createGeoEnricher, createRequestSizeEnricher, createTraceContextEnricher, createUserAgentEnricher };
|
|
187
|
+
export { createDefaultEnrichers, createGeoEnricher, createRequestSizeEnricher, createTraceContextEnricher, createUserAgentEnricher };
|
|
171
188
|
|
|
172
189
|
//# sourceMappingURL=enrichers.mjs.map
|
package/dist/enrichers.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enrichers.mjs","names":[],"sources":["../src/enrichers/index.ts"],"sourcesContent":["import type { EnrichContext } from '../types'\n\nexport interface EnricherOptions {\n /**\n * When true, overwrite any existing fields in the event.\n * Defaults to false to preserve user-provided data.\n */\n overwrite?: boolean\n}\n\nexport interface UserAgentInfo {\n raw: string\n browser?: { name: string; version?: string }\n os?: { name: string; version?: string }\n device?: { type: 'mobile' | 'tablet' | 'desktop' | 'bot' | 'unknown' }\n}\n\nexport interface GeoInfo {\n country?: string\n region?: string\n regionCode?: string\n city?: string\n latitude?: number\n longitude?: number\n}\n\nexport interface RequestSizeInfo {\n requestBytes?: number\n responseBytes?: number\n}\n\nexport interface TraceContextInfo {\n traceparent?: string\n tracestate?: string\n traceId?: string\n spanId?: string\n}\n\nfunction getHeader(headers: Record<string, string> | undefined, name: string): string | undefined {\n if (!headers) return undefined\n if (headers[name] !== undefined) return headers[name]\n const lowerName = name.toLowerCase()\n if (headers[lowerName] !== undefined) return headers[lowerName]\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerName) return value\n }\n return undefined\n}\n\nfunction parseUserAgent(ua: string): UserAgentInfo {\n const lower = ua.toLowerCase()\n\n let deviceType: UserAgentInfo['device'] = { type: 'unknown' }\n if (/bot|crawl|spider|slurp|bingpreview/.test(lower)) {\n deviceType = { type: 'bot' }\n } else if (/ipad|tablet/.test(lower)) {\n deviceType = { type: 'tablet' }\n } else if (/mobi|iphone|android/.test(lower)) {\n deviceType = { type: 'mobile' }\n } else if (ua.length > 0) {\n deviceType = { type: 'desktop' }\n }\n\n const browserMatchers: Array<{ name: string, regex: RegExp }> = [\n { name: 'Edge', regex: /edg\\/([\\d.]+)/i },\n { name: 'Chrome', regex: /chrome\\/([\\d.]+)/i },\n { name: 'Firefox', regex: /firefox\\/([\\d.]+)/i },\n { name: 'Safari', regex: /version\\/([\\d.]+).*safari/i },\n ]\n\n let browser: UserAgentInfo['browser']\n for (const matcher of browserMatchers) {\n const match = ua.match(matcher.regex)\n if (match) {\n browser = { name: matcher.name, version: match[1] }\n break\n }\n }\n\n let os: UserAgentInfo['os']\n if (/windows nt/i.test(ua)) {\n const match = ua.match(/windows nt ([\\d.]+)/i)\n os = { name: 'Windows', version: match?.[1] }\n } else if (/mac os x/i.test(ua) && !/iphone|ipad|ipod/i.test(ua)) {\n const match = ua.match(/mac os x ([\\d_]+)/i)\n os = { name: 'macOS', version: match?.[1]?.replace(/_/g, '.') }\n } else if (/iphone|ipad|ipod/i.test(ua)) {\n const match = ua.match(/os ([\\d_]+)/i)\n os = { name: 'iOS', version: match?.[1]?.replace(/_/g, '.') }\n } else if (/android/i.test(ua)) {\n const match = ua.match(/android ([\\d.]+)/i)\n os = { name: 'Android', version: match?.[1] }\n } else if (/linux/i.test(ua)) {\n os = { name: 'Linux' }\n }\n\n return {\n raw: ua,\n browser,\n os,\n device: deviceType,\n }\n}\n\nfunction parseTraceparent(traceparent: string): Pick<TraceContextInfo, 'traceId' | 'spanId'> | undefined {\n const match = traceparent.match(/^[\\da-f]{2}-([\\da-f]{32})-([\\da-f]{16})-[\\da-f]{2}$/i)\n if (!match) return undefined\n return { traceId: match[1], spanId: match[2] }\n}\n\nfunction mergeEventField<T extends object>(\n existing: unknown,\n computed: T,\n overwrite?: boolean,\n): T {\n if (overwrite || existing === undefined || existing === null || typeof existing !== 'object') {\n return computed\n }\n return { ...computed, ...(existing as T) }\n}\n\nfunction normalizeNumber(value: string | undefined): number | undefined {\n if (!value) return undefined\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\n/**\n * Enrich events with parsed user agent data.\n * Sets `event.userAgent` with `UserAgentInfo` shape: `{ raw, browser?, os?, device? }`.\n */\nexport function createUserAgentEnricher(options: EnricherOptions = {}): (ctx: EnrichContext) => void {\n return (ctx) => {\n const ua = getHeader(ctx.headers, 'user-agent')\n if (!ua) return\n const info = parseUserAgent(ua)\n ctx.event.userAgent = mergeEventField<UserAgentInfo>(ctx.event.userAgent, info, options.overwrite)\n }\n}\n\n/**\n * Enrich events with geo data from platform headers.\n * Sets `event.geo` with `GeoInfo` shape: `{ country?, region?, regionCode?, city?, latitude?, longitude? }`.\n *\n * Supports Vercel (`x-vercel-ip-*`) headers out of the box.\n *\n * **Cloudflare note:** Only `cf-ipcountry` is an actual HTTP header added by Cloudflare.\n * The `cf-region`, `cf-city`, `cf-latitude`, `cf-longitude` headers are NOT standard\n * Cloudflare headers — they are properties of `request.cf` which is not exposed as HTTP\n * headers. For full geo data on Cloudflare, write a custom enricher that reads `request.cf`\n * or use a Workers middleware to copy `cf` properties into custom headers.\n */\nexport function createGeoEnricher(options: EnricherOptions = {}): (ctx: EnrichContext) => void {\n return (ctx) => {\n const { headers } = ctx\n if (!headers) return\n\n const geo: GeoInfo = {\n country: getHeader(headers, 'x-vercel-ip-country') ?? getHeader(headers, 'cf-ipcountry'),\n region: getHeader(headers, 'x-vercel-ip-country-region') ?? getHeader(headers, 'cf-region'),\n regionCode: getHeader(headers, 'x-vercel-ip-country-region-code') ?? getHeader(headers, 'cf-region-code'),\n city: getHeader(headers, 'x-vercel-ip-city') ?? getHeader(headers, 'cf-city'),\n latitude: normalizeNumber(getHeader(headers, 'x-vercel-ip-latitude') ?? getHeader(headers, 'cf-latitude')),\n longitude: normalizeNumber(getHeader(headers, 'x-vercel-ip-longitude') ?? getHeader(headers, 'cf-longitude')),\n }\n\n if (Object.values(geo).every(value => value === undefined)) return\n ctx.event.geo = mergeEventField<GeoInfo>(ctx.event.geo, geo, options.overwrite)\n }\n}\n\n/**\n * Enrich events with request/response payload sizes.\n * Sets `event.requestSize` with `RequestSizeInfo` shape: `{ requestBytes?, responseBytes? }`.\n */\nexport function createRequestSizeEnricher(options: EnricherOptions = {}): (ctx: EnrichContext) => void {\n return (ctx) => {\n const requestBytes = normalizeNumber(getHeader(ctx.headers, 'content-length'))\n const responseBytes = normalizeNumber(getHeader(ctx.response?.headers, 'content-length'))\n\n const sizes: RequestSizeInfo = {\n requestBytes,\n responseBytes,\n }\n\n if (requestBytes === undefined && responseBytes === undefined) return\n ctx.event.requestSize = mergeEventField<RequestSizeInfo>(ctx.event.requestSize, sizes, options.overwrite)\n }\n}\n\n/**\n * Enrich events with W3C trace context data.\n * Sets `event.traceContext` with `TraceContextInfo` shape: `{ traceparent?, tracestate?, traceId?, spanId? }`.\n * Also sets `event.traceId` and `event.spanId` at the top level.\n */\nexport function createTraceContextEnricher(options: EnricherOptions = {}): (ctx: EnrichContext) => void {\n return (ctx) => {\n const traceparent = getHeader(ctx.headers, 'traceparent')\n const tracestate = getHeader(ctx.headers, 'tracestate')\n if (!traceparent && !tracestate) return\n\n const parsed = traceparent ? parseTraceparent(traceparent) : undefined\n const incomingTraceContext: TraceContextInfo = {\n traceparent,\n tracestate,\n traceId: parsed?.traceId ?? (ctx.event.traceId as string | undefined),\n spanId: parsed?.spanId ?? (ctx.event.spanId as string | undefined),\n }\n\n const mergedTraceContext = mergeEventField<TraceContextInfo>(\n ctx.event.traceContext,\n incomingTraceContext,\n options.overwrite,\n )\n ctx.event.traceContext = mergedTraceContext\n\n if (mergedTraceContext.traceId && (options.overwrite || ctx.event.traceId === undefined)) {\n ctx.event.traceId = mergedTraceContext.traceId\n }\n if (mergedTraceContext.spanId && (options.overwrite || ctx.event.spanId === undefined)) {\n ctx.event.spanId = mergedTraceContext.spanId\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"enrichers.mjs","names":[],"sources":["../src/enrichers/index.ts"],"sourcesContent":["import type { EnrichContext } from '../types'\nimport { composeEnrichers } from '../shared/compose'\nimport { defineEnricher, type EnricherOptions } from '../shared/enricher'\nimport { getHeader, normalizeNumber } from '../shared/headers'\n\nexport type { EnricherOptions }\n\nexport interface UserAgentInfo {\n raw: string\n browser?: { name: string; version?: string }\n os?: { name: string; version?: string }\n device?: { type: 'mobile' | 'tablet' | 'desktop' | 'bot' | 'unknown' }\n}\n\nexport interface GeoInfo {\n country?: string\n region?: string\n regionCode?: string\n city?: string\n latitude?: number\n longitude?: number\n}\n\nexport interface RequestSizeInfo {\n requestBytes?: number\n responseBytes?: number\n}\n\nexport interface TraceContextInfo {\n traceparent?: string\n tracestate?: string\n traceId?: string\n spanId?: string\n}\n\nfunction parseUserAgent(ua: string): UserAgentInfo {\n const lower = ua.toLowerCase()\n\n let deviceType: UserAgentInfo['device'] = { type: 'unknown' }\n if (/bot|crawl|spider|slurp|bingpreview/.test(lower)) {\n deviceType = { type: 'bot' }\n } else if (/ipad|tablet/.test(lower)) {\n deviceType = { type: 'tablet' }\n } else if (/mobi|iphone|android/.test(lower)) {\n deviceType = { type: 'mobile' }\n } else if (ua.length > 0) {\n deviceType = { type: 'desktop' }\n }\n\n const browserMatchers: Array<{ name: string, regex: RegExp }> = [\n { name: 'Edge', regex: /edg\\/([\\d.]+)/i },\n { name: 'Chrome', regex: /chrome\\/([\\d.]+)/i },\n { name: 'Firefox', regex: /firefox\\/([\\d.]+)/i },\n { name: 'Safari', regex: /version\\/([\\d.]+).*safari/i },\n ]\n\n let browser: UserAgentInfo['browser']\n for (const matcher of browserMatchers) {\n const match = ua.match(matcher.regex)\n if (match) {\n browser = { name: matcher.name, version: match[1] }\n break\n }\n }\n\n let os: UserAgentInfo['os']\n if (/windows nt/i.test(ua)) {\n const match = ua.match(/windows nt ([\\d.]+)/i)\n os = { name: 'Windows', version: match?.[1] }\n } else if (/mac os x/i.test(ua) && !/iphone|ipad|ipod/i.test(ua)) {\n const match = ua.match(/mac os x ([\\d_]+)/i)\n os = { name: 'macOS', version: match?.[1]?.replace(/_/g, '.') }\n } else if (/iphone|ipad|ipod/i.test(ua)) {\n const match = ua.match(/os ([\\d_]+)/i)\n os = { name: 'iOS', version: match?.[1]?.replace(/_/g, '.') }\n } else if (/android/i.test(ua)) {\n const match = ua.match(/android ([\\d.]+)/i)\n os = { name: 'Android', version: match?.[1] }\n } else if (/linux/i.test(ua)) {\n os = { name: 'Linux' }\n }\n\n return {\n raw: ua,\n browser,\n os,\n device: deviceType,\n }\n}\n\nfunction parseTraceparent(traceparent: string): Pick<TraceContextInfo, 'traceId' | 'spanId'> | undefined {\n const match = traceparent.match(/^[\\da-f]{2}-([\\da-f]{32})-([\\da-f]{16})-[\\da-f]{2}$/i)\n if (!match) return undefined\n return { traceId: match[1], spanId: match[2] }\n}\n\n/**\n * Enrich events with parsed user agent data.\n * Sets `event.userAgent` with `UserAgentInfo` shape: `{ raw, browser?, os?, device? }`.\n */\nexport function createUserAgentEnricher(options: EnricherOptions = {}): (ctx: EnrichContext) => void {\n return defineEnricher<UserAgentInfo>({\n name: 'userAgent',\n field: 'userAgent',\n compute: ({ headers }) => {\n const ua = getHeader(headers, 'user-agent')\n return ua ? parseUserAgent(ua) : undefined\n },\n }, options)\n}\n\n/**\n * Enrich events with geo data from platform headers.\n * Sets `event.geo` with `GeoInfo` shape: `{ country?, region?, regionCode?, city?, latitude?, longitude? }`.\n *\n * Supports Vercel (`x-vercel-ip-*`) headers out of the box.\n *\n * **Cloudflare note:** Only `cf-ipcountry` is an actual HTTP header added by Cloudflare.\n * The `cf-region`, `cf-city`, `cf-latitude`, `cf-longitude` headers are NOT standard\n * Cloudflare headers — they are properties of `request.cf` which is not exposed as HTTP\n * headers. For full geo data on Cloudflare, write a custom enricher that reads `request.cf`\n * or use a Workers middleware to copy `cf` properties into custom headers.\n */\nexport function createGeoEnricher(options: EnricherOptions = {}): (ctx: EnrichContext) => void {\n return defineEnricher<GeoInfo>({\n name: 'geo',\n field: 'geo',\n compute: ({ headers }) => {\n if (!headers) return undefined\n const geo: GeoInfo = {\n country: getHeader(headers, 'x-vercel-ip-country') ?? getHeader(headers, 'cf-ipcountry'),\n region: getHeader(headers, 'x-vercel-ip-country-region') ?? getHeader(headers, 'cf-region'),\n regionCode: getHeader(headers, 'x-vercel-ip-country-region-code') ?? getHeader(headers, 'cf-region-code'),\n city: getHeader(headers, 'x-vercel-ip-city') ?? getHeader(headers, 'cf-city'),\n latitude: normalizeNumber(getHeader(headers, 'x-vercel-ip-latitude') ?? getHeader(headers, 'cf-latitude')),\n longitude: normalizeNumber(getHeader(headers, 'x-vercel-ip-longitude') ?? getHeader(headers, 'cf-longitude')),\n }\n return Object.values(geo).every(value => value === undefined) ? undefined : geo\n },\n }, options)\n}\n\n/**\n * Enrich events with request/response payload sizes.\n * Sets `event.requestSize` with `RequestSizeInfo` shape: `{ requestBytes?, responseBytes? }`.\n */\nexport function createRequestSizeEnricher(options: EnricherOptions = {}): (ctx: EnrichContext) => void {\n return defineEnricher<RequestSizeInfo>({\n name: 'requestSize',\n field: 'requestSize',\n compute: ({ headers, response }) => {\n const requestBytes = normalizeNumber(getHeader(headers, 'content-length'))\n const responseBytes = normalizeNumber(getHeader(response?.headers, 'content-length'))\n if (requestBytes === undefined && responseBytes === undefined) return undefined\n return { requestBytes, responseBytes }\n },\n }, options)\n}\n\n/**\n * Enrich events with W3C trace context data.\n * Sets `event.traceContext` with `TraceContextInfo` shape: `{ traceparent?, tracestate?, traceId?, spanId? }`.\n * Also sets `event.traceId` and `event.spanId` at the top level.\n */\nexport function createTraceContextEnricher(options: EnricherOptions = {}): (ctx: EnrichContext) => void {\n const enricher = defineEnricher<TraceContextInfo>({\n name: 'traceContext',\n field: 'traceContext',\n compute: ({ event, headers }) => {\n const traceparent = getHeader(headers, 'traceparent')\n const tracestate = getHeader(headers, 'tracestate')\n if (!traceparent && !tracestate) return undefined\n const parsed = traceparent ? parseTraceparent(traceparent) : undefined\n return {\n traceparent,\n tracestate,\n traceId: parsed?.traceId ?? (event.traceId as string | undefined),\n spanId: parsed?.spanId ?? (event.spanId as string | undefined),\n }\n },\n }, options)\n\n // Trace context also pins traceId/spanId at the top level for transports that\n // expect them outside the nested object.\n return (ctx) => {\n enricher(ctx)\n const merged = ctx.event.traceContext as TraceContextInfo | undefined\n if (!merged) return\n if (merged.traceId && (options.overwrite || ctx.event.traceId === undefined)) {\n ctx.event.traceId = merged.traceId\n }\n if (merged.spanId && (options.overwrite || ctx.event.spanId === undefined)) {\n ctx.event.spanId = merged.spanId\n }\n }\n}\n\n/**\n * Compose every built-in enricher into a single async enricher, in the order\n * `userAgent → geo → requestSize → traceContext`.\n *\n * Drop-in shorthand for the most common middleware setup:\n *\n * ```ts\n * import { createDefaultEnrichers } from 'evlog/enrichers'\n *\n * app.use(evlog({ enrich: createDefaultEnrichers() }))\n * ```\n */\nexport function createDefaultEnrichers(options: EnricherOptions = {}): (ctx: EnrichContext) => Promise<void> {\n return composeEnrichers(\n [\n createUserAgentEnricher(options),\n createGeoEnricher(options),\n createRequestSizeEnricher(options),\n createTraceContextEnricher(options),\n ],\n { name: 'default-enrichers' },\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as ErrorOptions } from "./audit-
|
|
1
|
+
import { R as ErrorOptions } from "./audit-X1uUukm3.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/error.d.ts
|
|
4
4
|
/**
|
|
@@ -7,6 +7,7 @@ import { R as ErrorOptions } from "./audit-CTIviX3P.mjs";
|
|
|
7
7
|
* @example
|
|
8
8
|
* ```ts
|
|
9
9
|
* throw new EvlogError({
|
|
10
|
+
* code: 'GITHUB_RATE_LIMIT',
|
|
10
11
|
* message: 'Failed to sync repository',
|
|
11
12
|
* status: 503,
|
|
12
13
|
* why: 'GitHub API rate limit exceeded',
|
|
@@ -17,6 +18,8 @@ import { R as ErrorOptions } from "./audit-CTIviX3P.mjs";
|
|
|
17
18
|
* ```
|
|
18
19
|
*/
|
|
19
20
|
declare class EvlogError extends Error {
|
|
21
|
+
/** Stable, machine-readable identifier (e.g. `'PAYMENT_DECLINED'`). */
|
|
22
|
+
readonly code?: string;
|
|
20
23
|
/** HTTP status code */
|
|
21
24
|
readonly status: number;
|
|
22
25
|
readonly why?: string;
|
|
@@ -36,6 +39,7 @@ declare class EvlogError extends Error {
|
|
|
36
39
|
get statusMessage(): string;
|
|
37
40
|
/** Structured data for serialization */
|
|
38
41
|
get data(): {
|
|
42
|
+
code?: string;
|
|
39
43
|
why?: string;
|
|
40
44
|
fix?: string;
|
|
41
45
|
link?: string;
|
|
@@ -56,6 +60,7 @@ declare class EvlogError extends Error {
|
|
|
56
60
|
*
|
|
57
61
|
* // Structured error with context
|
|
58
62
|
* throw createError({
|
|
63
|
+
* code: 'PAYMENT_DECLINED',
|
|
59
64
|
* message: 'Payment failed',
|
|
60
65
|
* status: 402,
|
|
61
66
|
* why: 'Card declined by issuer',
|
|
@@ -67,4 +72,4 @@ declare class EvlogError extends Error {
|
|
|
67
72
|
declare function createError(options: ErrorOptions | string): EvlogError;
|
|
68
73
|
//#endregion
|
|
69
74
|
export { createError as n, EvlogError as t };
|
|
70
|
-
//# sourceMappingURL=error-
|
|
75
|
+
//# sourceMappingURL=error-Cpc7RVz6.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-Cpc7RVz6.d.mts","names":[],"sources":["../src/error.ts"],"mappings":";;;;;AAsBA;;;;;;;;;;;;;;cAAa,UAAA,SAAmB,KAAA;EAc1B;EAAA,SAXK,IAAA;;WAEA,MAAA;EAAA,SACA,GAAA;EAAA,SACA,GAAA;EAAA,SACA,IAAA;EAgDL;;;;EAAA,IA1CA,QAAA,CAAA,GAAY,MAAA;cAIJ,OAAA,EAAS,YAAA;EAkDZ;EAAA,IAtBL,UAAA,CAAA;EA2DM;EAAA,IAtDN,UAAA,CAAA;EAsDY;EAAA,IAjDZ,aAAA,CAAA;EAsFqB;EAAA,IAjFrB,IAAA,CAAA;IAAU,IAAA;IAAe,GAAA;IAAc,GAAA;IAAc,IAAA;EAAA;EAOhD,QAAA,CAAA;EAqCT,MAAA,CAAA,GAAU,MAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;iBAqCI,WAAA,CAAY,OAAA,EAAS,YAAA,YAAwB,UAAA"}
|
package/dist/error.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as createError, t as EvlogError } from "./error-
|
|
1
|
+
import { n as createError, t as EvlogError } from "./error-Cpc7RVz6.mjs";
|
|
2
2
|
export { EvlogError, createError, createError as createEvlogError };
|
package/dist/error.mjs
CHANGED
|
@@ -8,6 +8,7 @@ const evlogErrorInternalKey = Symbol.for("evlog.error.internal");
|
|
|
8
8
|
* @example
|
|
9
9
|
* ```ts
|
|
10
10
|
* throw new EvlogError({
|
|
11
|
+
* code: 'GITHUB_RATE_LIMIT',
|
|
11
12
|
* message: 'Failed to sync repository',
|
|
12
13
|
* status: 503,
|
|
13
14
|
* why: 'GitHub API rate limit exceeded',
|
|
@@ -18,6 +19,8 @@ const evlogErrorInternalKey = Symbol.for("evlog.error.internal");
|
|
|
18
19
|
* ```
|
|
19
20
|
*/
|
|
20
21
|
var EvlogError = class EvlogError extends Error {
|
|
22
|
+
/** Stable, machine-readable identifier (e.g. `'PAYMENT_DECLINED'`). */
|
|
23
|
+
code;
|
|
21
24
|
/** HTTP status code */
|
|
22
25
|
status;
|
|
23
26
|
why;
|
|
@@ -34,6 +37,7 @@ var EvlogError = class EvlogError extends Error {
|
|
|
34
37
|
const opts = typeof options === "string" ? { message: options } : options;
|
|
35
38
|
super(opts.message, { cause: opts.cause });
|
|
36
39
|
this.name = "EvlogError";
|
|
40
|
+
this.code = opts.code;
|
|
37
41
|
this.status = opts.status ?? 500;
|
|
38
42
|
this.why = opts.why;
|
|
39
43
|
this.fix = opts.fix;
|
|
@@ -60,7 +64,8 @@ var EvlogError = class EvlogError extends Error {
|
|
|
60
64
|
}
|
|
61
65
|
/** Structured data for serialization */
|
|
62
66
|
get data() {
|
|
63
|
-
if (this.why || this.fix || this.link) return {
|
|
67
|
+
if (this.code || this.why || this.fix || this.link) return {
|
|
68
|
+
code: this.code,
|
|
64
69
|
why: this.why,
|
|
65
70
|
fix: this.fix,
|
|
66
71
|
link: this.link
|
|
@@ -76,6 +81,7 @@ var EvlogError = class EvlogError extends Error {
|
|
|
76
81
|
const bold = useColors ? colors.bold : "";
|
|
77
82
|
const lines = [];
|
|
78
83
|
lines.push(`${red}${bold}Error:${reset} ${this.message}`);
|
|
84
|
+
if (this.code) lines.push(`${dim}Code:${reset} ${this.code}`);
|
|
79
85
|
if (this.why) lines.push(`${yellow}Why:${reset} ${this.why}`);
|
|
80
86
|
if (this.fix) lines.push(`${cyan}Fix:${reset} ${this.fix}`);
|
|
81
87
|
if (this.link) lines.push(`${dim}More info:${reset} ${this.link}`);
|
|
@@ -109,6 +115,7 @@ var EvlogError = class EvlogError extends Error {
|
|
|
109
115
|
*
|
|
110
116
|
* // Structured error with context
|
|
111
117
|
* throw createError({
|
|
118
|
+
* code: 'PAYMENT_DECLINED',
|
|
112
119
|
* message: 'Payment failed',
|
|
113
120
|
* status: 402,
|
|
114
121
|
* why: 'Card declined by issuer',
|
package/dist/error.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.mjs","names":[],"sources":["../src/error.ts"],"sourcesContent":["import type { ErrorOptions } from './types'\nimport { colors, isServer } from './utils'\n\n/** Non-enumerable storage so `JSON.stringify(error)` never exposes internal context */\nconst evlogErrorInternalKey = Symbol.for('evlog.error.internal')\n\n/**\n * Structured error with context for better debugging\n *\n * @example\n * ```ts\n * throw new EvlogError({\n * message: 'Failed to sync repository',\n * status: 503,\n * why: 'GitHub API rate limit exceeded',\n * fix: 'Wait 1 hour or use a different token',\n * link: 'https://docs.github.com/en/rest/rate-limit',\n * cause: originalError,\n * })\n * ```\n */\nexport class EvlogError extends Error {\n\n /** HTTP status code */\n readonly status: number\n readonly why?: string\n readonly fix?: string\n readonly link?: string\n\n /**\n * Backend-only context from `createError({ internal: … })`.\n * Omitted from {@link EvlogError#toJSON} and all framework HTTP serializers.\n */\n get internal(): Record<string, unknown> | undefined {\n return (this as EvlogError & { [evlogErrorInternalKey]?: Record<string, unknown> })[evlogErrorInternalKey]\n }\n\n constructor(options: ErrorOptions | string) {\n const opts = typeof options === 'string' ? { message: options } : options\n\n super(opts.message, { cause: opts.cause })\n\n this.name = 'EvlogError'\n this.status = opts.status ?? 500\n this.why = opts.why\n this.fix = opts.fix\n this.link = opts.link\n\n if (opts.internal !== undefined) {\n Object.defineProperty(this, evlogErrorInternalKey, {\n value: opts.internal,\n enumerable: false,\n writable: false,\n configurable: true,\n })\n }\n\n // Maintain proper stack trace in V8\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, EvlogError)\n }\n }\n\n /** HTTP status text (alias for message) */\n get statusText(): string {\n return this.message\n }\n\n /** HTTP status code (alias for compatibility) */\n get statusCode(): number {\n return this.status\n }\n\n /** HTTP status message (alias for compatibility) */\n get statusMessage(): string {\n return this.message\n }\n\n /** Structured data for serialization */\n get data(): { why?: string, fix?: string, link?: string } | undefined {\n if (this.why || this.fix || this.link) {\n return { why: this.why, fix: this.fix, link: this.link }\n }\n return undefined\n }\n\n override toString(): string {\n const useColors = isServer()\n\n const red = useColors ? colors.red : ''\n const yellow = useColors ? colors.yellow : ''\n const cyan = useColors ? colors.cyan : ''\n const dim = useColors ? colors.dim : ''\n const reset = useColors ? colors.reset : ''\n const bold = useColors ? colors.bold : ''\n\n const lines: string[] = []\n\n lines.push(`${red}${bold}Error:${reset} ${this.message}`)\n\n if (this.why) {\n lines.push(`${yellow}Why:${reset} ${this.why}`)\n }\n\n if (this.fix) {\n lines.push(`${cyan}Fix:${reset} ${this.fix}`)\n }\n\n if (this.link) {\n lines.push(`${dim}More info:${reset} ${this.link}`)\n }\n\n if (this.cause) {\n lines.push(`${dim}Caused by:${reset} ${(this.cause as Error).message}`)\n }\n\n return lines.join('\\n')\n }\n\n toJSON(): Record<string, unknown> {\n const { data } = this\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n ...(data && { data }),\n ...(this.cause instanceof Error && {\n cause: { name: this.cause.name, message: this.cause.message },\n }),\n }\n }\n\n}\n\n/**\n * Create a structured error with context for debugging and user-facing messages.\n *\n * @param options - Error message string or full options object\n * @returns EvlogError with HTTP metadata (`status`, `statusText`) and `data`; also includes `statusCode` and `statusMessage` for legacy compatibility\n *\n * @example\n * ```ts\n * // Simple error\n * throw createError('Something went wrong')\n *\n * // Structured error with context\n * throw createError({\n * message: 'Payment failed',\n * status: 402,\n * why: 'Card declined by issuer',\n * fix: 'Try a different payment method',\n * link: 'https://docs.example.com/payments',\n * })\n * ```\n */\nexport function createError(options: ErrorOptions | string): EvlogError {\n return new EvlogError(options)\n}\n\nexport { createError as createEvlogError }\n"],"mappings":";;;AAIA,MAAM,wBAAwB,OAAO,IAAI,uBAAuB
|
|
1
|
+
{"version":3,"file":"error.mjs","names":[],"sources":["../src/error.ts"],"sourcesContent":["import type { ErrorOptions } from './types'\nimport { colors, isServer } from './utils'\n\n/** Non-enumerable storage so `JSON.stringify(error)` never exposes internal context */\nconst evlogErrorInternalKey = Symbol.for('evlog.error.internal')\n\n/**\n * Structured error with context for better debugging\n *\n * @example\n * ```ts\n * throw new EvlogError({\n * code: 'GITHUB_RATE_LIMIT',\n * message: 'Failed to sync repository',\n * status: 503,\n * why: 'GitHub API rate limit exceeded',\n * fix: 'Wait 1 hour or use a different token',\n * link: 'https://docs.github.com/en/rest/rate-limit',\n * cause: originalError,\n * })\n * ```\n */\nexport class EvlogError extends Error {\n\n /** Stable, machine-readable identifier (e.g. `'PAYMENT_DECLINED'`). */\n readonly code?: string\n /** HTTP status code */\n readonly status: number\n readonly why?: string\n readonly fix?: string\n readonly link?: string\n\n /**\n * Backend-only context from `createError({ internal: … })`.\n * Omitted from {@link EvlogError#toJSON} and all framework HTTP serializers.\n */\n get internal(): Record<string, unknown> | undefined {\n return (this as EvlogError & { [evlogErrorInternalKey]?: Record<string, unknown> })[evlogErrorInternalKey]\n }\n\n constructor(options: ErrorOptions | string) {\n const opts = typeof options === 'string' ? { message: options } : options\n\n super(opts.message, { cause: opts.cause })\n\n this.name = 'EvlogError'\n this.code = opts.code\n this.status = opts.status ?? 500\n this.why = opts.why\n this.fix = opts.fix\n this.link = opts.link\n\n if (opts.internal !== undefined) {\n Object.defineProperty(this, evlogErrorInternalKey, {\n value: opts.internal,\n enumerable: false,\n writable: false,\n configurable: true,\n })\n }\n\n // Maintain proper stack trace in V8\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, EvlogError)\n }\n }\n\n /** HTTP status text (alias for message) */\n get statusText(): string {\n return this.message\n }\n\n /** HTTP status code (alias for compatibility) */\n get statusCode(): number {\n return this.status\n }\n\n /** HTTP status message (alias for compatibility) */\n get statusMessage(): string {\n return this.message\n }\n\n /** Structured data for serialization */\n get data(): { code?: string, why?: string, fix?: string, link?: string } | undefined {\n if (this.code || this.why || this.fix || this.link) {\n return { code: this.code, why: this.why, fix: this.fix, link: this.link }\n }\n return undefined\n }\n\n override toString(): string {\n const useColors = isServer()\n\n const red = useColors ? colors.red : ''\n const yellow = useColors ? colors.yellow : ''\n const cyan = useColors ? colors.cyan : ''\n const dim = useColors ? colors.dim : ''\n const reset = useColors ? colors.reset : ''\n const bold = useColors ? colors.bold : ''\n\n const lines: string[] = []\n\n lines.push(`${red}${bold}Error:${reset} ${this.message}`)\n\n if (this.code) {\n lines.push(`${dim}Code:${reset} ${this.code}`)\n }\n\n if (this.why) {\n lines.push(`${yellow}Why:${reset} ${this.why}`)\n }\n\n if (this.fix) {\n lines.push(`${cyan}Fix:${reset} ${this.fix}`)\n }\n\n if (this.link) {\n lines.push(`${dim}More info:${reset} ${this.link}`)\n }\n\n if (this.cause) {\n lines.push(`${dim}Caused by:${reset} ${(this.cause as Error).message}`)\n }\n\n return lines.join('\\n')\n }\n\n toJSON(): Record<string, unknown> {\n const { data } = this\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n ...(data && { data }),\n ...(this.cause instanceof Error && {\n cause: { name: this.cause.name, message: this.cause.message },\n }),\n }\n }\n\n}\n\n/**\n * Create a structured error with context for debugging and user-facing messages.\n *\n * @param options - Error message string or full options object\n * @returns EvlogError with HTTP metadata (`status`, `statusText`) and `data`; also includes `statusCode` and `statusMessage` for legacy compatibility\n *\n * @example\n * ```ts\n * // Simple error\n * throw createError('Something went wrong')\n *\n * // Structured error with context\n * throw createError({\n * code: 'PAYMENT_DECLINED',\n * message: 'Payment failed',\n * status: 402,\n * why: 'Card declined by issuer',\n * fix: 'Try a different payment method',\n * link: 'https://docs.example.com/payments',\n * })\n * ```\n */\nexport function createError(options: ErrorOptions | string): EvlogError {\n return new EvlogError(options)\n}\n\nexport { createError as createEvlogError }\n"],"mappings":";;;AAIA,MAAM,wBAAwB,OAAO,IAAI,uBAAuB;;;;;;;;;;;;;;;;;AAkBhE,IAAa,aAAb,MAAa,mBAAmB,MAAM;;CAGpC;;CAEA;CACA;CACA;CACA;;;;;CAMA,IAAI,WAAgD;AAClD,SAAQ,KAA4E;;CAGtF,YAAY,SAAgC;EAC1C,MAAM,OAAO,OAAO,YAAY,WAAW,EAAE,SAAS,SAAS,GAAG;AAElE,QAAM,KAAK,SAAS,EAAE,OAAO,KAAK,OAAO,CAAC;AAE1C,OAAK,OAAO;AACZ,OAAK,OAAO,KAAK;AACjB,OAAK,SAAS,KAAK,UAAU;AAC7B,OAAK,MAAM,KAAK;AAChB,OAAK,MAAM,KAAK;AAChB,OAAK,OAAO,KAAK;AAEjB,MAAI,KAAK,aAAa,KAAA,EACpB,QAAO,eAAe,MAAM,uBAAuB;GACjD,OAAO,KAAK;GACZ,YAAY;GACZ,UAAU;GACV,cAAc;GACf,CAAC;AAIJ,MAAI,MAAM,kBACR,OAAM,kBAAkB,MAAM,WAAW;;;CAK7C,IAAI,aAAqB;AACvB,SAAO,KAAK;;;CAId,IAAI,aAAqB;AACvB,SAAO,KAAK;;;CAId,IAAI,gBAAwB;AAC1B,SAAO,KAAK;;;CAId,IAAI,OAAiF;AACnF,MAAI,KAAK,QAAQ,KAAK,OAAO,KAAK,OAAO,KAAK,KAC5C,QAAO;GAAE,MAAM,KAAK;GAAM,KAAK,KAAK;GAAK,KAAK,KAAK;GAAK,MAAM,KAAK;GAAM;;CAK7E,WAA4B;EAC1B,MAAM,YAAY,UAAU;EAE5B,MAAM,MAAM,YAAY,OAAO,MAAM;EACrC,MAAM,SAAS,YAAY,OAAO,SAAS;EAC3C,MAAM,OAAO,YAAY,OAAO,OAAO;EACvC,MAAM,MAAM,YAAY,OAAO,MAAM;EACrC,MAAM,QAAQ,YAAY,OAAO,QAAQ;EACzC,MAAM,OAAO,YAAY,OAAO,OAAO;EAEvC,MAAM,QAAkB,EAAE;AAE1B,QAAM,KAAK,GAAG,MAAM,KAAK,QAAQ,MAAM,GAAG,KAAK,UAAU;AAEzD,MAAI,KAAK,KACP,OAAM,KAAK,GAAG,IAAI,OAAO,MAAM,GAAG,KAAK,OAAO;AAGhD,MAAI,KAAK,IACP,OAAM,KAAK,GAAG,OAAO,MAAM,MAAM,GAAG,KAAK,MAAM;AAGjD,MAAI,KAAK,IACP,OAAM,KAAK,GAAG,KAAK,MAAM,MAAM,GAAG,KAAK,MAAM;AAG/C,MAAI,KAAK,KACP,OAAM,KAAK,GAAG,IAAI,YAAY,MAAM,GAAG,KAAK,OAAO;AAGrD,MAAI,KAAK,MACP,OAAM,KAAK,GAAG,IAAI,YAAY,MAAM,GAAI,KAAK,MAAgB,UAAU;AAGzE,SAAO,MAAM,KAAK,KAAK;;CAGzB,SAAkC;EAChC,MAAM,EAAE,SAAS;AACjB,SAAO;GACL,MAAM,KAAK;GACX,SAAS,KAAK;GACd,QAAQ,KAAK;GACb,GAAI,QAAQ,EAAE,MAAM;GACpB,GAAI,KAAK,iBAAiB,SAAS,EACjC,OAAO;IAAE,MAAM,KAAK,MAAM;IAAM,SAAS,KAAK,MAAM;IAAS,EAC9D;GACF;;;;;;;;;;;;;;;;;;;;;;;;;AA2BL,SAAgB,YAAY,SAA4C;AACtE,QAAO,IAAI,WAAW,QAAQ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors-
|
|
1
|
+
{"version":3,"file":"errors-BQgyQ9xe.mjs","names":[],"sources":["../src/shared/errors.ts"],"sourcesContent":["/**\n * Extract HTTP status from an error, checking both `status` and `statusCode`.\n *\n * Works with any error shape (H3, Nitro, EvlogError, plain objects).\n *\n * @beta This function is part of the evlog toolkit API for building custom framework integrations.\n */\nexport function extractErrorStatus(error: unknown): number {\n if (error === null || typeof error !== 'object') return 500\n const raw = (error as { status?: unknown }).status\n ?? (error as { statusCode?: unknown }).statusCode\n const status = Number(raw)\n return Number.isFinite(status) ? status : 500\n}\n"],"mappings":";;;;;;;;AAOA,SAAgB,mBAAmB,OAAwB;AACzD,KAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO;CACxD,MAAM,MAAO,MAA+B,UACtC,MAAmC;CACzC,MAAM,SAAS,OAAO,IAAI;AAC1B,QAAO,OAAO,SAAS,OAAO,GAAG,SAAS"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Z as RouteConfig } from "./audit-
|
|
1
|
+
import { Z as RouteConfig } from "./audit-X1uUukm3.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/shared/routes.d.ts
|
|
4
4
|
declare function shouldLog(path: string, include?: string[], exclude?: string[]): boolean;
|
|
@@ -36,4 +36,4 @@ declare function getServiceForPath(path: string, routes?: Record<string, RouteCo
|
|
|
36
36
|
declare function extractErrorStatus(error: unknown): number;
|
|
37
37
|
//#endregion
|
|
38
38
|
export { getServiceForPath as n, shouldLog as r, extractErrorStatus as t };
|
|
39
|
-
//# sourceMappingURL=errors-
|
|
39
|
+
//# sourceMappingURL=errors-prnQ3kES.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors-
|
|
1
|
+
{"version":3,"file":"errors-prnQ3kES.d.mts","names":[],"sources":["../src/shared/routes.ts","../src/shared/errors.ts"],"mappings":";;;iBAGgB,SAAA,CAAU,IAAA,UAAc,OAAA,aAAoB,OAAA;;AAA5D;;;;;;;;;AAsCA;;;;;;;;;;;iBAAgB,iBAAA,CAAkB,IAAA,UAAc,MAAA,GAAS,MAAA,SAAe,WAAA;;;;;;AAtCxE;;;;iBCIgB,kBAAA,CAAmB,KAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//#region src/shared/event.ts
|
|
2
|
+
/**
|
|
3
|
+
* Helpers for building / mutating wide events from inside enrichers and adapters.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Merge a computed value onto an existing event field. By default, existing
|
|
7
|
+
* object values win over computed ones — so `log.set({ geo: ... })` keeps
|
|
8
|
+
* precedence over an enricher's automatic detection.
|
|
9
|
+
*/
|
|
10
|
+
function mergeEventField(existing, computed, overwrite) {
|
|
11
|
+
if (overwrite) return computed;
|
|
12
|
+
if (typeof computed !== "object" || computed === null) return existing === void 0 || existing === null ? computed : existing;
|
|
13
|
+
if (existing === void 0 || existing === null || typeof existing !== "object") return computed;
|
|
14
|
+
return {
|
|
15
|
+
...computed,
|
|
16
|
+
...existing
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** Convert a JS value to a {@link TypedAttributeValue}. Objects are JSON-serialized. */
|
|
20
|
+
function toTypedAttributeValue(value) {
|
|
21
|
+
if (value === null || value === void 0) return void 0;
|
|
22
|
+
if (typeof value === "string") return {
|
|
23
|
+
value,
|
|
24
|
+
type: "string"
|
|
25
|
+
};
|
|
26
|
+
if (typeof value === "boolean") return {
|
|
27
|
+
value,
|
|
28
|
+
type: "boolean"
|
|
29
|
+
};
|
|
30
|
+
if (typeof value === "number") {
|
|
31
|
+
if (Number.isInteger(value)) return {
|
|
32
|
+
value,
|
|
33
|
+
type: "integer"
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
value,
|
|
37
|
+
type: "double"
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
value: JSON.stringify(value),
|
|
42
|
+
type: "string"
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Convert a JS value to the OTLP `AnyValue` shape (`stringValue` / `intValue` / `boolValue`). */
|
|
46
|
+
function toOtlpAttributeValue(value) {
|
|
47
|
+
if (typeof value === "boolean") return { boolValue: value };
|
|
48
|
+
if (typeof value === "number" && Number.isInteger(value)) return { intValue: String(value) };
|
|
49
|
+
if (typeof value === "string") return { stringValue: value };
|
|
50
|
+
return { stringValue: JSON.stringify(value) };
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { toOtlpAttributeValue as n, toTypedAttributeValue as r, mergeEventField as t };
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=event-DcHmEm3O.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-DcHmEm3O.mjs","names":[],"sources":["../src/shared/event.ts"],"sourcesContent":["/**\n * Helpers for building / mutating wide events from inside enrichers and adapters.\n */\n\n/**\n * Merge a computed value onto an existing event field. By default, existing\n * object values win over computed ones — so `log.set({ geo: ... })` keeps\n * precedence over an enricher's automatic detection.\n */\nexport function mergeEventField<T>(\n existing: unknown,\n computed: T,\n overwrite?: boolean,\n): T {\n if (overwrite) return computed\n if (typeof computed !== 'object' || computed === null) {\n return existing === undefined || existing === null ? computed : existing as T\n }\n if (existing === undefined || existing === null || typeof existing !== 'object') {\n return computed\n }\n return { ...computed, ...(existing as T) }\n}\n\n/** Typed attribute used when flattening events for OTLP/Sentry/Datadog/PostHog. */\nexport type AttributeValueKind = 'string' | 'integer' | 'double' | 'boolean'\n\nexport interface TypedAttributeValue {\n value: string | number | boolean\n type: AttributeValueKind\n}\n\n/** Convert a JS value to a {@link TypedAttributeValue}. Objects are JSON-serialized. */\nexport function toTypedAttributeValue(value: unknown): TypedAttributeValue | undefined {\n if (value === null || value === undefined) return undefined\n if (typeof value === 'string') return { value, type: 'string' }\n if (typeof value === 'boolean') return { value, type: 'boolean' }\n if (typeof value === 'number') {\n if (Number.isInteger(value)) return { value, type: 'integer' }\n return { value, type: 'double' }\n }\n return { value: JSON.stringify(value), type: 'string' }\n}\n\n/** Convert a JS value to the OTLP `AnyValue` shape (`stringValue` / `intValue` / `boolValue`). */\nexport function toOtlpAttributeValue(value: unknown): {\n stringValue?: string\n intValue?: string\n boolValue?: boolean\n} {\n if (typeof value === 'boolean') return { boolValue: value }\n if (typeof value === 'number' && Number.isInteger(value)) return { intValue: String(value) }\n if (typeof value === 'string') return { stringValue: value }\n return { stringValue: JSON.stringify(value) }\n}\n"],"mappings":";;;;;;;;;AASA,SAAgB,gBACd,UACA,UACA,WACG;AACH,KAAI,UAAW,QAAO;AACtB,KAAI,OAAO,aAAa,YAAY,aAAa,KAC/C,QAAO,aAAa,KAAA,KAAa,aAAa,OAAO,WAAW;AAElE,KAAI,aAAa,KAAA,KAAa,aAAa,QAAQ,OAAO,aAAa,SACrE,QAAO;AAET,QAAO;EAAE,GAAG;EAAU,GAAI;EAAgB;;;AAY5C,SAAgB,sBAAsB,OAAiD;AACrF,KAAI,UAAU,QAAQ,UAAU,KAAA,EAAW,QAAO,KAAA;AAClD,KAAI,OAAO,UAAU,SAAU,QAAO;EAAE;EAAO,MAAM;EAAU;AAC/D,KAAI,OAAO,UAAU,UAAW,QAAO;EAAE;EAAO,MAAM;EAAW;AACjE,KAAI,OAAO,UAAU,UAAU;AAC7B,MAAI,OAAO,UAAU,MAAM,CAAE,QAAO;GAAE;GAAO,MAAM;GAAW;AAC9D,SAAO;GAAE;GAAO,MAAM;GAAU;;AAElC,QAAO;EAAE,OAAO,KAAK,UAAU,MAAM;EAAE,MAAM;EAAU;;;AAIzD,SAAgB,qBAAqB,OAInC;AACA,KAAI,OAAO,UAAU,UAAW,QAAO,EAAE,WAAW,OAAO;AAC3D,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,MAAM,CAAE,QAAO,EAAE,UAAU,OAAO,MAAM,EAAE;AAC5F,KAAI,OAAO,UAAU,SAAU,QAAO,EAAE,aAAa,OAAO;AAC5D,QAAO,EAAE,aAAa,KAAK,UAAU,MAAM,EAAE"}
|
package/dist/express/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Y as RequestLogger } from "../audit-
|
|
2
|
-
import { t as BaseEvlogOptions } from "../middleware-
|
|
1
|
+
import { Y as RequestLogger } from "../audit-X1uUukm3.mjs";
|
|
2
|
+
import { t as BaseEvlogOptions } from "../middleware-CAQHJRN1.mjs";
|
|
3
3
|
import { RequestHandler } from "express";
|
|
4
4
|
|
|
5
5
|
//#region src/express/index.d.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/express/index.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/express/index.ts"],"mappings":";;;;;cAMiB,SAAA,sBAAS,MAAA,wBAAA,aAAA,CAAA,CAAA;AAAA,KAId,mBAAA,GAAsB,gBAAA;AAAA;EAAA,UAKtB,OAAA;IACR,GAAA,EAAK,aAAA;EAAA;AAAA;;;;;;;;;AANT;;;;;AAEoB;;;;;iBAwCJ,KAAA,CAAM,OAAA,GAAS,mBAAA,GAA2B,cAAA"}
|
package/dist/express/index.mjs
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import { t as
|
|
3
|
-
import { n as extractSafeNodeHeaders } from "../headers-D74M0wsg.mjs";
|
|
4
|
-
import { t as createLoggerStorage } from "../storage-CFGTn37X.mjs";
|
|
1
|
+
import { t as defineFrameworkIntegration } from "../integration-DSZPbI9N.mjs";
|
|
2
|
+
import { t as createLoggerStorage } from "../storage-BT-3fT1-.mjs";
|
|
5
3
|
//#region src/express/index.ts
|
|
6
4
|
const { storage, useLogger } = createLoggerStorage("middleware context. Make sure app.use(evlog()) is registered before your routes.");
|
|
5
|
+
const integration = defineFrameworkIntegration({
|
|
6
|
+
name: "express",
|
|
7
|
+
extractRequest: (req) => ({
|
|
8
|
+
method: req.method,
|
|
9
|
+
path: new URL(req.originalUrl || req.url || "/", "http://localhost").pathname,
|
|
10
|
+
headers: req.headers,
|
|
11
|
+
requestId: req.get("x-request-id")
|
|
12
|
+
}),
|
|
13
|
+
attachLogger: (req, logger) => {
|
|
14
|
+
req.log = logger;
|
|
15
|
+
},
|
|
16
|
+
storage
|
|
17
|
+
});
|
|
7
18
|
/**
|
|
8
19
|
* Create an evlog middleware for Express.
|
|
9
20
|
*
|
|
@@ -24,24 +35,15 @@ const { storage, useLogger } = createLoggerStorage("middleware context. Make sur
|
|
|
24
35
|
*/
|
|
25
36
|
function evlog(options = {}) {
|
|
26
37
|
return (req, res, next) => {
|
|
27
|
-
const
|
|
28
|
-
method: req.method,
|
|
29
|
-
path: new URL(req.originalUrl || req.url || "/", "http://localhost").pathname,
|
|
30
|
-
requestId: req.get("x-request-id") || crypto.randomUUID(),
|
|
31
|
-
headers: extractSafeNodeHeaders(req.headers),
|
|
32
|
-
...options
|
|
33
|
-
};
|
|
34
|
-
const { logger, finish, skipped } = createMiddlewareLogger(middlewareOpts);
|
|
38
|
+
const { finish, skipped, runWith } = integration.start(req, options);
|
|
35
39
|
if (skipped) {
|
|
36
40
|
next();
|
|
37
41
|
return;
|
|
38
42
|
}
|
|
39
|
-
attachForkToLogger(storage, logger, middlewareOpts);
|
|
40
|
-
req.log = logger;
|
|
41
43
|
res.on("finish", () => {
|
|
42
44
|
finish({ status: res.statusCode }).catch(() => {});
|
|
43
45
|
});
|
|
44
|
-
|
|
46
|
+
runWith(() => next());
|
|
45
47
|
};
|
|
46
48
|
}
|
|
47
49
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/express/index.ts"],"sourcesContent":["import type { Request, Response, NextFunction, RequestHandler } from 'express'\nimport type { RequestLogger } from '../types'\nimport {
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/express/index.ts"],"sourcesContent":["import type { Request, Response, NextFunction, RequestHandler } from 'express'\nimport type { RequestLogger } from '../types'\nimport { defineFrameworkIntegration } from '../shared/integration'\nimport type { BaseEvlogOptions } from '../shared/middleware'\nimport { createLoggerStorage } from '../shared/storage'\n\nconst { storage, useLogger } = createLoggerStorage(\n 'middleware context. Make sure app.use(evlog()) is registered before your routes.',\n)\n\nexport type EvlogExpressOptions = BaseEvlogOptions\n\nexport { useLogger }\n\ndeclare module 'express-serve-static-core' {\n interface Request {\n log: RequestLogger\n }\n}\n\nconst integration = defineFrameworkIntegration<Request>({\n name: 'express',\n extractRequest: (req) => ({\n method: req.method,\n path: new URL(req.originalUrl || req.url || '/', 'http://localhost').pathname,\n headers: req.headers,\n requestId: req.get('x-request-id'),\n }),\n attachLogger: (req, logger) => {\n req.log = logger\n },\n storage,\n})\n\n/**\n * Create an evlog middleware for Express.\n *\n * @example\n * ```ts\n * import express from 'express'\n * import { evlog } from 'evlog/express'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * const app = express()\n * app.use(evlog({\n * drain: createAxiomDrain(),\n * enrich: (ctx) => {\n * ctx.event.region = process.env.FLY_REGION\n * },\n * }))\n * ```\n */\nexport function evlog(options: EvlogExpressOptions = {}): RequestHandler {\n return (req: Request, res: Response, next: NextFunction) => {\n const { finish, skipped, runWith } = integration.start(req, options)\n\n if (skipped) {\n next()\n return\n }\n\n res.on('finish', () => {\n finish({ status: res.statusCode }).catch(() => {})\n })\n\n void runWith(() => next())\n }\n}\n"],"mappings":";;;AAMA,MAAM,EAAE,SAAS,cAAc,oBAC7B,mFACD;AAYD,MAAM,cAAc,2BAAoC;CACtD,MAAM;CACN,iBAAiB,SAAS;EACxB,QAAQ,IAAI;EACZ,MAAM,IAAI,IAAI,IAAI,eAAe,IAAI,OAAO,KAAK,mBAAmB,CAAC;EACrE,SAAS,IAAI;EACb,WAAW,IAAI,IAAI,eAAe;EACnC;CACD,eAAe,KAAK,WAAW;AAC7B,MAAI,MAAM;;CAEZ;CACD,CAAC;;;;;;;;;;;;;;;;;;;AAoBF,SAAgB,MAAM,UAA+B,EAAE,EAAkB;AACvE,SAAQ,KAAc,KAAe,SAAuB;EAC1D,MAAM,EAAE,QAAQ,SAAS,YAAY,YAAY,MAAM,KAAK,QAAQ;AAEpE,MAAI,SAAS;AACX,SAAM;AACN;;AAGF,MAAI,GAAG,gBAAgB;AACrB,UAAO,EAAE,QAAQ,IAAI,YAAY,CAAC,CAAC,YAAY,GAAG;IAClD;AAEG,gBAAc,MAAM,CAAC"}
|
package/dist/fastify/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Y as RequestLogger } from "../audit-
|
|
2
|
-
import { t as BaseEvlogOptions } from "../middleware-
|
|
1
|
+
import { Y as RequestLogger } from "../audit-X1uUukm3.mjs";
|
|
2
|
+
import { t as BaseEvlogOptions } from "../middleware-CAQHJRN1.mjs";
|
|
3
3
|
import { FastifyPluginCallback } from "fastify";
|
|
4
4
|
|
|
5
5
|
//#region src/fastify/index.d.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/fastify/index.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/fastify/index.ts"],"mappings":";;;;;cAKiB,SAAA,sBAAS,MAAA,wBAAA,aAAA,CAAA,CAAA;AAAA,KAId,mBAAA,GAAsB,gBAAA;AAAA;EAAA,UAKtB,cAAA;IAER,GAAA;EAAA;AAAA;;;;;;;;;;;AAPJ;;;;;AAEoB;;;;;;cAsFP,KAAA,EAAK,qBAAA,CAAA,gBAAA"}
|
package/dist/fastify/index.mjs
CHANGED
|
@@ -1,32 +1,31 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import { t as
|
|
3
|
-
import { n as extractSafeNodeHeaders } from "../headers-D74M0wsg.mjs";
|
|
4
|
-
import { t as createLoggerStorage } from "../storage-CFGTn37X.mjs";
|
|
1
|
+
import { t as defineFrameworkIntegration } from "../integration-DSZPbI9N.mjs";
|
|
2
|
+
import { t as createLoggerStorage } from "../storage-BT-3fT1-.mjs";
|
|
5
3
|
//#region src/fastify/index.ts
|
|
6
4
|
const { storage, useLogger } = createLoggerStorage("plugin context. Make sure app.register(evlog) is called before your routes.");
|
|
5
|
+
const integration = defineFrameworkIntegration({
|
|
6
|
+
name: "fastify",
|
|
7
|
+
extractRequest: (req) => ({
|
|
8
|
+
method: req.method,
|
|
9
|
+
path: new URL(req.url, "http://localhost").pathname,
|
|
10
|
+
headers: req.headers,
|
|
11
|
+
requestId: typeof req.headers["x-request-id"] === "string" ? req.headers["x-request-id"] : void 0
|
|
12
|
+
}),
|
|
13
|
+
attachLogger: (req, logger) => {
|
|
14
|
+
req.log = logger;
|
|
15
|
+
},
|
|
16
|
+
storage
|
|
17
|
+
});
|
|
7
18
|
const evlogPlugin = (fastify, options, done) => {
|
|
8
19
|
const emitted = /* @__PURE__ */ new WeakSet();
|
|
9
20
|
const requestState = /* @__PURE__ */ new WeakMap();
|
|
10
|
-
fastify.addHook("onRequest", (request, _reply,
|
|
11
|
-
const
|
|
12
|
-
const path = new URL(request.url, "http://localhost").pathname;
|
|
13
|
-
const middlewareOpts = {
|
|
14
|
-
method: request.method,
|
|
15
|
-
path,
|
|
16
|
-
requestId: headers["x-request-id"] || crypto.randomUUID(),
|
|
17
|
-
headers,
|
|
18
|
-
...options
|
|
19
|
-
};
|
|
20
|
-
const { logger, finish, skipped } = createMiddlewareLogger(middlewareOpts);
|
|
21
|
+
fastify.addHook("onRequest", (request, _reply, next) => {
|
|
22
|
+
const { finish, skipped, runWith } = integration.start(request, options);
|
|
21
23
|
if (skipped) {
|
|
22
|
-
|
|
24
|
+
next();
|
|
23
25
|
return;
|
|
24
26
|
}
|
|
25
|
-
attachForkToLogger(storage, logger, middlewareOpts);
|
|
26
|
-
const req = request;
|
|
27
|
-
req.log = logger;
|
|
28
27
|
requestState.set(request, { finish });
|
|
29
|
-
|
|
28
|
+
runWith(() => next());
|
|
30
29
|
});
|
|
31
30
|
fastify.addHook("onResponse", async (request, reply) => {
|
|
32
31
|
const state = requestState.get(request);
|