evlog 2.1.0 → 2.3.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.
@@ -0,0 +1,75 @@
1
+ import { DrainContext, EnrichContext, RequestLogger, RouteConfig, TailSamplingContext } from "../types.mjs";
2
+ import { Elysia } from "elysia";
3
+
4
+ //#region src/elysia/index.d.ts
5
+ interface EvlogElysiaOptions {
6
+ /** Route patterns to include in logging (glob). If not set, all routes are logged */
7
+ include?: string[];
8
+ /** Route patterns to exclude from logging. Exclusions take precedence over inclusions */
9
+ exclude?: string[];
10
+ /** Route-specific service configuration */
11
+ routes?: Record<string, RouteConfig>;
12
+ /**
13
+ * Drain callback called with every emitted event.
14
+ * Use with drain adapters (Axiom, OTLP, Sentry, etc.) or custom endpoints.
15
+ */
16
+ drain?: (ctx: DrainContext) => void | Promise<void>;
17
+ /**
18
+ * Enrich callback called after emit, before drain.
19
+ * Use to add derived context (geo, deployment info, user agent, etc.).
20
+ */
21
+ enrich?: (ctx: EnrichContext) => void | Promise<void>;
22
+ /**
23
+ * Custom tail sampling callback.
24
+ * Set `ctx.shouldKeep = true` to force-keep the log regardless of head sampling.
25
+ */
26
+ keep?: (ctx: TailSamplingContext) => void | Promise<void>;
27
+ }
28
+ /**
29
+ * Get the request-scoped logger from anywhere in the call stack.
30
+ * Must be called inside a request handled by the `evlog()` plugin.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * import { useLogger } from 'evlog/elysia'
35
+ *
36
+ * function findUser(id: string) {
37
+ * const log = useLogger()
38
+ * log.set({ user: { id } })
39
+ * }
40
+ * ```
41
+ */
42
+ declare function useLogger<T extends object = Record<string, unknown>>(): RequestLogger<T>;
43
+ declare function evlog(options?: EvlogElysiaOptions): Elysia<"", {
44
+ decorator: {};
45
+ store: {};
46
+ derive: {
47
+ readonly log: RequestLogger<Record<string, unknown>>;
48
+ };
49
+ resolve: {};
50
+ }, {
51
+ typebox: {};
52
+ error: {};
53
+ }, {
54
+ schema: {};
55
+ standaloneSchema: {};
56
+ macro: {};
57
+ macroFn: {};
58
+ parser: {};
59
+ response: {};
60
+ }, {}, {
61
+ derive: {};
62
+ resolve: {};
63
+ schema: {};
64
+ standaloneSchema: {};
65
+ response: {};
66
+ }, {
67
+ derive: {};
68
+ resolve: {};
69
+ schema: {};
70
+ standaloneSchema: {};
71
+ response: {};
72
+ }>;
73
+ //#endregion
74
+ export { EvlogElysiaOptions, evlog, useLogger };
75
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/elysia/index.ts"],"mappings":";;;;UAQiB,kBAAA;;EAEf,OAAA;EAFiC;EAIjC,OAAA;EAEwB;EAAxB,MAAA,GAAS,MAAA,SAAe,WAAA;EAKV;;;;EAAd,KAAA,IAAS,GAAA,EAAK,YAAA,YAAwB,OAAA;EAUM;;;;EAL5C,MAAA,IAAU,GAAA,EAAK,aAAA,YAAyB,OAAA;EAVxC;;;;EAeA,IAAA,IAAQ,GAAA,EAAK,mBAAA,YAA+B,OAAA;AAAA;;;;;;;;;;;;AAiB9C;;;iBAAgB,SAAA,oBAA6B,MAAA,kBAAA,CAAA,GAA4B,aAAA,CAAc,CAAA;AAAA,iBAuCvE,KAAA,CAAM,OAAA,GAAS,kBAAA,GAAuB,MAAA"}
@@ -0,0 +1,62 @@
1
+ import { r as createMiddlewareLogger, t as extractSafeHeaders } from "../headers-CXOd5EyZ.mjs";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+ import { Elysia } from "elysia";
4
+
5
+ //#region src/elysia/index.ts
6
+ const storage = new AsyncLocalStorage();
7
+ /**
8
+ * Get the request-scoped logger from anywhere in the call stack.
9
+ * Must be called inside a request handled by the `evlog()` plugin.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { useLogger } from 'evlog/elysia'
14
+ *
15
+ * function findUser(id: string) {
16
+ * const log = useLogger()
17
+ * log.set({ user: { id } })
18
+ * }
19
+ * ```
20
+ */
21
+ function useLogger() {
22
+ const logger = storage.getStore();
23
+ if (!logger) throw new Error("[evlog] useLogger() was called outside of an evlog plugin context. Make sure app.use(evlog()) is registered before your routes.");
24
+ return logger;
25
+ }
26
+ function evlog(options = {}) {
27
+ const emitted = /* @__PURE__ */ new WeakSet();
28
+ const requestState = /* @__PURE__ */ new WeakMap();
29
+ return new Elysia({ name: "evlog" }).derive({ as: "global" }, ({ request }) => {
30
+ const url = new URL(request.url);
31
+ const { logger, finish, skipped } = createMiddlewareLogger({
32
+ method: request.method,
33
+ path: url.pathname,
34
+ requestId: request.headers.get("x-request-id") || crypto.randomUUID(),
35
+ headers: extractSafeHeaders(request.headers),
36
+ ...options
37
+ });
38
+ storage.enterWith(logger);
39
+ requestState.set(request, {
40
+ finish,
41
+ skipped
42
+ });
43
+ return { log: logger };
44
+ }).onAfterHandle({ as: "global" }, async ({ request, set }) => {
45
+ const state = requestState.get(request);
46
+ if (!state || state.skipped || emitted.has(request)) return;
47
+ emitted.add(request);
48
+ await state.finish({ status: set.status || 200 });
49
+ }).onError({ as: "global" }, async ({ request, error }) => {
50
+ const state = requestState.get(request);
51
+ if (!state || state.skipped || emitted.has(request)) return;
52
+ emitted.add(request);
53
+ const logger = storage.getStore();
54
+ const err = error instanceof Error ? error : new Error(String(error));
55
+ if (logger) logger.error(err);
56
+ await state.finish({ error: err });
57
+ });
58
+ }
59
+
60
+ //#endregion
61
+ export { evlog, useLogger };
62
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/elysia/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport { Elysia } from 'elysia'\nimport type { DrainContext, EnrichContext, RequestLogger, RouteConfig, TailSamplingContext } from '../types'\nimport { createMiddlewareLogger } from '../shared/middleware'\nimport { extractSafeHeaders } from '../shared/headers'\n\nconst storage = new AsyncLocalStorage<RequestLogger>()\n\nexport interface EvlogElysiaOptions {\n /** Route patterns to include in logging (glob). If not set, all routes are logged */\n include?: string[]\n /** Route patterns to exclude from logging. Exclusions take precedence over inclusions */\n exclude?: string[]\n /** Route-specific service configuration */\n routes?: Record<string, RouteConfig>\n /**\n * Drain callback called with every emitted event.\n * Use with drain adapters (Axiom, OTLP, Sentry, etc.) or custom endpoints.\n */\n drain?: (ctx: DrainContext) => void | Promise<void>\n /**\n * Enrich callback called after emit, before drain.\n * Use to add derived context (geo, deployment info, user agent, etc.).\n */\n enrich?: (ctx: EnrichContext) => void | Promise<void>\n /**\n * Custom tail sampling callback.\n * Set `ctx.shouldKeep = true` to force-keep the log regardless of head sampling.\n */\n keep?: (ctx: TailSamplingContext) => void | Promise<void>\n}\n\n/**\n * Get the request-scoped logger from anywhere in the call stack.\n * Must be called inside a request handled by the `evlog()` plugin.\n *\n * @example\n * ```ts\n * import { useLogger } from 'evlog/elysia'\n *\n * function findUser(id: string) {\n * const log = useLogger()\n * log.set({ user: { id } })\n * }\n * ```\n */\nexport function useLogger<T extends object = Record<string, unknown>>(): RequestLogger<T> {\n const logger = storage.getStore()\n if (!logger) {\n throw new Error(\n '[evlog] useLogger() was called outside of an evlog plugin context. '\n + 'Make sure app.use(evlog()) is registered before your routes.',\n )\n }\n return logger as RequestLogger<T>\n}\n\n/**\n * Create an evlog plugin for Elysia.\n *\n * @example\n * ```ts\n * import { Elysia } from 'elysia'\n * import { evlog } from 'evlog/elysia'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * const app = new Elysia()\n * .use(evlog({\n * drain: createAxiomDrain(),\n * enrich: (ctx) => {\n * ctx.event.region = process.env.FLY_REGION\n * },\n * }))\n * .get('/health', ({ log }) => {\n * log.set({ route: 'health' })\n * return { ok: true }\n * })\n * .listen(3000)\n * ```\n */\ninterface RequestState {\n finish: (opts?: { status?: number; error?: Error }) => Promise<unknown>\n skipped: boolean\n}\n\nexport function evlog(options: EvlogElysiaOptions = {}) {\n const emitted = new WeakSet<Request>()\n const requestState = new WeakMap<Request, RequestState>()\n\n return new Elysia({ name: 'evlog' })\n .derive({ as: 'global' }, ({ request }) => {\n const url = new URL(request.url)\n\n const { logger, finish, skipped } = createMiddlewareLogger({\n method: request.method,\n path: url.pathname,\n requestId: request.headers.get('x-request-id') || crypto.randomUUID(),\n headers: extractSafeHeaders(request.headers),\n ...options,\n })\n\n storage.enterWith(logger)\n requestState.set(request, { finish, skipped })\n\n return { log: logger }\n })\n .onAfterHandle({ as: 'global' }, async ({ request, set }) => {\n const state = requestState.get(request)\n if (!state || state.skipped || emitted.has(request)) return\n emitted.add(request)\n await state.finish({ status: set.status as number || 200 })\n })\n .onError({ as: 'global' }, async ({ request, error }) => {\n const state = requestState.get(request)\n if (!state || state.skipped || emitted.has(request)) return\n emitted.add(request)\n const logger = storage.getStore()\n const err = error instanceof Error ? error : new Error(String(error))\n if (logger) logger.error(err)\n await state.finish({ error: err })\n })\n}\n"],"mappings":";;;;;AAMA,MAAM,UAAU,IAAI,mBAAkC;;;;;;;;;;;;;;;AAwCtD,SAAgB,YAA0E;CACxF,MAAM,SAAS,QAAQ,UAAU;AACjC,KAAI,CAAC,OACH,OAAM,IAAI,MACR,kIAED;AAEH,QAAO;;AA+BT,SAAgB,MAAM,UAA8B,EAAE,EAAE;CACtD,MAAM,0BAAU,IAAI,SAAkB;CACtC,MAAM,+BAAe,IAAI,SAAgC;AAEzD,QAAO,IAAI,OAAO,EAAE,MAAM,SAAS,CAAC,CACjC,OAAO,EAAE,IAAI,UAAU,GAAG,EAAE,cAAc;EACzC,MAAM,MAAM,IAAI,IAAI,QAAQ,IAAI;EAEhC,MAAM,EAAE,QAAQ,QAAQ,YAAY,uBAAuB;GACzD,QAAQ,QAAQ;GAChB,MAAM,IAAI;GACV,WAAW,QAAQ,QAAQ,IAAI,eAAe,IAAI,OAAO,YAAY;GACrE,SAAS,mBAAmB,QAAQ,QAAQ;GAC5C,GAAG;GACJ,CAAC;AAEF,UAAQ,UAAU,OAAO;AACzB,eAAa,IAAI,SAAS;GAAE;GAAQ;GAAS,CAAC;AAE9C,SAAO,EAAE,KAAK,QAAQ;GACtB,CACD,cAAc,EAAE,IAAI,UAAU,EAAE,OAAO,EAAE,SAAS,UAAU;EAC3D,MAAM,QAAQ,aAAa,IAAI,QAAQ;AACvC,MAAI,CAAC,SAAS,MAAM,WAAW,QAAQ,IAAI,QAAQ,CAAE;AACrD,UAAQ,IAAI,QAAQ;AACpB,QAAM,MAAM,OAAO,EAAE,QAAQ,IAAI,UAAoB,KAAK,CAAC;GAC3D,CACD,QAAQ,EAAE,IAAI,UAAU,EAAE,OAAO,EAAE,SAAS,YAAY;EACvD,MAAM,QAAQ,aAAa,IAAI,QAAQ;AACvC,MAAI,CAAC,SAAS,MAAM,WAAW,QAAQ,IAAI,QAAQ,CAAE;AACrD,UAAQ,IAAI,QAAQ;EACpB,MAAM,SAAS,QAAQ,UAAU;EACjC,MAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;AACrE,MAAI,OAAQ,QAAO,MAAM,IAAI;AAC7B,QAAM,MAAM,OAAO,EAAE,OAAO,KAAK,CAAC;GAClC"}
@@ -0,0 +1,69 @@
1
+ import { DrainContext, EnrichContext, RequestLogger, RouteConfig, TailSamplingContext } from "../types.mjs";
2
+ import { RequestHandler } from "express";
3
+
4
+ //#region src/express/index.d.ts
5
+ interface EvlogExpressOptions {
6
+ /** Route patterns to include in logging (glob). If not set, all routes are logged */
7
+ include?: string[];
8
+ /** Route patterns to exclude from logging. Exclusions take precedence over inclusions */
9
+ exclude?: string[];
10
+ /** Route-specific service configuration */
11
+ routes?: Record<string, RouteConfig>;
12
+ /**
13
+ * Drain callback called with every emitted event.
14
+ * Use with drain adapters (Axiom, OTLP, Sentry, etc.) or custom endpoints.
15
+ */
16
+ drain?: (ctx: DrainContext) => void | Promise<void>;
17
+ /**
18
+ * Enrich callback called after emit, before drain.
19
+ * Use to add derived context (geo, deployment info, user agent, etc.).
20
+ */
21
+ enrich?: (ctx: EnrichContext) => void | Promise<void>;
22
+ /**
23
+ * Custom tail sampling callback.
24
+ * Set `ctx.shouldKeep = true` to force-keep the log regardless of head sampling.
25
+ */
26
+ keep?: (ctx: TailSamplingContext) => void | Promise<void>;
27
+ }
28
+ declare module 'express-serve-static-core' {
29
+ interface Request {
30
+ log: RequestLogger;
31
+ }
32
+ }
33
+ /**
34
+ * Get the request-scoped logger from anywhere in the call stack.
35
+ * Must be called inside a request handled by the `evlog()` middleware.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * import { useLogger } from 'evlog/express'
40
+ *
41
+ * function findUser(id: string) {
42
+ * const log = useLogger()
43
+ * log.set({ user: { id } })
44
+ * }
45
+ * ```
46
+ */
47
+ declare function useLogger<T extends object = Record<string, unknown>>(): RequestLogger<T>;
48
+ /**
49
+ * Create an evlog middleware for Express.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * import express from 'express'
54
+ * import { evlog } from 'evlog/express'
55
+ * import { createAxiomDrain } from 'evlog/axiom'
56
+ *
57
+ * const app = express()
58
+ * app.use(evlog({
59
+ * drain: createAxiomDrain(),
60
+ * enrich: (ctx) => {
61
+ * ctx.event.region = process.env.FLY_REGION
62
+ * },
63
+ * }))
64
+ * ```
65
+ */
66
+ declare function evlog(options?: EvlogExpressOptions): RequestHandler;
67
+ //#endregion
68
+ export { EvlogExpressOptions, evlog, useLogger };
69
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/express/index.ts"],"mappings":";;;;UAQiB,mBAAA;;EAEf,OAAA;EAFkC;EAIlC,OAAA;EAEwB;EAAxB,MAAA,GAAS,MAAA,SAAe,WAAA;EAKV;;;;EAAd,KAAA,IAAS,GAAA,EAAK,YAAA,YAAwB,OAAA;EAUM;;;;EAL5C,MAAA,IAAU,GAAA,EAAK,aAAA,YAAyB,OAAA;EAVxC;;;;EAeA,IAAA,IAAQ,GAAA,EAAK,mBAAA,YAA+B,OAAA;AAAA;AAAA;EAAA,UAIlC,OAAA;IACR,GAAA,EAAK,aAAA;EAAA;AAAA;;;;;;;AAJR;;;;;;;;iBAsBe,SAAA,oBAA6B,MAAA,kBAAA,CAAA,GAA4B,aAAA,CAAc,CAAA;;AAAvF;;;;;;;;;;;;;;AA6BA;;;iBAAgB,KAAA,CAAM,OAAA,GAAS,mBAAA,GAA2B,cAAA"}
@@ -0,0 +1,66 @@
1
+ import { n as extractSafeNodeHeaders, r as createMiddlewareLogger } from "../headers-CXOd5EyZ.mjs";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+
4
+ //#region src/express/index.ts
5
+ const storage = new AsyncLocalStorage();
6
+ /**
7
+ * Get the request-scoped logger from anywhere in the call stack.
8
+ * Must be called inside a request handled by the `evlog()` middleware.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { useLogger } from 'evlog/express'
13
+ *
14
+ * function findUser(id: string) {
15
+ * const log = useLogger()
16
+ * log.set({ user: { id } })
17
+ * }
18
+ * ```
19
+ */
20
+ function useLogger() {
21
+ const logger = storage.getStore();
22
+ if (!logger) throw new Error("[evlog] useLogger() was called outside of an evlog middleware context. Make sure app.use(evlog()) is registered before your routes.");
23
+ return logger;
24
+ }
25
+ /**
26
+ * Create an evlog middleware for Express.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * import express from 'express'
31
+ * import { evlog } from 'evlog/express'
32
+ * import { createAxiomDrain } from 'evlog/axiom'
33
+ *
34
+ * const app = express()
35
+ * app.use(evlog({
36
+ * drain: createAxiomDrain(),
37
+ * enrich: (ctx) => {
38
+ * ctx.event.region = process.env.FLY_REGION
39
+ * },
40
+ * }))
41
+ * ```
42
+ */
43
+ function evlog(options = {}) {
44
+ return (req, res, next) => {
45
+ const { logger, finish, skipped } = createMiddlewareLogger({
46
+ method: req.method,
47
+ path: req.path,
48
+ requestId: req.get("x-request-id") || crypto.randomUUID(),
49
+ headers: extractSafeNodeHeaders(req.headers),
50
+ ...options
51
+ });
52
+ if (skipped) {
53
+ next();
54
+ return;
55
+ }
56
+ req.log = logger;
57
+ res.on("finish", () => {
58
+ finish({ status: res.statusCode }).catch(() => {});
59
+ });
60
+ storage.run(logger, () => next());
61
+ };
62
+ }
63
+
64
+ //#endregion
65
+ export { evlog, useLogger };
66
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/express/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport type { Request, Response, NextFunction, RequestHandler } from 'express'\nimport type { DrainContext, EnrichContext, RequestLogger, RouteConfig, TailSamplingContext } from '../types'\nimport { createMiddlewareLogger } from '../shared/middleware'\nimport { extractSafeNodeHeaders } from '../shared/headers'\n\nconst storage = new AsyncLocalStorage<RequestLogger>()\n\nexport interface EvlogExpressOptions {\n /** Route patterns to include in logging (glob). If not set, all routes are logged */\n include?: string[]\n /** Route patterns to exclude from logging. Exclusions take precedence over inclusions */\n exclude?: string[]\n /** Route-specific service configuration */\n routes?: Record<string, RouteConfig>\n /**\n * Drain callback called with every emitted event.\n * Use with drain adapters (Axiom, OTLP, Sentry, etc.) or custom endpoints.\n */\n drain?: (ctx: DrainContext) => void | Promise<void>\n /**\n * Enrich callback called after emit, before drain.\n * Use to add derived context (geo, deployment info, user agent, etc.).\n */\n enrich?: (ctx: EnrichContext) => void | Promise<void>\n /**\n * Custom tail sampling callback.\n * Set `ctx.shouldKeep = true` to force-keep the log regardless of head sampling.\n */\n keep?: (ctx: TailSamplingContext) => void | Promise<void>\n}\n\ndeclare module 'express-serve-static-core' {\n interface Request {\n log: RequestLogger\n }\n}\n\n/**\n * Get the request-scoped logger from anywhere in the call stack.\n * Must be called inside a request handled by the `evlog()` middleware.\n *\n * @example\n * ```ts\n * import { useLogger } from 'evlog/express'\n *\n * function findUser(id: string) {\n * const log = useLogger()\n * log.set({ user: { id } })\n * }\n * ```\n */\nexport function useLogger<T extends object = Record<string, unknown>>(): RequestLogger<T> {\n const logger = storage.getStore()\n if (!logger) {\n throw new Error(\n '[evlog] useLogger() was called outside of an evlog middleware context. '\n + 'Make sure app.use(evlog()) is registered before your routes.',\n )\n }\n return logger as RequestLogger<T>\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 { logger, finish, skipped } = createMiddlewareLogger({\n method: req.method,\n path: req.path,\n requestId: req.get('x-request-id') || crypto.randomUUID(),\n headers: extractSafeNodeHeaders(req.headers),\n ...options,\n })\n\n if (skipped) {\n next()\n return\n }\n\n req.log = logger\n\n res.on('finish', () => {\n finish({ status: res.statusCode }).catch(() => {})\n })\n\n storage.run(logger, () => next())\n }\n}\n"],"mappings":";;;;AAMA,MAAM,UAAU,IAAI,mBAAkC;;;;;;;;;;;;;;;AA8CtD,SAAgB,YAA0E;CACxF,MAAM,SAAS,QAAQ,UAAU;AACjC,KAAI,CAAC,OACH,OAAM,IAAI,MACR,sIAED;AAEH,QAAO;;;;;;;;;;;;;;;;;;;;AAqBT,SAAgB,MAAM,UAA+B,EAAE,EAAkB;AACvE,SAAQ,KAAc,KAAe,SAAuB;EAC1D,MAAM,EAAE,QAAQ,QAAQ,YAAY,uBAAuB;GACzD,QAAQ,IAAI;GACZ,MAAM,IAAI;GACV,WAAW,IAAI,IAAI,eAAe,IAAI,OAAO,YAAY;GACzD,SAAS,uBAAuB,IAAI,QAAQ;GAC5C,GAAG;GACJ,CAAC;AAEF,MAAI,SAAS;AACX,SAAM;AACN;;AAGF,MAAI,MAAM;AAEV,MAAI,GAAG,gBAAgB;AACrB,UAAO,EAAE,QAAQ,IAAI,YAAY,CAAC,CAAC,YAAY,GAAG;IAClD;AAEF,UAAQ,IAAI,cAAc,MAAM,CAAC"}
@@ -0,0 +1,141 @@
1
+ import { filterSafeHeaders } from "./utils.mjs";
2
+ import { createRequestLogger, isEnabled, shouldKeep } from "./logger.mjs";
3
+ import { n as shouldLog, t as getServiceForPath } from "./routes-BNbrnm14.mjs";
4
+ import { t as extractErrorStatus } from "./nitro-Da8tEfJ3.mjs";
5
+
6
+ //#region src/shared/middleware.ts
7
+ const noopResult = {
8
+ logger: {
9
+ set() {},
10
+ error() {},
11
+ info() {},
12
+ warn() {},
13
+ emit() {
14
+ return null;
15
+ },
16
+ getContext() {
17
+ return {};
18
+ }
19
+ },
20
+ finish: () => Promise.resolve(null),
21
+ skipped: true
22
+ };
23
+ async function runEnrichAndDrain(emittedEvent, options, requestInfo, responseStatus) {
24
+ if (options.enrich) {
25
+ const enrichCtx = {
26
+ event: emittedEvent,
27
+ request: requestInfo,
28
+ headers: options.headers,
29
+ response: { status: responseStatus }
30
+ };
31
+ try {
32
+ await options.enrich(enrichCtx);
33
+ } catch (err) {
34
+ console.error("[evlog] enrich failed:", err);
35
+ }
36
+ }
37
+ if (options.drain) {
38
+ const drainCtx = {
39
+ event: emittedEvent,
40
+ request: requestInfo,
41
+ headers: options.headers
42
+ };
43
+ try {
44
+ await options.drain(drainCtx);
45
+ } catch (err) {
46
+ console.error("[evlog] drain failed:", err);
47
+ }
48
+ }
49
+ }
50
+ /**
51
+ * Create a middleware-aware request logger with full lifecycle management.
52
+ *
53
+ * Handles the complete pipeline shared across all framework integrations:
54
+ * route filtering, logger creation, service overrides, duration tracking,
55
+ * tail sampling evaluation, event emission, enrichment, and draining.
56
+ *
57
+ * Framework adapters only need to:
58
+ * 1. Extract method/path/requestId/headers from the framework request
59
+ * 2. Call `createMiddlewareLogger()` with those + user options
60
+ * 3. Check `skipped` — if true, skip to next middleware
61
+ * 4. Store `logger` in framework-specific context (e.g., `c.set('log', logger)`)
62
+ * 5. Call `finish({ status })` or `finish({ error })` at response end
63
+ */
64
+ function createMiddlewareLogger(options) {
65
+ if (!isEnabled()) return noopResult;
66
+ const { method, path, requestId, include, exclude, routes, keep } = options;
67
+ if (!shouldLog(path, include, exclude)) return noopResult;
68
+ const resolvedRequestId = requestId || crypto.randomUUID();
69
+ const logger = createRequestLogger({
70
+ method,
71
+ path,
72
+ requestId: resolvedRequestId
73
+ });
74
+ const routeService = getServiceForPath(path, routes);
75
+ if (routeService) logger.set({ service: routeService });
76
+ const startTime = Date.now();
77
+ const requestInfo = {
78
+ method,
79
+ path,
80
+ requestId: resolvedRequestId
81
+ };
82
+ const finish = async (opts) => {
83
+ const { status, error } = opts ?? {};
84
+ if (error) {
85
+ logger.error(error);
86
+ const errorStatus = extractErrorStatus(error);
87
+ logger.set({ status: errorStatus });
88
+ } else if (status !== void 0) logger.set({ status });
89
+ const durationMs = Date.now() - startTime;
90
+ const resolvedStatus = error ? extractErrorStatus(error) : status ?? logger.getContext().status;
91
+ const tailCtx = {
92
+ status: resolvedStatus,
93
+ duration: durationMs,
94
+ path,
95
+ method,
96
+ context: logger.getContext(),
97
+ shouldKeep: false
98
+ };
99
+ if (keep) await keep(tailCtx);
100
+ const forceKeep = tailCtx.shouldKeep || shouldKeep(tailCtx);
101
+ const emittedEvent = logger.emit({ _forceKeep: forceKeep });
102
+ if (emittedEvent && (options.enrich || options.drain)) await runEnrichAndDrain(emittedEvent, options, requestInfo, resolvedStatus);
103
+ return emittedEvent;
104
+ };
105
+ return {
106
+ logger,
107
+ finish,
108
+ skipped: false
109
+ };
110
+ }
111
+
112
+ //#endregion
113
+ //#region src/shared/headers.ts
114
+ /**
115
+ * Extract headers from a Web API `Headers` object and filter out sensitive ones.
116
+ * Works with any runtime that supports the standard `Headers` API (Hono, Elysia,
117
+ * Nitro v3, Cloudflare Workers, Bun, Deno, etc.).
118
+ */
119
+ function extractSafeHeaders(headers) {
120
+ const raw = {};
121
+ headers.forEach((value, key) => {
122
+ raw[key] = value;
123
+ });
124
+ return filterSafeHeaders(raw);
125
+ }
126
+ /**
127
+ * Extract headers from Node.js `IncomingHttpHeaders` and filter out sensitive ones.
128
+ * Works with Express, Fastify, and any Node.js HTTP server using `req.headers`.
129
+ */
130
+ function extractSafeNodeHeaders(headers) {
131
+ const raw = {};
132
+ for (const [key, value] of Object.entries(headers)) {
133
+ if (value === void 0) continue;
134
+ raw[key] = Array.isArray(value) ? value.join(", ") : value;
135
+ }
136
+ return filterSafeHeaders(raw);
137
+ }
138
+
139
+ //#endregion
140
+ export { extractSafeNodeHeaders as n, createMiddlewareLogger as r, extractSafeHeaders as t };
141
+ //# sourceMappingURL=headers-CXOd5EyZ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers-CXOd5EyZ.mjs","names":[],"sources":["../src/shared/middleware.ts","../src/shared/headers.ts"],"sourcesContent":["import type { DrainContext, EnrichContext, RequestLogger, RouteConfig, TailSamplingContext, WideEvent } from '../types'\nimport { createRequestLogger, isEnabled, shouldKeep } from '../logger'\nimport { extractErrorStatus } from '../nitro'\nimport { shouldLog, getServiceForPath } from './routes'\n\n/**\n * Base options shared by all framework integrations.\n * Each framework adapter spreads its user-facing options into this.\n */\nexport interface MiddlewareLoggerOptions {\n method: string\n path: string\n requestId?: string\n include?: string[]\n exclude?: string[]\n routes?: Record<string, RouteConfig>\n /** Tail sampling callback — set `ctx.shouldKeep = true` to force-keep */\n keep?: (ctx: TailSamplingContext) => void | Promise<void>\n /** Drain callback — send events to external services */\n drain?: (ctx: DrainContext) => void | Promise<void>\n /** Enrich callback — add derived context after emit, before drain */\n enrich?: (ctx: EnrichContext) => void | Promise<void>\n /** Pre-filtered safe request headers (used for enrich/drain context) */\n headers?: Record<string, string>\n}\n\nexport interface MiddlewareLoggerResult {\n logger: RequestLogger\n finish: (opts?: { status?: number; error?: Error }) => Promise<WideEvent | null>\n skipped: boolean\n}\n\nconst noopResult: MiddlewareLoggerResult = {\n logger: {\n set() {},\n error() {},\n info() {},\n warn() {},\n emit() {\n return null \n },\n getContext() {\n return {} \n },\n },\n finish: () => Promise.resolve(null),\n skipped: true,\n}\n\nasync function runEnrichAndDrain(\n emittedEvent: WideEvent,\n options: MiddlewareLoggerOptions,\n requestInfo: { method: string; path: string; requestId?: string },\n responseStatus?: number,\n): Promise<void> {\n if (options.enrich) {\n const enrichCtx: EnrichContext = {\n event: emittedEvent,\n request: requestInfo,\n headers: options.headers,\n response: { status: responseStatus },\n }\n try {\n await options.enrich(enrichCtx)\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n }\n\n if (options.drain) {\n const drainCtx: DrainContext = {\n event: emittedEvent,\n request: requestInfo,\n headers: options.headers,\n }\n try {\n await options.drain(drainCtx)\n } catch (err) {\n console.error('[evlog] drain failed:', err)\n }\n }\n}\n\n/**\n * Create a middleware-aware request logger with full lifecycle management.\n *\n * Handles the complete pipeline shared across all framework integrations:\n * route filtering, logger creation, service overrides, duration tracking,\n * tail sampling evaluation, event emission, enrichment, and draining.\n *\n * Framework adapters only need to:\n * 1. Extract method/path/requestId/headers from the framework request\n * 2. Call `createMiddlewareLogger()` with those + user options\n * 3. Check `skipped` — if true, skip to next middleware\n * 4. Store `logger` in framework-specific context (e.g., `c.set('log', logger)`)\n * 5. Call `finish({ status })` or `finish({ error })` at response end\n */\nexport function createMiddlewareLogger(options: MiddlewareLoggerOptions): MiddlewareLoggerResult {\n if (!isEnabled()) return noopResult\n\n const { method, path, requestId, include, exclude, routes, keep } = options\n\n if (!shouldLog(path, include, exclude)) {\n return noopResult\n }\n\n const resolvedRequestId = requestId || crypto.randomUUID()\n\n const logger = createRequestLogger({\n method,\n path,\n requestId: resolvedRequestId,\n })\n\n const routeService = getServiceForPath(path, routes)\n if (routeService) {\n logger.set({ service: routeService })\n }\n\n const startTime = Date.now()\n const requestInfo = { method, path, requestId: resolvedRequestId }\n\n const finish = async (opts?: { status?: number; error?: Error }): Promise<WideEvent | null> => {\n const { status, error } = opts ?? {}\n\n if (error) {\n logger.error(error)\n const errorStatus = extractErrorStatus(error)\n logger.set({ status: errorStatus })\n } else if (status !== undefined) {\n logger.set({ status })\n }\n\n const durationMs = Date.now() - startTime\n\n const resolvedStatus = error\n ? extractErrorStatus(error)\n : status ?? (logger.getContext().status as number | undefined)\n\n const tailCtx: TailSamplingContext = {\n status: resolvedStatus,\n duration: durationMs,\n path,\n method,\n context: logger.getContext(),\n shouldKeep: false,\n }\n\n if (keep) {\n await keep(tailCtx)\n }\n\n const forceKeep = tailCtx.shouldKeep || shouldKeep(tailCtx)\n const emittedEvent = logger.emit({ _forceKeep: forceKeep })\n\n if (emittedEvent && (options.enrich || options.drain)) {\n await runEnrichAndDrain(emittedEvent, options, requestInfo, resolvedStatus)\n }\n\n return emittedEvent\n }\n\n return { logger, finish, skipped: false }\n}\n","import { filterSafeHeaders } from '../utils'\n\n/**\n * Extract headers from a Web API `Headers` object and filter out sensitive ones.\n * Works with any runtime that supports the standard `Headers` API (Hono, Elysia,\n * Nitro v3, Cloudflare Workers, Bun, Deno, etc.).\n */\nexport function extractSafeHeaders(headers: Headers): Record<string, string> {\n const raw: Record<string, string> = {}\n headers.forEach((value, key) => {\n raw[key] = value\n })\n return filterSafeHeaders(raw)\n}\n\n/**\n * Extract headers from Node.js `IncomingHttpHeaders` and filter out sensitive ones.\n * Works with Express, Fastify, and any Node.js HTTP server using `req.headers`.\n */\nexport function extractSafeNodeHeaders(headers: Record<string, string | string[] | undefined>): Record<string, string> {\n const raw: Record<string, string> = {}\n for (const [key, value] of Object.entries(headers)) {\n if (value === undefined) continue\n raw[key] = Array.isArray(value) ? value.join(', ') : value\n }\n return filterSafeHeaders(raw)\n}\n"],"mappings":";;;;;;AAgCA,MAAM,aAAqC;CACzC,QAAQ;EACN,MAAM;EACN,QAAQ;EACR,OAAO;EACP,OAAO;EACP,OAAO;AACL,UAAO;;EAET,aAAa;AACX,UAAO,EAAE;;EAEZ;CACD,cAAc,QAAQ,QAAQ,KAAK;CACnC,SAAS;CACV;AAED,eAAe,kBACb,cACA,SACA,aACA,gBACe;AACf,KAAI,QAAQ,QAAQ;EAClB,MAAM,YAA2B;GAC/B,OAAO;GACP,SAAS;GACT,SAAS,QAAQ;GACjB,UAAU,EAAE,QAAQ,gBAAgB;GACrC;AACD,MAAI;AACF,SAAM,QAAQ,OAAO,UAAU;WACxB,KAAK;AACZ,WAAQ,MAAM,0BAA0B,IAAI;;;AAIhD,KAAI,QAAQ,OAAO;EACjB,MAAM,WAAyB;GAC7B,OAAO;GACP,SAAS;GACT,SAAS,QAAQ;GAClB;AACD,MAAI;AACF,SAAM,QAAQ,MAAM,SAAS;WACtB,KAAK;AACZ,WAAQ,MAAM,yBAAyB,IAAI;;;;;;;;;;;;;;;;;;AAmBjD,SAAgB,uBAAuB,SAA0D;AAC/F,KAAI,CAAC,WAAW,CAAE,QAAO;CAEzB,MAAM,EAAE,QAAQ,MAAM,WAAW,SAAS,SAAS,QAAQ,SAAS;AAEpE,KAAI,CAAC,UAAU,MAAM,SAAS,QAAQ,CACpC,QAAO;CAGT,MAAM,oBAAoB,aAAa,OAAO,YAAY;CAE1D,MAAM,SAAS,oBAAoB;EACjC;EACA;EACA,WAAW;EACZ,CAAC;CAEF,MAAM,eAAe,kBAAkB,MAAM,OAAO;AACpD,KAAI,aACF,QAAO,IAAI,EAAE,SAAS,cAAc,CAAC;CAGvC,MAAM,YAAY,KAAK,KAAK;CAC5B,MAAM,cAAc;EAAE;EAAQ;EAAM,WAAW;EAAmB;CAElE,MAAM,SAAS,OAAO,SAAyE;EAC7F,MAAM,EAAE,QAAQ,UAAU,QAAQ,EAAE;AAEpC,MAAI,OAAO;AACT,UAAO,MAAM,MAAM;GACnB,MAAM,cAAc,mBAAmB,MAAM;AAC7C,UAAO,IAAI,EAAE,QAAQ,aAAa,CAAC;aAC1B,WAAW,OACpB,QAAO,IAAI,EAAE,QAAQ,CAAC;EAGxB,MAAM,aAAa,KAAK,KAAK,GAAG;EAEhC,MAAM,iBAAiB,QACnB,mBAAmB,MAAM,GACzB,UAAW,OAAO,YAAY,CAAC;EAEnC,MAAM,UAA+B;GACnC,QAAQ;GACR,UAAU;GACV;GACA;GACA,SAAS,OAAO,YAAY;GAC5B,YAAY;GACb;AAED,MAAI,KACF,OAAM,KAAK,QAAQ;EAGrB,MAAM,YAAY,QAAQ,cAAc,WAAW,QAAQ;EAC3D,MAAM,eAAe,OAAO,KAAK,EAAE,YAAY,WAAW,CAAC;AAE3D,MAAI,iBAAiB,QAAQ,UAAU,QAAQ,OAC7C,OAAM,kBAAkB,cAAc,SAAS,aAAa,eAAe;AAG7E,SAAO;;AAGT,QAAO;EAAE;EAAQ;EAAQ,SAAS;EAAO;;;;;;;;;;AC3J3C,SAAgB,mBAAmB,SAA0C;CAC3E,MAAM,MAA8B,EAAE;AACtC,SAAQ,SAAS,OAAO,QAAQ;AAC9B,MAAI,OAAO;GACX;AACF,QAAO,kBAAkB,IAAI;;;;;;AAO/B,SAAgB,uBAAuB,SAAgF;CACrH,MAAM,MAA8B,EAAE;AACtC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE;AAClD,MAAI,UAAU,OAAW;AACzB,MAAI,OAAO,MAAM,QAAQ,MAAM,GAAG,MAAM,KAAK,KAAK,GAAG;;AAEvD,QAAO,kBAAkB,IAAI"}
@@ -0,0 +1,68 @@
1
+ import { DrainContext, EnrichContext, RequestLogger, RouteConfig, TailSamplingContext } from "../types.mjs";
2
+ import { MiddlewareHandler } from "hono";
3
+
4
+ //#region src/hono/index.d.ts
5
+ interface EvlogHonoOptions {
6
+ /** Route patterns to include in logging (glob). If not set, all routes are logged */
7
+ include?: string[];
8
+ /** Route patterns to exclude from logging. Exclusions take precedence over inclusions */
9
+ exclude?: string[];
10
+ /** Route-specific service configuration */
11
+ routes?: Record<string, RouteConfig>;
12
+ /**
13
+ * Drain callback called with every emitted event.
14
+ * Use with drain adapters (Axiom, OTLP, Sentry, etc.) or custom endpoints.
15
+ */
16
+ drain?: (ctx: DrainContext) => void | Promise<void>;
17
+ /**
18
+ * Enrich callback called after emit, before drain.
19
+ * Use to add derived context (geo, deployment info, user agent, etc.).
20
+ */
21
+ enrich?: (ctx: EnrichContext) => void | Promise<void>;
22
+ /**
23
+ * Custom tail sampling callback.
24
+ * Set `ctx.shouldKeep = true` to force-keep the log regardless of head sampling.
25
+ */
26
+ keep?: (ctx: TailSamplingContext) => void | Promise<void>;
27
+ }
28
+ /**
29
+ * Hono variables type for typed `c.get('log')` access.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const app = new Hono<EvlogVariables>()
34
+ * app.use(evlog())
35
+ * app.get('/api/users', (c) => {
36
+ * const log = c.get('log')
37
+ * log.set({ users: { count: 42 } })
38
+ * return c.json({ users: [] })
39
+ * })
40
+ * ```
41
+ */
42
+ type EvlogVariables = {
43
+ Variables: {
44
+ log: RequestLogger;
45
+ };
46
+ };
47
+ /**
48
+ * Create an evlog middleware for Hono.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * import { Hono } from 'hono'
53
+ * import { evlog, type EvlogVariables } from 'evlog/hono'
54
+ * import { createAxiomDrain } from 'evlog/axiom'
55
+ *
56
+ * const app = new Hono<EvlogVariables>()
57
+ * app.use(evlog({
58
+ * drain: createAxiomDrain(),
59
+ * enrich: (ctx) => {
60
+ * ctx.event.region = process.env.FLY_REGION
61
+ * },
62
+ * }))
63
+ * ```
64
+ */
65
+ declare function evlog(options?: EvlogHonoOptions): MiddlewareHandler;
66
+ //#endregion
67
+ export { EvlogHonoOptions, EvlogVariables, evlog };
68
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/hono/index.ts"],"mappings":";;;;UAKiB,gBAAA;;EAEf,OAAA;EAF+B;EAI/B,OAAA;EAEwB;EAAxB,MAAA,GAAS,MAAA,SAAe,WAAA;EAKV;;;;EAAd,KAAA,IAAS,GAAA,EAAK,YAAA,YAAwB,OAAA;EAUM;;;;EAL5C,MAAA,IAAU,GAAA,EAAK,aAAA,YAAyB,OAAA;EAVxC;;;;EAeA,IAAA,IAAQ,GAAA,EAAK,mBAAA,YAA+B,OAAA;AAAA;;;;;;;;;;;;AAiB9C;;;KAAY,cAAA;EAAmB,SAAA;IAAa,GAAA,EAAK,aAAA;EAAA;AAAA;;AAoBjD;;;;;;;;;;;;;;;;;iBAAgB,KAAA,CAAM,OAAA,GAAS,gBAAA,GAAwB,iBAAA"}
@@ -0,0 +1,48 @@
1
+ import { r as createMiddlewareLogger, t as extractSafeHeaders } from "../headers-CXOd5EyZ.mjs";
2
+
3
+ //#region src/hono/index.ts
4
+ /**
5
+ * Create an evlog middleware for Hono.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { Hono } from 'hono'
10
+ * import { evlog, type EvlogVariables } from 'evlog/hono'
11
+ * import { createAxiomDrain } from 'evlog/axiom'
12
+ *
13
+ * const app = new Hono<EvlogVariables>()
14
+ * app.use(evlog({
15
+ * drain: createAxiomDrain(),
16
+ * enrich: (ctx) => {
17
+ * ctx.event.region = process.env.FLY_REGION
18
+ * },
19
+ * }))
20
+ * ```
21
+ */
22
+ function evlog(options = {}) {
23
+ return async (c, next) => {
24
+ const { logger, finish, skipped } = createMiddlewareLogger({
25
+ method: c.req.method,
26
+ path: c.req.path,
27
+ requestId: c.req.header("x-request-id") || crypto.randomUUID(),
28
+ headers: extractSafeHeaders(c.req.raw.headers),
29
+ ...options
30
+ });
31
+ if (skipped) {
32
+ await next();
33
+ return;
34
+ }
35
+ c.set("log", logger);
36
+ try {
37
+ await next();
38
+ await finish({ status: c.res.status });
39
+ } catch (error) {
40
+ await finish({ error });
41
+ throw error;
42
+ }
43
+ };
44
+ }
45
+
46
+ //#endregion
47
+ export { evlog };
48
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/hono/index.ts"],"sourcesContent":["import type { MiddlewareHandler } from 'hono'\nimport type { DrainContext, EnrichContext, RequestLogger, RouteConfig, TailSamplingContext } from '../types'\nimport { createMiddlewareLogger } from '../shared/middleware'\nimport { extractSafeHeaders } from '../shared/headers'\n\nexport interface EvlogHonoOptions {\n /** Route patterns to include in logging (glob). If not set, all routes are logged */\n include?: string[]\n /** Route patterns to exclude from logging. Exclusions take precedence over inclusions */\n exclude?: string[]\n /** Route-specific service configuration */\n routes?: Record<string, RouteConfig>\n /**\n * Drain callback called with every emitted event.\n * Use with drain adapters (Axiom, OTLP, Sentry, etc.) or custom endpoints.\n */\n drain?: (ctx: DrainContext) => void | Promise<void>\n /**\n * Enrich callback called after emit, before drain.\n * Use to add derived context (geo, deployment info, user agent, etc.).\n */\n enrich?: (ctx: EnrichContext) => void | Promise<void>\n /**\n * Custom tail sampling callback.\n * Set `ctx.shouldKeep = true` to force-keep the log regardless of head sampling.\n */\n keep?: (ctx: TailSamplingContext) => void | Promise<void>\n}\n\n/**\n * Hono variables type for typed `c.get('log')` access.\n *\n * @example\n * ```ts\n * const app = new Hono<EvlogVariables>()\n * app.use(evlog())\n * app.get('/api/users', (c) => {\n * const log = c.get('log')\n * log.set({ users: { count: 42 } })\n * return c.json({ users: [] })\n * })\n * ```\n */\nexport type EvlogVariables = { Variables: { log: RequestLogger } }\n\n/**\n * Create an evlog middleware for Hono.\n *\n * @example\n * ```ts\n * import { Hono } from 'hono'\n * import { evlog, type EvlogVariables } from 'evlog/hono'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * const app = new Hono<EvlogVariables>()\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: EvlogHonoOptions = {}): MiddlewareHandler {\n return async (c, next) => {\n const { logger, finish, skipped } = createMiddlewareLogger({\n method: c.req.method,\n path: c.req.path,\n requestId: c.req.header('x-request-id') || crypto.randomUUID(),\n headers: extractSafeHeaders(c.req.raw.headers),\n ...options,\n })\n\n if (skipped) {\n await next()\n return\n }\n\n c.set('log', logger)\n\n try {\n await next()\n await finish({ status: c.res.status })\n } catch (error) {\n await finish({ error: error as Error })\n throw error\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA+DA,SAAgB,MAAM,UAA4B,EAAE,EAAqB;AACvE,QAAO,OAAO,GAAG,SAAS;EACxB,MAAM,EAAE,QAAQ,QAAQ,YAAY,uBAAuB;GACzD,QAAQ,EAAE,IAAI;GACd,MAAM,EAAE,IAAI;GACZ,WAAW,EAAE,IAAI,OAAO,eAAe,IAAI,OAAO,YAAY;GAC9D,SAAS,mBAAmB,EAAE,IAAI,IAAI,QAAQ;GAC9C,GAAG;GACJ,CAAC;AAEF,MAAI,SAAS;AACX,SAAM,MAAM;AACZ;;AAGF,IAAE,IAAI,OAAO,OAAO;AAEpB,MAAI;AACF,SAAM,MAAM;AACZ,SAAM,OAAO,EAAE,QAAQ,EAAE,IAAI,QAAQ,CAAC;WAC/B,OAAO;AACd,SAAM,OAAO,EAAS,OAAgB,CAAC;AACvC,SAAM"}
@@ -1,5 +1,5 @@
1
1
  import { useLogger } from "../runtime/server/useLogger.mjs";
2
- import { t as NitroModuleOptions } from "../nitro-mfub2f8G.mjs";
2
+ import { t as NitroModuleOptions } from "../nitro-Nxg6qcXd.mjs";
3
3
  import { Nitro } from "nitropack";
4
4
 
5
5
  //#region src/nitro/module.d.ts
@@ -1,4 +1,4 @@
1
- import { t as NitroModuleOptions } from "../../nitro-mfub2f8G.mjs";
1
+ import { t as NitroModuleOptions } from "../../nitro-Nxg6qcXd.mjs";
2
2
  import { Nitro } from "nitro/types";
3
3
 
4
4
  //#region src/nitro-v3/module.d.ts
@@ -39,4 +39,4 @@ interface NitroModuleOptions {
39
39
  }
40
40
  //#endregion
41
41
  export { NitroModuleOptions as t };
42
- //# sourceMappingURL=nitro-mfub2f8G.d.mts.map
42
+ //# sourceMappingURL=nitro-Nxg6qcXd.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nitro-mfub2f8G.d.mts","names":[],"sources":["../src/nitro.ts"],"mappings":";;;UAIiB,kBAAA;EAAA;;;;EAKf,OAAA;EA8BwB;;;EAzBxB,GAAA,GAAM,OAAA,CAAQ,kBAAA;EA8BW;;;;EAxBzB,MAAA;EAAA;;;;;EAOA,OAAA;EAiBA;;;;;EAVA,OAAA;;;;EAKA,MAAA,GAAS,MAAA,SAAe,WAAA;;;;EAKxB,QAAA,GAAW,cAAA;AAAA"}
1
+ {"version":3,"file":"nitro-Nxg6qcXd.d.mts","names":[],"sources":["../src/nitro.ts"],"mappings":";;;UAIiB,kBAAA;EAAA;;;;EAKf,OAAA;EA8BwB;;;EAzBxB,GAAA,GAAM,OAAA,CAAQ,kBAAA;EA8BW;;;;EAxBzB,MAAA;EAAA;;;;;EAOA,OAAA;EAiBA;;;;;EAVA,OAAA;;;;EAKA,MAAA,GAAS,MAAA,SAAe,WAAA;;;;EAKxB,QAAA,GAAW,cAAA;AAAA"}
@@ -2,7 +2,7 @@ import { addImports, addPlugin, addServerHandler, addServerImports, addServerPlu
2
2
 
3
3
  //#region package.json
4
4
  var name = "evlog";
5
- var version = "2.1.0";
5
+ var version = "2.3.0";
6
6
 
7
7
  //#endregion
8
8
  //#region src/nuxt/module.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evlog",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "Wide event logging library with structured error handling. Inspired by LoggingSucks.",
5
5
  "author": "HugoRCD <contact@hrcd.fr>",
6
6
  "homepage": "https://evlog.dev",
@@ -20,6 +20,9 @@
20
20
  "nitro",
21
21
  "nextjs",
22
22
  "tanstack-start",
23
+ "express",
24
+ "hono",
25
+ "elysia",
23
26
  "typescript"
24
27
  ],
25
28
  "license": "MIT",
@@ -85,6 +88,18 @@
85
88
  "./next/client": {
86
89
  "types": "./dist/next/client.d.mts",
87
90
  "import": "./dist/next/client.mjs"
91
+ },
92
+ "./hono": {
93
+ "types": "./dist/hono/index.d.mts",
94
+ "import": "./dist/hono/index.mjs"
95
+ },
96
+ "./express": {
97
+ "types": "./dist/express/index.d.mts",
98
+ "import": "./dist/express/index.mjs"
99
+ },
100
+ "./elysia": {
101
+ "types": "./dist/elysia/index.d.mts",
102
+ "import": "./dist/elysia/index.mjs"
88
103
  }
89
104
  },
90
105
  "main": "./dist/index.mjs",
@@ -135,6 +150,15 @@
135
150
  ],
136
151
  "next/client": [
137
152
  "./dist/next/client.d.mts"
153
+ ],
154
+ "hono": [
155
+ "./dist/hono/index.d.mts"
156
+ ],
157
+ "express": [
158
+ "./dist/express/index.d.mts"
159
+ ],
160
+ "elysia": [
161
+ "./dist/elysia/index.d.mts"
138
162
  ]
139
163
  }
140
164
  },
@@ -154,19 +178,24 @@
154
178
  "typecheck": "echo 'Typecheck handled by build'"
155
179
  },
156
180
  "devDependencies": {
157
- "ufo": "^1.6.3",
158
181
  "@nuxt/devtools": "^3.2.2",
159
182
  "@nuxt/schema": "^4.3.1",
160
183
  "@nuxt/test-utils": "^4.0.0",
184
+ "@types/express": "^5.0.6",
185
+ "@types/supertest": "^7.2.0",
161
186
  "changelogen": "^0.6.2",
162
187
  "consola": "^3.4.2",
188
+ "elysia": "^1.4.27",
189
+ "express": "^5.2.1",
163
190
  "h3": "^1.15.5",
164
- "happy-dom": "^20.7.0",
191
+ "happy-dom": "^20.7.2",
165
192
  "nitro": "^3.0.1-alpha.2",
166
193
  "nitropack": "^2.13.1",
167
194
  "nuxt": "^4.3.1",
195
+ "supertest": "^7.2.2",
168
196
  "tsdown": "^0.20.3",
169
- "typescript": "^5.9.3"
197
+ "typescript": "^5.9.3",
198
+ "ufo": "^1.6.3"
170
199
  },
171
200
  "peerDependencies": {
172
201
  "@nuxt/kit": "^4.3.1",
@@ -175,7 +204,10 @@
175
204
  "ofetch": "^1.5.1",
176
205
  "nitro": "^3.0.1-alpha.2",
177
206
  "next": ">=16.1.6",
178
- "react": ">=19.2.4"
207
+ "react": ">=19.2.4",
208
+ "hono": "",
209
+ "express": ">=4.21.0",
210
+ "elysia": ">=1.0.0"
179
211
  },
180
212
  "peerDependenciesMeta": {
181
213
  "@nuxt/kit": {
@@ -198,6 +230,15 @@
198
230
  },
199
231
  "react": {
200
232
  "optional": true
233
+ },
234
+ "hono": {
235
+ "optional": true
236
+ },
237
+ "express": {
238
+ "optional": true
239
+ },
240
+ "elysia": {
241
+ "optional": true
201
242
  }
202
243
  }
203
244
  }