evlog 2.16.0 → 2.18.1
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 +102 -9
- package/dist/adapters/axiom.d.mts +1 -1
- package/dist/adapters/axiom.mjs +4 -2
- package/dist/adapters/axiom.mjs.map +1 -1
- package/dist/adapters/better-stack.d.mts +1 -1
- package/dist/adapters/better-stack.mjs +4 -2
- package/dist/adapters/better-stack.mjs.map +1 -1
- package/dist/adapters/datadog.d.mts +1 -1
- package/dist/adapters/datadog.mjs +4 -2
- package/dist/adapters/datadog.mjs.map +1 -1
- package/dist/adapters/fs.d.mts +64 -2
- package/dist/adapters/fs.d.mts.map +1 -1
- package/dist/adapters/fs.mjs +222 -3
- package/dist/adapters/fs.mjs.map +1 -1
- package/dist/adapters/hyperdx.d.mts +1 -1
- package/dist/adapters/hyperdx.mjs +1 -1
- package/dist/adapters/memory.d.mts +116 -0
- package/dist/adapters/memory.d.mts.map +1 -0
- package/dist/adapters/memory.mjs +191 -0
- package/dist/adapters/memory.mjs.map +1 -0
- package/dist/adapters/otlp.d.mts +1 -1
- package/dist/adapters/otlp.mjs +6 -4
- package/dist/adapters/otlp.mjs.map +1 -1
- package/dist/adapters/posthog.d.mts +1 -1
- package/dist/adapters/posthog.mjs +4 -2
- package/dist/adapters/posthog.mjs.map +1 -1
- package/dist/adapters/sentry.d.mts +1 -1
- package/dist/adapters/sentry.mjs +5 -3
- package/dist/adapters/sentry.mjs.map +1 -1
- package/dist/ai/index.d.mts +1 -1
- package/dist/{audit-pV5aLGP0.mjs → audit-BUI3af4w.mjs} +121 -53
- package/dist/audit-BUI3af4w.mjs.map +1 -0
- package/dist/{audit-X1uUukm3.d.mts → audit-DVdkntSO.d.mts} +76 -5
- package/dist/audit-DVdkntSO.d.mts.map +1 -0
- package/dist/better-auth/index.d.mts +14 -7
- package/dist/better-auth/index.d.mts.map +1 -1
- package/dist/better-auth/index.mjs +11 -1
- package/dist/better-auth/index.mjs.map +1 -1
- package/dist/browser.d.mts +1 -1
- package/dist/{define-CuXOqecD.d.mts → define-D-BVMf2l.d.mts} +3 -3
- package/dist/{define-CuXOqecD.d.mts.map → define-D-BVMf2l.d.mts.map} +1 -1
- package/dist/define-D6OJdSUH.mjs.map +1 -1
- package/dist/{dist-BIlS38vi.mjs → dist-H3GIh-KK.mjs} +1 -1
- package/dist/{dist-BIlS38vi.mjs.map → dist-H3GIh-KK.mjs.map} +1 -1
- package/dist/{drain-ByWUeOQC.mjs → drain-7n3K6kPe.mjs} +6 -49
- package/dist/drain-7n3K6kPe.mjs.map +1 -0
- package/dist/elysia/index.d.mts +2 -2
- package/dist/elysia/index.mjs +2 -2
- package/dist/{enricher-Dy06T17G.mjs → enricher-N0erZS87.mjs} +2 -2
- package/dist/{enricher-Dy06T17G.mjs.map → enricher-N0erZS87.mjs.map} +1 -1
- package/dist/{enricher-DYTr9I16.d.mts → enricher-UW9npoB2.d.mts} +2 -2
- package/dist/{enricher-DYTr9I16.d.mts.map → enricher-UW9npoB2.d.mts.map} +1 -1
- package/dist/enrichers.d.mts +2 -2
- package/dist/enrichers.mjs +1 -1
- package/dist/{error-Cpc7RVz6.d.mts → error-CVtn5U7b.d.mts} +2 -2
- package/dist/{error-Cpc7RVz6.d.mts.map → error-CVtn5U7b.d.mts.map} +1 -1
- package/dist/error.d.mts +1 -1
- package/dist/{errors-prnQ3kES.d.mts → errors-dEMNQCiL.d.mts} +2 -2
- package/dist/{errors-prnQ3kES.d.mts.map → errors-dEMNQCiL.d.mts.map} +1 -1
- package/dist/{event-DcHmEm3O.mjs → event-1BMl7o0k.mjs} +1 -1
- package/dist/{event-DcHmEm3O.mjs.map → event-1BMl7o0k.mjs.map} +1 -1
- package/dist/express/index.d.mts +3 -3
- package/dist/express/index.d.mts.map +1 -1
- package/dist/express/index.mjs +5 -6
- package/dist/express/index.mjs.map +1 -1
- package/dist/fastify/index.d.mts +9 -4
- package/dist/fastify/index.d.mts.map +1 -1
- package/dist/fastify/index.mjs +10 -8
- package/dist/fastify/index.mjs.map +1 -1
- package/dist/{fork-DPN8aL8O.mjs → fork-Bga8x-X4.mjs} +4 -3
- package/dist/fork-Bga8x-X4.mjs.map +1 -0
- package/dist/hono/index.d.mts +2 -2
- package/dist/hono/index.mjs +1 -1
- package/dist/http-B6YgAhyN.mjs +82 -0
- package/dist/http-B6YgAhyN.mjs.map +1 -0
- package/dist/http.d.mts +1 -1
- package/dist/http.mjs +1 -0
- package/dist/http.mjs.map +1 -1
- package/dist/index-ZSRQP_BI.d.mts +213 -0
- package/dist/index-ZSRQP_BI.d.mts.map +1 -0
- package/dist/index.d.mts +9 -8
- package/dist/index.mjs +210 -2
- package/dist/index.mjs.map +1 -0
- package/dist/{integration-DSZPbI9N.mjs → integration-Dhig7ae6.mjs} +2 -2
- package/dist/{integration-DSZPbI9N.mjs.map → integration-Dhig7ae6.mjs.map} +1 -1
- package/dist/{logger-U8lgdc9x.d.mts → logger-CTcvd5Cc.d.mts} +7 -3
- package/dist/logger-CTcvd5Cc.d.mts.map +1 -0
- package/dist/logger.d.mts +2 -2
- package/dist/logger.mjs +2 -2
- package/dist/{middleware-CAQHJRN1.d.mts → middleware-31KhtiEF.d.mts} +2 -2
- package/dist/{middleware-CAQHJRN1.d.mts.map → middleware-31KhtiEF.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 +4 -5
- package/dist/nestjs/index.mjs.map +1 -1
- package/dist/next/client.d.mts +1 -1
- package/dist/next/index.d.mts +6 -5
- package/dist/next/index.d.mts.map +1 -1
- package/dist/next/index.mjs +4 -4
- package/dist/next/index.mjs.map +1 -1
- package/dist/next/instrumentation.d.mts +1 -1
- package/dist/next/instrumentation.mjs +1 -1
- package/dist/next/instrumentation.mjs.map +1 -1
- package/dist/next/stream.d.mts +29 -0
- package/dist/next/stream.d.mts.map +1 -0
- package/dist/next/stream.mjs +78 -0
- package/dist/next/stream.mjs.map +1 -0
- package/dist/nitro/errorHandler.mjs +1 -1
- package/dist/nitro/module.d.mts +2 -2
- package/dist/nitro/module.d.mts.map +1 -1
- package/dist/nitro/module.mjs +7 -2
- package/dist/nitro/module.mjs.map +1 -1
- package/dist/nitro/plugin.mjs +13 -3
- package/dist/nitro/plugin.mjs.map +1 -1
- package/dist/nitro/v3/errorHandler.mjs +2 -2
- package/dist/nitro/v3/index.d.mts +2 -2
- package/dist/nitro/v3/module.d.mts +1 -1
- package/dist/nitro/v3/module.d.mts.map +1 -1
- package/dist/nitro/v3/module.mjs +9 -4
- package/dist/nitro/v3/module.mjs.map +1 -1
- package/dist/nitro/v3/plugin.mjs +5 -4
- package/dist/nitro/v3/plugin.mjs.map +1 -1
- package/dist/nitro/v3/useLogger.d.mts +1 -1
- package/dist/{nitro-C6Bd682U.d.mts → nitro-BRddgqSb.d.mts} +2 -2
- package/dist/{nitro-C6Bd682U.d.mts.map → nitro-BRddgqSb.d.mts.map} +1 -1
- package/dist/{nitro-DavLelNz.mjs → nitro-DErMq_Zj.mjs} +1 -1
- package/dist/{nitro-DavLelNz.mjs.map → nitro-DErMq_Zj.mjs.map} +1 -1
- package/dist/nitroConfigBridge-NbFn-sIK.mjs +157 -0
- package/dist/nitroConfigBridge-NbFn-sIK.mjs.map +1 -0
- package/dist/nodeResponse-BkkionWl.mjs +42 -0
- package/dist/nodeResponse-BkkionWl.mjs.map +1 -0
- package/dist/nuxt/module.d.mts +35 -4
- package/dist/nuxt/module.d.mts.map +1 -1
- package/dist/nuxt/module.mjs +11 -4
- package/dist/nuxt/module.mjs.map +1 -1
- package/dist/orpc/index.d.mts +115 -0
- package/dist/orpc/index.d.mts.map +1 -0
- package/dist/orpc/index.mjs +144 -0
- package/dist/orpc/index.mjs.map +1 -0
- package/dist/package-B23bR3tK.mjs +7 -0
- package/dist/package-B23bR3tK.mjs.map +1 -0
- package/dist/{parseError-B-dKF6Fd.d.mts → parseError-D4PIxEWo.d.mts} +2 -2
- package/dist/parseError-D4PIxEWo.d.mts.map +1 -0
- package/dist/react-router/index.d.mts +2 -2
- package/dist/react-router/index.mjs +2 -2
- package/dist/{routes-B48wm7Pb.mjs → routes-CnIgYWf8.mjs} +1 -1
- package/dist/{routes-B48wm7Pb.mjs.map → routes-CnIgYWf8.mjs.map} +1 -1
- package/dist/runtime/client/log.d.mts +1 -1
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs +28 -12
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs.map +1 -1
- package/dist/runtime/server/routes/_evlog/stream-info.get.d.mts +18 -0
- package/dist/runtime/server/routes/_evlog/stream-info.get.d.mts.map +1 -0
- package/dist/runtime/server/routes/_evlog/stream-info.get.mjs +28 -0
- package/dist/runtime/server/routes/_evlog/stream-info.get.mjs.map +1 -0
- package/dist/runtime/server/useLogger.d.mts +1 -1
- package/dist/runtime/utils/parseError.d.mts +2 -2
- package/dist/{severity-BYWZ96Sb.mjs → severity-R5Egq3qz.mjs} +1 -1
- package/dist/{severity-BYWZ96Sb.mjs.map → severity-R5Egq3qz.mjs.map} +1 -1
- package/dist/{storage-BT-3fT1-.mjs → storage-BNubsWwz.mjs} +2 -1
- package/dist/{storage-BT-3fT1-.mjs.map → storage-BNubsWwz.mjs.map} +1 -1
- package/dist/stream.d.mts +185 -0
- package/dist/stream.d.mts.map +1 -0
- package/dist/stream.mjs +374 -0
- package/dist/stream.mjs.map +1 -0
- package/dist/sveltekit/index.d.mts +3 -3
- package/dist/sveltekit/index.d.mts.map +1 -1
- package/dist/sveltekit/index.mjs +44 -11
- package/dist/sveltekit/index.mjs.map +1 -1
- package/dist/toolkit.d.mts +43 -8
- package/dist/toolkit.d.mts.map +1 -1
- package/dist/toolkit.mjs +11 -10
- package/dist/types.d.mts +2 -2
- package/dist/{useLogger-CoNgTjp5.d.mts → useLogger-CqvH6qOf.d.mts} +2 -2
- package/dist/{useLogger-CoNgTjp5.d.mts.map → useLogger-CqvH6qOf.d.mts.map} +1 -1
- package/dist/{utils-Db4qhBWn.d.mts → utils-DxqvIOyR.d.mts} +12 -3
- package/dist/{utils-Db4qhBWn.d.mts.map → utils-DxqvIOyR.d.mts.map} +1 -1
- package/dist/utils.d.mts +1 -1
- package/dist/utils.mjs +10 -1
- package/dist/utils.mjs.map +1 -1
- package/dist/vite/index.d.mts +1 -1
- package/dist/workers.d.mts +1 -1
- package/dist/workers.mjs +1 -1
- package/package.json +64 -15
- package/dist/audit-X1uUukm3.d.mts.map +0 -1
- package/dist/audit-pV5aLGP0.mjs.map +0 -1
- package/dist/drain-ByWUeOQC.mjs.map +0 -1
- package/dist/fork-DPN8aL8O.mjs.map +0 -1
- package/dist/logger-U8lgdc9x.d.mts.map +0 -1
- package/dist/nitroConfigBridge-aZ1e5upQ.mjs +0 -92
- package/dist/nitroConfigBridge-aZ1e5upQ.mjs.map +0 -1
- package/dist/parseError-B-dKF6Fd.d.mts.map +0 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { EvlogError } from "../error.mjs";
|
|
2
|
+
import { parseError } from "../runtime/utils/parseError.mjs";
|
|
3
|
+
import { t as defineFrameworkIntegration } from "../integration-Dhig7ae6.mjs";
|
|
4
|
+
import { t as createLoggerStorage } from "../storage-BNubsWwz.mjs";
|
|
5
|
+
import { ORPCError } from "@orpc/server";
|
|
6
|
+
//#region src/orpc/index.ts
|
|
7
|
+
const { storage, useLogger } = createLoggerStorage("oRPC handler. Wrap your handler with `withEvlog()` from evlog/orpc.");
|
|
8
|
+
const integration = defineFrameworkIntegration({
|
|
9
|
+
name: "orpc",
|
|
10
|
+
extractRequest: ({ request }) => {
|
|
11
|
+
const url = new URL(request.url);
|
|
12
|
+
return {
|
|
13
|
+
method: request.method,
|
|
14
|
+
path: url.pathname,
|
|
15
|
+
headers: request.headers,
|
|
16
|
+
requestId: request.headers.get("x-request-id") ?? void 0
|
|
17
|
+
};
|
|
18
|
+
},
|
|
19
|
+
attachLogger: () => {},
|
|
20
|
+
storage
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* Wrap an oRPC handler so each matched request emits a single wide event.
|
|
24
|
+
* Works with any handler that exposes `.handle(request, options)` from
|
|
25
|
+
* `@orpc/server/fetch` (RPCHandler, OpenAPIHandler, custom handlers).
|
|
26
|
+
*
|
|
27
|
+
* The returned proxy preserves the original handler's identity (instance
|
|
28
|
+
* methods, plugins, etc.) and only intercepts `handle`. Inside procedures,
|
|
29
|
+
* the request logger is exposed as `context.log` — pair this with
|
|
30
|
+
* `os.use(evlog())` to also accumulate `operation` (`path.join('.')`) on the
|
|
31
|
+
* wide event.
|
|
32
|
+
*
|
|
33
|
+
* Routes that are filtered out by `include`/`exclude` are passed straight to
|
|
34
|
+
* the underlying handler with no instrumentation.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* import { RPCHandler } from '@orpc/server/fetch'
|
|
39
|
+
* import { withEvlog } from 'evlog/orpc'
|
|
40
|
+
* import { router } from './router'
|
|
41
|
+
*
|
|
42
|
+
* const handler = withEvlog(new RPCHandler(router), {
|
|
43
|
+
* include: ['/rpc/**'],
|
|
44
|
+
* })
|
|
45
|
+
*
|
|
46
|
+
* export default async function fetch(request: Request) {
|
|
47
|
+
* const { matched, response } = await handler.handle(request, { prefix: '/rpc' })
|
|
48
|
+
* return matched ? response : new Response('Not Found', { status: 404 })
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
function withEvlog(handler, options = {}) {
|
|
53
|
+
const handle = async (request, callOptions) => {
|
|
54
|
+
const { skipped, finish, runWith, logger } = integration.start({ request }, options);
|
|
55
|
+
const initialContext = callOptions?.context ?? {};
|
|
56
|
+
const finalOptions = {
|
|
57
|
+
...callOptions,
|
|
58
|
+
context: {
|
|
59
|
+
...initialContext,
|
|
60
|
+
log: logger
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
if (skipped) return handler.handle(request, finalOptions);
|
|
64
|
+
try {
|
|
65
|
+
const result = await runWith(() => handler.handle(request, finalOptions));
|
|
66
|
+
await finish({ status: result.matched ? result.response.status : 404 });
|
|
67
|
+
return result;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
await finish({ error });
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
return new Proxy(handler, { get(target, prop, receiver) {
|
|
74
|
+
if (prop === "handle") return handle;
|
|
75
|
+
return Reflect.get(target, prop, receiver);
|
|
76
|
+
} });
|
|
77
|
+
}
|
|
78
|
+
function isEvlogError(error) {
|
|
79
|
+
return error instanceof EvlogError || error instanceof Error && error.name === "EvlogError";
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Procedure-level middleware. Three responsibilities:
|
|
83
|
+
*
|
|
84
|
+
* 1. Adds `operation` (the procedure path joined by `.`) to the wide event,
|
|
85
|
+
* so consumers can group events by procedure without parsing URLs.
|
|
86
|
+
* 2. Captures errors thrown by the procedure on the wide event so the level
|
|
87
|
+
* is promoted to `error`.
|
|
88
|
+
* 3. Converts {@link EvlogError} (from `createError()` / `defineErrorCatalog`)
|
|
89
|
+
* into a structurally-equivalent {@link ORPCError} before re-throwing, so
|
|
90
|
+
* the wire response carries the catalog `code`, status, message, and the
|
|
91
|
+
* `why` / `fix` / `link` guidance under `data` — instead of being wrapped
|
|
92
|
+
* as `INTERNAL_SERVER_ERROR` by oRPC's default handler. The catalog and
|
|
93
|
+
* `createError()` stay the canonical evlog way to author errors;
|
|
94
|
+
* `evlog/orpc` is the bridge.
|
|
95
|
+
*
|
|
96
|
+
* Requires `withEvlog()` to be wrapped around the handler — the request
|
|
97
|
+
* logger flows in via `context.log`. Declare {@link EvlogOrpcContext} on
|
|
98
|
+
* your oRPC base for typed access.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* import { os } from '@orpc/server'
|
|
103
|
+
* import { evlog, type EvlogOrpcContext } from 'evlog/orpc'
|
|
104
|
+
*
|
|
105
|
+
* const base = os.$context<EvlogOrpcContext>().use(evlog())
|
|
106
|
+
*
|
|
107
|
+
* export const getUser = base
|
|
108
|
+
* .input(z.object({ id: z.string() }))
|
|
109
|
+
* .handler(async ({ input, context }) => {
|
|
110
|
+
* context.log.set({ user: { id: input.id } })
|
|
111
|
+
* return await db.user.findUnique(input)
|
|
112
|
+
* })
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
function evlog() {
|
|
116
|
+
return async function evlogMiddleware(options) {
|
|
117
|
+
const { context: { log }, path, next } = options;
|
|
118
|
+
if (log && path.length > 0) log.set({ operation: path.join(".") });
|
|
119
|
+
try {
|
|
120
|
+
return await next();
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (log) log.error(error);
|
|
123
|
+
if (isEvlogError(error)) throw toOrpcError(error);
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function toOrpcError(error) {
|
|
129
|
+
const parsed = parseError(error);
|
|
130
|
+
const data = {};
|
|
131
|
+
if (parsed.why !== void 0) data.why = parsed.why;
|
|
132
|
+
if (parsed.fix !== void 0) data.fix = parsed.fix;
|
|
133
|
+
if (parsed.link !== void 0) data.link = parsed.link;
|
|
134
|
+
return new ORPCError(parsed.code ?? "EVLOG_ERROR", {
|
|
135
|
+
status: parsed.status,
|
|
136
|
+
message: parsed.message,
|
|
137
|
+
data,
|
|
138
|
+
cause: error
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
export { evlog, useLogger, withEvlog };
|
|
143
|
+
|
|
144
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/orpc/index.ts"],"sourcesContent":["import { ORPCError, type Context, type MiddlewareOptions, type MiddlewareResult } from '@orpc/server'\nimport type { RequestLogger } from '../types'\nimport { EvlogError } from '../error'\nimport { parseError } from '../runtime/utils/parseError'\nimport { defineFrameworkIntegration } from '../shared/integration'\nimport type { BaseEvlogOptions } from '../shared/middleware'\nimport { createLoggerStorage } from '../shared/storage'\n\nconst { storage, useLogger } = createLoggerStorage(\n 'oRPC handler. Wrap your handler with `withEvlog()` from evlog/orpc.',\n)\n\n/** Options accepted by {@link withEvlog} for oRPC request instrumentation. */\nexport type EvlogOrpcOptions = BaseEvlogOptions\n\n/**\n * Access the current request-scoped logger outside oRPC context callbacks.\n * Requires {@link withEvlog} on the handler.\n */\nexport { useLogger }\n\n/**\n * Inject this type into your oRPC initial context to access `context.log`\n * inside procedures.\n *\n * @example\n * ```ts\n * import { os } from '@orpc/server'\n * import { evlog, type EvlogOrpcContext } from 'evlog/orpc'\n *\n * const base = os.$context<EvlogOrpcContext>().use(evlog())\n * ```\n */\nexport interface EvlogOrpcContext {\n log: RequestLogger\n}\n\n/**\n * Result shape of `handler.handle()` for oRPC's fetch adapter\n * ({@link https://orpc.dev/docs/adapters/http RPCHandler / OpenAPIHandler}).\n */\ntype OrpcFetchHandleResult =\n | { matched: true, response: Response }\n | { matched: false, response: undefined }\n\n/**\n * Minimal subset of oRPC's `FetchHandler` that we need to wrap. Anything\n * compatible (RPCHandler, OpenAPIHandler, custom handler) plugs in.\n *\n * `options` is intentionally typed loosely so this matches both the\n * `(req, opts)` and `(req, opts?)` overloads that oRPC produces depending on\n * whether the router declares a non-empty initial context. The wrapper just\n * splats the original options through and injects `log` into `context`.\n */\ninterface OrpcFetchHandlerLike {\n handle: (\n request: Request,\n options?: any,\n ) => Promise<OrpcFetchHandleResult>\n}\n\nconst integration = defineFrameworkIntegration<{ request: Request }>({\n name: 'orpc',\n extractRequest: ({ request }) => {\n const url = new URL(request.url)\n return {\n method: request.method,\n path: url.pathname,\n headers: request.headers,\n requestId: request.headers.get('x-request-id') ?? undefined,\n }\n },\n attachLogger: () => {\n /* logger is injected into the oRPC context inside withEvlog() */\n },\n storage,\n})\n\n/**\n * Wrap an oRPC handler so each matched request emits a single wide event.\n * Works with any handler that exposes `.handle(request, options)` from\n * `@orpc/server/fetch` (RPCHandler, OpenAPIHandler, custom handlers).\n *\n * The returned proxy preserves the original handler's identity (instance\n * methods, plugins, etc.) and only intercepts `handle`. Inside procedures,\n * the request logger is exposed as `context.log` — pair this with\n * `os.use(evlog())` to also accumulate `operation` (`path.join('.')`) on the\n * wide event.\n *\n * Routes that are filtered out by `include`/`exclude` are passed straight to\n * the underlying handler with no instrumentation.\n *\n * @example\n * ```ts\n * import { RPCHandler } from '@orpc/server/fetch'\n * import { withEvlog } from 'evlog/orpc'\n * import { router } from './router'\n *\n * const handler = withEvlog(new RPCHandler(router), {\n * include: ['/rpc/**'],\n * })\n *\n * export default async function fetch(request: Request) {\n * const { matched, response } = await handler.handle(request, { prefix: '/rpc' })\n * return matched ? response : new Response('Not Found', { status: 404 })\n * }\n * ```\n */\nexport function withEvlog<THandler extends OrpcFetchHandlerLike>(\n handler: THandler,\n options: EvlogOrpcOptions = {},\n): THandler {\n const handle: THandler['handle'] = async (request, callOptions) => {\n const { skipped, finish, runWith, logger } = integration.start({ request }, options)\n\n const initialContext = (callOptions as { context?: Record<string, unknown> } | undefined)?.context ?? {}\n const finalOptions = {\n ...callOptions,\n context: { ...initialContext, log: logger },\n } as Parameters<THandler['handle']>[1]\n\n if (skipped) {\n return handler.handle(request, finalOptions)\n }\n\n try {\n const result = await runWith(() => handler.handle(request, finalOptions))\n const status = result.matched ? result.response.status : 404\n await finish({ status })\n return result\n } catch (error) {\n await finish({ error: error as Error })\n throw error\n }\n }\n\n return new Proxy(handler, {\n get(target, prop, receiver) {\n if (prop === 'handle') return handle\n return Reflect.get(target, prop, receiver)\n },\n })\n}\n\nfunction isEvlogError(error: unknown): error is EvlogError {\n return error instanceof EvlogError || (error instanceof Error && error.name === 'EvlogError')\n}\n\n/**\n * Procedure-level middleware. Three responsibilities:\n *\n * 1. Adds `operation` (the procedure path joined by `.`) to the wide event,\n * so consumers can group events by procedure without parsing URLs.\n * 2. Captures errors thrown by the procedure on the wide event so the level\n * is promoted to `error`.\n * 3. Converts {@link EvlogError} (from `createError()` / `defineErrorCatalog`)\n * into a structurally-equivalent {@link ORPCError} before re-throwing, so\n * the wire response carries the catalog `code`, status, message, and the\n * `why` / `fix` / `link` guidance under `data` — instead of being wrapped\n * as `INTERNAL_SERVER_ERROR` by oRPC's default handler. The catalog and\n * `createError()` stay the canonical evlog way to author errors;\n * `evlog/orpc` is the bridge.\n *\n * Requires `withEvlog()` to be wrapped around the handler — the request\n * logger flows in via `context.log`. Declare {@link EvlogOrpcContext} on\n * your oRPC base for typed access.\n *\n * @example\n * ```ts\n * import { os } from '@orpc/server'\n * import { evlog, type EvlogOrpcContext } from 'evlog/orpc'\n *\n * const base = os.$context<EvlogOrpcContext>().use(evlog())\n *\n * export const getUser = base\n * .input(z.object({ id: z.string() }))\n * .handler(async ({ input, context }) => {\n * context.log.set({ user: { id: input.id } })\n * return await db.user.findUnique(input)\n * })\n * ```\n */\nexport function evlog<TContext extends Partial<EvlogOrpcContext> & Context = EvlogOrpcContext>() {\n return async function evlogMiddleware(\n options: MiddlewareOptions<TContext, unknown, any, any>,\n ): Promise<MiddlewareResult<Record<never, never>, unknown>> {\n const { context: { log }, path, next } = options\n if (log && path.length > 0) {\n log.set({ operation: path.join('.') })\n }\n try {\n return await next()\n } catch (error) {\n if (log) log.error(error as Error)\n if (isEvlogError(error)) {\n throw toOrpcError(error)\n }\n throw error\n }\n }\n}\n\nfunction toOrpcError(error: EvlogError): ORPCError<string, Record<string, unknown>> {\n const parsed = parseError(error)\n const data: Record<string, unknown> = {}\n if (parsed.why !== undefined) data.why = parsed.why\n if (parsed.fix !== undefined) data.fix = parsed.fix\n if (parsed.link !== undefined) data.link = parsed.link\n return new ORPCError(parsed.code ?? 'EVLOG_ERROR', {\n status: parsed.status,\n message: parsed.message,\n data,\n cause: error,\n })\n}\n"],"mappings":";;;;;;AAQA,MAAM,EAAE,SAAS,cAAc,oBAC7B,sEACD;AAmDD,MAAM,cAAc,2BAAiD;CACnE,MAAM;CACN,iBAAiB,EAAE,cAAc;EAC/B,MAAM,MAAM,IAAI,IAAI,QAAQ,IAAI;AAChC,SAAO;GACL,QAAQ,QAAQ;GAChB,MAAM,IAAI;GACV,SAAS,QAAQ;GACjB,WAAW,QAAQ,QAAQ,IAAI,eAAe,IAAI,KAAA;GACnD;;CAEH,oBAAoB;CAGpB;CACD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCF,SAAgB,UACd,SACA,UAA4B,EAAE,EACpB;CACV,MAAM,SAA6B,OAAO,SAAS,gBAAgB;EACjE,MAAM,EAAE,SAAS,QAAQ,SAAS,WAAW,YAAY,MAAM,EAAE,SAAS,EAAE,QAAQ;EAEpF,MAAM,iBAAkB,aAAmE,WAAW,EAAE;EACxG,MAAM,eAAe;GACnB,GAAG;GACH,SAAS;IAAE,GAAG;IAAgB,KAAK;IAAQ;GAC5C;AAED,MAAI,QACF,QAAO,QAAQ,OAAO,SAAS,aAAa;AAG9C,MAAI;GACF,MAAM,SAAS,MAAM,cAAc,QAAQ,OAAO,SAAS,aAAa,CAAC;AAEzE,SAAM,OAAO,EAAE,QADA,OAAO,UAAU,OAAO,SAAS,SAAS,KAClC,CAAC;AACxB,UAAO;WACA,OAAO;AACd,SAAM,OAAO,EAAS,OAAgB,CAAC;AACvC,SAAM;;;AAIV,QAAO,IAAI,MAAM,SAAS,EACxB,IAAI,QAAQ,MAAM,UAAU;AAC1B,MAAI,SAAS,SAAU,QAAO;AAC9B,SAAO,QAAQ,IAAI,QAAQ,MAAM,SAAS;IAE7C,CAAC;;AAGJ,SAAS,aAAa,OAAqC;AACzD,QAAO,iBAAiB,cAAe,iBAAiB,SAAS,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqClF,SAAgB,QAAiF;AAC/F,QAAO,eAAe,gBACpB,SAC0D;EAC1D,MAAM,EAAE,SAAS,EAAE,OAAO,MAAM,SAAS;AACzC,MAAI,OAAO,KAAK,SAAS,EACvB,KAAI,IAAI,EAAE,WAAW,KAAK,KAAK,IAAI,EAAE,CAAC;AAExC,MAAI;AACF,UAAO,MAAM,MAAM;WACZ,OAAO;AACd,OAAI,IAAK,KAAI,MAAM,MAAe;AAClC,OAAI,aAAa,MAAM,CACrB,OAAM,YAAY,MAAM;AAE1B,SAAM;;;;AAKZ,SAAS,YAAY,OAA+D;CAClF,MAAM,SAAS,WAAW,MAAM;CAChC,MAAM,OAAgC,EAAE;AACxC,KAAI,OAAO,QAAQ,KAAA,EAAW,MAAK,MAAM,OAAO;AAChD,KAAI,OAAO,QAAQ,KAAA,EAAW,MAAK,MAAM,OAAO;AAChD,KAAI,OAAO,SAAS,KAAA,EAAW,MAAK,OAAO,OAAO;AAClD,QAAO,IAAI,UAAU,OAAO,QAAQ,eAAe;EACjD,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB;EACA,OAAO;EACR,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-B23bR3tK.mjs","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { J as ParsedError } from "./audit-DVdkntSO.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-D4PIxEWo.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseError-D4PIxEWo.d.mts","names":[],"sources":["../src/runtime/utils/parseError.ts"],"mappings":";;;iBAcgB,UAAA,CAAW,KAAA,YAAiB,WAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as BaseEvlogOptions } from "../middleware-
|
|
1
|
+
import { $ as RequestLogger } from "../audit-DVdkntSO.mjs";
|
|
2
|
+
import { t as BaseEvlogOptions } from "../middleware-31KhtiEF.mjs";
|
|
3
3
|
import * as _$react_router0 from "react-router";
|
|
4
4
|
|
|
5
5
|
//#region src/react-router/index.d.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as extractSafeHeaders } from "../headers-CU-QqnYg.mjs";
|
|
2
|
-
import { r as createMiddlewareLogger, t as attachForkToLogger } from "../fork-
|
|
3
|
-
import { t as createLoggerStorage } from "../storage-
|
|
2
|
+
import { r as createMiddlewareLogger, t as attachForkToLogger } from "../fork-Bga8x-X4.mjs";
|
|
3
|
+
import { t as createLoggerStorage } from "../storage-BNubsWwz.mjs";
|
|
4
4
|
import { createContext } from "react-router";
|
|
5
5
|
//#region src/react-router/index.ts
|
|
6
6
|
const { storage, useLogger } = createLoggerStorage("middleware context. Make sure the evlog middleware is added to your route.");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes-
|
|
1
|
+
{"version":3,"file":"routes-CnIgYWf8.mjs","names":[],"sources":["../src/shared/routes.ts"],"sourcesContent":["import type { RouteConfig } from '../types'\nimport { matchesPattern } from '../utils'\n\nexport function shouldLog(path: string, include?: string[], exclude?: string[]): boolean {\n // Check exclusions first (they take precedence)\n if (exclude && exclude.length > 0) {\n if (exclude.some(pattern => matchesPattern(path, pattern))) {\n return false\n }\n }\n\n // If no include patterns, log everything (that wasn't excluded)\n if (!include || include.length === 0) {\n return true\n }\n\n // Log only if path matches at least one include pattern\n return include.some(pattern => matchesPattern(path, pattern))\n}\n\n/**\n * Find the service name for a given path based on route patterns.\n *\n * When multiple patterns match the same path, the first matching pattern wins\n * based on object iteration order. To ensure predictable behavior, order your\n * route patterns from most specific to most general.\n *\n * @param path - The request path to match\n * @param routes - Route configuration mapping patterns to service names\n * @returns The service name for the matching route, or undefined if no match\n *\n * @example\n * ```ts\n * // Good: specific patterns first, general patterns last\n * routes: {\n * '/api/auth/admin/**': { service: 'admin-service' },\n * '/api/auth/**': { service: 'auth-service' },\n * '/api/**': { service: 'api-service' },\n * }\n * ```\n */\nexport function getServiceForPath(path: string, routes?: Record<string, RouteConfig>): string | undefined {\n if (!routes) return undefined\n\n for (const [pattern, config] of Object.entries(routes)) {\n if (matchesPattern(path, pattern)) {\n return config.service\n }\n }\n\n return undefined\n}\n"],"mappings":";;AAGA,SAAgB,UAAU,MAAc,SAAoB,SAA6B;AAEvF,KAAI,WAAW,QAAQ,SAAS;MAC1B,QAAQ,MAAK,YAAW,eAAe,MAAM,QAAQ,CAAC,CACxD,QAAO;;AAKX,KAAI,CAAC,WAAW,QAAQ,WAAW,EACjC,QAAO;AAIT,QAAO,QAAQ,MAAK,YAAW,eAAe,MAAM,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;AAwB/D,SAAgB,kBAAkB,MAAc,QAA0D;AACxG,KAAI,CAAC,OAAQ,QAAO,KAAA;AAEpB,MAAK,MAAM,CAAC,SAAS,WAAW,OAAO,QAAQ,OAAO,CACpD,KAAI,eAAe,MAAM,QAAQ,CAC/B,QAAO,OAAO"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { G as Log, K as LogLevel, st as TransportConfig } from "../../audit-DVdkntSO.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/runtime/client/log.d.ts
|
|
4
4
|
declare function setIdentity(identity: Record<string, unknown>): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as getEnvironment, y as getGlobalPluginRunner } from "../../../../audit-
|
|
1
|
+
import { _ as getEnvironment, y as getGlobalPluginRunner } from "../../../../audit-BUI3af4w.mjs";
|
|
2
2
|
import { filterSafeHeaders } from "../../../../utils.mjs";
|
|
3
3
|
import { createError, defineEventHandler, getHeader, getHeaders, getRequestHost, readBody, setResponseStatus } from "h3";
|
|
4
4
|
import { useNitroApp } from "nitropack/runtime";
|
|
@@ -9,6 +9,12 @@ const VALID_LEVELS = [
|
|
|
9
9
|
"warn",
|
|
10
10
|
"debug"
|
|
11
11
|
];
|
|
12
|
+
function isRecord(value) {
|
|
13
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
|
+
}
|
|
15
|
+
function isLogLevel(value) {
|
|
16
|
+
return VALID_LEVELS.includes(value);
|
|
17
|
+
}
|
|
12
18
|
function validateOrigin(event) {
|
|
13
19
|
const origin = getHeader(event, "origin");
|
|
14
20
|
const referer = getHeader(event, "referer");
|
|
@@ -30,16 +36,15 @@ function isValidISOTimestamp(value) {
|
|
|
30
36
|
return !Number.isNaN(date.getTime());
|
|
31
37
|
}
|
|
32
38
|
function validatePayload(body) {
|
|
33
|
-
if (!
|
|
39
|
+
if (!isRecord(body)) throw createError({
|
|
34
40
|
statusCode: 400,
|
|
35
41
|
message: "Invalid request body"
|
|
36
42
|
});
|
|
37
|
-
|
|
38
|
-
if (payload.timestamp === void 0 || payload.timestamp === null) throw createError({
|
|
43
|
+
if (body.timestamp === void 0 || body.timestamp === null) throw createError({
|
|
39
44
|
statusCode: 400,
|
|
40
45
|
message: "Missing required field: timestamp"
|
|
41
46
|
});
|
|
42
|
-
const { timestamp: rawTimestamp } =
|
|
47
|
+
const { timestamp: rawTimestamp } = body;
|
|
43
48
|
let timestamp;
|
|
44
49
|
if (typeof rawTimestamp === "number") {
|
|
45
50
|
const minTimestamp = (/* @__PURE__ */ new Date("2000-01-01")).getTime();
|
|
@@ -59,23 +64,35 @@ function validatePayload(body) {
|
|
|
59
64
|
statusCode: 400,
|
|
60
65
|
message: "Invalid timestamp: must be string or number"
|
|
61
66
|
});
|
|
62
|
-
if (!
|
|
67
|
+
if (!body.level || typeof body.level !== "string") throw createError({
|
|
63
68
|
statusCode: 400,
|
|
64
69
|
message: "Missing required field: level"
|
|
65
70
|
});
|
|
66
|
-
if (!
|
|
71
|
+
if (!isLogLevel(body.level)) throw createError({
|
|
67
72
|
statusCode: 400,
|
|
68
73
|
message: `Invalid level: must be one of ${VALID_LEVELS.join(", ")}`
|
|
69
74
|
});
|
|
70
75
|
return {
|
|
71
|
-
...
|
|
76
|
+
...body,
|
|
72
77
|
timestamp,
|
|
73
|
-
level:
|
|
78
|
+
level: body.level
|
|
74
79
|
};
|
|
75
80
|
}
|
|
76
81
|
function getSafeHeaders(event) {
|
|
77
82
|
return filterSafeHeaders(getHeaders(event));
|
|
78
83
|
}
|
|
84
|
+
function hasWaitUntil(value) {
|
|
85
|
+
return isRecord(value) && typeof value.waitUntil === "function";
|
|
86
|
+
}
|
|
87
|
+
/** Resolve platform waitUntil from Nitro event context (Cloudflare Workers, Vercel Edge). */
|
|
88
|
+
function resolveWaitUntilContext(event) {
|
|
89
|
+
if (!isRecord(event)) return void 0;
|
|
90
|
+
const { context } = event;
|
|
91
|
+
if (!isRecord(context)) return void 0;
|
|
92
|
+
const { cloudflare } = context;
|
|
93
|
+
if (isRecord(cloudflare) && isRecord(cloudflare.context)) return cloudflare.context;
|
|
94
|
+
return context;
|
|
95
|
+
}
|
|
79
96
|
var ingest_post_default = defineEventHandler(async (event) => {
|
|
80
97
|
validateOrigin(event);
|
|
81
98
|
const payload = validatePayload(await readBody(event));
|
|
@@ -120,9 +137,8 @@ var ingest_post_default = defineEventHandler(async (event) => {
|
|
|
120
137
|
})];
|
|
121
138
|
if (runner.hasDrain) drainTasks.push(runner.runDrain(drainCtx));
|
|
122
139
|
const drainPromise = Promise.all(drainTasks);
|
|
123
|
-
const waitUntilCtx = event
|
|
124
|
-
|
|
125
|
-
if (typeof cfCtx.waitUntil === "function") cfCtx.waitUntil(drainPromise);
|
|
140
|
+
const waitUntilCtx = resolveWaitUntilContext(event);
|
|
141
|
+
if (waitUntilCtx && hasWaitUntil(waitUntilCtx)) waitUntilCtx.waitUntil(drainPromise);
|
|
126
142
|
else await drainPromise;
|
|
127
143
|
setResponseStatus(event, 204);
|
|
128
144
|
return null;
|
|
@@ -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, getGlobalPluginRunner } 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 (!
|
|
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, getGlobalPluginRunner } from '../../../../logger'\nimport { filterSafeHeaders } from '../../../../utils'\n\nconst VALID_LEVELS = ['info', 'error', 'warn', 'debug'] as const\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction isLogLevel(value: string): value is IngestPayload['level'] {\n return (VALID_LEVELS as readonly string[]).includes(value)\n}\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 (!isRecord(body)) {\n throw createError({ statusCode: 400, message: 'Invalid request body' })\n }\n\n if (body.timestamp === undefined || body.timestamp === null) {\n throw createError({ statusCode: 400, message: 'Missing required field: timestamp' })\n }\n\n const { timestamp: rawTimestamp } = body\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 (!body.level || typeof body.level !== 'string') {\n throw createError({ statusCode: 400, message: 'Missing required field: level' })\n }\n\n if (!isLogLevel(body.level)) {\n throw createError({ statusCode: 400, message: `Invalid level: must be one of ${VALID_LEVELS.join(', ')}` })\n }\n\n return {\n ...body,\n timestamp,\n level: body.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\ninterface WaitUntilHost {\n waitUntil?: (promise: Promise<unknown>) => void\n}\n\nfunction hasWaitUntil(value: unknown): value is WaitUntilHost & { waitUntil: (promise: Promise<unknown>) => void } {\n return isRecord(value) && typeof value.waitUntil === 'function'\n}\n\n/** Resolve platform waitUntil from Nitro event context (Cloudflare Workers, Vercel Edge). */\nfunction resolveWaitUntilContext(event: unknown): WaitUntilHost | undefined {\n if (!isRecord(event)) return undefined\n const { context } = event\n if (!isRecord(context)) return undefined\n const { cloudflare } = context\n if (isRecord(cloudflare) && isRecord(cloudflare.context)) {\n return cloudflare.context\n }\n return context\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\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 const runner = getGlobalPluginRunner()\n\n if (runner.hasClientLog) {\n runner.runOnClientLog({\n payload,\n request,\n headers,\n })\n }\n\n const enrichCtx = {\n event: wideEvent,\n request,\n headers,\n response: { status: 204 },\n }\n try {\n await nitroApp.hooks.callHook('evlog:enrich', enrichCtx)\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n if (runner.hasEnrich) {\n await runner.runEnrich(enrichCtx)\n }\n\n const drainCtx = {\n event: wideEvent,\n request,\n headers,\n }\n const drainTasks: Array<Promise<unknown>> = [\n nitroApp.hooks.callHook('evlog:drain', drainCtx).catch((err) => {\n console.error('[evlog] drain failed:', err)\n }),\n ]\n if (runner.hasDrain) {\n drainTasks.push(runner.runDrain(drainCtx))\n }\n const drainPromise = Promise.all(drainTasks)\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 = resolveWaitUntilContext(event)\n if (waitUntilCtx && hasWaitUntil(waitUntilCtx)) {\n waitUntilCtx.waitUntil(drainPromise)\n } else {\n await drainPromise\n }\n\n setResponseStatus(event, 204)\n return null\n})\n"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as _$h3 from "h3";
|
|
2
|
+
|
|
3
|
+
//#region src/runtime/server/routes/_evlog/stream-info.get.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Discovery endpoint for the local evlog stream server. Reads
|
|
6
|
+
* `<cwd>/.evlog/stream.url` and returns the URL so a browser tab (or any
|
|
7
|
+
* other consumer that reaches the user's HTTP server) can find the
|
|
8
|
+
* mini-server's port without hard-coding it.
|
|
9
|
+
*
|
|
10
|
+
* Returns `{ url: null }` when the stream server isn't running — the
|
|
11
|
+
* consumer should treat that as "not available" and not error.
|
|
12
|
+
*/
|
|
13
|
+
declare const _default: _$h3.EventHandler<_$h3.EventHandlerRequest, Promise<{
|
|
14
|
+
url: string | null;
|
|
15
|
+
}>>;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { _default as default };
|
|
18
|
+
//# sourceMappingURL=stream-info.get.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-info.get.d.mts","names":[],"sources":["../../../../../src/runtime/server/routes/_evlog/stream-info.get.ts"],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { defineEventHandler, setResponseHeaders } from "h3";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
//#region src/runtime/server/routes/_evlog/stream-info.get.ts
|
|
5
|
+
/**
|
|
6
|
+
* Discovery endpoint for the local evlog stream server. Reads
|
|
7
|
+
* `<cwd>/.evlog/stream.url` and returns the URL so a browser tab (or any
|
|
8
|
+
* other consumer that reaches the user's HTTP server) can find the
|
|
9
|
+
* mini-server's port without hard-coding it.
|
|
10
|
+
*
|
|
11
|
+
* Returns `{ url: null }` when the stream server isn't running — the
|
|
12
|
+
* consumer should treat that as "not available" and not error.
|
|
13
|
+
*/
|
|
14
|
+
var stream_info_get_default = defineEventHandler(async (event) => {
|
|
15
|
+
setResponseHeaders(event, {
|
|
16
|
+
"Cache-Control": "no-store",
|
|
17
|
+
"Access-Control-Allow-Origin": "*"
|
|
18
|
+
});
|
|
19
|
+
try {
|
|
20
|
+
return { url: (await readFile(join(process.cwd(), ".evlog", "stream.url"), "utf-8")).trim() || null };
|
|
21
|
+
} catch {
|
|
22
|
+
return { url: null };
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
//#endregion
|
|
26
|
+
export { stream_info_get_default as default };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=stream-info.get.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-info.get.mjs","names":[],"sources":["../../../../../src/runtime/server/routes/_evlog/stream-info.get.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { defineEventHandler, setResponseHeaders } from 'h3'\n\n/**\n * Discovery endpoint for the local evlog stream server. Reads\n * `<cwd>/.evlog/stream.url` and returns the URL so a browser tab (or any\n * other consumer that reaches the user's HTTP server) can find the\n * mini-server's port without hard-coding it.\n *\n * Returns `{ url: null }` when the stream server isn't running — the\n * consumer should treat that as \"not available\" and not error.\n */\nexport default defineEventHandler(async (event) => {\n setResponseHeaders(event, {\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n })\n\n try {\n const path = join(process.cwd(), '.evlog', 'stream.url')\n const url = (await readFile(path, 'utf-8')).trim()\n return { url: url || null }\n } catch {\n return { url: null }\n }\n})\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAA,0BAAe,mBAAmB,OAAO,UAAU;AACjD,oBAAmB,OAAO;EACxB,iBAAiB;EACjB,+BAA+B;EAChC,CAAC;AAEF,KAAI;AAGF,SAAO,EAAE,MADI,MAAM,SADN,KAAK,QAAQ,KAAK,EAAE,UAAU,aACX,EAAE,QAAQ,EAAE,MAC3B,IAAI,MAAM;SACrB;AACN,SAAO,EAAE,KAAK,MAAM;;EAEtB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as useLogger } from "../../useLogger-
|
|
1
|
+
import { t as useLogger } from "../../useLogger-CqvH6qOf.mjs";
|
|
2
2
|
export { useLogger };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as parseError } from "../../parseError-
|
|
1
|
+
import { J as ParsedError } from "../../audit-DVdkntSO.mjs";
|
|
2
|
+
import { t as parseError } from "../../parseError-D4PIxEWo.mjs";
|
|
3
3
|
export { ParsedError, parseError };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"severity-
|
|
1
|
+
{"version":3,"file":"severity-R5Egq3qz.mjs","names":[],"sources":["../src/shared/severity.ts"],"sourcesContent":["import type { LogLevel } from '../types'\n\n/**\n * OpenTelemetry severity numbers per evlog log level.\n * @see https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber\n */\nexport const OTEL_SEVERITY_NUMBER: Record<LogLevel, number> = {\n debug: 5,\n info: 9,\n warn: 13,\n error: 17,\n}\n\nexport const OTEL_SEVERITY_TEXT: Record<LogLevel, string> = {\n debug: 'DEBUG',\n info: 'INFO',\n warn: 'WARN',\n error: 'ERROR',\n}\n"],"mappings":";;;;;AAMA,MAAa,uBAAiD;CAC5D,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACR;AAED,MAAa,qBAA+C;CAC1D,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACR"}
|
|
@@ -14,6 +14,7 @@ function createLoggerStorage(contextHint) {
|
|
|
14
14
|
function useLogger() {
|
|
15
15
|
const logger = storage.getStore();
|
|
16
16
|
if (!logger) throw new Error(`[evlog] useLogger() was called outside of an evlog ${contextHint}`);
|
|
17
|
+
/** @internal ALS store is untyped; cast satisfies the caller's generic `T`. */
|
|
17
18
|
return logger;
|
|
18
19
|
}
|
|
19
20
|
return {
|
|
@@ -24,4 +25,4 @@ function createLoggerStorage(contextHint) {
|
|
|
24
25
|
//#endregion
|
|
25
26
|
export { createLoggerStorage as t };
|
|
26
27
|
|
|
27
|
-
//# sourceMappingURL=storage-
|
|
28
|
+
//# sourceMappingURL=storage-BNubsWwz.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-
|
|
1
|
+
{"version":3,"file":"storage-BNubsWwz.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 matching `useLogger`\n * accessor. Every framework that exposes `useLogger()` (Express, Fastify,\n * NestJS, SvelteKit) calls this once at module level.\n *\n * @param contextHint - Appended to the error message when `useLogger()` is\n * called outside of a request, e.g. `\"middleware context. Make sure\n * app.use(evlog()) is registered before your routes.\"`.\n */\nexport function createLoggerStorage(contextHint: string) {\n const storage = new AsyncLocalStorage<RequestLogger>()\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 /** @internal ALS store is untyped; cast satisfies the caller's generic `T`. */\n return logger as RequestLogger<T>\n }\n\n return { storage, useLogger }\n}\n"],"mappings":";;;;;;;;;;;AAYA,SAAgB,oBAAoB,aAAqB;CACvD,MAAM,UAAU,IAAI,mBAAkC;CAEtD,SAAS,YAA0E;EACjF,MAAM,SAAS,QAAQ,UAAU;AACjC,MAAI,CAAC,OACH,OAAM,IAAI,MACR,sDAAsD,cACvD;;AAGH,SAAO;;AAGT,QAAO;EAAE;EAAS;EAAW"}
|