evlog 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/_drain-FZVTbHn9.mjs +18 -0
- package/dist/_drain-FZVTbHn9.mjs.map +1 -0
- package/dist/{_http-DHpGetLZ.mjs → _http-DpL_o_Wk.mjs} +2 -17
- package/dist/_http-DpL_o_Wk.mjs.map +1 -0
- package/dist/{_severity-Q1BuITU_.mjs → _severity-fhhv2Nq0.mjs} +1 -1
- package/dist/{_severity-Q1BuITU_.mjs.map → _severity-fhhv2Nq0.mjs.map} +1 -1
- package/dist/adapters/axiom.d.mts +1 -1
- package/dist/adapters/axiom.mjs +2 -1
- package/dist/adapters/axiom.mjs.map +1 -1
- package/dist/adapters/better-stack.d.mts +1 -1
- package/dist/adapters/better-stack.mjs +2 -1
- package/dist/adapters/better-stack.mjs.map +1 -1
- package/dist/adapters/fs.d.mts +37 -0
- package/dist/adapters/fs.d.mts.map +1 -0
- package/dist/adapters/fs.mjs +106 -0
- package/dist/adapters/fs.mjs.map +1 -0
- package/dist/adapters/otlp.d.mts +1 -1
- package/dist/adapters/otlp.mjs +3 -2
- package/dist/adapters/otlp.mjs.map +1 -1
- package/dist/adapters/posthog.d.mts +1 -1
- package/dist/adapters/posthog.mjs +2 -1
- package/dist/adapters/posthog.mjs.map +1 -1
- package/dist/adapters/sentry.d.mts +1 -1
- package/dist/adapters/sentry.mjs +3 -2
- package/dist/adapters/sentry.mjs.map +1 -1
- package/dist/browser.d.mts +1 -1
- package/dist/elysia/index.d.mts +2 -2
- package/dist/elysia/index.mjs +1 -1
- package/dist/enrichers.d.mts +1 -1
- package/dist/{error-iV3zJCY3.d.mts → error-BuPbEDGO.d.mts} +2 -2
- package/dist/{error-iV3zJCY3.d.mts.map → error-BuPbEDGO.d.mts.map} +1 -1
- package/dist/error.d.mts +1 -1
- package/dist/{errors-CKSfdvLa.d.mts → errors-nScQVwHW.d.mts} +2 -2
- package/dist/{errors-CKSfdvLa.d.mts.map → errors-nScQVwHW.d.mts.map} +1 -1
- package/dist/express/index.d.mts +2 -2
- package/dist/express/index.mjs +3 -3
- package/dist/express/index.mjs.map +1 -1
- package/dist/fastify/index.d.mts +2 -2
- package/dist/fastify/index.mjs +2 -2
- package/dist/{headers-Ba1eKT3i.mjs → headers-BSgpnR0c.mjs} +7 -6
- package/dist/headers-BSgpnR0c.mjs.map +1 -0
- package/dist/hono/index.d.mts +2 -2
- package/dist/hono/index.mjs +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/{logger-CvDYZUze.d.mts → logger-BH1gOdNP.d.mts} +21 -5
- package/dist/logger-BH1gOdNP.d.mts.map +1 -0
- package/dist/logger.d.mts +2 -2
- package/dist/logger.mjs +25 -13
- package/dist/logger.mjs.map +1 -1
- package/dist/{middleware-hZqyXoSk.d.mts → middleware-CDLTVOBs.d.mts} +2 -2
- package/dist/{middleware-hZqyXoSk.d.mts.map → middleware-CDLTVOBs.d.mts.map} +1 -1
- package/dist/nestjs/index.d.mts +2 -2
- package/dist/nestjs/index.d.mts.map +1 -1
- package/dist/nestjs/index.mjs +3 -3
- package/dist/nestjs/index.mjs.map +1 -1
- package/dist/next/client.d.mts +1 -1
- package/dist/next/index.d.mts +10 -4
- package/dist/next/index.d.mts.map +1 -1
- package/dist/next/index.mjs +7 -4
- package/dist/next/index.mjs.map +1 -1
- package/dist/nitro/module.d.mts +2 -2
- package/dist/nitro/plugin.mjs +4 -2
- package/dist/nitro/plugin.mjs.map +1 -1
- package/dist/nitro/v3/module.d.mts +1 -1
- package/dist/nitro/v3/plugin.mjs +4 -2
- package/dist/nitro/v3/plugin.mjs.map +1 -1
- package/dist/nitro/v3/useLogger.d.mts +1 -1
- package/dist/{nitro-CGGTUned.d.mts → nitro-CaIIZfdG.d.mts} +10 -2
- package/dist/nitro-CaIIZfdG.d.mts.map +1 -0
- package/dist/nitro-D1pPm37T.mjs.map +1 -1
- package/dist/nuxt/module.d.mts +9 -1
- package/dist/nuxt/module.d.mts.map +1 -1
- package/dist/nuxt/module.mjs +1 -1
- package/dist/nuxt/module.mjs.map +1 -1
- package/dist/{parseError-BztqcPwZ.d.mts → parseError-DYrhDD1r.d.mts} +2 -2
- package/dist/parseError-DYrhDD1r.d.mts.map +1 -0
- package/dist/runtime/client/log.d.mts +1 -1
- package/dist/runtime/server/useLogger.d.mts +1 -1
- package/dist/runtime/utils/parseError.d.mts +2 -2
- package/dist/{storage-CJBW5Vos.mjs → storage-DHU1gGqV.mjs} +1 -1
- package/dist/{storage-CJBW5Vos.mjs.map → storage-DHU1gGqV.mjs.map} +1 -1
- package/dist/sveltekit/index.d.mts +2 -2
- package/dist/sveltekit/index.mjs +2 -2
- package/dist/toolkit.d.mts +3 -3
- package/dist/toolkit.mjs +2 -2
- package/dist/{types-B8-kC2ME.d.mts → types-US-1hJZl.d.mts} +11 -1
- package/dist/types-US-1hJZl.d.mts.map +1 -0
- package/dist/types.d.mts +1 -1
- package/dist/{useLogger-_Ec6mXoR.d.mts → useLogger-DBHI03WK.d.mts} +2 -2
- package/dist/{useLogger-_Ec6mXoR.d.mts.map → useLogger-DBHI03WK.d.mts.map} +1 -1
- package/dist/utils.d.mts +1 -1
- package/dist/workers.d.mts +1 -1
- package/package.json +19 -8
- package/dist/_http-DHpGetLZ.mjs.map +0 -1
- package/dist/headers-Ba1eKT3i.mjs.map +0 -1
- package/dist/logger-CvDYZUze.d.mts.map +0 -1
- package/dist/nitro-CGGTUned.d.mts.map +0 -1
- package/dist/parseError-BztqcPwZ.d.mts.map +0 -1
- package/dist/types-B8-kC2ME.d.mts.map +0 -1
|
@@ -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":";;;;;;;UAGiB,gBAAA,SAAyB,gBAAA;;;;;EAKxC,OAAA;;;AALF;EAUE,GAAA,GAAM,OAAA,CAAQ,kBAAA;;;;;EAMd,MAAA;EAhBwD;;;;EAsBxD,OAAA;EAZM;;;EAiBN,QAAA,GAAW,cAAA;EAAX;;;;EAMA,SAAA;AAAA;AAAA,UAGe,qBAAA
|
|
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":";;;;;;;UAGiB,gBAAA,SAAyB,gBAAA;;;;;EAKxC,OAAA;;;AALF;EAUE,GAAA,GAAM,OAAA,CAAQ,kBAAA;;;;;EAMd,MAAA;EAhBwD;;;;EAsBxD,OAAA;EAZM;;;EAiBN,QAAA,GAAW,cAAA;EAAX;;;;EAMA,SAAA;EAOM;AAGR;;;;EAHE,MAAA;AAAA;AAAA,UAGe,qBAAA;;AC1BjB;;;ED+BE,OAAA;EC/BqF;;;;EDqCrF,OAAA;AAAA;;;;;;;;;;AAtDF;;;;;;;;iBCiBgB,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;;;;;AF3BpC;;;;;;;;;;;;;;;;;;;;;;AA2CA;;;;;iBGJgB,WAAA,CAAY,OAAA,GAAS,gBAAA;6DAW8jE,IAAA,EAAA,KAAA,KAAA,OAAA,SAAkC,IAAA,EAAA,KAAA,KAAA,OAAA,CAAA,OAAA,CAAA,OAAA"}
|
package/dist/next/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { filterSafeHeaders } from "../utils.mjs";
|
|
2
2
|
import { EvlogError, createError } from "../error.mjs";
|
|
3
|
-
import { createRequestLogger, initLogger, isEnabled, log as _log } from "../logger.mjs";
|
|
3
|
+
import { createRequestLogger, getGlobalDrain, initLogger, isEnabled, log as _log } from "../logger.mjs";
|
|
4
4
|
import { n as shouldLog, t as getServiceForPath } from "../routes-CE3_c-iZ.mjs";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
//#region src/next/storage.ts
|
|
@@ -41,8 +41,10 @@ function configureHandler(options) {
|
|
|
41
41
|
...options.env
|
|
42
42
|
},
|
|
43
43
|
pretty: options.pretty,
|
|
44
|
+
silent: options.silent,
|
|
44
45
|
sampling: options.sampling,
|
|
45
|
-
stringify: options.stringify
|
|
46
|
+
stringify: options.stringify,
|
|
47
|
+
_suppressDrainWarning: true
|
|
46
48
|
});
|
|
47
49
|
}
|
|
48
50
|
function extractRequestInfo(request) {
|
|
@@ -60,7 +62,8 @@ function extractRequestInfo(request) {
|
|
|
60
62
|
}
|
|
61
63
|
async function callEnrichAndDrain(emittedEvent, requestInfo, headers, responseStatus) {
|
|
62
64
|
if (!emittedEvent) return;
|
|
63
|
-
const { enrich
|
|
65
|
+
const { enrich } = state.options;
|
|
66
|
+
const drain = state.options.drain ?? getGlobalDrain();
|
|
64
67
|
const run = async () => {
|
|
65
68
|
if (enrich) {
|
|
66
69
|
const enrichCtx = {
|
|
@@ -137,7 +140,7 @@ function createWithEvlog(options) {
|
|
|
137
140
|
method,
|
|
138
141
|
path,
|
|
139
142
|
requestId
|
|
140
|
-
});
|
|
143
|
+
}, { _deferDrain: true });
|
|
141
144
|
const routeService = getServiceForPath(path, state.options.routes);
|
|
142
145
|
if (routeService) logger.set({ service: routeService });
|
|
143
146
|
if (isRequest) {
|
package/dist/next/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/next/storage.ts","../../src/next/handler.ts","../../src/next/middleware.ts","../../src/next/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport type { RequestLogger } from '../types'\n\nexport const evlogStorage = new AsyncLocalStorage<RequestLogger>()\n\n/**\n * Get the current request-scoped logger.\n * Must be called inside a `withEvlog()` wrapper.\n *\n * @throws {Error} if called outside of `withEvlog()` context\n *\n * @example\n * ```ts\n * export const POST = withEvlog(async (request) => {\n * const log = useLogger()\n * log.set({ user: { id: '123' } })\n * return Response.json({ ok: true })\n * })\n * ```\n */\nexport function useLogger<T extends object = Record<string, unknown>>(): RequestLogger<T> {\n const logger = evlogStorage.getStore()\n if (!logger) {\n throw new Error(\n '[evlog] useLogger() was called outside of a withEvlog() context. '\n + 'Wrap your route handler or server action with withEvlog().',\n )\n }\n return logger as RequestLogger<T>\n}\n","import type { DrainContext, EnrichContext, TailSamplingContext, WideEvent } from '../types'\nimport { createRequestLogger, initLogger, isEnabled } from '../logger'\nimport { filterSafeHeaders } from '../utils'\nimport { shouldLog, getServiceForPath } from '../shared/routes'\nimport { EvlogError } from '../error'\nimport type { NextEvlogOptions } from './types'\nimport { evlogStorage } from './storage'\n\ninterface WithEvlogState {\n initialized: boolean\n options: NextEvlogOptions\n}\n\nconst state: WithEvlogState = {\n initialized: false,\n options: {},\n}\n\nexport function configureHandler(options: NextEvlogOptions): void {\n state.options = options\n state.initialized = true\n\n // Don't pass drain to initLogger — the global drain fires inside emitWideEvent\n // which doesn't have request/header context. Instead, we call drain ourselves\n // in callEnrichAndDrain after enrich, with full context.\n initLogger({\n enabled: options.enabled,\n env: {\n service: options.service,\n ...options.env,\n },\n pretty: options.pretty,\n sampling: options.sampling,\n stringify: options.stringify,\n })\n}\n\nfunction extractRequestInfo(request: Request): { method: string, path: string, headers: Record<string, string> } {\n const { method } = request\n const url = new URL(request.url, 'http://localhost')\n const path = url.pathname\n\n const headers: Record<string, string> = {}\n request.headers.forEach((value, key) => {\n headers[key] = value\n })\n\n return { method, path, headers: filterSafeHeaders(headers) }\n}\n\nasync function callEnrichAndDrain(\n emittedEvent: WideEvent | null,\n requestInfo: { method: string, path: string, requestId: string },\n headers: Record<string, string>,\n responseStatus?: number,\n): Promise<void> {\n if (!emittedEvent) return\n\n const { enrich, drain } = state.options\n\n const run = async () => {\n if (enrich) {\n const enrichCtx: EnrichContext = {\n event: emittedEvent,\n request: requestInfo,\n headers,\n response: { status: responseStatus },\n }\n try {\n await enrich(enrichCtx)\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n }\n\n if (drain) {\n const drainCtx: DrainContext = {\n event: emittedEvent,\n request: requestInfo,\n headers,\n }\n try {\n await drain(drainCtx)\n } catch (err) {\n console.error('[evlog] drain failed:', err)\n }\n }\n }\n\n // Use next/server after() if available to run enrich+drain after response\n try {\n const { after } = await import('next/server')\n if (typeof after === 'function') {\n after(run)\n return\n }\n } catch {\n // next/server not available or after() not exported — run inline\n }\n\n // Fallback: fire-and-forget (enrich still awaited for correctness)\n run().catch(() => {})\n}\n\n/**\n * Wrap a Next.js route handler or server action with evlog request-scoped logging.\n *\n * @example\n * ```ts\n * // Route handler\n * export const POST = withEvlog(async (request: NextRequest) => {\n * const log = useLogger()\n * log.set({ user: { id: '123' } })\n * return Response.json({ success: true })\n * })\n *\n * // Server action\n * export const checkout = withEvlog(async (formData: FormData) => {\n * const log = useLogger()\n * log.set({ action: 'checkout' })\n * })\n * ```\n */\nexport function createWithEvlog(options: NextEvlogOptions) {\n configureHandler(options)\n\n return function withEvlog<TArgs extends unknown[], TReturn>(\n handler: (...args: TArgs) => TReturn,\n ): (...args: TArgs) => Promise<Awaited<TReturn>> {\n return async (...args: TArgs): Promise<Awaited<TReturn>> => {\n if (!isEnabled()) {\n return await handler(...args) as Awaited<TReturn>\n }\n\n // Extract request info from first argument if it's a Request\n const [firstArg] = args\n const isRequest = firstArg instanceof Request\n\n let method = 'UNKNOWN'\n let path = '/'\n let headers: Record<string, string> = {}\n let requestId = crypto.randomUUID()\n\n if (isRequest) {\n ({ method, path, headers } = extractRequestInfo(firstArg))\n\n // Reuse request-id from middleware if present\n const middlewareRequestId = firstArg.headers.get('x-request-id')\n if (middlewareRequestId) requestId = middlewareRequestId\n }\n\n // Check include/exclude patterns\n if (!shouldLog(path, state.options.include, state.options.exclude)) {\n return await handler(...args) as Awaited<TReturn>\n }\n\n const logger = createRequestLogger({ method, path, requestId })\n\n // Apply route-based service configuration\n const routeService = getServiceForPath(path, state.options.routes)\n if (routeService) {\n logger.set({ service: routeService })\n }\n\n // Apply start time from middleware if present\n if (isRequest) {\n const startHeader = firstArg.headers.get('x-evlog-start')\n if (startHeader) {\n logger.set({ middlewareStart: Number(startHeader) })\n }\n }\n\n try {\n const result = await evlogStorage.run(logger, () => handler(...args))\n\n // Extract response status\n let { status } = { status: 200 }\n if (result instanceof Response) {\n ({ status } = result)\n }\n logger.set({ status })\n\n // Build tail sampling context and call keep callback\n let forceKeep = false\n if (state.options.keep) {\n try {\n const tailCtx: TailSamplingContext = {\n status,\n path,\n method,\n context: logger.getContext(),\n shouldKeep: false,\n }\n await state.options.keep(tailCtx)\n forceKeep = tailCtx.shouldKeep ?? false\n } catch (err) {\n console.error('[evlog] keep callback failed:', err)\n }\n }\n\n const emittedEvent = logger.emit({ _forceKeep: forceKeep })\n await callEnrichAndDrain(emittedEvent, { method, path, requestId }, headers, status)\n\n return result as Awaited<TReturn>\n } catch (error) {\n logger.error(error instanceof Error ? error : new Error(String(error)))\n\n const errorStatus = (error as { status?: number }).status\n ?? (error as { statusCode?: number }).statusCode\n ?? 500\n logger.set({ status: errorStatus })\n\n // Build tail sampling context and call keep callback\n let forceKeep = false\n if (state.options.keep) {\n try {\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n path,\n method,\n context: logger.getContext(),\n shouldKeep: false,\n }\n await state.options.keep(tailCtx)\n forceKeep = tailCtx.shouldKeep ?? false\n } catch (err) {\n console.error('[evlog] keep callback failed:', err)\n }\n }\n\n const emittedEvent = logger.emit({ _forceKeep: forceKeep })\n await callEnrichAndDrain(emittedEvent, { method, path, requestId }, headers, errorStatus)\n\n // Return structured JSON response for EvlogErrors (like H3 does for Nuxt)\n if (isRequest && error instanceof EvlogError) {\n return Response.json(error.toJSON(), { status: error.status }) as Awaited<TReturn>\n }\n\n throw error\n }\n }\n }\n}\n","import { shouldLog } from '../shared/routes'\nimport type { EvlogMiddlewareConfig } from './types'\n\ntype NextRequest = {\n nextUrl: { pathname: string }\n headers: { get(name: string): string | null }\n}\n\ntype NextResponse = {\n headers: { set(name: string, value: string): void }\n}\n\ntype NextResponseStatic = {\n next(options?: { request?: { headers: Headers } }): NextResponse\n}\n\n/**\n * Create an evlog middleware for Next.js.\n * Sets `x-request-id` and `x-evlog-start` headers so `withEvlog()` can reuse them\n * for timing consistency across the middleware -> handler chain.\n *\n * @example\n * ```ts\n * // middleware.ts\n * import { evlogMiddleware } from 'evlog/next'\n * export const middleware = evlogMiddleware()\n * export const config = { matcher: ['/api/:path*'] }\n * ```\n */\nexport function evlogMiddleware(config?: EvlogMiddlewareConfig) {\n return async (request: NextRequest) => {\n const path = request.nextUrl.pathname\n\n // Check include/exclude patterns\n if (!shouldLog(path, config?.include, config?.exclude)) {\n const { NextResponse: nextResponse } = await import('next/server') as { NextResponse: NextResponseStatic }\n return nextResponse.next()\n }\n\n // Generate or reuse request ID\n const existingId = request.headers.get('x-request-id')\n const requestId = existingId || crypto.randomUUID()\n\n // Forward modified headers to the route handler\n const requestHeaders = new Headers(request.headers as HeadersInit)\n\n requestHeaders.set('x-request-id', requestId)\n requestHeaders.set('x-evlog-start', String(Date.now()))\n\n const { NextResponse: nextResponse } = await import('next/server') as { NextResponse: NextResponseStatic }\n const response = nextResponse.next({\n request: { headers: requestHeaders },\n })\n\n // Also set on response for downstream consumers\n response.headers.set('x-request-id', requestId)\n\n return response\n }\n}\n","import { log } from '../logger'\nimport { createError, createEvlogError } from '../error'\nimport type { NextEvlogOptions } from './types'\nimport { createWithEvlog } from './handler'\nimport { useLogger } from './storage'\n\nexport type { NextEvlogOptions, EvlogMiddlewareConfig } from './types'\n\nexport { evlogMiddleware } from './middleware'\nexport { useLogger } from './storage'\nexport { log } from '../logger'\nexport { createError, createEvlogError } from '../error'\n\n/**\n * Create an evlog instance configured for Next.js.\n * Returns all helpers needed for server-side logging.\n *\n * @example\n * ```ts\n * // lib/evlog.ts\n * import { createEvlog } from 'evlog/next'\n * import { createAxiomDrain } from 'evlog/axiom'\n * import { createDrainPipeline } from 'evlog/pipeline'\n *\n * const pipeline = createDrainPipeline({ batch: { size: 50 } })\n *\n * export const { withEvlog, useLogger, log, createEvlogError } = createEvlog({\n * service: 'my-app',\n * sampling: {\n * rates: { info: 10 },\n * keep: [{ status: 400 }, { duration: 1000 }],\n * },\n * drain: pipeline(createAxiomDrain({\n * dataset: 'logs',\n * token: process.env.AXIOM_TOKEN!,\n * })),\n * enrich: (ctx) => {\n * ctx.event.deploymentId = process.env.VERCEL_DEPLOYMENT_ID\n * },\n * })\n * ```\n */\nexport function createEvlog(options: NextEvlogOptions = {}) {\n const withEvlog = createWithEvlog(options)\n\n return {\n withEvlog,\n useLogger,\n log,\n createError,\n createEvlogError,\n }\n}\n"],"mappings":";;;;;;AAGA,MAAa,eAAe,IAAI,mBAAkC;;;;;;;;;;;;;;;;AAiBlE,SAAgB,YAA0E;CACxF,MAAM,SAAS,aAAa,UAAU;AACtC,KAAI,CAAC,OACH,OAAM,IAAI,MACR,8HAED;AAEH,QAAO;;;;ACfT,MAAM,QAAwB;CAC5B,aAAa;CACb,SAAS,EAAE;CACZ;AAED,SAAgB,iBAAiB,SAAiC;AAChE,OAAM,UAAU;AAChB,OAAM,cAAc;AAKpB,YAAW;EACT,SAAS,QAAQ;EACjB,KAAK;GACH,SAAS,QAAQ;GACjB,GAAG,QAAQ;GACZ;EACD,QAAQ,QAAQ;EAChB,UAAU,QAAQ;EAClB,WAAW,QAAQ;EACpB,CAAC;;AAGJ,SAAS,mBAAmB,SAAqF;CAC/G,MAAM,EAAE,WAAW;CAEnB,MAAM,OADM,IAAI,IAAI,QAAQ,KAAK,mBAAmB,CACnC;CAEjB,MAAM,UAAkC,EAAE;AAC1C,SAAQ,QAAQ,SAAS,OAAO,QAAQ;AACtC,UAAQ,OAAO;GACf;AAEF,QAAO;EAAE;EAAQ;EAAM,SAAS,kBAAkB,QAAQ;EAAE;;AAG9D,eAAe,mBACb,cACA,aACA,SACA,gBACe;AACf,KAAI,CAAC,aAAc;CAEnB,MAAM,EAAE,QAAQ,UAAU,MAAM;CAEhC,MAAM,MAAM,YAAY;AACtB,MAAI,QAAQ;GACV,MAAM,YAA2B;IAC/B,OAAO;IACP,SAAS;IACT;IACA,UAAU,EAAE,QAAQ,gBAAgB;IACrC;AACD,OAAI;AACF,UAAM,OAAO,UAAU;YAChB,KAAK;AACZ,YAAQ,MAAM,0BAA0B,IAAI;;;AAIhD,MAAI,OAAO;GACT,MAAM,WAAyB;IAC7B,OAAO;IACP,SAAS;IACT;IACD;AACD,OAAI;AACF,UAAM,MAAM,SAAS;YACd,KAAK;AACZ,YAAQ,MAAM,yBAAyB,IAAI;;;;AAMjD,KAAI;EACF,MAAM,EAAE,UAAU,MAAM,OAAO;AAC/B,MAAI,OAAO,UAAU,YAAY;AAC/B,SAAM,IAAI;AACV;;SAEI;AAKR,MAAK,CAAC,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;AAsBvB,SAAgB,gBAAgB,SAA2B;AACzD,kBAAiB,QAAQ;AAEzB,QAAO,SAAS,UACd,SAC+C;AAC/C,SAAO,OAAO,GAAG,SAA2C;AAC1D,OAAI,CAAC,WAAW,CACd,QAAO,MAAM,QAAQ,GAAG,KAAK;GAI/B,MAAM,CAAC,YAAY;GACnB,MAAM,YAAY,oBAAoB;GAEtC,IAAI,SAAS;GACb,IAAI,OAAO;GACX,IAAI,UAAkC,EAAE;GACxC,IAAI,YAAY,OAAO,YAAY;AAEnC,OAAI,WAAW;AACb,KAAC,CAAE,QAAQ,MAAM,WAAY,mBAAmB,SAAS;IAGzD,MAAM,sBAAsB,SAAS,QAAQ,IAAI,eAAe;AAChE,QAAI,oBAAqB,aAAY;;AAIvC,OAAI,CAAC,UAAU,MAAM,MAAM,QAAQ,SAAS,MAAM,QAAQ,QAAQ,CAChE,QAAO,MAAM,QAAQ,GAAG,KAAK;GAG/B,MAAM,SAAS,oBAAoB;IAAE;IAAQ;IAAM;IAAW,CAAC;GAG/D,MAAM,eAAe,kBAAkB,MAAM,MAAM,QAAQ,OAAO;AAClE,OAAI,aACF,QAAO,IAAI,EAAE,SAAS,cAAc,CAAC;AAIvC,OAAI,WAAW;IACb,MAAM,cAAc,SAAS,QAAQ,IAAI,gBAAgB;AACzD,QAAI,YACF,QAAO,IAAI,EAAE,iBAAiB,OAAO,YAAY,EAAE,CAAC;;AAIxD,OAAI;IACF,MAAM,SAAS,MAAM,aAAa,IAAI,cAAc,QAAQ,GAAG,KAAK,CAAC;IAGrE,IAAI,EAAE,WAAW,EAAE,QAAQ,KAAK;AAChC,QAAI,kBAAkB,SACpB,EAAC,CAAE,UAAW;AAEhB,WAAO,IAAI,EAAE,QAAQ,CAAC;IAGtB,IAAI,YAAY;AAChB,QAAI,MAAM,QAAQ,KAChB,KAAI;KACF,MAAM,UAA+B;MACnC;MACA;MACA;MACA,SAAS,OAAO,YAAY;MAC5B,YAAY;MACb;AACD,WAAM,MAAM,QAAQ,KAAK,QAAQ;AACjC,iBAAY,QAAQ,cAAc;aAC3B,KAAK;AACZ,aAAQ,MAAM,iCAAiC,IAAI;;AAKvD,UAAM,mBADe,OAAO,KAAK,EAAE,YAAY,WAAW,CAAC,EACpB;KAAE;KAAQ;KAAM;KAAW,EAAE,SAAS,OAAO;AAEpF,WAAO;YACA,OAAO;AACd,WAAO,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,CAAC;IAEvE,MAAM,cAAe,MAA8B,UAC7C,MAAkC,cACnC;AACL,WAAO,IAAI,EAAE,QAAQ,aAAa,CAAC;IAGnC,IAAI,YAAY;AAChB,QAAI,MAAM,QAAQ,KAChB,KAAI;KACF,MAAM,UAA+B;MACnC,QAAQ;MACR;MACA;MACA,SAAS,OAAO,YAAY;MAC5B,YAAY;MACb;AACD,WAAM,MAAM,QAAQ,KAAK,QAAQ;AACjC,iBAAY,QAAQ,cAAc;aAC3B,KAAK;AACZ,aAAQ,MAAM,iCAAiC,IAAI;;AAKvD,UAAM,mBADe,OAAO,KAAK,EAAE,YAAY,WAAW,CAAC,EACpB;KAAE;KAAQ;KAAM;KAAW,EAAE,SAAS,YAAY;AAGzF,QAAI,aAAa,iBAAiB,WAChC,QAAO,SAAS,KAAK,MAAM,QAAQ,EAAE,EAAE,QAAQ,MAAM,QAAQ,CAAC;AAGhE,UAAM;;;;;;;;;;;;;;;;;;;;ACjNd,SAAgB,gBAAgB,QAAgC;AAC9D,QAAO,OAAO,YAAyB;EACrC,MAAM,OAAO,QAAQ,QAAQ;AAG7B,MAAI,CAAC,UAAU,MAAM,QAAQ,SAAS,QAAQ,QAAQ,EAAE;GACtD,MAAM,EAAE,cAAc,iBAAiB,MAAM,OAAO;AACpD,UAAO,aAAa,MAAM;;EAK5B,MAAM,YADa,QAAQ,QAAQ,IAAI,eAAe,IACtB,OAAO,YAAY;EAGnD,MAAM,iBAAiB,IAAI,QAAQ,QAAQ,QAAuB;AAElE,iBAAe,IAAI,gBAAgB,UAAU;AAC7C,iBAAe,IAAI,iBAAiB,OAAO,KAAK,KAAK,CAAC,CAAC;EAEvD,MAAM,EAAE,cAAc,iBAAiB,MAAM,OAAO;EACpD,MAAM,WAAW,aAAa,KAAK,EACjC,SAAS,EAAE,SAAS,gBAAgB,EACrC,CAAC;AAGF,WAAS,QAAQ,IAAI,gBAAgB,UAAU;AAE/C,SAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACfX,SAAgB,YAAY,UAA4B,EAAE,EAAE;AAG1D,QAAO;EACL,WAHgB,gBAAgB,QAAQ;EAIxC;EACA,KAAA;EACA;EACA,kBAAA;EACD"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/next/storage.ts","../../src/next/handler.ts","../../src/next/middleware.ts","../../src/next/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport type { RequestLogger } from '../types'\n\nexport const evlogStorage = new AsyncLocalStorage<RequestLogger>()\n\n/**\n * Get the current request-scoped logger.\n * Must be called inside a `withEvlog()` wrapper.\n *\n * @throws {Error} if called outside of `withEvlog()` context\n *\n * @example\n * ```ts\n * export const POST = withEvlog(async (request) => {\n * const log = useLogger()\n * log.set({ user: { id: '123' } })\n * return Response.json({ ok: true })\n * })\n * ```\n */\nexport function useLogger<T extends object = Record<string, unknown>>(): RequestLogger<T> {\n const logger = evlogStorage.getStore()\n if (!logger) {\n throw new Error(\n '[evlog] useLogger() was called outside of a withEvlog() context. '\n + 'Wrap your route handler or server action with withEvlog().',\n )\n }\n return logger as RequestLogger<T>\n}\n","import type { DrainContext, EnrichContext, TailSamplingContext, WideEvent } from '../types'\nimport { createRequestLogger, getGlobalDrain, initLogger, isEnabled } from '../logger'\nimport { filterSafeHeaders } from '../utils'\nimport { shouldLog, getServiceForPath } from '../shared/routes'\nimport { EvlogError } from '../error'\nimport type { NextEvlogOptions } from './types'\nimport { evlogStorage } from './storage'\n\ninterface WithEvlogState {\n initialized: boolean\n options: NextEvlogOptions\n}\n\nconst state: WithEvlogState = {\n initialized: false,\n options: {},\n}\n\nexport function configureHandler(options: NextEvlogOptions): void {\n state.options = options\n state.initialized = true\n\n // Don't pass drain to initLogger — the global drain fires inside emitWideEvent\n // which doesn't have request/header context. Instead, we call drain ourselves\n // in callEnrichAndDrain after enrich, with full context.\n initLogger({\n enabled: options.enabled,\n env: {\n service: options.service,\n ...options.env,\n },\n pretty: options.pretty,\n silent: options.silent,\n sampling: options.sampling,\n stringify: options.stringify,\n _suppressDrainWarning: true,\n })\n}\n\nfunction extractRequestInfo(request: Request): { method: string, path: string, headers: Record<string, string> } {\n const { method } = request\n const url = new URL(request.url, 'http://localhost')\n const path = url.pathname\n\n const headers: Record<string, string> = {}\n request.headers.forEach((value, key) => {\n headers[key] = value\n })\n\n return { method, path, headers: filterSafeHeaders(headers) }\n}\n\nasync function callEnrichAndDrain(\n emittedEvent: WideEvent | null,\n requestInfo: { method: string, path: string, requestId: string },\n headers: Record<string, string>,\n responseStatus?: number,\n): Promise<void> {\n if (!emittedEvent) return\n\n const { enrich } = state.options\n const drain = state.options.drain ?? getGlobalDrain()\n\n const run = async () => {\n if (enrich) {\n const enrichCtx: EnrichContext = {\n event: emittedEvent,\n request: requestInfo,\n headers,\n response: { status: responseStatus },\n }\n try {\n await enrich(enrichCtx)\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n }\n\n if (drain) {\n const drainCtx: DrainContext = {\n event: emittedEvent,\n request: requestInfo,\n headers,\n }\n try {\n await drain(drainCtx)\n } catch (err) {\n console.error('[evlog] drain failed:', err)\n }\n }\n }\n\n // Use next/server after() if available to run enrich+drain after response\n try {\n const { after } = await import('next/server')\n if (typeof after === 'function') {\n after(run)\n return\n }\n } catch {\n // next/server not available or after() not exported — run inline\n }\n\n // Fallback: fire-and-forget (enrich still awaited for correctness)\n run().catch(() => {})\n}\n\n/**\n * Wrap a Next.js route handler or server action with evlog request-scoped logging.\n *\n * @example\n * ```ts\n * // Route handler\n * export const POST = withEvlog(async (request: NextRequest) => {\n * const log = useLogger()\n * log.set({ user: { id: '123' } })\n * return Response.json({ success: true })\n * })\n *\n * // Server action\n * export const checkout = withEvlog(async (formData: FormData) => {\n * const log = useLogger()\n * log.set({ action: 'checkout' })\n * })\n * ```\n */\nexport function createWithEvlog(options: NextEvlogOptions) {\n configureHandler(options)\n\n return function withEvlog<TArgs extends unknown[], TReturn>(\n handler: (...args: TArgs) => TReturn,\n ): (...args: TArgs) => Promise<Awaited<TReturn>> {\n return async (...args: TArgs): Promise<Awaited<TReturn>> => {\n if (!isEnabled()) {\n return await handler(...args) as Awaited<TReturn>\n }\n\n // Extract request info from first argument if it's a Request\n const [firstArg] = args\n const isRequest = firstArg instanceof Request\n\n let method = 'UNKNOWN'\n let path = '/'\n let headers: Record<string, string> = {}\n let requestId = crypto.randomUUID()\n\n if (isRequest) {\n ({ method, path, headers } = extractRequestInfo(firstArg))\n\n // Reuse request-id from middleware if present\n const middlewareRequestId = firstArg.headers.get('x-request-id')\n if (middlewareRequestId) requestId = middlewareRequestId\n }\n\n // Check include/exclude patterns\n if (!shouldLog(path, state.options.include, state.options.exclude)) {\n return await handler(...args) as Awaited<TReturn>\n }\n\n const logger = createRequestLogger({ method, path, requestId }, { _deferDrain: true })\n\n // Apply route-based service configuration\n const routeService = getServiceForPath(path, state.options.routes)\n if (routeService) {\n logger.set({ service: routeService })\n }\n\n // Apply start time from middleware if present\n if (isRequest) {\n const startHeader = firstArg.headers.get('x-evlog-start')\n if (startHeader) {\n logger.set({ middlewareStart: Number(startHeader) })\n }\n }\n\n try {\n const result = await evlogStorage.run(logger, () => handler(...args))\n\n // Extract response status\n let { status } = { status: 200 }\n if (result instanceof Response) {\n ({ status } = result)\n }\n logger.set({ status })\n\n // Build tail sampling context and call keep callback\n let forceKeep = false\n if (state.options.keep) {\n try {\n const tailCtx: TailSamplingContext = {\n status,\n path,\n method,\n context: logger.getContext(),\n shouldKeep: false,\n }\n await state.options.keep(tailCtx)\n forceKeep = tailCtx.shouldKeep ?? false\n } catch (err) {\n console.error('[evlog] keep callback failed:', err)\n }\n }\n\n const emittedEvent = logger.emit({ _forceKeep: forceKeep })\n await callEnrichAndDrain(emittedEvent, { method, path, requestId }, headers, status)\n\n return result as Awaited<TReturn>\n } catch (error) {\n logger.error(error instanceof Error ? error : new Error(String(error)))\n\n const errorStatus = (error as { status?: number }).status\n ?? (error as { statusCode?: number }).statusCode\n ?? 500\n logger.set({ status: errorStatus })\n\n // Build tail sampling context and call keep callback\n let forceKeep = false\n if (state.options.keep) {\n try {\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n path,\n method,\n context: logger.getContext(),\n shouldKeep: false,\n }\n await state.options.keep(tailCtx)\n forceKeep = tailCtx.shouldKeep ?? false\n } catch (err) {\n console.error('[evlog] keep callback failed:', err)\n }\n }\n\n const emittedEvent = logger.emit({ _forceKeep: forceKeep })\n await callEnrichAndDrain(emittedEvent, { method, path, requestId }, headers, errorStatus)\n\n // Return structured JSON response for EvlogErrors (like H3 does for Nuxt)\n if (isRequest && error instanceof EvlogError) {\n return Response.json(error.toJSON(), { status: error.status }) as Awaited<TReturn>\n }\n\n throw error\n }\n }\n }\n}\n","import { shouldLog } from '../shared/routes'\nimport type { EvlogMiddlewareConfig } from './types'\n\ntype NextRequest = {\n nextUrl: { pathname: string }\n headers: { get(name: string): string | null }\n}\n\ntype NextResponse = {\n headers: { set(name: string, value: string): void }\n}\n\ntype NextResponseStatic = {\n next(options?: { request?: { headers: Headers } }): NextResponse\n}\n\n/**\n * Create an evlog middleware for Next.js.\n * Sets `x-request-id` and `x-evlog-start` headers so `withEvlog()` can reuse them\n * for timing consistency across the middleware -> handler chain.\n *\n * @example\n * ```ts\n * // middleware.ts\n * import { evlogMiddleware } from 'evlog/next'\n * export const middleware = evlogMiddleware()\n * export const config = { matcher: ['/api/:path*'] }\n * ```\n */\nexport function evlogMiddleware(config?: EvlogMiddlewareConfig) {\n return async (request: NextRequest) => {\n const path = request.nextUrl.pathname\n\n // Check include/exclude patterns\n if (!shouldLog(path, config?.include, config?.exclude)) {\n const { NextResponse: nextResponse } = await import('next/server') as { NextResponse: NextResponseStatic }\n return nextResponse.next()\n }\n\n // Generate or reuse request ID\n const existingId = request.headers.get('x-request-id')\n const requestId = existingId || crypto.randomUUID()\n\n // Forward modified headers to the route handler\n const requestHeaders = new Headers(request.headers as HeadersInit)\n\n requestHeaders.set('x-request-id', requestId)\n requestHeaders.set('x-evlog-start', String(Date.now()))\n\n const { NextResponse: nextResponse } = await import('next/server') as { NextResponse: NextResponseStatic }\n const response = nextResponse.next({\n request: { headers: requestHeaders },\n })\n\n // Also set on response for downstream consumers\n response.headers.set('x-request-id', requestId)\n\n return response\n }\n}\n","import { log } from '../logger'\nimport { createError, createEvlogError } from '../error'\nimport type { NextEvlogOptions } from './types'\nimport { createWithEvlog } from './handler'\nimport { useLogger } from './storage'\n\nexport type { NextEvlogOptions, EvlogMiddlewareConfig } from './types'\n\nexport { evlogMiddleware } from './middleware'\nexport { useLogger } from './storage'\nexport { log } from '../logger'\nexport { createError, createEvlogError } from '../error'\n\n/**\n * Create an evlog instance configured for Next.js.\n * Returns all helpers needed for server-side logging.\n *\n * @example\n * ```ts\n * // lib/evlog.ts\n * import { createEvlog } from 'evlog/next'\n * import { createAxiomDrain } from 'evlog/axiom'\n * import { createDrainPipeline } from 'evlog/pipeline'\n *\n * const pipeline = createDrainPipeline({ batch: { size: 50 } })\n *\n * export const { withEvlog, useLogger, log, createEvlogError } = createEvlog({\n * service: 'my-app',\n * sampling: {\n * rates: { info: 10 },\n * keep: [{ status: 400 }, { duration: 1000 }],\n * },\n * drain: pipeline(createAxiomDrain({\n * dataset: 'logs',\n * token: process.env.AXIOM_TOKEN!,\n * })),\n * enrich: (ctx) => {\n * ctx.event.deploymentId = process.env.VERCEL_DEPLOYMENT_ID\n * },\n * })\n * ```\n */\nexport function createEvlog(options: NextEvlogOptions = {}) {\n const withEvlog = createWithEvlog(options)\n\n return {\n withEvlog,\n useLogger,\n log,\n createError,\n createEvlogError,\n }\n}\n"],"mappings":"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"}
|
package/dist/nitro/module.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as useLogger } from "../useLogger-
|
|
2
|
-
import { t as NitroModuleOptions } from "../nitro-
|
|
1
|
+
import { t as useLogger } from "../useLogger-DBHI03WK.mjs";
|
|
2
|
+
import { t as NitroModuleOptions } from "../nitro-CaIIZfdG.mjs";
|
|
3
3
|
import { Nitro } from "nitropack";
|
|
4
4
|
|
|
5
5
|
//#region src/nitro/module.d.ts
|
package/dist/nitro/plugin.mjs
CHANGED
|
@@ -74,7 +74,9 @@ var plugin_default = defineNitroPlugin(async (nitroApp) => {
|
|
|
74
74
|
enabled: evlogConfig?.enabled,
|
|
75
75
|
env: evlogConfig?.env,
|
|
76
76
|
pretty: evlogConfig?.pretty,
|
|
77
|
-
|
|
77
|
+
silent: evlogConfig?.silent,
|
|
78
|
+
sampling: evlogConfig?.sampling,
|
|
79
|
+
_suppressDrainWarning: true
|
|
78
80
|
});
|
|
79
81
|
if (!isEnabled()) return;
|
|
80
82
|
nitroApp.hooks.hook("request", (event) => {
|
|
@@ -90,7 +92,7 @@ var plugin_default = defineNitroPlugin(async (nitroApp) => {
|
|
|
90
92
|
method: e.method,
|
|
91
93
|
path: e.path,
|
|
92
94
|
requestId: requestIdOverride || e.context.requestId || crypto.randomUUID()
|
|
93
|
-
});
|
|
95
|
+
}, { _deferDrain: true });
|
|
94
96
|
const routeService = getServiceForPath(e.path, evlogConfig?.routes);
|
|
95
97
|
if (routeService) requestLog.set({ service: routeService });
|
|
96
98
|
e.context.log = requestLog;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.mjs","names":[],"sources":["../../src/nitro/plugin.ts"],"sourcesContent":["import type { NitroApp } from 'nitropack/types'\n// Import from specific subpaths to avoid the barrel 'nitropack/runtime' which\n// re-exports from internal/app.mjs — that file imports #nitro-internal-virtual/*\n// modules that only exist inside rollup builds and crash when loaded externally\n// (nitropack dev loads plugins outside the bundle via Worker threads).\nimport { defineNitroPlugin } from 'nitropack/runtime/internal/plugin'\nimport { getHeaders } from 'h3'\nimport { createRequestLogger, initLogger, isEnabled } from '../logger'\nimport { shouldLog, getServiceForPath, extractErrorStatus } from '../nitro'\nimport type { EvlogConfig } from '../nitro'\nimport type { EnrichContext, RequestLogger, ServerEvent, TailSamplingContext, WideEvent } from '../types'\nimport { filterSafeHeaders } from '../utils'\n\nfunction getSafeHeaders(event: ServerEvent): Record<string, string> {\n const allHeaders = getHeaders(event as Parameters<typeof getHeaders>[0])\n return filterSafeHeaders(allHeaders)\n}\n\nfunction getSafeResponseHeaders(event: ServerEvent): Record<string, string> | undefined {\n const headers: Record<string, string> = {}\n const nodeRes = event.node?.res as { getHeaders?: () => Record<string, unknown> } | undefined\n\n if (nodeRes?.getHeaders) {\n for (const [key, value] of Object.entries(nodeRes.getHeaders())) {\n if (value === undefined) continue\n headers[key] = Array.isArray(value) ? value.join(', ') : String(value)\n }\n }\n\n if (event.response?.headers) {\n event.response.headers.forEach((value, key) => {\n headers[key] = value\n })\n }\n\n if (Object.keys(headers).length === 0) return undefined\n return filterSafeHeaders(headers)\n}\n\nfunction getResponseStatus(event: ServerEvent): number {\n // Node.js style\n if (event.node?.res?.statusCode) {\n return event.node.res.statusCode\n }\n\n // Web Standard\n if (event.response?.status) {\n return event.response.status\n }\n\n // Context-based\n if (typeof event.context.status === 'number') {\n return event.context.status\n }\n\n return 200\n}\n\nfunction buildHookContext(event: ServerEvent): Omit<EnrichContext, 'event'> {\n const responseHeaders = getSafeResponseHeaders(event)\n return {\n request: { method: event.method, path: event.path },\n headers: getSafeHeaders(event),\n response: {\n status: getResponseStatus(event),\n headers: responseHeaders,\n },\n }\n}\n\nasync function callEnrichAndDrain(\n nitroApp: NitroApp,\n emittedEvent: WideEvent | null,\n event: ServerEvent,\n): Promise<void> {\n if (!emittedEvent) return\n\n const hookContext = buildHookContext(event)\n\n try {\n await nitroApp.hooks.callHook('evlog:enrich', { event: emittedEvent, ...hookContext })\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n\n const drainPromise = nitroApp.hooks.callHook('evlog:drain', {\n event: emittedEvent,\n request: hookContext.request,\n headers: hookContext.headers,\n }).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n\n // Use waitUntil if available (Cloudflare Workers, Vercel Edge, etc.)\n // This keeps the runtime alive for background work without blocking the response\n const waitUntilCtx = event.context.cloudflare?.context ?? event.context\n if (typeof waitUntilCtx?.waitUntil === 'function') {\n waitUntilCtx.waitUntil(drainPromise)\n } else {\n // Fallback: await drain to prevent lost logs in serverless environments\n // (e.g. Vercel Fluid Compute). On the normal path this runs from\n // afterResponse (response already sent); on the error path it may run\n // before the error response is finalized.\n await drainPromise\n }\n}\n\nexport default defineNitroPlugin(async (nitroApp) => {\n // Config resolution: process.env bridge first (always set by the module),\n // then lazy useRuntimeConfig() for production builds where env may not persist.\n let evlogConfig: EvlogConfig | undefined\n if (process.env.__EVLOG_CONFIG) {\n evlogConfig = JSON.parse(process.env.__EVLOG_CONFIG)\n } else {\n try {\n // nitropack/runtime/internal/config imports virtual modules —\n // only works inside rollup-bundled output (production builds).\n const { useRuntimeConfig } = await import('nitropack/runtime/internal/config')\n evlogConfig = (useRuntimeConfig() as Record<string, any>).evlog\n } catch {\n // Expected in dev mode — virtual modules unavailable outside rollup\n }\n }\n\n initLogger({\n enabled: evlogConfig?.enabled,\n env: evlogConfig?.env,\n pretty: evlogConfig?.pretty,\n sampling: evlogConfig?.sampling,\n })\n\n if (!isEnabled()) return\n\n nitroApp.hooks.hook('request', (event) => {\n const e = event as ServerEvent\n\n // Skip logging for routes not matching include/exclude patterns\n if (!shouldLog(e.path, evlogConfig?.include, evlogConfig?.exclude)) {\n return\n }\n\n // Store start time for duration calculation in tail sampling\n e.context._evlogStartTime = Date.now()\n\n let requestIdOverride: string | undefined = undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = getSafeHeaders(e)?.['cf-ray']\n if (cfRay) requestIdOverride = cfRay\n }\n\n const requestLog = createRequestLogger({\n method: e.method,\n path: e.path,\n requestId: requestIdOverride || e.context.requestId || crypto.randomUUID(),\n })\n\n // Apply route-based service configuration if a matching route is found\n const routeService = getServiceForPath(e.path, evlogConfig?.routes)\n if (routeService) {\n requestLog.set({ service: routeService })\n }\n\n e.context.log = requestLog\n })\n\n nitroApp.hooks.hook('error', async (error, { event }) => {\n const e = event as ServerEvent | undefined\n if (!e) return\n\n const requestLog = e.context.log as RequestLogger | undefined\n if (requestLog) {\n requestLog.error(error as Error)\n\n const errorStatus = extractErrorStatus(error)\n requestLog.set({ status: errorStatus })\n\n // Build tail sampling context\n const startTime = e.context._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n duration: durationMs,\n path: e.path,\n method: e.method,\n context: requestLog.getContext(),\n shouldKeep: false,\n }\n\n // Call evlog:emit:keep hook\n await nitroApp.hooks.callHook('evlog:emit:keep', tailCtx)\n\n e.context._evlogEmitted = true\n\n const emittedEvent = requestLog.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(nitroApp, emittedEvent, e)\n }\n })\n\n nitroApp.hooks.hook('afterResponse', async (event) => {\n const e = event as ServerEvent\n // Skip if already emitted by error hook\n if (e.context._evlogEmitted) return\n\n const requestLog = e.context.log as RequestLogger | undefined\n if (requestLog) {\n const status = getResponseStatus(e)\n requestLog.set({ status })\n\n const startTime = e.context._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status,\n duration: durationMs,\n path: e.path,\n method: e.method,\n context: requestLog.getContext(),\n shouldKeep: false,\n }\n\n await nitroApp.hooks.callHook('evlog:emit:keep', tailCtx)\n\n const emittedEvent = requestLog.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(nitroApp, emittedEvent, e)\n }\n })\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin.mjs","names":[],"sources":["../../src/nitro/plugin.ts"],"sourcesContent":["import type { NitroApp } from 'nitropack/types'\n// Import from specific subpaths to avoid the barrel 'nitropack/runtime' which\n// re-exports from internal/app.mjs — that file imports #nitro-internal-virtual/*\n// modules that only exist inside rollup builds and crash when loaded externally\n// (nitropack dev loads plugins outside the bundle via Worker threads).\nimport { defineNitroPlugin } from 'nitropack/runtime/internal/plugin'\nimport { getHeaders } from 'h3'\nimport { createRequestLogger, initLogger, isEnabled } from '../logger'\nimport { shouldLog, getServiceForPath, extractErrorStatus } from '../nitro'\nimport type { EvlogConfig } from '../nitro'\nimport type { EnrichContext, RequestLogger, ServerEvent, TailSamplingContext, WideEvent } from '../types'\nimport { filterSafeHeaders } from '../utils'\n\nfunction getSafeHeaders(event: ServerEvent): Record<string, string> {\n const allHeaders = getHeaders(event as Parameters<typeof getHeaders>[0])\n return filterSafeHeaders(allHeaders)\n}\n\nfunction getSafeResponseHeaders(event: ServerEvent): Record<string, string> | undefined {\n const headers: Record<string, string> = {}\n const nodeRes = event.node?.res as { getHeaders?: () => Record<string, unknown> } | undefined\n\n if (nodeRes?.getHeaders) {\n for (const [key, value] of Object.entries(nodeRes.getHeaders())) {\n if (value === undefined) continue\n headers[key] = Array.isArray(value) ? value.join(', ') : String(value)\n }\n }\n\n if (event.response?.headers) {\n event.response.headers.forEach((value, key) => {\n headers[key] = value\n })\n }\n\n if (Object.keys(headers).length === 0) return undefined\n return filterSafeHeaders(headers)\n}\n\nfunction getResponseStatus(event: ServerEvent): number {\n // Node.js style\n if (event.node?.res?.statusCode) {\n return event.node.res.statusCode\n }\n\n // Web Standard\n if (event.response?.status) {\n return event.response.status\n }\n\n // Context-based\n if (typeof event.context.status === 'number') {\n return event.context.status\n }\n\n return 200\n}\n\nfunction buildHookContext(event: ServerEvent): Omit<EnrichContext, 'event'> {\n const responseHeaders = getSafeResponseHeaders(event)\n return {\n request: { method: event.method, path: event.path },\n headers: getSafeHeaders(event),\n response: {\n status: getResponseStatus(event),\n headers: responseHeaders,\n },\n }\n}\n\nasync function callEnrichAndDrain(\n nitroApp: NitroApp,\n emittedEvent: WideEvent | null,\n event: ServerEvent,\n): Promise<void> {\n if (!emittedEvent) return\n\n const hookContext = buildHookContext(event)\n\n try {\n await nitroApp.hooks.callHook('evlog:enrich', { event: emittedEvent, ...hookContext })\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n\n const drainPromise = nitroApp.hooks.callHook('evlog:drain', {\n event: emittedEvent,\n request: hookContext.request,\n headers: hookContext.headers,\n }).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n\n // Use waitUntil if available (Cloudflare Workers, Vercel Edge, etc.)\n // This keeps the runtime alive for background work without blocking the response\n const waitUntilCtx = event.context.cloudflare?.context ?? event.context\n if (typeof waitUntilCtx?.waitUntil === 'function') {\n waitUntilCtx.waitUntil(drainPromise)\n } else {\n // Fallback: await drain to prevent lost logs in serverless environments\n // (e.g. Vercel Fluid Compute). On the normal path this runs from\n // afterResponse (response already sent); on the error path it may run\n // before the error response is finalized.\n await drainPromise\n }\n}\n\nexport default defineNitroPlugin(async (nitroApp) => {\n // Config resolution: process.env bridge first (always set by the module),\n // then lazy useRuntimeConfig() for production builds where env may not persist.\n let evlogConfig: EvlogConfig | undefined\n if (process.env.__EVLOG_CONFIG) {\n evlogConfig = JSON.parse(process.env.__EVLOG_CONFIG)\n } else {\n try {\n // nitropack/runtime/internal/config imports virtual modules —\n // only works inside rollup-bundled output (production builds).\n const { useRuntimeConfig } = await import('nitropack/runtime/internal/config')\n evlogConfig = (useRuntimeConfig() as Record<string, any>).evlog\n } catch {\n // Expected in dev mode — virtual modules unavailable outside rollup\n }\n }\n\n initLogger({\n enabled: evlogConfig?.enabled,\n env: evlogConfig?.env,\n pretty: evlogConfig?.pretty,\n silent: evlogConfig?.silent,\n sampling: evlogConfig?.sampling,\n _suppressDrainWarning: true,\n })\n\n if (!isEnabled()) return\n\n nitroApp.hooks.hook('request', (event) => {\n const e = event as ServerEvent\n\n // Skip logging for routes not matching include/exclude patterns\n if (!shouldLog(e.path, evlogConfig?.include, evlogConfig?.exclude)) {\n return\n }\n\n // Store start time for duration calculation in tail sampling\n e.context._evlogStartTime = Date.now()\n\n let requestIdOverride: string | undefined = undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = getSafeHeaders(e)?.['cf-ray']\n if (cfRay) requestIdOverride = cfRay\n }\n\n const requestLog = createRequestLogger({\n method: e.method,\n path: e.path,\n requestId: requestIdOverride || e.context.requestId || crypto.randomUUID(),\n }, { _deferDrain: true })\n\n // Apply route-based service configuration if a matching route is found\n const routeService = getServiceForPath(e.path, evlogConfig?.routes)\n if (routeService) {\n requestLog.set({ service: routeService })\n }\n\n e.context.log = requestLog\n })\n\n nitroApp.hooks.hook('error', async (error, { event }) => {\n const e = event as ServerEvent | undefined\n if (!e) return\n\n const requestLog = e.context.log as RequestLogger | undefined\n if (requestLog) {\n requestLog.error(error as Error)\n\n const errorStatus = extractErrorStatus(error)\n requestLog.set({ status: errorStatus })\n\n // Build tail sampling context\n const startTime = e.context._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n duration: durationMs,\n path: e.path,\n method: e.method,\n context: requestLog.getContext(),\n shouldKeep: false,\n }\n\n // Call evlog:emit:keep hook\n await nitroApp.hooks.callHook('evlog:emit:keep', tailCtx)\n\n e.context._evlogEmitted = true\n\n const emittedEvent = requestLog.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(nitroApp, emittedEvent, e)\n }\n })\n\n nitroApp.hooks.hook('afterResponse', async (event) => {\n const e = event as ServerEvent\n // Skip if already emitted by error hook\n if (e.context._evlogEmitted) return\n\n const requestLog = e.context.log as RequestLogger | undefined\n if (requestLog) {\n const status = getResponseStatus(e)\n requestLog.set({ status })\n\n const startTime = e.context._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status,\n duration: durationMs,\n path: e.path,\n method: e.method,\n context: requestLog.getContext(),\n shouldKeep: false,\n }\n\n await nitroApp.hooks.callHook('evlog:emit:keep', tailCtx)\n\n const emittedEvent = requestLog.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(nitroApp, emittedEvent, e)\n }\n })\n})\n"],"mappings":"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"}
|
package/dist/nitro/v3/plugin.mjs
CHANGED
|
@@ -86,7 +86,9 @@ var plugin_default = definePlugin((nitroApp) => {
|
|
|
86
86
|
enabled: evlogConfig?.enabled,
|
|
87
87
|
env: evlogConfig?.env,
|
|
88
88
|
pretty: evlogConfig?.pretty,
|
|
89
|
-
|
|
89
|
+
silent: evlogConfig?.silent,
|
|
90
|
+
sampling: evlogConfig?.sampling,
|
|
91
|
+
_suppressDrainWarning: true
|
|
90
92
|
});
|
|
91
93
|
if (!isEnabled()) return;
|
|
92
94
|
const hooks = nitroApp.hooks;
|
|
@@ -104,7 +106,7 @@ var plugin_default = definePlugin((nitroApp) => {
|
|
|
104
106
|
method: event.req.method,
|
|
105
107
|
path: pathname,
|
|
106
108
|
requestId: requestIdOverride || ctx.requestId || crypto.randomUUID()
|
|
107
|
-
});
|
|
109
|
+
}, { _deferDrain: true });
|
|
108
110
|
const routeService = getServiceForPath(pathname, evlogConfig?.routes);
|
|
109
111
|
if (routeService) log.set({ service: routeService });
|
|
110
112
|
ctx.log = log;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.mjs","names":[],"sources":["../../../src/nitro-v3/plugin.ts"],"sourcesContent":["import { definePlugin } from 'nitro'\nimport { useRuntimeConfig } from 'nitro/runtime-config'\nimport type { CaptureError } from 'nitro/types'\nimport type { HTTPEvent } from 'nitro/h3'\nimport { parseURL } from 'ufo'\nimport { createRequestLogger, initLogger, isEnabled } from '../logger'\nimport { shouldLog, getServiceForPath, extractErrorStatus } from '../nitro'\nimport type { EvlogConfig } from '../nitro'\nimport type { EnrichContext, RequestLogger, TailSamplingContext, WideEvent } from '../types'\nimport { filterSafeHeaders } from '../utils'\n\n// Nitro v3 doesn't fully export hook types yet\n// https://github.com/nitrojs/nitro/blob/8882bc9e1dbf2d342e73097f22a2156f70f50575/src/types/runtime/nitro.ts#L48-L53\ninterface NitroV3Hooks {\n close: () => void\n error: CaptureError\n request: (event: HTTPEvent) => void | Promise<void>\n response: (res: Response, event: HTTPEvent) => void | Promise<void>\n 'evlog:emit:keep': (ctx: TailSamplingContext) => void | Promise<void>\n 'evlog:enrich': (ctx: EnrichContext) => void | Promise<void>\n 'evlog:drain': (ctx: { event: WideEvent; request?: { method?: string; path: string; requestId?: string }; headers?: Record<string, string> }) => void | Promise<void>\n}\n\ntype Hooks = {\n hook: <T extends keyof NitroV3Hooks>(name: T, listener: NitroV3Hooks[T]) => void\n callHook: <T extends keyof NitroV3Hooks>(name: T, ...args: Parameters<NitroV3Hooks[T]>) => Promise<void>\n}\n\nfunction getContext(event: HTTPEvent): Record<string, unknown> {\n if (!event.req.context) {\n event.req.context = {}\n }\n return event.req.context\n}\n\nfunction getSafeRequestHeaders(event: HTTPEvent): Record<string, string> {\n const headers: Record<string, string> = {}\n event.req.headers.forEach((value, key) => {\n headers[key] = value\n })\n return filterSafeHeaders(headers)\n}\n\nfunction getSafeResponseHeaders(res: Response): Record<string, string> | undefined {\n const headers: Record<string, string> = {}\n res.headers.forEach((value, key) => {\n headers[key] = value\n })\n if (Object.keys(headers).length === 0) return undefined\n return filterSafeHeaders(headers)\n}\n\nfunction buildHookContext(\n event: HTTPEvent,\n res?: Response,\n): Omit<EnrichContext, 'event'> {\n const { pathname } = parseURL(event.req.url)\n const responseHeaders = res ? getSafeResponseHeaders(res) : undefined\n return {\n request: { method: event.req.method, path: pathname },\n headers: getSafeRequestHeaders(event),\n response: {\n status: res?.status ?? 200,\n headers: responseHeaders,\n },\n }\n}\n\nasync function callDrainHook(\n hooks: Hooks,\n emittedEvent: WideEvent | null,\n event: HTTPEvent,\n hookContext: Omit<EnrichContext, 'event'>,\n): Promise<void> {\n if (!emittedEvent) return\n\n let drainPromise: Promise<unknown> | undefined\n try {\n const result = hooks.callHook('evlog:drain', {\n event: emittedEvent,\n request: hookContext.request,\n headers: hookContext.headers,\n })\n drainPromise = result?.catch?.((err: unknown) => {\n console.error('[evlog] drain failed:', err)\n })\n } catch (err) {\n console.error('[evlog] drain failed:', err)\n }\n\n if (!drainPromise) return\n\n // Use waitUntil if available (srvx native — Cloudflare Workers, Vercel Edge, etc.)\n // This keeps the runtime alive for background work without blocking the response\n if (typeof event.req.waitUntil === 'function') {\n event.req.waitUntil(drainPromise)\n } else {\n // Fallback: await drain to prevent lost logs in serverless environments\n // (e.g. Vercel Fluid Compute). On the normal path this runs from the\n // response hook (response already sent); on the error path it may run\n // before the error response is finalized.\n await drainPromise\n }\n}\n\nasync function callEnrichAndDrain(\n hooks: Hooks,\n emittedEvent: WideEvent | null,\n event: HTTPEvent,\n res?: Response,\n): Promise<void> {\n if (!emittedEvent) return\n\n const hookContext = buildHookContext(event, res)\n\n try {\n await hooks.callHook('evlog:enrich', { event: emittedEvent, ...hookContext })\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n\n await callDrainHook(hooks, emittedEvent, event, hookContext)\n}\n\n/**\n * Nitro v3 plugin entry point.\n *\n * Usage in Nitro v3:\n * ```ts\n * // plugins/evlog.ts\n * export { default } from 'evlog/nitro/v3'\n * ```\n */\nexport default definePlugin((nitroApp) => {\n // In production builds the plugin is bundled and useRuntimeConfig()\n // resolves the virtual module correctly. In dev mode the plugin is\n // loaded externally so useRuntimeConfig() returns a stub — fall back\n // to the env var bridge set by the module.\n const evlogConfig = (useRuntimeConfig().evlog ?? (process.env.__EVLOG_CONFIG ? JSON.parse(process.env.__EVLOG_CONFIG) : undefined)) as EvlogConfig | undefined\n\n initLogger({\n enabled: evlogConfig?.enabled,\n env: evlogConfig?.env,\n pretty: evlogConfig?.pretty,\n sampling: evlogConfig?.sampling,\n })\n\n if (!isEnabled()) return\n\n const hooks = nitroApp.hooks as unknown as Hooks\n\n hooks.hook('request', (event) => {\n const { pathname } = parseURL(event.req.url)\n\n // Skip logging for routes not matching include/exclude patterns\n if (!shouldLog(pathname, evlogConfig?.include, evlogConfig?.exclude)) {\n return\n }\n\n const ctx = getContext(event)\n\n // Store start time for duration calculation in tail sampling\n ctx._evlogStartTime = Date.now()\n\n let requestIdOverride: string | undefined = undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = event.req.headers.get('cf-ray')\n if (cfRay) requestIdOverride = cfRay\n }\n\n const log = createRequestLogger({\n method: event.req.method,\n path: pathname,\n requestId: requestIdOverride || ctx.requestId as string | undefined || crypto.randomUUID(),\n })\n\n // Apply route-based service configuration if a matching route is found\n const routeService = getServiceForPath(pathname, evlogConfig?.routes)\n if (routeService) {\n log.set({ service: routeService })\n }\n\n ctx.log = log\n })\n\n hooks.hook('response', async (res, event) => {\n const ctx = event.req.context\n // Skip if already emitted by error hook\n if (ctx?._evlogEmitted) return\n\n const log = ctx?.log as RequestLogger | undefined\n if (!log || !ctx) return\n\n const { status } = res\n log.set({ status })\n\n const startTime = ctx._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const { pathname } = parseURL(event.req.url)\n\n const tailCtx: TailSamplingContext = {\n status,\n duration: durationMs,\n path: pathname,\n method: event.req.method,\n context: log.getContext(),\n shouldKeep: false,\n }\n\n await hooks.callHook('evlog:emit:keep', tailCtx)\n\n const emittedEvent = log.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(hooks, emittedEvent, event, res)\n })\n\n hooks.hook('error', async (error, { event }) => {\n if (!event) return\n const e = event as HTTPEvent\n\n const ctx = e.req.context\n const log = ctx?.log as RequestLogger | undefined\n if (!log || !ctx) return\n\n // Check if error.cause is an EvlogError (thrown errors get wrapped in HTTPError by nitro)\n const actualError = (error.cause as Error)?.name === 'EvlogError' \n ? error.cause as Error \n : error as Error\n\n log.error(actualError)\n\n const errorStatus = extractErrorStatus(actualError)\n log.set({ status: errorStatus })\n\n const { pathname } = parseURL(e.req.url)\n const startTime = ctx._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n duration: durationMs,\n path: pathname,\n method: e.req.method,\n context: log.getContext(),\n shouldKeep: false,\n }\n\n await hooks.callHook('evlog:emit:keep', tailCtx)\n\n ctx._evlogEmitted = true\n\n const emittedEvent = log.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(hooks, emittedEvent, e)\n })\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin.mjs","names":[],"sources":["../../../src/nitro-v3/plugin.ts"],"sourcesContent":["import { definePlugin } from 'nitro'\nimport { useRuntimeConfig } from 'nitro/runtime-config'\nimport type { CaptureError } from 'nitro/types'\nimport type { HTTPEvent } from 'nitro/h3'\nimport { parseURL } from 'ufo'\nimport { createRequestLogger, initLogger, isEnabled } from '../logger'\nimport { shouldLog, getServiceForPath, extractErrorStatus } from '../nitro'\nimport type { EvlogConfig } from '../nitro'\nimport type { EnrichContext, RequestLogger, TailSamplingContext, WideEvent } from '../types'\nimport { filterSafeHeaders } from '../utils'\n\n// Nitro v3 doesn't fully export hook types yet\n// https://github.com/nitrojs/nitro/blob/8882bc9e1dbf2d342e73097f22a2156f70f50575/src/types/runtime/nitro.ts#L48-L53\ninterface NitroV3Hooks {\n close: () => void\n error: CaptureError\n request: (event: HTTPEvent) => void | Promise<void>\n response: (res: Response, event: HTTPEvent) => void | Promise<void>\n 'evlog:emit:keep': (ctx: TailSamplingContext) => void | Promise<void>\n 'evlog:enrich': (ctx: EnrichContext) => void | Promise<void>\n 'evlog:drain': (ctx: { event: WideEvent; request?: { method?: string; path: string; requestId?: string }; headers?: Record<string, string> }) => void | Promise<void>\n}\n\ntype Hooks = {\n hook: <T extends keyof NitroV3Hooks>(name: T, listener: NitroV3Hooks[T]) => void\n callHook: <T extends keyof NitroV3Hooks>(name: T, ...args: Parameters<NitroV3Hooks[T]>) => Promise<void>\n}\n\nfunction getContext(event: HTTPEvent): Record<string, unknown> {\n if (!event.req.context) {\n event.req.context = {}\n }\n return event.req.context\n}\n\nfunction getSafeRequestHeaders(event: HTTPEvent): Record<string, string> {\n const headers: Record<string, string> = {}\n event.req.headers.forEach((value, key) => {\n headers[key] = value\n })\n return filterSafeHeaders(headers)\n}\n\nfunction getSafeResponseHeaders(res: Response): Record<string, string> | undefined {\n const headers: Record<string, string> = {}\n res.headers.forEach((value, key) => {\n headers[key] = value\n })\n if (Object.keys(headers).length === 0) return undefined\n return filterSafeHeaders(headers)\n}\n\nfunction buildHookContext(\n event: HTTPEvent,\n res?: Response,\n): Omit<EnrichContext, 'event'> {\n const { pathname } = parseURL(event.req.url)\n const responseHeaders = res ? getSafeResponseHeaders(res) : undefined\n return {\n request: { method: event.req.method, path: pathname },\n headers: getSafeRequestHeaders(event),\n response: {\n status: res?.status ?? 200,\n headers: responseHeaders,\n },\n }\n}\n\nasync function callDrainHook(\n hooks: Hooks,\n emittedEvent: WideEvent | null,\n event: HTTPEvent,\n hookContext: Omit<EnrichContext, 'event'>,\n): Promise<void> {\n if (!emittedEvent) return\n\n let drainPromise: Promise<unknown> | undefined\n try {\n const result = hooks.callHook('evlog:drain', {\n event: emittedEvent,\n request: hookContext.request,\n headers: hookContext.headers,\n })\n drainPromise = result?.catch?.((err: unknown) => {\n console.error('[evlog] drain failed:', err)\n })\n } catch (err) {\n console.error('[evlog] drain failed:', err)\n }\n\n if (!drainPromise) return\n\n // Use waitUntil if available (srvx native — Cloudflare Workers, Vercel Edge, etc.)\n // This keeps the runtime alive for background work without blocking the response\n if (typeof event.req.waitUntil === 'function') {\n event.req.waitUntil(drainPromise)\n } else {\n // Fallback: await drain to prevent lost logs in serverless environments\n // (e.g. Vercel Fluid Compute). On the normal path this runs from the\n // response hook (response already sent); on the error path it may run\n // before the error response is finalized.\n await drainPromise\n }\n}\n\nasync function callEnrichAndDrain(\n hooks: Hooks,\n emittedEvent: WideEvent | null,\n event: HTTPEvent,\n res?: Response,\n): Promise<void> {\n if (!emittedEvent) return\n\n const hookContext = buildHookContext(event, res)\n\n try {\n await hooks.callHook('evlog:enrich', { event: emittedEvent, ...hookContext })\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n\n await callDrainHook(hooks, emittedEvent, event, hookContext)\n}\n\n/**\n * Nitro v3 plugin entry point.\n *\n * Usage in Nitro v3:\n * ```ts\n * // plugins/evlog.ts\n * export { default } from 'evlog/nitro/v3'\n * ```\n */\nexport default definePlugin((nitroApp) => {\n // In production builds the plugin is bundled and useRuntimeConfig()\n // resolves the virtual module correctly. In dev mode the plugin is\n // loaded externally so useRuntimeConfig() returns a stub — fall back\n // to the env var bridge set by the module.\n const evlogConfig = (useRuntimeConfig().evlog ?? (process.env.__EVLOG_CONFIG ? JSON.parse(process.env.__EVLOG_CONFIG) : undefined)) as EvlogConfig | undefined\n\n initLogger({\n enabled: evlogConfig?.enabled,\n env: evlogConfig?.env,\n pretty: evlogConfig?.pretty,\n silent: evlogConfig?.silent,\n sampling: evlogConfig?.sampling,\n _suppressDrainWarning: true,\n })\n\n if (!isEnabled()) return\n\n const hooks = nitroApp.hooks as unknown as Hooks\n\n hooks.hook('request', (event) => {\n const { pathname } = parseURL(event.req.url)\n\n // Skip logging for routes not matching include/exclude patterns\n if (!shouldLog(pathname, evlogConfig?.include, evlogConfig?.exclude)) {\n return\n }\n\n const ctx = getContext(event)\n\n // Store start time for duration calculation in tail sampling\n ctx._evlogStartTime = Date.now()\n\n let requestIdOverride: string | undefined = undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = event.req.headers.get('cf-ray')\n if (cfRay) requestIdOverride = cfRay\n }\n\n const log = createRequestLogger({\n method: event.req.method,\n path: pathname,\n requestId: requestIdOverride || ctx.requestId as string | undefined || crypto.randomUUID(),\n }, { _deferDrain: true })\n\n // Apply route-based service configuration if a matching route is found\n const routeService = getServiceForPath(pathname, evlogConfig?.routes)\n if (routeService) {\n log.set({ service: routeService })\n }\n\n ctx.log = log\n })\n\n hooks.hook('response', async (res, event) => {\n const ctx = event.req.context\n // Skip if already emitted by error hook\n if (ctx?._evlogEmitted) return\n\n const log = ctx?.log as RequestLogger | undefined\n if (!log || !ctx) return\n\n const { status } = res\n log.set({ status })\n\n const startTime = ctx._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const { pathname } = parseURL(event.req.url)\n\n const tailCtx: TailSamplingContext = {\n status,\n duration: durationMs,\n path: pathname,\n method: event.req.method,\n context: log.getContext(),\n shouldKeep: false,\n }\n\n await hooks.callHook('evlog:emit:keep', tailCtx)\n\n const emittedEvent = log.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(hooks, emittedEvent, event, res)\n })\n\n hooks.hook('error', async (error, { event }) => {\n if (!event) return\n const e = event as HTTPEvent\n\n const ctx = e.req.context\n const log = ctx?.log as RequestLogger | undefined\n if (!log || !ctx) return\n\n // Check if error.cause is an EvlogError (thrown errors get wrapped in HTTPError by nitro)\n const actualError = (error.cause as Error)?.name === 'EvlogError' \n ? error.cause as Error \n : error as Error\n\n log.error(actualError)\n\n const errorStatus = extractErrorStatus(actualError)\n log.set({ status: errorStatus })\n\n const { pathname } = parseURL(e.req.url)\n const startTime = ctx._evlogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n duration: durationMs,\n path: pathname,\n method: e.req.method,\n context: log.getContext(),\n shouldKeep: false,\n }\n\n await hooks.callHook('evlog:emit:keep', tailCtx)\n\n ctx._evlogEmitted = true\n\n const emittedEvent = log.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(hooks, emittedEvent, e)\n })\n})\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as EnvironmentContext, v as RouteConfig, y as SamplingConfig } from "./types-
|
|
1
|
+
import { a as EnvironmentContext, v as RouteConfig, y as SamplingConfig } from "./types-US-1hJZl.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/nitro.d.ts
|
|
4
4
|
interface NitroModuleOptions {
|
|
@@ -16,6 +16,14 @@ interface NitroModuleOptions {
|
|
|
16
16
|
* @default true in development, false in production
|
|
17
17
|
*/
|
|
18
18
|
pretty?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Suppress built-in console output.
|
|
21
|
+
* When true, events are still built, sampled, and passed to drains,
|
|
22
|
+
* but nothing is written to console. Use when drains own the output
|
|
23
|
+
* channel (e.g., stdout-based platforms like GCP Cloud Run, AWS Lambda).
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
silent?: boolean;
|
|
19
27
|
/**
|
|
20
28
|
* Route patterns to include in logging.
|
|
21
29
|
* Supports glob patterns like '/api/**'.
|
|
@@ -39,4 +47,4 @@ interface NitroModuleOptions {
|
|
|
39
47
|
}
|
|
40
48
|
//#endregion
|
|
41
49
|
export { NitroModuleOptions as t };
|
|
42
|
-
//# sourceMappingURL=nitro-
|
|
50
|
+
//# sourceMappingURL=nitro-CaIIZfdG.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nitro-CaIIZfdG.d.mts","names":[],"sources":["../src/nitro.ts"],"mappings":";;;UAKiB,kBAAA;EAAA;;;;EAKf,OAAA;EAuCwB;;;EAlCxB,GAAA,GAAM,OAAA,CAAQ,kBAAA;EAuCW;;;;EAjCzB,MAAA;EAAA;;;;;;;EASA,MAAA;EAwBW;;;;;EAjBX,OAAA;;;;;;EAOA,OAAA;;;;EAKA,MAAA,GAAS,MAAA,SAAe,WAAA;;;;EAKxB,QAAA,GAAW,cAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nitro-D1pPm37T.mjs","names":[],"sources":["../src/nitro.ts"],"sourcesContent":["import type { EnvironmentContext, RouteConfig, SamplingConfig } from './types'\nimport { extractErrorStatus } from './shared/errors'\n\nexport { shouldLog, getServiceForPath } from './shared/routes'\n\nexport interface NitroModuleOptions {\n /**\n * Enable or disable all logging globally.\n * @default true\n */\n enabled?: boolean\n\n /**\n * Environment context overrides.\n */\n env?: Partial<EnvironmentContext>\n\n /**\n * Enable pretty printing.\n * @default true in development, false in production\n */\n pretty?: boolean\n\n /**\n * Route patterns to include in logging.\n * Supports glob patterns like '/api/**'.\n * If not set, all routes are logged.\n */\n include?: string[]\n\n /**\n * Route patterns to exclude from logging.\n * Supports glob patterns like '/_nitro/**'.\n * Exclusions take precedence over inclusions.\n */\n exclude?: string[]\n\n /**\n * Route-specific service configuration.\n */\n routes?: Record<string, RouteConfig>\n\n /**\n * Sampling configuration for filtering logs.\n */\n sampling?: SamplingConfig\n}\n\nexport interface EvlogConfig {\n enabled?: boolean\n env?: Record<string, unknown>\n pretty?: boolean\n include?: string[]\n exclude?: string[]\n routes?: Record<string, RouteConfig>\n sampling?: SamplingConfig\n}\n\n/**\n * Resolve an EvlogError from an error or its cause chain.\n * Both Nitro v2 (h3) and v3 wrap thrown errors — this unwraps them.\n */\nexport function resolveEvlogError(error: Error): Error | null {\n if (error.name === 'EvlogError') return error\n if ((error.cause as Error)?.name === 'EvlogError') return error.cause as Error\n return null\n}\n\nexport { extractErrorStatus } from './shared/errors'\n\n/**\n * Build a standard evlog error JSON response body.\n * Used by both v2 and v3 error handlers to ensure consistent shape.\n */\nexport function serializeEvlogErrorResponse(error: Error, url: string): Record<string, unknown> {\n const status = extractErrorStatus(error)\n const { data } = error as { data?: unknown }\n const statusMessage = (error as { statusMessage?: string }).statusMessage || error.message\n return {\n url,\n status,\n statusCode: status,\n statusText: statusMessage,\n statusMessage,\n message: error.message,\n error: true,\n ...(data !== undefined && { data }),\n }\n}\n\n"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"nitro-D1pPm37T.mjs","names":[],"sources":["../src/nitro.ts"],"sourcesContent":["import type { EnvironmentContext, RouteConfig, SamplingConfig } from './types'\nimport { extractErrorStatus } from './shared/errors'\n\nexport { shouldLog, getServiceForPath } from './shared/routes'\n\nexport interface NitroModuleOptions {\n /**\n * Enable or disable all logging globally.\n * @default true\n */\n enabled?: boolean\n\n /**\n * Environment context overrides.\n */\n env?: Partial<EnvironmentContext>\n\n /**\n * Enable pretty printing.\n * @default true in development, false in production\n */\n pretty?: boolean\n\n /**\n * Suppress built-in console output.\n * When true, events are still built, sampled, and passed to drains,\n * but nothing is written to console. Use when drains own the output\n * channel (e.g., stdout-based platforms like GCP Cloud Run, AWS Lambda).\n * @default false\n */\n silent?: boolean\n\n /**\n * Route patterns to include in logging.\n * Supports glob patterns like '/api/**'.\n * If not set, all routes are logged.\n */\n include?: string[]\n\n /**\n * Route patterns to exclude from logging.\n * Supports glob patterns like '/_nitro/**'.\n * Exclusions take precedence over inclusions.\n */\n exclude?: string[]\n\n /**\n * Route-specific service configuration.\n */\n routes?: Record<string, RouteConfig>\n\n /**\n * Sampling configuration for filtering logs.\n */\n sampling?: SamplingConfig\n}\n\nexport interface EvlogConfig {\n enabled?: boolean\n env?: Record<string, unknown>\n pretty?: boolean\n silent?: boolean\n include?: string[]\n exclude?: string[]\n routes?: Record<string, RouteConfig>\n sampling?: SamplingConfig\n}\n\n/**\n * Resolve an EvlogError from an error or its cause chain.\n * Both Nitro v2 (h3) and v3 wrap thrown errors — this unwraps them.\n */\nexport function resolveEvlogError(error: Error): Error | null {\n if (error.name === 'EvlogError') return error\n if ((error.cause as Error)?.name === 'EvlogError') return error.cause as Error\n return null\n}\n\nexport { extractErrorStatus } from './shared/errors'\n\n/**\n * Build a standard evlog error JSON response body.\n * Used by both v2 and v3 error handlers to ensure consistent shape.\n */\nexport function serializeEvlogErrorResponse(error: Error, url: string): Record<string, unknown> {\n const status = extractErrorStatus(error)\n const { data } = error as { data?: unknown }\n const statusMessage = (error as { statusMessage?: string }).statusMessage || error.message\n return {\n url,\n status,\n statusCode: status,\n statusText: statusMessage,\n statusMessage,\n message: error.message,\n error: true,\n ...(data !== undefined && { data }),\n }\n}\n\n"],"mappings":";;;;;;AAwEA,SAAgB,kBAAkB,OAA4B;AAC5D,KAAI,MAAM,SAAS,aAAc,QAAO;AACxC,KAAK,MAAM,OAAiB,SAAS,aAAc,QAAO,MAAM;AAChE,QAAO;;;;;;AAST,SAAgB,4BAA4B,OAAc,KAAsC;CAC9F,MAAM,SAAS,mBAAmB,MAAM;CACxC,MAAM,EAAE,SAAS;CACjB,MAAM,gBAAiB,MAAqC,iBAAiB,MAAM;AACnF,QAAO;EACL;EACA;EACA,YAAY;EACZ,YAAY;EACZ;EACA,SAAS,MAAM;EACf,OAAO;EACP,GAAI,SAAS,KAAA,KAAa,EAAE,MAAM;EACnC"}
|
package/dist/nuxt/module.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as EnvironmentContext, v as RouteConfig, w as TransportConfig, y as SamplingConfig } from "../types-
|
|
1
|
+
import { a as EnvironmentContext, v as RouteConfig, w as TransportConfig, y as SamplingConfig } from "../types-US-1hJZl.mjs";
|
|
2
2
|
import * as _nuxt_schema0 from "@nuxt/schema";
|
|
3
3
|
|
|
4
4
|
//#region src/nuxt/module.d.ts
|
|
@@ -52,6 +52,14 @@ interface ModuleOptions {
|
|
|
52
52
|
* @default true in development, false in production
|
|
53
53
|
*/
|
|
54
54
|
pretty?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Suppress built-in console output.
|
|
57
|
+
* When true, events are still built, sampled, and passed to drains,
|
|
58
|
+
* but nothing is written to console. Use when drains own the output
|
|
59
|
+
* channel (e.g., stdout-based platforms like GCP Cloud Run, AWS Lambda).
|
|
60
|
+
* @default false
|
|
61
|
+
*/
|
|
62
|
+
silent?: boolean;
|
|
55
63
|
/**
|
|
56
64
|
* Route patterns to include in logging.
|
|
57
65
|
* Supports glob patterns like '/api/**'.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.mts","names":[],"sources":["../../src/nuxt/module.ts"],"mappings":";;;;UAaU,qBAAA;;EAER,OAAA;EAFQ;EAIR,KAAA;;EAEA,KAAA;EAJA;EAMA,OAAA;AAAA;AAAA,UAGQ,qBAAA;EAHD;;AAAA;;;EASP,OAAA;EAEO;EAAP,OAAA;AAAA;AAAA,UAGQ,yBAAA;EAER;EAAA,OAAA;EAKG;EAHH,OAAA;AAAA;AAAA,KAGG,iBAAA,GAAoB,qBAAA,IAAyB,qBAAA,GAAwB,yBAAA;AAAA,UAEzD,aAAA;EAFyD;;;;;EAQxE,OAAA;EARiG;;AAEnG;EAWE,GAAA,GAAM,OAAA,CAAQ,kBAAA;;;;;;;EAQd,OAAA;
|
|
1
|
+
{"version":3,"file":"module.d.mts","names":[],"sources":["../../src/nuxt/module.ts"],"mappings":";;;;UAaU,qBAAA;;EAER,OAAA;EAFQ;EAIR,KAAA;;EAEA,KAAA;EAJA;EAMA,OAAA;AAAA;AAAA,UAGQ,qBAAA;EAHD;;AAAA;;;EASP,OAAA;EAEO;EAAP,OAAA;AAAA;AAAA,UAGQ,yBAAA;EAER;EAAA,OAAA;EAKG;EAHH,OAAA;AAAA;AAAA,KAGG,iBAAA,GAAoB,qBAAA,IAAyB,qBAAA,GAAwB,yBAAA;AAAA,UAEzD,aAAA;EAFyD;;;;;EAQxE,OAAA;EARiG;;AAEnG;EAWE,GAAA,GAAM,OAAA,CAAQ,kBAAA;;;;;;;EAQd,OAAA;EA2FQ;;;;EArFR,MAAA;EA0Je;;;;;;;EAjJf,MAAA;EAQA;;;;;;EAAA,OAAA;EAsDA;;;;;;EA9CA,OAAA;EAkFE;;;;;;;;;;;;;EAnEF,MAAA,GAAS,MAAA,SAAe,WAAA;EAkHf;;;;;AAWV;;;;;;;;;;;EA3GC,QAAA,GAAW,cAAA;;;;;;;;;;;;EAaX,SAAA,GAAY,eAAA;;;;;;;;;;;;;EAcZ,KAAA,GAAQ,iBAAA;;;;;;;;;;;;;;;EAgBR,IAAA;2DAEE,QAAA;IAEA,WAAA;IAEA,kBAAA,GAAqB,MAAA;IAErB,OAAA,GAAU,MAAA;IAEV,OAAA;EAAA;;;;;;;;;;;;;EAeF,OAAA;kCAEE,MAAA;IAEA,IAAA;IAEA,OAAA;EAAA;;;;;;;;;;;;EAcF,MAAA;qBAEE,GAAA;IAEA,WAAA;IAEA,OAAA;IAEA,IAAA,GAAO,MAAA;IAEP,OAAA;EAAA;;;;;;EAQF,SAAA;AAAA;AAAA,cACD,QAAA"}
|
package/dist/nuxt/module.mjs
CHANGED
package/dist/nuxt/module.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":[],"sources":["../../package.json","../../src/nuxt/module.ts"],"sourcesContent":["","import {\n addImports,\n addPlugin,\n addServerHandler,\n addServerImports,\n addServerPlugin,\n createResolver,\n defineNuxtModule,\n} from '@nuxt/kit'\nimport type { NitroConfig } from 'nitropack'\nimport type { EnvironmentContext, RouteConfig, SamplingConfig, TransportConfig } from '../types'\nimport { name, version } from '../../package.json'\n\ninterface ModuleAxiomBaseConfig {\n /** Axiom dataset name */\n dataset: string\n /** Axiom API token */\n token: string\n /** Organization ID (required for Personal Access Tokens) */\n orgId?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n}\n\ninterface ModuleAxiomEdgeConfig {\n /**\n * Edge URL for Axiom ingest/query endpoints.\n * If no path is provided, uses /v1/ingest/{dataset}.\n * If a custom path is provided, it is used as-is (trailing slash trimmed).\n */\n edgeUrl: string\n /** Mutually exclusive with edgeUrl. */\n baseUrl?: never\n}\n\ninterface ModuleAxiomEndpointConfig {\n /** Base URL for Axiom API. Uses /v1/datasets/{dataset}/ingest. */\n baseUrl?: string\n /** Mutually exclusive with baseUrl. */\n edgeUrl?: never\n}\n\ntype ModuleAxiomConfig = ModuleAxiomBaseConfig & (ModuleAxiomEdgeConfig | ModuleAxiomEndpointConfig)\n\nexport interface ModuleOptions {\n /**\n * Enable or disable all logging globally.\n * When false, all emits, tagged logs, and request logger operations become no-ops.\n * @default true\n */\n enabled?: boolean\n\n /**\n * Environment context overrides.\n */\n env?: Partial<EnvironmentContext>\n\n /**\n * Enable or disable browser console output.\n * When false, client-side 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 /**\n * Enable pretty printing.\n * @default true in development, false in production\n */\n pretty?: boolean\n\n /**\n * Route patterns to include in logging.\n * Supports glob patterns like '/api/**'.\n * If not set, all routes are logged.\n * @example ['/api/**', '/auth/**']\n */\n include?: string[]\n\n /**\n * Route patterns to exclude from logging.\n * Supports glob patterns like '/api/_nuxt_icon/**'.\n * Exclusions take precedence over inclusions.\n * @example ['/api/_nuxt_icon/**', '/health']\n */\n exclude?: string[]\n\n /**\n * Route-specific service configuration.\n * Allows setting different service names for different routes.\n * Patterns are matched using glob syntax.\n *\n * @example\n * ```ts\n * routes: {\n * '/api/foo/**': { service: 'service1' },\n * '/api/bar/**': { service: 'service2' }\n * }\n * ```\n */\n routes?: Record<string, RouteConfig>\n\n /**\n * Sampling configuration for filtering logs.\n * Allows configuring what percentage of logs to keep per level.\n *\n * @example\n * ```ts\n * sampling: {\n * rates: {\n * info: 10, // Keep 10% of info logs\n * warn: 50, // Keep 50% of warning logs\n * debug: 5, // Keep 5% of debug logs\n * error: 100, // Always keep errors (default)\n * }\n * }\n * ```\n */\n sampling?: SamplingConfig\n\n /**\n * Transport configuration for sending client logs to the server.\n *\n * @example\n * ```ts\n * transport: {\n * enabled: true, // Send logs to server API\n * endpoint: '/api/_evlog/ingest' // Custom endpoint\n * }\n * ```\n */\n transport?: TransportConfig\n\n /**\n * Axiom adapter configuration.\n * When configured, use `createAxiomDrain()` from `evlog/axiom` to send logs.\n *\n * @example\n * ```ts\n * axiom: {\n * dataset: 'my-app-logs',\n * token: process.env.AXIOM_TOKEN,\n * }\n * ```\n */\n axiom?: ModuleAxiomConfig\n\n /**\n * OTLP adapter configuration.\n * When configured, use `createOTLPDrain()` from `evlog/otlp` to send logs.\n *\n * @example\n * ```ts\n * otlp: {\n * endpoint: 'http://localhost:4318',\n * headers: {\n * 'Authorization': `Basic ${process.env.GRAFANA_TOKEN}`,\n * },\n * }\n * ```\n */\n otlp?: {\n /** OTLP HTTP endpoint (e.g., http://localhost:4318) */\n endpoint: string\n /** Override service name (defaults to event.service) */\n serviceName?: string\n /** Additional resource attributes */\n resourceAttributes?: Record<string, string | number | boolean>\n /** Custom headers (e.g., for authentication) */\n headers?: Record<string, string>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * PostHog adapter configuration.\n * When configured, use `createPostHogDrain()` from `evlog/posthog` to send logs\n * via PostHog Logs (OTLP).\n *\n * @example\n * ```ts\n * posthog: {\n * apiKey: process.env.POSTHOG_API_KEY,\n * }\n * ```\n */\n posthog?: {\n /** PostHog project API key */\n apiKey: string\n /** PostHog host URL. Default: https://us.i.posthog.com */\n host?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * Sentry adapter configuration.\n * When configured, use `createSentryDrain()` from `evlog/sentry` to send logs.\n *\n * @example\n * ```ts\n * sentry: {\n * dsn: process.env.SENTRY_DSN,\n * }\n * ```\n */\n sentry?: {\n /** Sentry DSN */\n dsn: string\n /** Environment override (defaults to event.environment) */\n environment?: string\n /** Release version override (defaults to event.version) */\n release?: string\n /** Additional tags to attach as attributes */\n tags?: Record<string, string>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * How long to retain events before cleanup (used by @evlog/nuxthub).\n * Supports \"30d\" (days), \"24h\" (hours), \"60m\" (minutes).\n * @default '30d'\n */\n retention?: string\n}\n\nexport default defineNuxtModule<ModuleOptions>({\n meta: {\n name,\n version,\n configKey: name,\n docs: 'https://evlog.dev',\n },\n defaults: {},\n setup(options, nuxt) {\n const resolver = createResolver(import.meta.url)\n\n const transportEnabled = options.transport?.enabled ?? false\n const transportEndpoint = options.transport?.endpoint ?? '/api/_evlog/ingest'\n\n // Register custom error handler for proper EvlogError serialization\n // Only set if not already configured to avoid overwriting user's custom handler\n // @ts-expect-error nitro:config hook exists but is not in NuxtHooks type\n nuxt.hook('nitro:config', (nitroConfig: NitroConfig) => {\n nitroConfig.errorHandler = nitroConfig.errorHandler || resolver.resolve('../nitro/errorHandler')\n })\n\n nuxt.options.runtimeConfig.evlog = options\n nuxt.options.runtimeConfig.public.evlog = {\n enabled: options.enabled ?? true,\n console: options.console,\n pretty: options.pretty,\n transport: {\n enabled: transportEnabled,\n endpoint: transportEndpoint,\n },\n }\n\n if (transportEnabled) {\n addServerHandler({\n route: transportEndpoint,\n method: 'post',\n handler: resolver.resolve('../runtime/server/routes/_evlog/ingest.post'),\n })\n }\n\n addServerPlugin(resolver.resolve('../nitro/plugin'))\n\n addPlugin({\n src: resolver.resolve('../runtime/client/plugin'),\n mode: 'client',\n })\n\n addImports([\n {\n name: 'log',\n from: resolver.resolve('../runtime/client/log'),\n },\n {\n name: 'setIdentity',\n from: resolver.resolve('../runtime/client/log'),\n },\n {\n name: 'clearIdentity',\n from: resolver.resolve('../runtime/client/log'),\n },\n {\n name: 'createEvlogError',\n from: resolver.resolve('../error'),\n },\n {\n name: 'parseError',\n from: resolver.resolve('../runtime/utils/parseError'),\n },\n ])\n\n addServerImports([\n {\n name: 'useLogger',\n from: resolver.resolve('../runtime/server/useLogger'),\n },\n {\n name: 'log',\n from: resolver.resolve('../logger'),\n },\n {\n name: 'createEvlogError',\n from: resolver.resolve('../error'),\n },\n ])\n },\n})\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"module.mjs","names":[],"sources":["../../package.json","../../src/nuxt/module.ts"],"sourcesContent":["","import {\n addImports,\n addPlugin,\n addServerHandler,\n addServerImports,\n addServerPlugin,\n createResolver,\n defineNuxtModule,\n} from '@nuxt/kit'\nimport type { NitroConfig } from 'nitropack'\nimport type { EnvironmentContext, RouteConfig, SamplingConfig, TransportConfig } from '../types'\nimport { name, version } from '../../package.json'\n\ninterface ModuleAxiomBaseConfig {\n /** Axiom dataset name */\n dataset: string\n /** Axiom API token */\n token: string\n /** Organization ID (required for Personal Access Tokens) */\n orgId?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n}\n\ninterface ModuleAxiomEdgeConfig {\n /**\n * Edge URL for Axiom ingest/query endpoints.\n * If no path is provided, uses /v1/ingest/{dataset}.\n * If a custom path is provided, it is used as-is (trailing slash trimmed).\n */\n edgeUrl: string\n /** Mutually exclusive with edgeUrl. */\n baseUrl?: never\n}\n\ninterface ModuleAxiomEndpointConfig {\n /** Base URL for Axiom API. Uses /v1/datasets/{dataset}/ingest. */\n baseUrl?: string\n /** Mutually exclusive with baseUrl. */\n edgeUrl?: never\n}\n\ntype ModuleAxiomConfig = ModuleAxiomBaseConfig & (ModuleAxiomEdgeConfig | ModuleAxiomEndpointConfig)\n\nexport interface ModuleOptions {\n /**\n * Enable or disable all logging globally.\n * When false, all emits, tagged logs, and request logger operations become no-ops.\n * @default true\n */\n enabled?: boolean\n\n /**\n * Environment context overrides.\n */\n env?: Partial<EnvironmentContext>\n\n /**\n * Enable or disable browser console output.\n * When false, client-side 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 /**\n * Enable pretty printing.\n * @default true in development, false in production\n */\n pretty?: boolean\n\n /**\n * Suppress built-in console output.\n * When true, events are still built, sampled, and passed to drains,\n * but nothing is written to console. Use when drains own the output\n * channel (e.g., stdout-based platforms like GCP Cloud Run, AWS Lambda).\n * @default false\n */\n silent?: boolean\n\n /**\n * Route patterns to include in logging.\n * Supports glob patterns like '/api/**'.\n * If not set, all routes are logged.\n * @example ['/api/**', '/auth/**']\n */\n include?: string[]\n\n /**\n * Route patterns to exclude from logging.\n * Supports glob patterns like '/api/_nuxt_icon/**'.\n * Exclusions take precedence over inclusions.\n * @example ['/api/_nuxt_icon/**', '/health']\n */\n exclude?: string[]\n\n /**\n * Route-specific service configuration.\n * Allows setting different service names for different routes.\n * Patterns are matched using glob syntax.\n *\n * @example\n * ```ts\n * routes: {\n * '/api/foo/**': { service: 'service1' },\n * '/api/bar/**': { service: 'service2' }\n * }\n * ```\n */\n routes?: Record<string, RouteConfig>\n\n /**\n * Sampling configuration for filtering logs.\n * Allows configuring what percentage of logs to keep per level.\n *\n * @example\n * ```ts\n * sampling: {\n * rates: {\n * info: 10, // Keep 10% of info logs\n * warn: 50, // Keep 50% of warning logs\n * debug: 5, // Keep 5% of debug logs\n * error: 100, // Always keep errors (default)\n * }\n * }\n * ```\n */\n sampling?: SamplingConfig\n\n /**\n * Transport configuration for sending client logs to the server.\n *\n * @example\n * ```ts\n * transport: {\n * enabled: true, // Send logs to server API\n * endpoint: '/api/_evlog/ingest' // Custom endpoint\n * }\n * ```\n */\n transport?: TransportConfig\n\n /**\n * Axiom adapter configuration.\n * When configured, use `createAxiomDrain()` from `evlog/axiom` to send logs.\n *\n * @example\n * ```ts\n * axiom: {\n * dataset: 'my-app-logs',\n * token: process.env.AXIOM_TOKEN,\n * }\n * ```\n */\n axiom?: ModuleAxiomConfig\n\n /**\n * OTLP adapter configuration.\n * When configured, use `createOTLPDrain()` from `evlog/otlp` to send logs.\n *\n * @example\n * ```ts\n * otlp: {\n * endpoint: 'http://localhost:4318',\n * headers: {\n * 'Authorization': `Basic ${process.env.GRAFANA_TOKEN}`,\n * },\n * }\n * ```\n */\n otlp?: {\n /** OTLP HTTP endpoint (e.g., http://localhost:4318) */\n endpoint: string\n /** Override service name (defaults to event.service) */\n serviceName?: string\n /** Additional resource attributes */\n resourceAttributes?: Record<string, string | number | boolean>\n /** Custom headers (e.g., for authentication) */\n headers?: Record<string, string>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * PostHog adapter configuration.\n * When configured, use `createPostHogDrain()` from `evlog/posthog` to send logs\n * via PostHog Logs (OTLP).\n *\n * @example\n * ```ts\n * posthog: {\n * apiKey: process.env.POSTHOG_API_KEY,\n * }\n * ```\n */\n posthog?: {\n /** PostHog project API key */\n apiKey: string\n /** PostHog host URL. Default: https://us.i.posthog.com */\n host?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * Sentry adapter configuration.\n * When configured, use `createSentryDrain()` from `evlog/sentry` to send logs.\n *\n * @example\n * ```ts\n * sentry: {\n * dsn: process.env.SENTRY_DSN,\n * }\n * ```\n */\n sentry?: {\n /** Sentry DSN */\n dsn: string\n /** Environment override (defaults to event.environment) */\n environment?: string\n /** Release version override (defaults to event.version) */\n release?: string\n /** Additional tags to attach as attributes */\n tags?: Record<string, string>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * How long to retain events before cleanup (used by @evlog/nuxthub).\n * Supports \"30d\" (days), \"24h\" (hours), \"60m\" (minutes).\n * @default '30d'\n */\n retention?: string\n}\n\nexport default defineNuxtModule<ModuleOptions>({\n meta: {\n name,\n version,\n configKey: name,\n docs: 'https://evlog.dev',\n },\n defaults: {},\n setup(options, nuxt) {\n const resolver = createResolver(import.meta.url)\n\n const transportEnabled = options.transport?.enabled ?? false\n const transportEndpoint = options.transport?.endpoint ?? '/api/_evlog/ingest'\n\n // Register custom error handler for proper EvlogError serialization\n // Only set if not already configured to avoid overwriting user's custom handler\n // @ts-expect-error nitro:config hook exists but is not in NuxtHooks type\n nuxt.hook('nitro:config', (nitroConfig: NitroConfig) => {\n nitroConfig.errorHandler = nitroConfig.errorHandler || resolver.resolve('../nitro/errorHandler')\n })\n\n nuxt.options.runtimeConfig.evlog = options\n nuxt.options.runtimeConfig.public.evlog = {\n enabled: options.enabled ?? true,\n console: options.console,\n pretty: options.pretty,\n transport: {\n enabled: transportEnabled,\n endpoint: transportEndpoint,\n },\n }\n\n if (transportEnabled) {\n addServerHandler({\n route: transportEndpoint,\n method: 'post',\n handler: resolver.resolve('../runtime/server/routes/_evlog/ingest.post'),\n })\n }\n\n addServerPlugin(resolver.resolve('../nitro/plugin'))\n\n addPlugin({\n src: resolver.resolve('../runtime/client/plugin'),\n mode: 'client',\n })\n\n addImports([\n {\n name: 'log',\n from: resolver.resolve('../runtime/client/log'),\n },\n {\n name: 'setIdentity',\n from: resolver.resolve('../runtime/client/log'),\n },\n {\n name: 'clearIdentity',\n from: resolver.resolve('../runtime/client/log'),\n },\n {\n name: 'createEvlogError',\n from: resolver.resolve('../error'),\n },\n {\n name: 'parseError',\n from: resolver.resolve('../runtime/utils/parseError'),\n },\n ])\n\n addServerImports([\n {\n name: 'useLogger',\n from: resolver.resolve('../runtime/server/useLogger'),\n },\n {\n name: 'log',\n from: resolver.resolve('../logger'),\n },\n {\n name: 'createEvlogError',\n from: resolver.resolve('../error'),\n },\n ])\n },\n})\n"],"mappings":";;;;;AC4OA,IAAA,iBAAe,iBAAgC;CAC7C,MAAM;EACJ;EACA;EACA,WAAW;EACX,MAAM;EACP;CACD,UAAU,EAAE;CACZ,MAAM,SAAS,MAAM;EACnB,MAAM,WAAW,eAAe,OAAO,KAAK,IAAI;EAEhD,MAAM,mBAAmB,QAAQ,WAAW,WAAW;EACvD,MAAM,oBAAoB,QAAQ,WAAW,YAAY;AAKzD,OAAK,KAAK,iBAAiB,gBAA6B;AACtD,eAAY,eAAe,YAAY,gBAAgB,SAAS,QAAQ,wBAAwB;IAChG;AAEF,OAAK,QAAQ,cAAc,QAAQ;AACnC,OAAK,QAAQ,cAAc,OAAO,QAAQ;GACxC,SAAS,QAAQ,WAAW;GAC5B,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB,WAAW;IACT,SAAS;IACT,UAAU;IACX;GACF;AAED,MAAI,iBACF,kBAAiB;GACf,OAAO;GACP,QAAQ;GACR,SAAS,SAAS,QAAQ,8CAA8C;GACzE,CAAC;AAGJ,kBAAgB,SAAS,QAAQ,kBAAkB,CAAC;AAEpD,YAAU;GACR,KAAK,SAAS,QAAQ,2BAA2B;GACjD,MAAM;GACP,CAAC;AAEF,aAAW;GACT;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,wBAAwB;IAChD;GACD;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,wBAAwB;IAChD;GACD;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,wBAAwB;IAChD;GACD;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,WAAW;IACnC;GACD;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,8BAA8B;IACtD;GACF,CAAC;AAEF,mBAAiB;GACf;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,8BAA8B;IACtD;GACD;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,YAAY;IACpC;GACD;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,WAAW;IACnC;GACF,CAAC;;CAEL,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { m as ParsedError } from "./types-
|
|
1
|
+
import { m as ParsedError } from "./types-US-1hJZl.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/runtime/utils/parseError.d.ts
|
|
4
4
|
declare function parseError(error: unknown): ParsedError;
|
|
5
5
|
//#endregion
|
|
6
6
|
export { parseError as t };
|
|
7
|
-
//# sourceMappingURL=parseError-
|
|
7
|
+
//# sourceMappingURL=parseError-DYrhDD1r.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseError-DYrhDD1r.d.mts","names":[],"sources":["../src/runtime/utils/parseError.ts"],"mappings":";;;iBAKgB,UAAA,CAAW,KAAA,YAAiB,WAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as useLogger } from "../../useLogger-
|
|
1
|
+
import { t as useLogger } from "../../useLogger-DBHI03WK.mjs";
|
|
2
2
|
export { useLogger };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { m as ParsedError } from "../../types-
|
|
2
|
-
import { t as parseError } from "../../parseError-
|
|
1
|
+
import { m as ParsedError } from "../../types-US-1hJZl.mjs";
|
|
2
|
+
import { t as parseError } from "../../parseError-DYrhDD1r.mjs";
|
|
3
3
|
export { ParsedError, parseError };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-
|
|
1
|
+
{"version":3,"file":"storage-DHU1gGqV.mjs","names":[],"sources":["../src/shared/storage.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport type { RequestLogger } from '../types'\n\n/**\n * Create a request-scoped `AsyncLocalStorage` and a matching `useLogger` accessor.\n *\n * Every framework that needs `useLogger()` (Express, Fastify, NestJS, SvelteKit)\n * calls this once at module level to get its own isolated storage + accessor pair.\n *\n * @param contextHint - Human-readable hint appended to the error message when\n * `useLogger()` is called outside of a request (e.g.\n * `\"middleware context. Make sure app.use(evlog()) is registered before your routes.\"`).\n *\n * @beta Part of `evlog/toolkit` — the public API for building custom integrations.\n */\nexport function createLoggerStorage(contextHint: string) {\n const storage = new AsyncLocalStorage<RequestLogger>()\n\n /**\n * Access the request-scoped logger created by the evlog middleware.\n *\n * Must be called inside a request that is handled by the evlog middleware.\n * Throws if called outside of a request context.\n *\n * @example\n * ```ts\n * import { useLogger } from 'evlog/express' // or /fastify, /nestjs, /sveltekit, /elysia\n *\n * function myService() {\n * const log = useLogger()\n * log.set({ users: { count: 42 } })\n * }\n * ```\n */\n 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 ${contextHint}`,\n )\n }\n return logger as RequestLogger<T>\n }\n\n return { storage, useLogger }\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,SAAgB,oBAAoB,aAAqB;CACvD,MAAM,UAAU,IAAI,mBAAkC;;;;;;;;;;;;;;;;;CAkBtD,SAAS,YAA0E;EACjF,MAAM,SAAS,QAAQ,UAAU;AACjC,MAAI,CAAC,OACH,OAAM,IAAI,MACR,sDAAsD,cACvD;AAEH,SAAO;;AAGT,QAAO;EAAE;EAAS;EAAW"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { g as RequestLogger } from "../types-
|
|
2
|
-
import { t as BaseEvlogOptions } from "../middleware-
|
|
1
|
+
import { g as RequestLogger } from "../types-US-1hJZl.mjs";
|
|
2
|
+
import { t as BaseEvlogOptions } from "../middleware-CDLTVOBs.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/sveltekit/index.d.ts
|
|
5
5
|
declare const useLogger: <T extends object = Record<string, unknown>>() => RequestLogger<T>;
|
package/dist/sveltekit/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EvlogError } from "../error.mjs";
|
|
2
2
|
import { t as extractErrorStatus } from "../errors-BJRXUfMg.mjs";
|
|
3
3
|
import { n as serializeEvlogErrorResponse, t as resolveEvlogError } from "../nitro-D1pPm37T.mjs";
|
|
4
|
-
import { r as createMiddlewareLogger, t as extractSafeHeaders } from "../headers-
|
|
5
|
-
import { t as createLoggerStorage } from "../storage-
|
|
4
|
+
import { r as createMiddlewareLogger, t as extractSafeHeaders } from "../headers-BSgpnR0c.mjs";
|
|
5
|
+
import { t as createLoggerStorage } from "../storage-DHU1gGqV.mjs";
|
|
6
6
|
//#region src/sveltekit/index.ts
|
|
7
7
|
const { storage, useLogger } = createLoggerStorage("handle context. Make sure evlog() handle is added to your hooks.server.ts.");
|
|
8
8
|
/**
|
package/dist/toolkit.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { g as RequestLogger } from "./types-
|
|
2
|
-
import { i as createMiddlewareLogger, n as MiddlewareLoggerOptions, r as MiddlewareLoggerResult, t as BaseEvlogOptions } from "./middleware-
|
|
3
|
-
import { n as getServiceForPath, r as shouldLog, t as extractErrorStatus } from "./errors-
|
|
1
|
+
import { g as RequestLogger } from "./types-US-1hJZl.mjs";
|
|
2
|
+
import { i as createMiddlewareLogger, n as MiddlewareLoggerOptions, r as MiddlewareLoggerResult, t as BaseEvlogOptions } from "./middleware-CDLTVOBs.mjs";
|
|
3
|
+
import { n as getServiceForPath, r as shouldLog, t as extractErrorStatus } from "./errors-nScQVwHW.mjs";
|
|
4
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
5
|
|
|
6
6
|
//#region src/shared/headers.d.ts
|
package/dist/toolkit.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as extractErrorStatus } from "./errors-BJRXUfMg.mjs";
|
|
2
2
|
import { n as shouldLog, t as getServiceForPath } from "./routes-CE3_c-iZ.mjs";
|
|
3
|
-
import { n as extractSafeNodeHeaders, r as createMiddlewareLogger, t as extractSafeHeaders } from "./headers-
|
|
4
|
-
import { t as createLoggerStorage } from "./storage-
|
|
3
|
+
import { n as extractSafeNodeHeaders, r as createMiddlewareLogger, t as extractSafeHeaders } from "./headers-BSgpnR0c.mjs";
|
|
4
|
+
import { t as createLoggerStorage } from "./storage-DHU1gGqV.mjs";
|
|
5
5
|
export { createLoggerStorage, createMiddlewareLogger, extractErrorStatus, extractSafeHeaders, extractSafeNodeHeaders, getServiceForPath, shouldLog };
|
|
@@ -245,6 +245,14 @@ interface LoggerConfig {
|
|
|
245
245
|
* @default true
|
|
246
246
|
*/
|
|
247
247
|
stringify?: boolean;
|
|
248
|
+
/**
|
|
249
|
+
* Suppress built-in console output.
|
|
250
|
+
* When true, events are still built, sampled, and passed to drains,
|
|
251
|
+
* but nothing is written to console. Use when drains own the output
|
|
252
|
+
* channel (e.g., stdout-based platforms like GCP Cloud Run, AWS Lambda).
|
|
253
|
+
* @default false
|
|
254
|
+
*/
|
|
255
|
+
silent?: boolean;
|
|
248
256
|
/**
|
|
249
257
|
* Drain callback called with every emitted event (fire-and-forget).
|
|
250
258
|
* Use this to send logs to external services outside of Nitro.
|
|
@@ -277,6 +285,8 @@ interface LoggerConfig {
|
|
|
277
285
|
* ```
|
|
278
286
|
*/
|
|
279
287
|
drain?: (ctx: DrainContext) => void | Promise<void>;
|
|
288
|
+
/** @internal Suppress the "silent without drain" warning (used by hook-based frameworks like Nitro/Nuxt) */
|
|
289
|
+
_suppressDrainWarning?: boolean;
|
|
280
290
|
}
|
|
281
291
|
/**
|
|
282
292
|
* Base structure for all wide events
|
|
@@ -493,4 +503,4 @@ interface ParsedError {
|
|
|
493
503
|
}
|
|
494
504
|
//#endregion
|
|
495
505
|
export { TailSamplingContext as C, TailSamplingCondition as S, WideEvent as T, RequestLoggerOptions as _, EnvironmentContext as a, SamplingRates as b, H3EventContext as c, Log as d, LogLevel as f, RequestLogger as g, RequestLogEntry as h, EnrichContext as i, IngestPayload as l, ParsedError as m, DeepPartial as n, ErrorOptions as o, LoggerConfig as p, DrainContext as r, FieldContext as s, BaseWideEvent as t, InternalFields as u, RouteConfig as v, TransportConfig as w, ServerEvent as x, SamplingConfig as y };
|
|
496
|
-
//# sourceMappingURL=types-
|
|
506
|
+
//# sourceMappingURL=types-US-1hJZl.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-US-1hJZl.d.mts","names":[],"sources":["../src/types.ts"],"mappings":"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"}
|
package/dist/types.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as TailSamplingContext, S as TailSamplingCondition, T as WideEvent, _ as RequestLoggerOptions, a as EnvironmentContext, b as SamplingRates, c as H3EventContext, d as Log, f as LogLevel, g as RequestLogger, h as RequestLogEntry, i as EnrichContext, l as IngestPayload, m as ParsedError, n as DeepPartial, o as ErrorOptions, p as LoggerConfig, r as DrainContext, s as FieldContext, t as BaseWideEvent, u as InternalFields, v as RouteConfig, w as TransportConfig, x as ServerEvent, y as SamplingConfig } from "./types-
|
|
1
|
+
import { C as TailSamplingContext, S as TailSamplingCondition, T as WideEvent, _ as RequestLoggerOptions, a as EnvironmentContext, b as SamplingRates, c as H3EventContext, d as Log, f as LogLevel, g as RequestLogger, h as RequestLogEntry, i as EnrichContext, l as IngestPayload, m as ParsedError, n as DeepPartial, o as ErrorOptions, p as LoggerConfig, r as DrainContext, s as FieldContext, t as BaseWideEvent, u as InternalFields, v as RouteConfig, w as TransportConfig, x as ServerEvent, y as SamplingConfig } from "./types-US-1hJZl.mjs";
|
|
2
2
|
export { BaseWideEvent, DeepPartial, DrainContext, EnrichContext, EnvironmentContext, ErrorOptions, FieldContext, H3EventContext, IngestPayload, InternalFields, Log, LogLevel, LoggerConfig, ParsedError, RequestLogEntry, RequestLogger, RequestLoggerOptions, RouteConfig, SamplingConfig, SamplingRates, ServerEvent, TailSamplingCondition, TailSamplingContext, TransportConfig, WideEvent };
|