evlog 2.0.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.
Files changed (66) hide show
  1. package/dist/{_severity-D_IU9-90.mjs → _severity-78FkT5MD.mjs} +1 -1
  2. package/dist/{_severity-D_IU9-90.mjs.map → _severity-78FkT5MD.mjs.map} +1 -1
  3. package/dist/adapters/axiom.d.mts +0 -2
  4. package/dist/adapters/axiom.d.mts.map +1 -1
  5. package/dist/adapters/better-stack.d.mts +0 -2
  6. package/dist/adapters/better-stack.d.mts.map +1 -1
  7. package/dist/adapters/otlp.d.mts +0 -2
  8. package/dist/adapters/otlp.d.mts.map +1 -1
  9. package/dist/adapters/otlp.mjs +1 -1
  10. package/dist/adapters/posthog.d.mts +0 -2
  11. package/dist/adapters/posthog.d.mts.map +1 -1
  12. package/dist/adapters/sentry.d.mts +0 -2
  13. package/dist/adapters/sentry.d.mts.map +1 -1
  14. package/dist/adapters/sentry.mjs +1 -1
  15. package/dist/dist-By0jiJRA.mjs +52 -0
  16. package/dist/dist-By0jiJRA.mjs.map +1 -0
  17. package/dist/elysia/index.d.mts +75 -0
  18. package/dist/elysia/index.d.mts.map +1 -0
  19. package/dist/elysia/index.mjs +62 -0
  20. package/dist/elysia/index.mjs.map +1 -0
  21. package/dist/express/index.d.mts +69 -0
  22. package/dist/express/index.d.mts.map +1 -0
  23. package/dist/express/index.mjs +66 -0
  24. package/dist/express/index.mjs.map +1 -0
  25. package/dist/headers-CXOd5EyZ.mjs +141 -0
  26. package/dist/headers-CXOd5EyZ.mjs.map +1 -0
  27. package/dist/hono/index.d.mts +68 -0
  28. package/dist/hono/index.d.mts.map +1 -0
  29. package/dist/hono/index.mjs +48 -0
  30. package/dist/hono/index.mjs.map +1 -0
  31. package/dist/index.d.mts +2 -2
  32. package/dist/index.mjs +2 -2
  33. package/dist/logger.d.mts +14 -1
  34. package/dist/logger.d.mts.map +1 -1
  35. package/dist/logger.mjs +29 -14
  36. package/dist/logger.mjs.map +1 -1
  37. package/dist/next/client.d.mts +8 -0
  38. package/dist/next/client.d.mts.map +1 -1
  39. package/dist/next/client.mjs +3 -1
  40. package/dist/next/client.mjs.map +1 -1
  41. package/dist/next/index.d.mts +0 -1
  42. package/dist/next/index.d.mts.map +1 -1
  43. package/dist/nitro/module.d.mts +3 -2
  44. package/dist/nitro/module.d.mts.map +1 -1
  45. package/dist/nitro/module.mjs +1 -0
  46. package/dist/nitro/module.mjs.map +1 -1
  47. package/dist/nitro/v3/errorHandler.mjs +1 -1
  48. package/dist/nitro/v3/index.d.mts +0 -1
  49. package/dist/nitro/v3/module.d.mts +3 -2
  50. package/dist/nitro/v3/module.d.mts.map +1 -1
  51. package/dist/nitro/v3/module.mjs +2 -0
  52. package/dist/nitro/v3/module.mjs.map +1 -1
  53. package/dist/nitro/v3/plugin.mjs +1 -1
  54. package/dist/{nitro-CrFBjY1Y.d.mts → nitro-Nxg6qcXd.d.mts} +1 -1
  55. package/dist/{nitro-CrFBjY1Y.d.mts.map → nitro-Nxg6qcXd.d.mts.map} +1 -1
  56. package/dist/nuxt/module.d.mts +7 -0
  57. package/dist/nuxt/module.d.mts.map +1 -1
  58. package/dist/nuxt/module.mjs +2 -1
  59. package/dist/nuxt/module.mjs.map +1 -1
  60. package/dist/runtime/client/log.d.mts +1 -0
  61. package/dist/runtime/client/log.d.mts.map +1 -1
  62. package/dist/runtime/client/log.mjs +10 -6
  63. package/dist/runtime/client/log.mjs.map +1 -1
  64. package/dist/runtime/client/plugin.mjs +1 -0
  65. package/dist/runtime/client/plugin.mjs.map +1 -1
  66. package/package.json +47 -6
@@ -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"}
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { BaseWideEvent, DeepPartial, DrainContext, EnrichContext, EnvironmentContext, ErrorOptions, FieldContext, H3EventContext, IngestPayload, InternalFields, Log, LogLevel, LoggerConfig, ParsedError, RequestLogger, RequestLoggerOptions, SamplingConfig, SamplingRates, ServerEvent, TailSamplingCondition, TailSamplingContext, TransportConfig, WideEvent } from "./types.mjs";
2
2
  import { EvlogError, createError } from "./error.mjs";
3
- import { createRequestLogger, getEnvironment, initLogger, isEnabled, log as _log, shouldKeep } from "./logger.mjs";
3
+ import { createLogger, createRequestLogger, getEnvironment, initLogger, isEnabled, log as _log, shouldKeep } from "./logger.mjs";
4
4
  import { useLogger } from "./runtime/server/useLogger.mjs";
5
5
  import { parseError } from "./runtime/utils/parseError.mjs";
6
- export { type BaseWideEvent, type DeepPartial, type DrainContext, type EnrichContext, type EnvironmentContext, type ErrorOptions, EvlogError, type FieldContext, type H3EventContext, type IngestPayload, type InternalFields, type Log, type LogLevel, type LoggerConfig, type ParsedError, type RequestLogger, type RequestLoggerOptions, type SamplingConfig, type SamplingRates, type ServerEvent, type TailSamplingCondition, type TailSamplingContext, type TransportConfig, type WideEvent, createError, createError as createEvlogError, createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, parseError, shouldKeep, useLogger };
6
+ export { type BaseWideEvent, type DeepPartial, type DrainContext, type EnrichContext, type EnvironmentContext, type ErrorOptions, EvlogError, type FieldContext, type H3EventContext, type IngestPayload, type InternalFields, type Log, type LogLevel, type LoggerConfig, type ParsedError, type RequestLogger, type RequestLoggerOptions, type SamplingConfig, type SamplingRates, type ServerEvent, type TailSamplingCondition, type TailSamplingContext, type TransportConfig, type WideEvent, createError, createError as createEvlogError, createLogger, createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, parseError, shouldKeep, useLogger };
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { EvlogError, createError } from "./error.mjs";
2
- import { createRequestLogger, getEnvironment, initLogger, isEnabled, log as _log, shouldKeep } from "./logger.mjs";
2
+ import { createLogger, createRequestLogger, getEnvironment, initLogger, isEnabled, log as _log, shouldKeep } from "./logger.mjs";
3
3
  import { useLogger } from "./runtime/server/useLogger.mjs";
