evlog 2.4.0 → 2.5.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/dist/{_http-DVDwNag0.mjs → _http-DHpGetLZ.mjs} +2 -6
- package/dist/{_http-DVDwNag0.mjs.map → _http-DHpGetLZ.mjs.map} +1 -1
- package/dist/{_severity-78FkT5MD.mjs → _severity-CLNgC2HU.mjs} +2 -2
- package/dist/{_severity-78FkT5MD.mjs.map → _severity-CLNgC2HU.mjs.map} +1 -1
- package/dist/adapters/axiom.d.mts +1 -1
- package/dist/adapters/axiom.d.mts.map +1 -1
- package/dist/adapters/axiom.mjs +2 -3
- package/dist/adapters/axiom.mjs.map +1 -1
- package/dist/adapters/better-stack.d.mts +1 -1
- package/dist/adapters/better-stack.d.mts.map +1 -1
- package/dist/adapters/better-stack.mjs +2 -3
- package/dist/adapters/better-stack.mjs.map +1 -1
- package/dist/adapters/otlp.d.mts +1 -1
- package/dist/adapters/otlp.d.mts.map +1 -1
- package/dist/adapters/otlp.mjs +14 -11
- package/dist/adapters/otlp.mjs.map +1 -1
- package/dist/adapters/posthog.d.mts +1 -1
- package/dist/adapters/posthog.d.mts.map +1 -1
- package/dist/adapters/posthog.mjs +2 -3
- package/dist/adapters/posthog.mjs.map +1 -1
- package/dist/adapters/sentry.d.mts +1 -1
- package/dist/adapters/sentry.d.mts.map +1 -1
- package/dist/adapters/sentry.mjs +3 -4
- package/dist/adapters/sentry.mjs.map +1 -1
- package/dist/browser.d.mts +1 -1
- package/dist/browser.mjs +1 -2
- package/dist/browser.mjs.map +1 -1
- package/dist/{dist-By0jiJRA.mjs → dist-Dalk68oO.mjs} +3 -4
- package/dist/{dist-By0jiJRA.mjs.map → dist-Dalk68oO.mjs.map} +1 -1
- package/dist/elysia/index.d.mts +2 -2
- package/dist/elysia/index.mjs +2 -3
- package/dist/elysia/index.mjs.map +1 -1
- package/dist/enrichers.d.mts +1 -1
- package/dist/enrichers.mjs +1 -1
- package/dist/enrichers.mjs.map +1 -1
- package/dist/error-Bu4fv0NO.d.mts +65 -0
- package/dist/error-Bu4fv0NO.d.mts.map +1 -0
- package/dist/error.d.mts +2 -65
- package/dist/error.mjs +1 -2
- package/dist/error.mjs.map +1 -1
- package/dist/express/index.d.mts +2 -2
- package/dist/express/index.mjs +3 -4
- package/dist/express/index.mjs.map +1 -1
- package/dist/fastify/index.d.mts +2 -2
- package/dist/fastify/index.d.mts.map +1 -1
- package/dist/fastify/index.mjs +3 -4
- package/dist/fastify/index.mjs.map +1 -1
- package/dist/{headers-CXOd5EyZ.mjs → headers-C95MOQ4w.mjs} +4 -6
- package/dist/{headers-CXOd5EyZ.mjs.map → headers-C95MOQ4w.mjs.map} +1 -1
- package/dist/hono/index.d.mts +2 -2
- package/dist/hono/index.mjs +2 -3
- package/dist/hono/index.mjs.map +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +1 -2
- package/dist/logger-BNxG5Kyd.d.mts +59 -0
- package/dist/logger-BNxG5Kyd.d.mts.map +1 -0
- package/dist/logger.d.mts +2 -59
- package/dist/logger.mjs +1 -2
- package/dist/logger.mjs.map +1 -1
- package/dist/{middleware-BoVCgsfQ.d.mts → middleware-gCuB0w7F.d.mts} +2 -2
- package/dist/{middleware-BoVCgsfQ.d.mts.map → middleware-gCuB0w7F.d.mts.map} +1 -1
- package/dist/nestjs/index.d.mts +2 -2
- package/dist/nestjs/index.mjs +3 -4
- package/dist/nestjs/index.mjs.map +1 -1
- package/dist/next/client.d.mts +1 -1
- package/dist/next/client.mjs +2 -4
- package/dist/next/client.mjs.map +1 -1
- package/dist/next/index.d.mts +4 -4
- package/dist/next/index.d.mts.map +1 -1
- package/dist/next/index.mjs +2 -6
- package/dist/next/index.mjs.map +1 -1
- package/dist/nitro/errorHandler.mjs +2 -3
- package/dist/nitro/errorHandler.mjs.map +1 -1
- package/dist/nitro/module.d.mts +2 -2
- package/dist/nitro/module.mjs +1 -2
- package/dist/nitro/module.mjs.map +1 -1
- package/dist/nitro/plugin.mjs +3 -4
- package/dist/nitro/plugin.mjs.map +1 -1
- package/dist/nitro/v3/errorHandler.mjs +3 -4
- package/dist/nitro/v3/errorHandler.mjs.map +1 -1
- package/dist/nitro/v3/index.mjs +1 -2
- package/dist/nitro/v3/middleware.mjs +1 -2
- package/dist/nitro/v3/middleware.mjs.map +1 -1
- package/dist/nitro/v3/module.d.mts +1 -1
- package/dist/nitro/v3/module.mjs +1 -2
- package/dist/nitro/v3/module.mjs.map +1 -1
- package/dist/nitro/v3/plugin.mjs +4 -5
- package/dist/nitro/v3/plugin.mjs.map +1 -1
- package/dist/nitro/v3/useLogger.d.mts +1 -1
- package/dist/nitro/v3/useLogger.mjs +1 -1
- package/dist/nitro/v3/useLogger.mjs.map +1 -1
- package/dist/{nitro-Da8tEfJ3.mjs → nitro-B3vZrLGI.mjs} +2 -2
- package/dist/{nitro-Da8tEfJ3.mjs.map → nitro-B3vZrLGI.mjs.map} +1 -1
- package/dist/{nitro-BRisWfGy.d.mts → nitro-wZ05H2wx.d.mts} +2 -2
- package/dist/{nitro-BRisWfGy.d.mts.map → nitro-wZ05H2wx.d.mts.map} +1 -1
- package/dist/nuxt/module.d.mts +1 -1
- package/dist/nuxt/module.mjs +2 -5
- package/dist/nuxt/module.mjs.map +1 -1
- package/dist/parseError-BeVEVQBh.d.mts +7 -0
- package/dist/parseError-BeVEVQBh.d.mts.map +1 -0
- package/dist/pipeline.mjs +1 -1
- package/dist/{routes-BNbrnm14.mjs → routes-DdmLpEnG.mjs} +2 -3
- package/dist/{routes-BNbrnm14.mjs.map → routes-DdmLpEnG.mjs.map} +1 -1
- package/dist/runtime/client/log.d.mts +1 -1
- package/dist/runtime/client/log.mjs +1 -2
- package/dist/runtime/client/log.mjs.map +1 -1
- package/dist/runtime/client/plugin.mjs +1 -2
- package/dist/runtime/client/plugin.mjs.map +1 -1
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs +1 -2
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs.map +1 -1
- package/dist/runtime/server/useLogger.d.mts +2 -39
- package/dist/runtime/server/useLogger.mjs +1 -1
- package/dist/runtime/server/useLogger.mjs.map +1 -1
- package/dist/runtime/utils/parseError.d.mts +3 -7
- package/dist/runtime/utils/parseError.mjs +1 -1
- package/dist/{storage-Dd3PHiMh.mjs → storage-CRSAAEiG.mjs} +18 -3
- package/dist/storage-CRSAAEiG.mjs.map +1 -0
- package/dist/sveltekit/index.d.mts +2 -2
- package/dist/sveltekit/index.mjs +4 -5
- package/dist/sveltekit/index.mjs.map +1 -1
- package/dist/types-CRj5tGVA.d.mts +496 -0
- package/dist/types-CRj5tGVA.d.mts.map +1 -0
- package/dist/types.d.mts +2 -496
- package/dist/types.mjs +1 -1
- package/dist/useLogger-w7MZjqW_.d.mts +39 -0
- package/dist/useLogger-w7MZjqW_.d.mts.map +1 -0
- package/dist/utils.d.mts +1 -1
- package/dist/utils.mjs +1 -1
- package/dist/workers.d.mts +1 -1
- package/dist/workers.mjs +1 -2
- package/dist/workers.mjs.map +1 -1
- package/package.json +55 -34
- package/dist/error.d.mts.map +0 -1
- package/dist/logger.d.mts.map +0 -1
- package/dist/runtime/server/useLogger.d.mts.map +0 -1
- package/dist/runtime/utils/parseError.d.mts.map +0 -1
- package/dist/storage-Dd3PHiMh.mjs.map +0 -1
- package/dist/types.d.mts.map +0 -1
|
@@ -2,7 +2,6 @@ import { filterSafeHeaders } from "../../../../utils.mjs";
|
|
|
2
2
|
import { getEnvironment } from "../../../../logger.mjs";
|
|
3
3
|
import { createError, defineEventHandler, getHeader, getHeaders, getRequestHost, readBody, setResponseStatus } from "h3";
|
|
4
4
|
import { useNitroApp } from "nitropack/runtime";
|
|
5
|
-
|
|
6
5
|
//#region src/runtime/server/routes/_evlog/ingest.post.ts
|
|
7
6
|
const VALID_LEVELS = [
|
|
8
7
|
"info",
|
|
@@ -117,7 +116,7 @@ var ingest_post_default = defineEventHandler(async (event) => {
|
|
|
117
116
|
setResponseStatus(event, 204);
|
|
118
117
|
return null;
|
|
119
118
|
});
|
|
120
|
-
|
|
121
119
|
//#endregion
|
|
122
120
|
export { ingest_post_default as default };
|
|
121
|
+
|
|
123
122
|
//# sourceMappingURL=ingest.post.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingest.post.mjs","names":[],"sources":["../../../../../src/runtime/server/routes/_evlog/ingest.post.ts"],"sourcesContent":["import { createError, defineEventHandler, getHeader, getHeaders, getRequestHost, readBody, setResponseStatus } from 'h3'\nimport { useNitroApp } from 'nitropack/runtime'\nimport type { IngestPayload, WideEvent } from '../../../../types'\nimport { getEnvironment } from '../../../../logger'\nimport { filterSafeHeaders } from '../../../../utils'\n\nconst VALID_LEVELS = ['info', 'error', 'warn', 'debug'] as const\n\nfunction validateOrigin(event: Parameters<typeof defineEventHandler>[0] extends (e: infer E) => unknown ? E : never): void {\n const origin = getHeader(event, 'origin')\n const referer = getHeader(event, 'referer')\n const host = getRequestHost(event)\n\n const requestOrigin = origin || (referer ? new URL(referer).origin : null)\n\n if (!requestOrigin) {\n throw createError({ statusCode: 403, message: 'Missing origin header' })\n }\n\n const originHost = new URL(requestOrigin).host\n\n if (originHost !== host) {\n throw createError({ statusCode: 403, message: 'Invalid origin' })\n }\n}\n\n// ISO 8601 datetime pattern (e.g., 2024-01-31T14:00:00.000Z)\nconst ISO_8601_REGEX = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$/\n\nfunction isValidISOTimestamp(value: string): boolean {\n if (!ISO_8601_REGEX.test(value)) return false\n const date = new Date(value)\n return !Number.isNaN(date.getTime())\n}\n\nfunction validatePayload(body: unknown): IngestPayload {\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n throw createError({ statusCode: 400, message: 'Invalid request body' })\n }\n\n const payload = body as Record<string, unknown>\n\n if (payload.timestamp === undefined || payload.timestamp === null) {\n throw createError({ statusCode: 400, message: 'Missing required field: timestamp' })\n }\n\n const { timestamp: rawTimestamp } = payload\n let timestamp: string\n if (typeof rawTimestamp === 'number') {\n const minTimestamp = new Date('2000-01-01').getTime()\n const maxTimestamp = Date.now() + 24 * 60 * 60 * 1000 // 1 day in the future\n if (rawTimestamp < minTimestamp || rawTimestamp > maxTimestamp) {\n throw createError({ statusCode: 400, message: 'Invalid timestamp: value out of reasonable range' })\n }\n timestamp = new Date(rawTimestamp).toISOString()\n } else if (typeof rawTimestamp === 'string') {\n if (!isValidISOTimestamp(rawTimestamp)) {\n throw createError({ statusCode: 400, message: 'Invalid timestamp: must be a valid ISO 8601 datetime string' })\n }\n timestamp = rawTimestamp\n } else {\n throw createError({ statusCode: 400, message: 'Invalid timestamp: must be string or number' })\n }\n\n if (!payload.level || typeof payload.level !== 'string') {\n throw createError({ statusCode: 400, message: 'Missing required field: level' })\n }\n\n if (!VALID_LEVELS.includes(payload.level as typeof VALID_LEVELS[number])) {\n throw createError({ statusCode: 400, message: `Invalid level: must be one of ${VALID_LEVELS.join(', ')}` })\n }\n\n return {\n ...payload,\n timestamp,\n level: payload.level as IngestPayload['level'],\n }\n}\n\nfunction getSafeHeaders(event: Parameters<typeof defineEventHandler>[0] extends (e: infer E) => unknown ? E : never): Record<string, string> {\n const allHeaders = getHeaders(event as Parameters<typeof getHeaders>[0])\n return filterSafeHeaders(allHeaders)\n}\n\nexport default defineEventHandler(async (event) => {\n validateOrigin(event)\n\n const body = await readBody(event)\n const payload = validatePayload(body)\n const nitroApp = useNitroApp()\n const env = getEnvironment()\n\n const { service: _clientService, ...sanitizedPayload } = payload as IngestPayload & { service?: unknown }\n\n const wideEvent: WideEvent = {\n ...sanitizedPayload,\n ...env,\n source: 'client',\n }\n\n const headers = getSafeHeaders(event)\n const request = { method: 'POST' as const, path: event.path }\n\n try {\n await nitroApp.hooks.callHook('evlog:enrich', {\n event: wideEvent,\n request,\n headers,\n response: { status: 204 },\n })\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n\n const drainPromise = nitroApp.hooks.callHook('evlog:drain', {\n event: wideEvent,\n request,\n headers,\n }).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n\n // Use waitUntil if available (Cloudflare Workers, Vercel Edge)\n // Otherwise, await the drain to prevent lost logs in serverless environments\n const waitUntilCtx = (event as unknown as { context: Record<string, unknown> }).context\n const cfCtx = (waitUntilCtx as { cloudflare?: { context?: { waitUntil?: (p: Promise<unknown>) => void } } }).cloudflare?.context ?? waitUntilCtx\n if (typeof (cfCtx as { waitUntil?: unknown }).waitUntil === 'function') {\n (cfCtx as { waitUntil: (p: Promise<unknown>) => void }).waitUntil(drainPromise)\n } else {\n await drainPromise\n }\n\n setResponseStatus(event, 204)\n return null\n})\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ingest.post.mjs","names":[],"sources":["../../../../../src/runtime/server/routes/_evlog/ingest.post.ts"],"sourcesContent":["import { createError, defineEventHandler, getHeader, getHeaders, getRequestHost, readBody, setResponseStatus } from 'h3'\nimport { useNitroApp } from 'nitropack/runtime'\nimport type { IngestPayload, WideEvent } from '../../../../types'\nimport { getEnvironment } from '../../../../logger'\nimport { filterSafeHeaders } from '../../../../utils'\n\nconst VALID_LEVELS = ['info', 'error', 'warn', 'debug'] as const\n\nfunction validateOrigin(event: Parameters<typeof defineEventHandler>[0] extends (e: infer E) => unknown ? E : never): void {\n const origin = getHeader(event, 'origin')\n const referer = getHeader(event, 'referer')\n const host = getRequestHost(event)\n\n const requestOrigin = origin || (referer ? new URL(referer).origin : null)\n\n if (!requestOrigin) {\n throw createError({ statusCode: 403, message: 'Missing origin header' })\n }\n\n const originHost = new URL(requestOrigin).host\n\n if (originHost !== host) {\n throw createError({ statusCode: 403, message: 'Invalid origin' })\n }\n}\n\n// ISO 8601 datetime pattern (e.g., 2024-01-31T14:00:00.000Z)\nconst ISO_8601_REGEX = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$/\n\nfunction isValidISOTimestamp(value: string): boolean {\n if (!ISO_8601_REGEX.test(value)) return false\n const date = new Date(value)\n return !Number.isNaN(date.getTime())\n}\n\nfunction validatePayload(body: unknown): IngestPayload {\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n throw createError({ statusCode: 400, message: 'Invalid request body' })\n }\n\n const payload = body as Record<string, unknown>\n\n if (payload.timestamp === undefined || payload.timestamp === null) {\n throw createError({ statusCode: 400, message: 'Missing required field: timestamp' })\n }\n\n const { timestamp: rawTimestamp } = payload\n let timestamp: string\n if (typeof rawTimestamp === 'number') {\n const minTimestamp = new Date('2000-01-01').getTime()\n const maxTimestamp = Date.now() + 24 * 60 * 60 * 1000 // 1 day in the future\n if (rawTimestamp < minTimestamp || rawTimestamp > maxTimestamp) {\n throw createError({ statusCode: 400, message: 'Invalid timestamp: value out of reasonable range' })\n }\n timestamp = new Date(rawTimestamp).toISOString()\n } else if (typeof rawTimestamp === 'string') {\n if (!isValidISOTimestamp(rawTimestamp)) {\n throw createError({ statusCode: 400, message: 'Invalid timestamp: must be a valid ISO 8601 datetime string' })\n }\n timestamp = rawTimestamp\n } else {\n throw createError({ statusCode: 400, message: 'Invalid timestamp: must be string or number' })\n }\n\n if (!payload.level || typeof payload.level !== 'string') {\n throw createError({ statusCode: 400, message: 'Missing required field: level' })\n }\n\n if (!VALID_LEVELS.includes(payload.level as typeof VALID_LEVELS[number])) {\n throw createError({ statusCode: 400, message: `Invalid level: must be one of ${VALID_LEVELS.join(', ')}` })\n }\n\n return {\n ...payload,\n timestamp,\n level: payload.level as IngestPayload['level'],\n }\n}\n\nfunction getSafeHeaders(event: Parameters<typeof defineEventHandler>[0] extends (e: infer E) => unknown ? E : never): Record<string, string> {\n const allHeaders = getHeaders(event as Parameters<typeof getHeaders>[0])\n return filterSafeHeaders(allHeaders)\n}\n\nexport default defineEventHandler(async (event) => {\n validateOrigin(event)\n\n const body = await readBody(event)\n const payload = validatePayload(body)\n const nitroApp = useNitroApp()\n const env = getEnvironment()\n\n const { service: _clientService, ...sanitizedPayload } = payload as IngestPayload & { service?: unknown }\n\n const wideEvent: WideEvent = {\n ...sanitizedPayload,\n ...env,\n source: 'client',\n }\n\n const headers = getSafeHeaders(event)\n const request = { method: 'POST' as const, path: event.path }\n\n try {\n await nitroApp.hooks.callHook('evlog:enrich', {\n event: wideEvent,\n request,\n headers,\n response: { status: 204 },\n })\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n\n const drainPromise = nitroApp.hooks.callHook('evlog:drain', {\n event: wideEvent,\n request,\n headers,\n }).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n\n // Use waitUntil if available (Cloudflare Workers, Vercel Edge)\n // Otherwise, await the drain to prevent lost logs in serverless environments\n const waitUntilCtx = (event as unknown as { context: Record<string, unknown> }).context\n const cfCtx = (waitUntilCtx as { cloudflare?: { context?: { waitUntil?: (p: Promise<unknown>) => void } } }).cloudflare?.context ?? waitUntilCtx\n if (typeof (cfCtx as { waitUntil?: unknown }).waitUntil === 'function') {\n (cfCtx as { waitUntil: (p: Promise<unknown>) => void }).waitUntil(drainPromise)\n } else {\n await drainPromise\n }\n\n setResponseStatus(event, 204)\n return null\n})\n"],"mappings":"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"}
|
|
@@ -1,39 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
//#region src/runtime/server/useLogger.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Returns the request logger attached to the given server event.
|
|
6
|
-
*
|
|
7
|
-
* @param event - The current server event containing the context with the logger.
|
|
8
|
-
* @param service - Optional service name to override the default service.
|
|
9
|
-
* @returns The request-scoped logger.
|
|
10
|
-
* @throws Error if the logger is not initialized on the event context.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* export default defineEventHandler((event) => {
|
|
14
|
-
* const log = useLogger(event)
|
|
15
|
-
* log.set({ foo: 'bar' })
|
|
16
|
-
* // ...
|
|
17
|
-
* })
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* // Override service name for specific routes
|
|
21
|
-
* export default defineEventHandler((event) => {
|
|
22
|
-
* const log = useLogger(event, 'payment-service')
|
|
23
|
-
* log.set({ foo: 'bar' })
|
|
24
|
-
* // ...
|
|
25
|
-
* })
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* // Typed fields — must use explicit import for type checking to work
|
|
29
|
-
* import { useLogger } from 'evlog'
|
|
30
|
-
*
|
|
31
|
-
* interface MyFields { user: { id: string; plan: string } }
|
|
32
|
-
* const log = useLogger<MyFields>(event)
|
|
33
|
-
* log.set({ user: { id: '123', plan: 'pro' } }) // OK
|
|
34
|
-
* log.set({ foo: 'bar' }) // TS error
|
|
35
|
-
*/
|
|
36
|
-
declare function useLogger<T extends object = Record<string, unknown>>(event: ServerEvent, service?: string): RequestLogger<T>;
|
|
37
|
-
//#endregion
|
|
38
|
-
export { useLogger };
|
|
39
|
-
//# sourceMappingURL=useLogger.d.mts.map
|
|
1
|
+
import { t as useLogger } from "../../useLogger-w7MZjqW_.mjs";
|
|
2
|
+
export { useLogger };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLogger.mjs","names":[],"sources":["../../../src/runtime/server/useLogger.ts"],"sourcesContent":["import type { RequestLogger, ServerEvent } from '../../types'\n\n/**\n * Returns the request logger attached to the given server event.\n *\n * @param event - The current server event containing the context with the logger.\n * @param service - Optional service name to override the default service.\n * @returns The request-scoped logger.\n * @throws Error if the logger is not initialized on the event context.\n *\n * @example\n * export default defineEventHandler((event) => {\n * const log = useLogger(event)\n * log.set({ foo: 'bar' })\n * // ...\n * })\n *\n * @example\n * // Override service name for specific routes\n * export default defineEventHandler((event) => {\n * const log = useLogger(event, 'payment-service')\n * log.set({ foo: 'bar' })\n * // ...\n * })\n *\n * @example\n * // Typed fields — must use explicit import for type checking to work\n * import { useLogger } from 'evlog'\n *\n * interface MyFields { user: { id: string; plan: string } }\n * const log = useLogger<MyFields>(event)\n * log.set({ user: { id: '123', plan: 'pro' } }) // OK\n * log.set({ foo: 'bar' }) // TS error\n */\nexport function useLogger<T extends object = Record<string, unknown>>(event: ServerEvent, service?: string): RequestLogger<T> {\n const log = event.context.log as RequestLogger<T> | undefined\n\n if (!log) {\n throw new Error(\n '[evlog] Logger not initialized. Make sure the evlog Nitro plugin is registered. '\n + 'If using Nuxt, add \"evlog\" to your modules.',\n )\n }\n\n if (service) {\n const untyped = log as unknown as RequestLogger\n untyped.set({ service })\n }\n\n return log\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,SAAgB,UAAsD,OAAoB,SAAoC;CAC5H,MAAM,MAAM,MAAM,QAAQ;AAE1B,KAAI,CAAC,IACH,OAAM,IAAI,MACR,gIAED;AAGH,KAAI,
|
|
1
|
+
{"version":3,"file":"useLogger.mjs","names":[],"sources":["../../../src/runtime/server/useLogger.ts"],"sourcesContent":["import type { RequestLogger, ServerEvent } from '../../types'\n\n/**\n * Returns the request logger attached to the given server event.\n *\n * @param event - The current server event containing the context with the logger.\n * @param service - Optional service name to override the default service.\n * @returns The request-scoped logger.\n * @throws Error if the logger is not initialized on the event context.\n *\n * @example\n * export default defineEventHandler((event) => {\n * const log = useLogger(event)\n * log.set({ foo: 'bar' })\n * // ...\n * })\n *\n * @example\n * // Override service name for specific routes\n * export default defineEventHandler((event) => {\n * const log = useLogger(event, 'payment-service')\n * log.set({ foo: 'bar' })\n * // ...\n * })\n *\n * @example\n * // Typed fields — must use explicit import for type checking to work\n * import { useLogger } from 'evlog'\n *\n * interface MyFields { user: { id: string; plan: string } }\n * const log = useLogger<MyFields>(event)\n * log.set({ user: { id: '123', plan: 'pro' } }) // OK\n * log.set({ foo: 'bar' }) // TS error\n */\nexport function useLogger<T extends object = Record<string, unknown>>(event: ServerEvent, service?: string): RequestLogger<T> {\n const log = event.context.log as RequestLogger<T> | undefined\n\n if (!log) {\n throw new Error(\n '[evlog] Logger not initialized. Make sure the evlog Nitro plugin is registered. '\n + 'If using Nuxt, add \"evlog\" to your modules.',\n )\n }\n\n if (service) {\n const untyped = log as unknown as RequestLogger\n untyped.set({ service })\n }\n\n return log\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,SAAgB,UAAsD,OAAoB,SAAoC;CAC5H,MAAM,MAAM,MAAM,QAAQ;AAE1B,KAAI,CAAC,IACH,OAAM,IAAI,MACR,gIAED;AAGH,KAAI,QACc,KACR,IAAI,EAAE,SAAS,CAAC;AAG1B,QAAO"}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import { ParsedError } from "../../types.mjs";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
declare function parseError(error: unknown): ParsedError;
|
|
5
|
-
//#endregion
|
|
6
|
-
export { type ParsedError, parseError };
|
|
7
|
-
//# sourceMappingURL=parseError.d.mts.map
|
|
1
|
+
import { m as ParsedError } from "../../types-CRj5tGVA.mjs";
|
|
2
|
+
import { t as parseError } from "../../parseError-BeVEVQBh.mjs";
|
|
3
|
+
export { ParsedError, parseError };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
-
|
|
3
2
|
//#region src/shared/storage.ts
|
|
4
3
|
/**
|
|
5
4
|
* Create a request-scoped `AsyncLocalStorage` and a matching `useLogger` accessor.
|
|
@@ -13,6 +12,22 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
13
12
|
*/
|
|
14
13
|
function createLoggerStorage(contextHint) {
|
|
15
14
|
const storage = new AsyncLocalStorage();
|
|
15
|
+
/**
|
|
16
|
+
* Access the request-scoped logger created by the evlog middleware.
|
|
17
|
+
*
|
|
18
|
+
* Must be called inside a request that is handled by the evlog middleware.
|
|
19
|
+
* Throws if called outside of a request context.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { useLogger } from 'evlog/express' // or /fastify, /nestjs, /sveltekit, /elysia
|
|
24
|
+
*
|
|
25
|
+
* function myService() {
|
|
26
|
+
* const log = useLogger()
|
|
27
|
+
* log.set({ users: { count: 42 } })
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
16
31
|
function useLogger() {
|
|
17
32
|
const logger = storage.getStore();
|
|
18
33
|
if (!logger) throw new Error(`[evlog] useLogger() was called outside of an evlog ${contextHint}`);
|
|
@@ -23,7 +38,7 @@ function createLoggerStorage(contextHint) {
|
|
|
23
38
|
useLogger
|
|
24
39
|
};
|
|
25
40
|
}
|
|
26
|
-
|
|
27
41
|
//#endregion
|
|
28
42
|
export { createLoggerStorage as t };
|
|
29
|
-
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=storage-CRSAAEiG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-CRSAAEiG.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 */\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":";;;;;;;;;;;;AAaA,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 { RequestLogger } from "../types.mjs";
|
|
2
|
-
import { t as BaseEvlogOptions } from "../middleware-
|
|
1
|
+
import { g as RequestLogger } from "../types-CRj5tGVA.mjs";
|
|
2
|
+
import { t as BaseEvlogOptions } from "../middleware-gCuB0w7F.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,7 @@
|
|
|
1
1
|
import { EvlogError } from "../error.mjs";
|
|
2
|
-
import { n as resolveEvlogError, r as serializeEvlogErrorResponse, t as extractErrorStatus } from "../nitro-
|
|
3
|
-
import { r as createMiddlewareLogger, t as extractSafeHeaders } from "../headers-
|
|
4
|
-
import { t as createLoggerStorage } from "../storage-
|
|
5
|
-
|
|
2
|
+
import { n as resolveEvlogError, r as serializeEvlogErrorResponse, t as extractErrorStatus } from "../nitro-B3vZrLGI.mjs";
|
|
3
|
+
import { r as createMiddlewareLogger, t as extractSafeHeaders } from "../headers-C95MOQ4w.mjs";
|
|
4
|
+
import { t as createLoggerStorage } from "../storage-CRSAAEiG.mjs";
|
|
6
5
|
//#region src/sveltekit/index.ts
|
|
7
6
|
const { storage, useLogger } = createLoggerStorage("handle context. Make sure evlog() handle is added to your hooks.server.ts.");
|
|
8
7
|
/**
|
|
@@ -157,7 +156,7 @@ function createEvlogHooks(options = {}) {
|
|
|
157
156
|
handleError: evlogHandleError()
|
|
158
157
|
};
|
|
159
158
|
}
|
|
160
|
-
|
|
161
159
|
//#endregion
|
|
162
160
|
export { createEvlogHooks, evlog, evlogHandleError, useLogger };
|
|
161
|
+
|
|
163
162
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/sveltekit/index.ts"],"sourcesContent":["import type { RequestLogger } from '../types'\nimport { createMiddlewareLogger, type BaseEvlogOptions } from '../shared/middleware'\nimport { extractSafeHeaders } from '../shared/headers'\nimport { createLoggerStorage } from '../shared/storage'\nimport { resolveEvlogError, extractErrorStatus, serializeEvlogErrorResponse } from '../nitro'\nimport { EvlogError } from '../error'\n\nconst { storage, useLogger } = createLoggerStorage(\n 'handle context. Make sure evlog() handle is added to your hooks.server.ts.',\n)\n\nexport type EvlogSvelteKitOptions = BaseEvlogOptions\n\nexport { useLogger }\n\n/**\n * SvelteKit `Handle` function signature — avoids a hard dependency on `@sveltejs/kit`.\n */\ntype SvelteKitHandle = (input: {\n event: { request: Request; url: URL; locals: Record<string, any> }\n resolve: (event: any) => Promise<Response>\n}) => Promise<Response>\n\n/**\n * SvelteKit `HandleServerError` signature — avoids a hard dependency on `@sveltejs/kit`.\n */\ntype SvelteKitHandleServerError = (input: {\n error: unknown\n event: { request: Request; url: URL; locals: Record<string, any> }\n status: number\n message: string\n}) => MaybePromise<void | AppError>\n\ntype MaybePromise<T> = T | Promise<T>\n\n/** Minimal SvelteKit `App.Error` shape */\ninterface AppError {\n message: string\n [key: string]: unknown\n}\n\n/**\n * Create an evlog handle hook for SvelteKit.\n *\n * Add it to your `src/hooks.server.ts` using SvelteKit's `sequence` helper\n * or as the sole handle export.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { initLogger } from 'evlog'\n * import { evlog } from 'evlog/sveltekit'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * initLogger({ env: { service: 'my-sveltekit-app' } })\n *\n * export const handle = evlog({\n * drain: createAxiomDrain(),\n * enrich: (ctx) => {\n * ctx.event.region = process.env.FLY_REGION\n * },\n * })\n * ```\n *\n * @example\n * ```ts\n * // Compose with other hooks using sequence\n * import { sequence } from '@sveltejs/kit/hooks'\n * import { evlog } from 'evlog/sveltekit'\n *\n * export const handle = sequence(evlog(), yourOtherHook)\n * ```\n */\nexport function evlog(options: EvlogSvelteKitOptions = {}): SvelteKitHandle {\n return async ({ event, resolve }) => {\n const { logger, finish, skipped } = createMiddlewareLogger({\n method: event.request.method,\n path: event.url.pathname,\n requestId: event.request.headers.get('x-request-id') || crypto.randomUUID(),\n headers: extractSafeHeaders(event.request.headers),\n ...options,\n })\n\n if (skipped) {\n return await resolve(event)\n }\n\n event.locals.log = logger\n\n return storage.run(logger, async () => {\n try {\n const response = await resolve(event)\n\n // SvelteKit catches route errors internally and returns 500.\n // If handleError already logged an EvlogError with a specific status,\n // return a structured JSON response instead of SvelteKit's generic 500.\n const ctx = logger.getContext()\n const errorData = ctx.error as { name?: string; status?: number; message?: string; data?: unknown } | undefined\n if (response.status >= 500 && errorData?.name === 'EvlogError' && errorData.status) {\n const { status } = errorData\n await finish({ status })\n const body = serializeEvlogErrorResponse(errorData as EvlogError, event.url.pathname)\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json' },\n })\n }\n\n await finish({ status: response.status })\n return response\n } catch (error) {\n await finish({ error: error as Error })\n\n // Return structured JSON for EvlogError (like NextJS withEvlog / Nuxt errorHandler)\n if (error instanceof EvlogError) {\n const status = error.status ?? 500\n const body = serializeEvlogErrorResponse(error, event.url.pathname)\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json' },\n })\n }\n\n throw error\n }\n })\n }\n}\n\n/**\n * Create an evlog error handler for SvelteKit.\n *\n * Logs unhandled errors via `event.locals.log` (if available) and returns\n * structured error responses for `EvlogError` instances. For non-evlog errors,\n * returns a generic error response with sanitized messages in production.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { evlog, evlogHandleError } from 'evlog/sveltekit'\n *\n * export const handle = evlog()\n * export const handleError = evlogHandleError()\n * ```\n */\nexport function evlogHandleError(): SvelteKitHandleServerError {\n return ({ error, event, status, message }) => {\n const logger = event.locals.log as RequestLogger | undefined\n\n if (logger && error instanceof Error) {\n logger.error(error)\n }\n\n const evlogError = error instanceof Error ? resolveEvlogError(error) : null\n\n if (evlogError) {\n const errorStatus = extractErrorStatus(evlogError)\n const response = serializeEvlogErrorResponse(evlogError, event.url.pathname)\n return {\n message: response.message as string,\n status: errorStatus,\n why: (response.data as { why?: string })?.why,\n fix: (response.data as { fix?: string })?.fix,\n link: (response.data as { link?: string })?.link,\n } as AppError\n }\n\n return { message, status } as AppError\n }\n}\n\n/**\n * Create both `handle` and `handleError` hooks in a single call.\n *\n * This is the recommended setup for SvelteKit — it returns both hooks\n * pre-configured and ready to export from `hooks.server.ts`.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { initLogger } from 'evlog'\n * import { createEvlogHooks } from 'evlog/sveltekit'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * initLogger({ env: { service: 'my-app' } })\n *\n * export const { handle, handleError } = createEvlogHooks({\n * drain: createAxiomDrain(),\n * enrich: (ctx) => {\n * ctx.event.region = process.env.FLY_REGION\n * },\n * })\n * ```\n *\n * @example\n * ```ts\n * // Compose with other hooks using sequence\n * import { sequence } from '@sveltejs/kit/hooks'\n * import { createEvlogHooks } from 'evlog/sveltekit'\n *\n * const evlogHooks = createEvlogHooks()\n *\n * export const handle = sequence(evlogHooks.handle, yourOtherHook)\n * export const handleError = evlogHooks.handleError\n * ```\n */\nexport function createEvlogHooks(options: EvlogSvelteKitOptions = {}) {\n return {\n handle: evlog(options),\n handleError: evlogHandleError(),\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/sveltekit/index.ts"],"sourcesContent":["import type { RequestLogger } from '../types'\nimport { createMiddlewareLogger, type BaseEvlogOptions } from '../shared/middleware'\nimport { extractSafeHeaders } from '../shared/headers'\nimport { createLoggerStorage } from '../shared/storage'\nimport { resolveEvlogError, extractErrorStatus, serializeEvlogErrorResponse } from '../nitro'\nimport { EvlogError } from '../error'\n\nconst { storage, useLogger } = createLoggerStorage(\n 'handle context. Make sure evlog() handle is added to your hooks.server.ts.',\n)\n\nexport type EvlogSvelteKitOptions = BaseEvlogOptions\n\nexport { useLogger }\n\n/**\n * SvelteKit `Handle` function signature — avoids a hard dependency on `@sveltejs/kit`.\n */\ntype SvelteKitHandle = (input: {\n event: { request: Request; url: URL; locals: Record<string, any> }\n resolve: (event: any) => Promise<Response>\n}) => Promise<Response>\n\n/**\n * SvelteKit `HandleServerError` signature — avoids a hard dependency on `@sveltejs/kit`.\n */\ntype SvelteKitHandleServerError = (input: {\n error: unknown\n event: { request: Request; url: URL; locals: Record<string, any> }\n status: number\n message: string\n}) => MaybePromise<void | AppError>\n\ntype MaybePromise<T> = T | Promise<T>\n\n/** Minimal SvelteKit `App.Error` shape */\ninterface AppError {\n message: string\n [key: string]: unknown\n}\n\n/**\n * Create an evlog handle hook for SvelteKit.\n *\n * Add it to your `src/hooks.server.ts` using SvelteKit's `sequence` helper\n * or as the sole handle export.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { initLogger } from 'evlog'\n * import { evlog } from 'evlog/sveltekit'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * initLogger({ env: { service: 'my-sveltekit-app' } })\n *\n * export const handle = evlog({\n * drain: createAxiomDrain(),\n * enrich: (ctx) => {\n * ctx.event.region = process.env.FLY_REGION\n * },\n * })\n * ```\n *\n * @example\n * ```ts\n * // Compose with other hooks using sequence\n * import { sequence } from '@sveltejs/kit/hooks'\n * import { evlog } from 'evlog/sveltekit'\n *\n * export const handle = sequence(evlog(), yourOtherHook)\n * ```\n */\nexport function evlog(options: EvlogSvelteKitOptions = {}): SvelteKitHandle {\n return async ({ event, resolve }) => {\n const { logger, finish, skipped } = createMiddlewareLogger({\n method: event.request.method,\n path: event.url.pathname,\n requestId: event.request.headers.get('x-request-id') || crypto.randomUUID(),\n headers: extractSafeHeaders(event.request.headers),\n ...options,\n })\n\n if (skipped) {\n return await resolve(event)\n }\n\n event.locals.log = logger\n\n return storage.run(logger, async () => {\n try {\n const response = await resolve(event)\n\n // SvelteKit catches route errors internally and returns 500.\n // If handleError already logged an EvlogError with a specific status,\n // return a structured JSON response instead of SvelteKit's generic 500.\n const ctx = logger.getContext()\n const errorData = ctx.error as { name?: string; status?: number; message?: string; data?: unknown } | undefined\n if (response.status >= 500 && errorData?.name === 'EvlogError' && errorData.status) {\n const { status } = errorData\n await finish({ status })\n const body = serializeEvlogErrorResponse(errorData as EvlogError, event.url.pathname)\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json' },\n })\n }\n\n await finish({ status: response.status })\n return response\n } catch (error) {\n await finish({ error: error as Error })\n\n // Return structured JSON for EvlogError (like NextJS withEvlog / Nuxt errorHandler)\n if (error instanceof EvlogError) {\n const status = error.status ?? 500\n const body = serializeEvlogErrorResponse(error, event.url.pathname)\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json' },\n })\n }\n\n throw error\n }\n })\n }\n}\n\n/**\n * Create an evlog error handler for SvelteKit.\n *\n * Logs unhandled errors via `event.locals.log` (if available) and returns\n * structured error responses for `EvlogError` instances. For non-evlog errors,\n * returns a generic error response with sanitized messages in production.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { evlog, evlogHandleError } from 'evlog/sveltekit'\n *\n * export const handle = evlog()\n * export const handleError = evlogHandleError()\n * ```\n */\nexport function evlogHandleError(): SvelteKitHandleServerError {\n return ({ error, event, status, message }) => {\n const logger = event.locals.log as RequestLogger | undefined\n\n if (logger && error instanceof Error) {\n logger.error(error)\n }\n\n const evlogError = error instanceof Error ? resolveEvlogError(error) : null\n\n if (evlogError) {\n const errorStatus = extractErrorStatus(evlogError)\n const response = serializeEvlogErrorResponse(evlogError, event.url.pathname)\n return {\n message: response.message as string,\n status: errorStatus,\n why: (response.data as { why?: string })?.why,\n fix: (response.data as { fix?: string })?.fix,\n link: (response.data as { link?: string })?.link,\n } as AppError\n }\n\n return { message, status } as AppError\n }\n}\n\n/**\n * Create both `handle` and `handleError` hooks in a single call.\n *\n * This is the recommended setup for SvelteKit — it returns both hooks\n * pre-configured and ready to export from `hooks.server.ts`.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { initLogger } from 'evlog'\n * import { createEvlogHooks } from 'evlog/sveltekit'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * initLogger({ env: { service: 'my-app' } })\n *\n * export const { handle, handleError } = createEvlogHooks({\n * drain: createAxiomDrain(),\n * enrich: (ctx) => {\n * ctx.event.region = process.env.FLY_REGION\n * },\n * })\n * ```\n *\n * @example\n * ```ts\n * // Compose with other hooks using sequence\n * import { sequence } from '@sveltejs/kit/hooks'\n * import { createEvlogHooks } from 'evlog/sveltekit'\n *\n * const evlogHooks = createEvlogHooks()\n *\n * export const handle = sequence(evlogHooks.handle, yourOtherHook)\n * export const handleError = evlogHooks.handleError\n * ```\n */\nexport function createEvlogHooks(options: EvlogSvelteKitOptions = {}) {\n return {\n handle: evlog(options),\n handleError: evlogHandleError(),\n }\n}\n"],"mappings":";;;;;AAOA,MAAM,EAAE,SAAS,cAAc,oBAC7B,6EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgED,SAAgB,MAAM,UAAiC,EAAE,EAAmB;AAC1E,QAAO,OAAO,EAAE,OAAO,cAAc;EACnC,MAAM,EAAE,QAAQ,QAAQ,YAAY,uBAAuB;GACzD,QAAQ,MAAM,QAAQ;GACtB,MAAM,MAAM,IAAI;GAChB,WAAW,MAAM,QAAQ,QAAQ,IAAI,eAAe,IAAI,OAAO,YAAY;GAC3E,SAAS,mBAAmB,MAAM,QAAQ,QAAQ;GAClD,GAAG;GACJ,CAAC;AAEF,MAAI,QACF,QAAO,MAAM,QAAQ,MAAM;AAG7B,QAAM,OAAO,MAAM;AAEnB,SAAO,QAAQ,IAAI,QAAQ,YAAY;AACrC,OAAI;IACF,MAAM,WAAW,MAAM,QAAQ,MAAM;IAMrC,MAAM,YADM,OAAO,YAAY,CACT;AACtB,QAAI,SAAS,UAAU,OAAO,WAAW,SAAS,gBAAgB,UAAU,QAAQ;KAClF,MAAM,EAAE,WAAW;AACnB,WAAM,OAAO,EAAE,QAAQ,CAAC;KACxB,MAAM,OAAO,4BAA4B,WAAyB,MAAM,IAAI,SAAS;AACrF,YAAO,IAAI,SAAS,KAAK,UAAU,KAAK,EAAE;MACxC;MACA,SAAS,EAAE,gBAAgB,oBAAoB;MAChD,CAAC;;AAGJ,UAAM,OAAO,EAAE,QAAQ,SAAS,QAAQ,CAAC;AACzC,WAAO;YACA,OAAO;AACd,UAAM,OAAO,EAAS,OAAgB,CAAC;AAGvC,QAAI,iBAAiB,YAAY;KAC/B,MAAM,SAAS,MAAM,UAAU;KAC/B,MAAM,OAAO,4BAA4B,OAAO,MAAM,IAAI,SAAS;AACnE,YAAO,IAAI,SAAS,KAAK,UAAU,KAAK,EAAE;MACxC;MACA,SAAS,EAAE,gBAAgB,oBAAoB;MAChD,CAAC;;AAGJ,UAAM;;IAER;;;;;;;;;;;;;;;;;;;AAoBN,SAAgB,mBAA+C;AAC7D,SAAQ,EAAE,OAAO,OAAO,QAAQ,cAAc;EAC5C,MAAM,SAAS,MAAM,OAAO;AAE5B,MAAI,UAAU,iBAAiB,MAC7B,QAAO,MAAM,MAAM;EAGrB,MAAM,aAAa,iBAAiB,QAAQ,kBAAkB,MAAM,GAAG;AAEvE,MAAI,YAAY;GACd,MAAM,cAAc,mBAAmB,WAAW;GAClD,MAAM,WAAW,4BAA4B,YAAY,MAAM,IAAI,SAAS;AAC5E,UAAO;IACL,SAAS,SAAS;IAClB,QAAQ;IACR,KAAM,SAAS,MAA2B;IAC1C,KAAM,SAAS,MAA2B;IAC1C,MAAO,SAAS,MAA4B;IAC7C;;AAGH,SAAO;GAAE;GAAS;GAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuC9B,SAAgB,iBAAiB,UAAiC,EAAE,EAAE;AACpE,QAAO;EACL,QAAQ,MAAM,QAAQ;EACtB,aAAa,kBAAkB;EAChC"}
|