4
4
  import { parseError } from "./runtime/utils/parseError.mjs";
5
5
 
6
- export { EvlogError, createError, createError as createEvlogError, createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, parseError, shouldKeep, useLogger };
6
+ export { EvlogError, createError, createError as createEvlogError, createLogger, createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, parseError, shouldKeep, useLogger };
package/dist/logger.d.mts CHANGED
@@ -25,8 +25,21 @@ declare function shouldKeep(ctx: TailSamplingContext): boolean;
25
25
  * ```
26
26
  */
27
27
  declare const _log: Log;
28
+ /**
29
+ * Create a scoped logger for building wide events.
30
+ * Use this for any context: workflows, jobs, scripts, queues, etc.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const log = createLogger({ jobId: job.id, queue: 'emails' })
35
+ * log.set({ batch: { size: 50, processed: 12 } })
36
+ * log.emit()
37
+ * ```
38
+ */
39
+ declare function createLogger<T extends object = Record<string, unknown>>(initialContext?: Record<string, unknown>): RequestLogger<T>;
28
40
  /**
29
41
  * Create a request-scoped logger for building wide events.
42
+ * Convenience wrapper around `createLogger` that pre-populates HTTP request fields.
30
43
  *
31
44
  * @example
32
45
  * ```ts
@@ -42,5 +55,5 @@ declare function createRequestLogger<T extends object = Record<string, unknown>>
42
55
  */
43
56
  declare function getEnvironment(): EnvironmentContext;
44
57
  //#endregion
45
- export { createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, shouldKeep };
58
+ export { createLogger, createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, shouldKeep };
46
59
  //# sourceMappingURL=logger.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.mts","names":[],"sources":["../src/logger.ts"],"mappings":";;;;;AAoCA;;iBAAgB,UAAA,CAAW,MAAA,GAAQ,YAAA;;;AAqBnC;iBAAgB,SAAA,CAAA;;;;AA8BhB;iBAAgB,UAAA,CAAW,GAAA,EAAK,mBAAA;;;;AAgB/B;;;;;AAkKD;cAjCM,IAAA,EAAM,GAAA;;;;;;;;;;;;iBAiCI,mBAAA,oBAAuC,MAAA,kBAAA,CAAyB,OAAA,GAAS,oBAAA,GAA4B,aAAA,CAAc,CAAA;;;AAiHnI;iBAAgB,cAAA,CAAA,GAAkB,kBAAA"}
1
+ {"version":3,"file":"logger.d.mts","names":[],"sources":["../src/logger.ts"],"mappings":";;;;;AAoCA;;iBAAgB,UAAA,CAAW,MAAA,GAAQ,YAAA;;;AAqBnC;iBAAgB,SAAA,CAAA;;;;AA8BhB;iBAAgB,UAAA,CAAW,GAAA,EAAK,mBAAA;;;;AAgB/B;;;;;AAkKD;cAjCM,IAAA,EAAM,GAAA;;;;;;;;;;;;iBAiCI,YAAA,oBAAgC,MAAA,kBAAA,CAAyB,cAAA,GAAgB,MAAA,oBAA+B,aAAA,CAAc,CAAA;;;AAsHtI;;;;;;;;;;iBAAgB,mBAAA,oBAAuC,MAAA,kBAAA,CAAyB,OAAA,GAAS,oBAAA,GAA4B,aAAA,CAAc,CAAA;;;;iBAWnH,cAAA,CAAA,GAAkB,kBAAA"}
package/dist/logger.mjs CHANGED
@@ -179,27 +179,23 @@ const noopLogger = {
179
179
  }
180
180
  };
181
181
  /**
182
- * Create a request-scoped logger for building wide events.
182
+ * Create a scoped logger for building wide events.
183
+ * Use this for any context: workflows, jobs, scripts, queues, etc.
183
184
  *
184
185
  * @example
185
186
  * ```ts
186
- * const log = createRequestLogger({ method: 'POST', path: '/checkout' })
187
- * log.set({ user: { id: '123' } })
188
- * log.set({ cart: { items: 3 } })
187
+ * const log = createLogger({ jobId: job.id, queue: 'emails' })
188
+ * log.set({ batch: { size: 50, processed: 12 } })
189
189
  * log.emit()
190
190
  * ```
191
191
  */
192
- function createRequestLogger(options = {}) {
192
+ function createLogger(initialContext = {}) {
193
193
  if (!globalEnabled) return noopLogger;
194
194
  const startTime = Date.now();
195
- let context = {
196
- method: options.method,
197
- path: options.path,
198
- requestId: options.requestId
199
- };
195
+ let context = { ...initialContext };
200
196
  let hasError = false;
201
197
  let hasWarn = false;
202
- function addRequestLog(level, message) {
198
+ function addLog(level, message) {
203
199
  const entry = {
204
200
  level,
205
201
  message,
@@ -234,7 +230,7 @@ function createRequestLogger(options = {}) {
234
230
  }, context);
235
231
  },
236
232
  info(message, infoContext) {
237
- addRequestLog("info", message);
233
+ addLog("info", message);
238
234
  if (infoContext) {
239
235
  const { requestLogs: _, ...rest } = infoContext;
240
236
  context = deepDefaults(rest, context);
@@ -242,7 +238,7 @@ function createRequestLogger(options = {}) {
242
238
  },
243
239
  warn(message, warnContext) {
244
240
  hasWarn = true;
245
- addRequestLog("warn", message);
241
+ addLog("warn", message);
246
242
  if (warnContext) {
247
243
  const { requestLogs: _, ...rest } = warnContext;
248
244
  context = deepDefaults(rest, context);
@@ -276,6 +272,25 @@ function createRequestLogger(options = {}) {
276
272
  };
277
273
  }
278
274
  /**
275
+ * Create a request-scoped logger for building wide events.
276
+ * Convenience wrapper around `createLogger` that pre-populates HTTP request fields.
277
+ *
278
+ * @example
279
+ * ```ts
280
+ * const log = createRequestLogger({ method: 'POST', path: '/checkout' })
281
+ * log.set({ user: { id: '123' } })
282
+ * log.set({ cart: { items: 3 } })
283
+ * log.emit()
284
+ * ```
285
+ */
286
+ function createRequestLogger(options = {}) {
287
+ const initial = {};
288
+ if (options.method !== void 0) initial.method = options.method;
289
+ if (options.path !== void 0) initial.path = options.path;
290
+ if (options.requestId !== void 0) initial.requestId = options.requestId;
291
+ return createLogger(initial);
292
+ }
293
+ /**
279
294
  * Get the current environment context.
280
295
  */
281
296
  function getEnvironment() {
@@ -283,5 +298,5 @@ function getEnvironment() {
283
298
  }
284
299
 
285
300
  //#endregion
286
- export { createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, shouldKeep };
301
+ export { createLogger, createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, shouldKeep };
287
302
  //# sourceMappingURL=logger.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.mjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["import type { DrainContext, EnvironmentContext, FieldContext, Log, LogLevel, LoggerConfig, RequestLogger, RequestLoggerOptions, SamplingConfig, TailSamplingContext, WideEvent } from './types'\nimport { colors, detectEnvironment, formatDuration, getConsoleMethod, getLevelColor, isDev, matchesPattern } from './utils'\n\nfunction isPlainObject(val: unknown): val is Record<string, unknown> {\n return val !== null && typeof val === 'object' && !Array.isArray(val)\n}\n\nfunction deepDefaults(base: Record<string, unknown>, defaults: Record<string, unknown>): Record<string, unknown> {\n const result = { ...base }\n for (const key in defaults) {\n const baseVal = result[key]\n const defaultVal = defaults[key]\n if (baseVal === undefined || baseVal === null) {\n result[key] = defaultVal\n } else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) {\n result[key] = deepDefaults(baseVal, defaultVal)\n }\n }\n return result\n}\n\nlet globalEnv: EnvironmentContext = {\n service: 'app',\n environment: 'development',\n}\n\nlet globalPretty = isDev()\nlet globalSampling: SamplingConfig = {}\nlet globalStringify = true\nlet globalDrain: ((ctx: DrainContext) => void | Promise<void>) | undefined\nlet globalEnabled = true\n\n/**\n * Initialize the logger with configuration.\n * Call this once at application startup.\n */\nexport function initLogger(config: LoggerConfig = {}): void {\n globalEnabled = config.enabled ?? true\n const detected = detectEnvironment()\n\n globalEnv = {\n service: config.env?.service ?? detected.service ?? 'app',\n environment: config.env?.environment ?? detected.environment ?? 'development',\n version: config.env?.version ?? detected.version,\n commitHash: config.env?.commitHash ?? detected.commitHash,\n region: config.env?.region ?? detected.region,\n }\n\n globalPretty = config.pretty ?? isDev()\n globalSampling = config.sampling ?? {}\n globalStringify = config.stringify ?? true\n globalDrain = config.drain\n}\n\n/**\n * Check if logging is globally enabled.\n */\nexport function isEnabled(): boolean {\n return globalEnabled\n}\n\n/**\n * Determine if a log at the given level should be emitted based on sampling config.\n * Error level defaults to 100% (always logged) unless explicitly configured otherwise.\n */\nfunction shouldSample(level: LogLevel): boolean {\n const { rates } = globalSampling\n if (!rates) {\n return true // No sampling configured, log everything\n }\n\n // Error defaults to 100% unless explicitly set\n const percentage = level === 'error' && rates.error === undefined\n ? 100\n : rates[level] ?? 100\n\n // 0% = never log, 100% = always log\n if (percentage <= 0) return false\n if (percentage >= 100) return true\n\n return Math.random() * 100 < percentage\n}\n\n/**\n * Evaluate tail sampling conditions to determine if a log should be force-kept.\n * Returns true if ANY condition matches (OR logic).\n */\nexport function shouldKeep(ctx: TailSamplingContext): boolean {\n const { keep } = globalSampling\n if (!keep?.length) return false\n\n return keep.some((condition) => {\n if (condition.status !== undefined && ctx.status !== undefined && ctx.status >= condition.status) {\n return true\n }\n if (condition.duration !== undefined && ctx.duration !== undefined && ctx.duration >= condition.duration) {\n return true\n }\n if (condition.path && ctx.path && matchesPattern(ctx.path, condition.path)) {\n return true\n }\n return false\n })\n}\n\nfunction emitWideEvent(level: LogLevel, event: Record<string, unknown>, skipSamplingCheck = false): WideEvent | null {\n if (!globalEnabled) return null\n\n if (!skipSamplingCheck && !shouldSample(level)) {\n return null\n }\n\n const formatted: WideEvent = {\n timestamp: new Date().toISOString(),\n level,\n ...globalEnv,\n ...event,\n }\n\n if (globalPretty) {\n prettyPrintWideEvent(formatted)\n } else if (globalStringify) {\n console[getConsoleMethod(level)](JSON.stringify(formatted))\n } else {\n console[getConsoleMethod(level)](formatted)\n }\n\n if (globalDrain) {\n Promise.resolve(globalDrain({ event: formatted })).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n }\n\n return formatted\n}\n\nfunction emitTaggedLog(level: LogLevel, tag: string, message: string): void {\n if (!globalEnabled) return\n\n if (globalPretty) {\n if (!shouldSample(level)) {\n return\n }\n const color = getLevelColor(level)\n const timestamp = new Date().toISOString().slice(11, 23)\n console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`)\n return\n }\n emitWideEvent(level, { tag, message })\n}\n\nfunction formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return String(value)\n }\n if (typeof value === 'object') {\n // Flatten object to key=value pairs\n const pairs: string[] = []\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (v !== undefined && v !== null) {\n if (typeof v === 'object') {\n // For nested objects, show as JSON\n pairs.push(`${k}=${JSON.stringify(v)}`)\n } else {\n pairs.push(`${k}=${v}`)\n }\n }\n }\n return pairs.join(' ')\n }\n return String(value)\n}\n\nfunction prettyPrintWideEvent(event: Record<string, unknown>): void {\n const { timestamp, level, service, environment, version, ...rest } = event\n const levelColor = getLevelColor(level as string)\n const ts = (timestamp as string).slice(11, 23)\n\n let header = `${colors.dim}${ts}${colors.reset} ${levelColor}${(level as string).toUpperCase()}${colors.reset}`\n header += ` ${colors.cyan}[${service}]${colors.reset}`\n\n if (rest.method && rest.path) {\n header += ` ${rest.method} ${rest.path}`\n delete rest.method\n delete rest.path\n }\n\n if (rest.status) {\n const statusColor = (rest.status as number) >= 400 ? colors.red : colors.green\n header += ` ${statusColor}${rest.status}${colors.reset}`\n delete rest.status\n }\n\n if (rest.duration) {\n header += ` ${colors.dim}in ${rest.duration}${colors.reset}`\n delete rest.duration\n }\n\n console.log(header)\n\n const entries = Object.entries(rest).filter(([_, v]) => v !== undefined)\n const lastIndex = entries.length - 1\n\n entries.forEach(([key, value], index) => {\n const isLast = index === lastIndex\n const prefix = isLast ? '└─' : '├─'\n const formatted = formatValue(value)\n console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`)\n })\n}\n\nfunction createLogMethod(level: LogLevel) {\n return function logMethod(tagOrEvent: string | Record<string, unknown>, message?: string): void {\n if (typeof tagOrEvent === 'string' && message !== undefined) {\n emitTaggedLog(level, tagOrEvent, message)\n } else if (typeof tagOrEvent === 'object') {\n emitWideEvent(level, tagOrEvent)\n } else {\n emitTaggedLog(level, 'log', String(tagOrEvent))\n }\n }\n}\n\n/**\n * Simple logging API - as easy as console.log\n *\n * @example\n * ```ts\n * log.info('auth', 'User logged in')\n * log.error({ action: 'payment', error: 'failed' })\n * ```\n */\nconst _log: Log = {\n info: createLogMethod('info'),\n error: createLogMethod('error'),\n warn: createLogMethod('warn'),\n debug: createLogMethod('debug'),\n}\n\nexport { _log as log }\n\nconst noopLogger: RequestLogger = {\n set() {},\n error() {},\n info() {},\n warn() {},\n emit() {\n return null\n },\n getContext() {\n return {}\n },\n}\n\n/**\n * Create a request-scoped logger for building wide events.\n *\n * @example\n * ```ts\n * const log = createRequestLogger({ method: 'POST', path: '/checkout' })\n * log.set({ user: { id: '123' } })\n * log.set({ cart: { items: 3 } })\n * log.emit()\n * ```\n */\nexport function createRequestLogger<T extends object = Record<string, unknown>>(options: RequestLoggerOptions = {}): RequestLogger<T> {\n if (!globalEnabled) return noopLogger as RequestLogger<T>\n\n const startTime = Date.now()\n let context: Record<string, unknown> = {\n method: options.method,\n path: options.path,\n requestId: options.requestId,\n }\n let hasError = false\n let hasWarn = false\n\n function addRequestLog(level: 'info' | 'warn', message: string): void {\n const entry = {\n level,\n message,\n timestamp: new Date().toISOString(),\n }\n\n const requestLogs = Array.isArray(context.requestLogs)\n ? [...context.requestLogs, entry]\n : [entry]\n\n context = {\n ...context,\n requestLogs,\n }\n }\n\n return {\n set(data: FieldContext<T>): void {\n context = deepDefaults(data as Record<string, unknown>, context) as Record<string, unknown>\n },\n\n error(error: Error | string, errorContext?: FieldContext<T>): void {\n hasError = true\n const err = typeof error === 'string' ? new Error(error) : error\n\n const errorData = {\n ...(errorContext as Record<string, unknown>),\n error: {\n name: err.name,\n message: err.message,\n stack: err.stack,\n ...('status' in err && { status: (err as Record<string, unknown>).status }),\n ...('statusText' in err && { statusText: (err as Record<string, unknown>).statusText }),\n ...('statusCode' in err && { statusCode: (err as Record<string, unknown>).statusCode }),\n ...('statusMessage' in err && { statusMessage: (err as Record<string, unknown>).statusMessage }),\n ...('data' in err && { data: (err as Record<string, unknown>).data }),\n ...('cause' in err && { cause: (err as unknown as Record<string, unknown>).cause }),\n },\n }\n context = deepDefaults(errorData, context) as Record<string, unknown>\n },\n\n info(message: string, infoContext?: FieldContext<T>): void {\n addRequestLog('info', message)\n if (infoContext) {\n const { requestLogs: _, ...rest } = infoContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n warn(message: string, warnContext?: FieldContext<T>): void {\n hasWarn = true\n addRequestLog('warn', message)\n if (warnContext) {\n const { requestLogs: _, ...rest } = warnContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n emit(overrides?: FieldContext<T> & { _forceKeep?: boolean }): WideEvent | null {\n const durationMs = Date.now() - startTime\n const duration = formatDuration(durationMs)\n const level: LogLevel = hasError ? 'error' : hasWarn ? 'warn' : 'info'\n\n // Extract _forceKeep from overrides (set by evlog:emit:keep hook)\n const { _forceKeep, ...restOverrides } = (overrides ?? {}) as Record<string, unknown> & { _forceKeep?: boolean }\n\n // Build tail sampling context\n const tailCtx: TailSamplingContext = {\n status: (context.status ?? restOverrides.status) as number | undefined,\n duration: durationMs,\n path: context.path as string | undefined,\n method: context.method as string | undefined,\n context: { ...context, ...restOverrides },\n }\n\n // Tail sampling: force keep if hook or built-in conditions match\n const forceKeep = _forceKeep || shouldKeep(tailCtx)\n\n // Apply head sampling only if not force-kept\n if (!forceKeep && !shouldSample(level)) {\n return null\n }\n\n return emitWideEvent(level, {\n ...context,\n ...restOverrides,\n duration,\n }, true)\n },\n\n getContext(): FieldContext<T> & Record<string, unknown> {\n return { ...context }\n },\n }\n}\n\n/**\n * Get the current environment context.\n */\nexport function getEnvironment(): EnvironmentContext {\n return { ...globalEnv }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"logger.mjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["import type { DrainContext, EnvironmentContext, FieldContext, Log, LogLevel, LoggerConfig, RequestLogger, RequestLoggerOptions, SamplingConfig, TailSamplingContext, WideEvent } from './types'\nimport { colors, detectEnvironment, formatDuration, getConsoleMethod, getLevelColor, isDev, matchesPattern } from './utils'\n\nfunction isPlainObject(val: unknown): val is Record<string, unknown> {\n return val !== null && typeof val === 'object' && !Array.isArray(val)\n}\n\nfunction deepDefaults(base: Record<string, unknown>, defaults: Record<string, unknown>): Record<string, unknown> {\n const result = { ...base }\n for (const key in defaults) {\n const baseVal = result[key]\n const defaultVal = defaults[key]\n if (baseVal === undefined || baseVal === null) {\n result[key] = defaultVal\n } else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) {\n result[key] = deepDefaults(baseVal, defaultVal)\n }\n }\n return result\n}\n\nlet globalEnv: EnvironmentContext = {\n service: 'app',\n environment: 'development',\n}\n\nlet globalPretty = isDev()\nlet globalSampling: SamplingConfig = {}\nlet globalStringify = true\nlet globalDrain: ((ctx: DrainContext) => void | Promise<void>) | undefined\nlet globalEnabled = true\n\n/**\n * Initialize the logger with configuration.\n * Call this once at application startup.\n */\nexport function initLogger(config: LoggerConfig = {}): void {\n globalEnabled = config.enabled ?? true\n const detected = detectEnvironment()\n\n globalEnv = {\n service: config.env?.service ?? detected.service ?? 'app',\n environment: config.env?.environment ?? detected.environment ?? 'development',\n version: config.env?.version ?? detected.version,\n commitHash: config.env?.commitHash ?? detected.commitHash,\n region: config.env?.region ?? detected.region,\n }\n\n globalPretty = config.pretty ?? isDev()\n globalSampling = config.sampling ?? {}\n globalStringify = config.stringify ?? true\n globalDrain = config.drain\n}\n\n/**\n * Check if logging is globally enabled.\n */\nexport function isEnabled(): boolean {\n return globalEnabled\n}\n\n/**\n * Determine if a log at the given level should be emitted based on sampling config.\n * Error level defaults to 100% (always logged) unless explicitly configured otherwise.\n */\nfunction shouldSample(level: LogLevel): boolean {\n const { rates } = globalSampling\n if (!rates) {\n return true // No sampling configured, log everything\n }\n\n // Error defaults to 100% unless explicitly set\n const percentage = level === 'error' && rates.error === undefined\n ? 100\n : rates[level] ?? 100\n\n // 0% = never log, 100% = always log\n if (percentage <= 0) return false\n if (percentage >= 100) return true\n\n return Math.random() * 100 < percentage\n}\n\n/**\n * Evaluate tail sampling conditions to determine if a log should be force-kept.\n * Returns true if ANY condition matches (OR logic).\n */\nexport function shouldKeep(ctx: TailSamplingContext): boolean {\n const { keep } = globalSampling\n if (!keep?.length) return false\n\n return keep.some((condition) => {\n if (condition.status !== undefined && ctx.status !== undefined && ctx.status >= condition.status) {\n return true\n }\n if (condition.duration !== undefined && ctx.duration !== undefined && ctx.duration >= condition.duration) {\n return true\n }\n if (condition.path && ctx.path && matchesPattern(ctx.path, condition.path)) {\n return true\n }\n return false\n })\n}\n\nfunction emitWideEvent(level: LogLevel, event: Record<string, unknown>, skipSamplingCheck = false): WideEvent | null {\n if (!globalEnabled) return null\n\n if (!skipSamplingCheck && !shouldSample(level)) {\n return null\n }\n\n const formatted: WideEvent = {\n timestamp: new Date().toISOString(),\n level,\n ...globalEnv,\n ...event,\n }\n\n if (globalPretty) {\n prettyPrintWideEvent(formatted)\n } else if (globalStringify) {\n console[getConsoleMethod(level)](JSON.stringify(formatted))\n } else {\n console[getConsoleMethod(level)](formatted)\n }\n\n if (globalDrain) {\n Promise.resolve(globalDrain({ event: formatted })).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n }\n\n return formatted\n}\n\nfunction emitTaggedLog(level: LogLevel, tag: string, message: string): void {\n if (!globalEnabled) return\n\n if (globalPretty) {\n if (!shouldSample(level)) {\n return\n }\n const color = getLevelColor(level)\n const timestamp = new Date().toISOString().slice(11, 23)\n console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`)\n return\n }\n emitWideEvent(level, { tag, message })\n}\n\nfunction formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return String(value)\n }\n if (typeof value === 'object') {\n // Flatten object to key=value pairs\n const pairs: string[] = []\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (v !== undefined && v !== null) {\n if (typeof v === 'object') {\n // For nested objects, show as JSON\n pairs.push(`${k}=${JSON.stringify(v)}`)\n } else {\n pairs.push(`${k}=${v}`)\n }\n }\n }\n return pairs.join(' ')\n }\n return String(value)\n}\n\nfunction prettyPrintWideEvent(event: Record<string, unknown>): void {\n const { timestamp, level, service, environment, version, ...rest } = event\n const levelColor = getLevelColor(level as string)\n const ts = (timestamp as string).slice(11, 23)\n\n let header = `${colors.dim}${ts}${colors.reset} ${levelColor}${(level as string).toUpperCase()}${colors.reset}`\n header += ` ${colors.cyan}[${service}]${colors.reset}`\n\n if (rest.method && rest.path) {\n header += ` ${rest.method} ${rest.path}`\n delete rest.method\n delete rest.path\n }\n\n if (rest.status) {\n const statusColor = (rest.status as number) >= 400 ? colors.red : colors.green\n header += ` ${statusColor}${rest.status}${colors.reset}`\n delete rest.status\n }\n\n if (rest.duration) {\n header += ` ${colors.dim}in ${rest.duration}${colors.reset}`\n delete rest.duration\n }\n\n console.log(header)\n\n const entries = Object.entries(rest).filter(([_, v]) => v !== undefined)\n const lastIndex = entries.length - 1\n\n entries.forEach(([key, value], index) => {\n const isLast = index === lastIndex\n const prefix = isLast ? '└─' : '├─'\n const formatted = formatValue(value)\n console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`)\n })\n}\n\nfunction createLogMethod(level: LogLevel) {\n return function logMethod(tagOrEvent: string | Record<string, unknown>, message?: string): void {\n if (typeof tagOrEvent === 'string' && message !== undefined) {\n emitTaggedLog(level, tagOrEvent, message)\n } else if (typeof tagOrEvent === 'object') {\n emitWideEvent(level, tagOrEvent)\n } else {\n emitTaggedLog(level, 'log', String(tagOrEvent))\n }\n }\n}\n\n/**\n * Simple logging API - as easy as console.log\n *\n * @example\n * ```ts\n * log.info('auth', 'User logged in')\n * log.error({ action: 'payment', error: 'failed' })\n * ```\n */\nconst _log: Log = {\n info: createLogMethod('info'),\n error: createLogMethod('error'),\n warn: createLogMethod('warn'),\n debug: createLogMethod('debug'),\n}\n\nexport { _log as log }\n\nconst noopLogger: RequestLogger = {\n set() {},\n error() {},\n info() {},\n warn() {},\n emit() {\n return null\n },\n getContext() {\n return {}\n },\n}\n\n/**\n * Create a scoped logger for building wide events.\n * Use this for any context: workflows, jobs, scripts, queues, etc.\n *\n * @example\n * ```ts\n * const log = createLogger({ jobId: job.id, queue: 'emails' })\n * log.set({ batch: { size: 50, processed: 12 } })\n * log.emit()\n * ```\n */\nexport function createLogger<T extends object = Record<string, unknown>>(initialContext: Record<string, unknown> = {}): RequestLogger<T> {\n if (!globalEnabled) return noopLogger as RequestLogger<T>\n\n const startTime = Date.now()\n let context: Record<string, unknown> = { ...initialContext }\n let hasError = false\n let hasWarn = false\n\n function addLog(level: 'info' | 'warn', message: string): void {\n const entry = {\n level,\n message,\n timestamp: new Date().toISOString(),\n }\n\n const requestLogs = Array.isArray(context.requestLogs)\n ? [...context.requestLogs, entry]\n : [entry]\n\n context = {\n ...context,\n requestLogs,\n }\n }\n\n return {\n set(data: FieldContext<T>): void {\n context = deepDefaults(data as Record<string, unknown>, context) as Record<string, unknown>\n },\n\n error(error: Error | string, errorContext?: FieldContext<T>): void {\n hasError = true\n const err = typeof error === 'string' ? new Error(error) : error\n\n const errorData = {\n ...(errorContext as Record<string, unknown>),\n error: {\n name: err.name,\n message: err.message,\n stack: err.stack,\n ...('status' in err && { status: (err as Record<string, unknown>).status }),\n ...('statusText' in err && { statusText: (err as Record<string, unknown>).statusText }),\n ...('statusCode' in err && { statusCode: (err as Record<string, unknown>).statusCode }),\n ...('statusMessage' in err && { statusMessage: (err as Record<string, unknown>).statusMessage }),\n ...('data' in err && { data: (err as Record<string, unknown>).data }),\n ...('cause' in err && { cause: (err as unknown as Record<string, unknown>).cause }),\n },\n }\n context = deepDefaults(errorData, context) as Record<string, unknown>\n },\n\n info(message: string, infoContext?: FieldContext<T>): void {\n addLog('info', message)\n if (infoContext) {\n const { requestLogs: _, ...rest } = infoContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n warn(message: string, warnContext?: FieldContext<T>): void {\n hasWarn = true\n addLog('warn', message)\n if (warnContext) {\n const { requestLogs: _, ...rest } = warnContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n emit(overrides?: FieldContext<T> & { _forceKeep?: boolean }): WideEvent | null {\n const durationMs = Date.now() - startTime\n const duration = formatDuration(durationMs)\n const level: LogLevel = hasError ? 'error' : hasWarn ? 'warn' : 'info'\n\n // Extract _forceKeep from overrides (set by evlog:emit:keep hook)\n const { _forceKeep, ...restOverrides } = (overrides ?? {}) as Record<string, unknown> & { _forceKeep?: boolean }\n\n // Build tail sampling context\n const tailCtx: TailSamplingContext = {\n status: (context.status ?? restOverrides.status) as number | undefined,\n duration: durationMs,\n path: context.path as string | undefined,\n method: context.method as string | undefined,\n context: { ...context, ...restOverrides },\n }\n\n // Tail sampling: force keep if hook or built-in conditions match\n const forceKeep = _forceKeep || shouldKeep(tailCtx)\n\n // Apply head sampling only if not force-kept\n if (!forceKeep && !shouldSample(level)) {\n return null\n }\n\n return emitWideEvent(level, {\n ...context,\n ...restOverrides,\n duration,\n }, true)\n },\n\n getContext(): FieldContext<T> & Record<string, unknown> {\n return { ...context }\n },\n }\n}\n\n/**\n * Create a request-scoped logger for building wide events.\n * Convenience wrapper around `createLogger` that pre-populates HTTP request fields.\n *\n * @example\n * ```ts\n * const log = createRequestLogger({ method: 'POST', path: '/checkout' })\n * log.set({ user: { id: '123' } })\n * log.set({ cart: { items: 3 } })\n * log.emit()\n * ```\n */\nexport function createRequestLogger<T extends object = Record<string, unknown>>(options: RequestLoggerOptions = {}): RequestLogger<T> {\n const initial: Record<string, unknown> = {}\n if (options.method !== undefined) initial.method = options.method\n if (options.path !== undefined) initial.path = options.path\n if (options.requestId !== undefined) initial.requestId = options.requestId\n return createLogger<T>(initial)\n}\n\n/**\n * Get the current environment context.\n */\nexport function getEnvironment(): EnvironmentContext {\n return { ...globalEnv }\n}\n"],"mappings":"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"}
@@ -23,6 +23,13 @@ interface EvlogProviderProps {
23
23
  * @default true
24
24
  */
25
25
  enabled?: boolean;
26
+ /**
27
+ * Enable or disable browser console output.
28
+ * When false, logs are suppressed in the browser DevTools console
29
+ * but still sent to the server via transport (if enabled).
30
+ * @default true
31
+ */
32
+ console?: boolean;
26
33
  children: React.ReactNode;
27
34
  }
28
35
  /**
@@ -48,6 +55,7 @@ declare function EvlogProvider({
48
55
  pretty,
49
56
  transport,
50
57
  enabled,
58
+ console: consoleOutput,
51
59
  children
52
60
  }: EvlogProviderProps): react.ReactNode;
53
61
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.mts","names":[],"sources":["../../src/next/client.ts"],"mappings":";;;;;UAQiB,kBAAA;;;AAAjB;;EAKE,OAAA;EAmByB;;;;EAbzB,MAAA;EAWA;;;EANA,SAAA,GAAY,eAAA;EAQa;;AAsB3B;;EAxBE,OAAA;EAEA,QAAA,EAAU,KAAA,CAAM,SAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAsBF,aAAA,CAAA;EAAgB,OAAA;EAAS,MAAA;EAAQ,SAAA;EAAW,OAAA;EAAS;AAAA,GAAY,kBAAA,GAAkB,KAAA,CAAA,SAAA"}
1
+ {"version":3,"file":"client.d.mts","names":[],"sources":["../../src/next/client.ts"],"mappings":";;;;;UAQiB,kBAAA;;;AAAjB;;EAKE,OAAA;EA2ByB;;;;EArBzB,MAAA;EAWA;;;EANA,SAAA,GAAY,eAAA;EAgBI;;;AAsBlB;EAhCE,OAAA;;;;;;;EAQA,OAAA;EAEA,QAAA,EAAU,KAAA,CAAM,SAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAsBF,aAAA,CAAA;EAAgB,OAAA;EAAS,MAAA;EAAQ,SAAA;EAAW,OAAA;EAAS,OAAA,EAAS,aAAA;EAAe;AAAA,GAAY,kBAAA,GAAkB,KAAA,CAAA,SAAA"}
@@ -22,16 +22,18 @@ import { useEffect } from "react";
22
22
  * }
23
23
  * ```
24
24
  */
25
- function EvlogProvider({ service, pretty, transport, enabled, children }) {
25
+ function EvlogProvider({ service, pretty, transport, enabled, console: consoleOutput, children }) {
26
26
  useEffect(() => {
27
27
  initLog({
28
28
  enabled,
29
+ console: consoleOutput,
29
30
  pretty,
30
31
  service,
31
32
  transport
32
33
  });
33
34
  }, [
34
35
  enabled,
36
+ consoleOutput,
35
37
  pretty,
36
38
  service,
37
39
  transport
@@ -1 +1 @@
1
- {"version":3,"file":"client.mjs","names":[],"sources":["../../src/next/client.ts"],"sourcesContent":["'use client'\n\nimport { useEffect } from 'react'\nimport type { TransportConfig } from '../types'\nimport { initLog, log, setIdentity, clearIdentity } from '../runtime/client/log'\n\nexport { log, setIdentity, clearIdentity } from '../runtime/client/log'\n\nexport interface EvlogProviderProps {\n /**\n * Service name for client-side logs.\n * @default 'client'\n */\n service?: string\n\n /**\n * Enable pretty printing in the browser console.\n * @default true\n */\n pretty?: boolean\n\n /**\n * Transport configuration for sending client logs to the server.\n */\n transport?: TransportConfig\n\n /**\n * Enable or disable client-side logging.\n * @default true\n */\n enabled?: boolean\n\n children: React.ReactNode\n}\n\n/**\n * React provider that initializes evlog client-side logging.\n * Place this in your root layout to enable client logging throughout your app.\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { EvlogProvider } from 'evlog/next/client'\n *\n * export default function Layout({ children }) {\n * return (\n * <EvlogProvider service=\"my-app\" transport={{ enabled: true }}>\n * {children}\n * </EvlogProvider>\n * )\n * }\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function EvlogProvider({ service, pretty, transport, enabled, children }: EvlogProviderProps) {\n useEffect(() => {\n initLog({\n enabled,\n pretty,\n service,\n transport,\n })\n }, [enabled, pretty, service, transport])\n\n return children\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAsDA,SAAgB,cAAc,EAAE,SAAS,QAAQ,WAAW,SAAS,YAAgC;AACnG,iBAAgB;AACd,UAAQ;GACN;GACA;GACA;GACA;GACD,CAAC;IACD;EAAC;EAAS;EAAQ;EAAS;EAAU,CAAC;AAEzC,QAAO"}
1
+ {"version":3,"file":"client.mjs","names":[],"sources":["../../src/next/client.ts"],"sourcesContent":["'use client'\n\nimport { useEffect } from 'react'\nimport type { TransportConfig } from '../types'\nimport { initLog, log, setIdentity, clearIdentity } from '../runtime/client/log'\n\nexport { log, setIdentity, clearIdentity } from '../runtime/client/log'\n\nexport interface EvlogProviderProps {\n /**\n * Service name for client-side logs.\n * @default 'client'\n */\n service?: string\n\n /**\n * Enable pretty printing in the browser console.\n * @default true\n */\n pretty?: boolean\n\n /**\n * Transport configuration for sending client logs to the server.\n */\n transport?: TransportConfig\n\n /**\n * Enable or disable client-side logging.\n * @default true\n */\n enabled?: boolean\n\n /**\n * Enable or disable browser console output.\n * When false, logs are suppressed in the browser DevTools console\n * but still sent to the server via transport (if enabled).\n * @default true\n */\n console?: boolean\n\n children: React.ReactNode\n}\n\n/**\n * React provider that initializes evlog client-side logging.\n * Place this in your root layout to enable client logging throughout your app.\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { EvlogProvider } from 'evlog/next/client'\n *\n * export default function Layout({ children }) {\n * return (\n * <EvlogProvider service=\"my-app\" transport={{ enabled: true }}>\n * {children}\n * </EvlogProvider>\n * )\n * }\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function EvlogProvider({ service, pretty, transport, enabled, console: consoleOutput, children }: EvlogProviderProps) {\n useEffect(() => {\n initLog({\n enabled,\n console: consoleOutput,\n pretty,\n service,\n transport,\n })\n }, [enabled, consoleOutput, pretty, service, transport])\n\n return children\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA8DA,SAAgB,cAAc,EAAE,SAAS,QAAQ,WAAW,SAAS,SAAS,eAAe,YAAgC;AAC3H,iBAAgB;AACd,UAAQ;GACN;GACA,SAAS;GACT;GACA;GACA;GACD,CAAC;IACD;EAAC;EAAS;EAAe;EAAQ;EAAS;EAAU,CAAC;AAExD,QAAO"}
@@ -1,7 +1,6 @@
1
1
  import { DrainContext, EnrichContext, EnvironmentContext, Log, RequestLogger, RouteConfig, SamplingConfig, TailSamplingContext } from "../types.mjs";
2
2
  import { createError } from "../error.mjs";
3
3
  import { log as _log } from "../logger.mjs";
4
- import "../index.mjs";
5
4
  import { AsyncLocalStorage } from "node:async_hooks";
6
5
 
7
6
  //#region src/next/types.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/next/types.ts","../../src/next/storage.ts","../../src/next/middleware.ts","../../src/next/index.ts"],"mappings":";;;;;;;UAEiB,gBAAA;;;;;EAKf,OAAA;EALe;;;EAUf,GAAA,GAAM,OAAA,CAAQ,kBAAA;EAAR;;;;EAMN,MAAA;EAoCsC;;;;EA9BtC,OAAA;EA2CmD;;;EAtCnD,QAAA,GAAW,cAAA;EAjBL;;;;;EAwBN,OAAA;EAAA;;;;;EAOA,OAAA;EAWc;;;EANd,MAAA,GAAS,MAAA,SAAe,WAAA;EAYT;;;;EANf,KAAA,IAAS,GAAA,EAAK,YAAA,YAAwB,OAAA;EAa9B;;;;EAPR,MAAA,IAAU,GAAA,EAAK,aAAA,YAAyB,OAAA;EAgBzB;;;;;EATf,IAAA,IAAQ,GAAA,EAAK,mBAAA,YAA+B,OAAA;;;AC/C9C;;EDqDE,SAAA;AAAA;AAAA,UAGe,qBAAA;ECxDwD;;;;ED6DvE,OAAA;EC7DuE;;;;EDmEvE,OAAA;AAAA;;;;;;;AArFF;;;;;;;;;;;iBCkBgB,SAAA,oBAA6B,MAAA,kBAAA,CAAA,GAA4B,aAAA,CAAc,CAAA;;;KCjBlF,WAAA;EACH,OAAA;IAAW,QAAA;EAAA;EACX,OAAA;IAAW,GAAA,CAAI,IAAA;EAAA;AAAA;AAAA,KAGZ,YAAA;EACH,OAAA;IAAW,GAAA,CAAI,IAAA,UAAc,KAAA;EAAA;AAAA;;;;;;;;;;;;;;iBAoBf,eAAA,CAAgB,MAAA,GAAS,qBAAA,IACzB,OAAA,EAAS,WAAA,KAAW,OAAA,CAAA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCYpB,WAAA,CAAY,OAAA,GAAS,gBAAA;6DAWg8D,IAAA,EAAA,KAAA,KAAA,OAAA,SAAkC,IAAA,EAAA,KAAA,KAAA,OAAA,CAAA,OAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/next/types.ts","../../src/next/storage.ts","../../src/next/middleware.ts","../../src/next/index.ts"],"mappings":";;;;;;UAEiB,gBAAA;;;;;EAKf,OAAA;EALe;;;EAUf,GAAA,GAAM,OAAA,CAAQ,kBAAA;EAAR;;;;EAMN,MAAA;EAoCsC;;;;EA9BtC,OAAA;EA2CmD;;;EAtCnD,QAAA,GAAW,cAAA;EAjBL;;;;;EAwBN,OAAA;EAAA;;;;;EAOA,OAAA;EAWc;;;EANd,MAAA,GAAS,MAAA,SAAe,WAAA;EAYT;;;;EANf,KAAA,IAAS,GAAA,EAAK,YAAA,YAAwB,OAAA;EAa9B;;;;EAPR,MAAA,IAAU,GAAA,EAAK,aAAA,YAAyB,OAAA;EAgBzB;;;;;EATf,IAAA,IAAQ,GAAA,EAAK,mBAAA,YAA+B,OAAA;;;AC/C9C;;EDqDE,SAAA;AAAA;AAAA,UAGe,qBAAA;ECxDwD;;;;ED6DvE,OAAA;EC7DuE;;;;EDmEvE,OAAA;AAAA;;;;;;;AArFF;;;;;;;;;;;iBCkBgB,SAAA,oBAA6B,MAAA,kBAAA,CAAA,GAA4B,aAAA,CAAc,CAAA;;;KCjBlF,WAAA;EACH,OAAA;IAAW,QAAA;EAAA;EACX,OAAA;IAAW,GAAA,CAAI,IAAA;EAAA;AAAA;AAAA,KAGZ,YAAA;EACH,OAAA;IAAW,GAAA,CAAI,IAAA,UAAc,KAAA;EAAA;AAAA;;;;;;;;;;;;;;iBAoBf,eAAA,CAAgB,MAAA,GAAS,qBAAA,IACzB,OAAA,EAAS,WAAA,KAAW,OAAA,CAAA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCYpB,WAAA,CAAY,OAAA,GAAS,gBAAA;6DAWg8D,IAAA,EAAA,KAAA,KAAA,OAAA,SAAkC,IAAA,EAAA,KAAA,KAAA,OAAA,CAAA,OAAA,CAAA,OAAA"}
@@ -1,10 +1,11 @@
1
1
  import { useLogger } from "../runtime/server/useLogger.mjs";
2
- import { t as NitroModuleOptions } from "../nitro-CrFBjY1Y.mjs";
2
+ import { t as NitroModuleOptions } from "../nitro-Nxg6qcXd.mjs";
3
+ import { Nitro } from "nitropack";
3
4
 
4
5
  //#region src/nitro/module.d.ts
5
6
  declare function evlog(options?: NitroModuleOptions): {
6
7
  name: string;
7
- setup(nitro: any): void;
8
+ setup(nitro: Nitro): void;
8
9
  };
9
10
  //#endregion
10
11
  export { type NitroModuleOptions, evlog as default, useLogger };
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.mts","names":[],"sources":["../../src/nitro/module.ts"],"mappings":";;;;iBAQwB,KAAA,CAAM,OAAA,GAAU,kBAAA"}
1
+ {"version":3,"file":"module.d.mts","names":[],"sources":["../../src/nitro/module.ts"],"mappings":";;;;;iBASwB,KAAA,CAAM,OAAA,GAAU,kBAAA;;eAGvB,KAAA;AAAA"}
@@ -11,6 +11,7 @@ function evlog(options) {
11
11
  nitro.options.plugins = nitro.options.plugins || [];
12
12
  nitro.options.plugins.push(resolve(_dir, "plugin"));
13
13
  if (!nitro.options.errorHandler) nitro.options.errorHandler = resolve(_dir, "errorHandler");
14
+ nitro.options.noExternals = true;
14
15
  nitro.options.runtimeConfig = nitro.options.runtimeConfig || {};
15
16
  nitro.options.runtimeConfig.evlog = options || {};
16
17
  process.env.__EVLOG_CONFIG = JSON.stringify(options || {});