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
package/dist/adapters/fs.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as resolveAdapterConfig, t as defineDrain } from "../drain-7n3K6kPe.mjs";
|
|
2
2
|
import { join, sep } from "node:path";
|
|
3
|
-
import { appendFile, mkdir, readdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { appendFile, mkdir, open, readdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
4
|
+
import { createReadStream } from "node:fs";
|
|
5
|
+
import { createInterface } from "node:readline";
|
|
4
6
|
//#region src/adapters/fs.ts
|
|
5
7
|
const FS_FIELDS = [
|
|
6
8
|
{
|
|
@@ -112,7 +114,224 @@ function createFsDrain(overrides) {
|
|
|
112
114
|
send: writeBatchToFs
|
|
113
115
|
});
|
|
114
116
|
}
|
|
117
|
+
function isLogFilename(filename) {
|
|
118
|
+
return /^\d{4}-\d{2}-\d{2}(\.\d+)?\.jsonl$/.test(filename);
|
|
119
|
+
}
|
|
120
|
+
function compareLogFiles(a, b) {
|
|
121
|
+
const pa = parseLogFilename(a);
|
|
122
|
+
const pb = parseLogFilename(b);
|
|
123
|
+
return pa.date.localeCompare(pb.date) || pa.index - pb.index;
|
|
124
|
+
}
|
|
125
|
+
function normalizeTimestamp(value) {
|
|
126
|
+
if (!value) return void 0;
|
|
127
|
+
const ts = (value instanceof Date ? value : new Date(value)).getTime();
|
|
128
|
+
return Number.isNaN(ts) ? void 0 : ts;
|
|
129
|
+
}
|
|
130
|
+
function buildFilter(options) {
|
|
131
|
+
const since = normalizeTimestamp(options.since);
|
|
132
|
+
const until = normalizeTimestamp(options.until);
|
|
133
|
+
const levels = options.level ? new Set(Array.isArray(options.level) ? options.level : [options.level]) : void 0;
|
|
134
|
+
const custom = options.filter;
|
|
135
|
+
return (event) => {
|
|
136
|
+
if (levels && !levels.has(event.level)) return false;
|
|
137
|
+
if (since !== void 0 || until !== void 0) {
|
|
138
|
+
const ts = typeof event.timestamp === "string" ? Date.parse(event.timestamp) : NaN;
|
|
139
|
+
if (Number.isNaN(ts)) return false;
|
|
140
|
+
if (since !== void 0 && ts < since) return false;
|
|
141
|
+
if (until !== void 0 && ts > until) return false;
|
|
142
|
+
}
|
|
143
|
+
if (custom && !custom(event)) return false;
|
|
144
|
+
return true;
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async function listLogFiles(dir) {
|
|
148
|
+
let files;
|
|
149
|
+
try {
|
|
150
|
+
files = await readdir(dir);
|
|
151
|
+
} catch {
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
return files.filter(isLogFilename).sort(compareLogFiles);
|
|
155
|
+
}
|
|
156
|
+
function fileDateMs(filename) {
|
|
157
|
+
const { date } = parseLogFilename(filename);
|
|
158
|
+
return date ? Date.parse(`${date}T00:00:00.000Z`) : NaN;
|
|
159
|
+
}
|
|
160
|
+
function fileWithinRange(filename, since, until) {
|
|
161
|
+
if (since === void 0 && until === void 0) return true;
|
|
162
|
+
const dayStart = fileDateMs(filename);
|
|
163
|
+
if (Number.isNaN(dayStart)) return true;
|
|
164
|
+
const dayEnd = dayStart + 1440 * 60 * 1e3 - 1;
|
|
165
|
+
if (since !== void 0 && dayEnd < since) return false;
|
|
166
|
+
if (until !== void 0 && dayStart > until) return false;
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
async function* iterateFile(filePath) {
|
|
170
|
+
const stream = createReadStream(filePath, { encoding: "utf-8" });
|
|
171
|
+
const rl = createInterface({
|
|
172
|
+
input: stream,
|
|
173
|
+
crlfDelay: Infinity
|
|
174
|
+
});
|
|
175
|
+
try {
|
|
176
|
+
for await (const line of rl) {
|
|
177
|
+
const trimmed = line.trim();
|
|
178
|
+
if (!trimmed) continue;
|
|
179
|
+
try {
|
|
180
|
+
yield JSON.parse(trimmed);
|
|
181
|
+
} catch {}
|
|
182
|
+
}
|
|
183
|
+
} finally {
|
|
184
|
+
rl.close();
|
|
185
|
+
stream.destroy();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Read past events from the local file system drain (NDJSON). Files are
|
|
190
|
+
* iterated in chronological order; events are yielded as they appear in
|
|
191
|
+
* each file.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* import { readFsLogs } from 'evlog/fs'
|
|
196
|
+
*
|
|
197
|
+
* for await (const event of readFsLogs({ since: '2026-01-01', level: 'error' })) {
|
|
198
|
+
* console.log(event)
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
async function* readFsLogs(options = {}) {
|
|
203
|
+
const dir = options.dir ?? ".evlog/logs";
|
|
204
|
+
const sinceMs = normalizeTimestamp(options.since);
|
|
205
|
+
const untilMs = normalizeTimestamp(options.until);
|
|
206
|
+
const predicate = buildFilter(options);
|
|
207
|
+
const files = await listLogFiles(dir);
|
|
208
|
+
for (const filename of files) {
|
|
209
|
+
if (!fileWithinRange(filename, sinceMs, untilMs)) continue;
|
|
210
|
+
for await (const event of iterateFile(join(dir, filename))) if (predicate(event)) yield event;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function safeStatSize(filePath) {
|
|
214
|
+
try {
|
|
215
|
+
return (await stat(filePath)).size;
|
|
216
|
+
} catch {
|
|
217
|
+
return 0;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async function readAppendedLines(filePath, fromOffset, carry) {
|
|
221
|
+
const size = await safeStatSize(filePath);
|
|
222
|
+
if (size <= fromOffset) return {
|
|
223
|
+
events: [],
|
|
224
|
+
offset: fromOffset,
|
|
225
|
+
carry
|
|
226
|
+
};
|
|
227
|
+
const handle = await open(filePath, "r");
|
|
228
|
+
try {
|
|
229
|
+
const length = size - fromOffset;
|
|
230
|
+
const buf = Buffer.alloc(length);
|
|
231
|
+
await handle.read(buf, 0, length, fromOffset);
|
|
232
|
+
const chunk = carry + buf.toString("utf-8");
|
|
233
|
+
const newlineIdx = chunk.lastIndexOf("\n");
|
|
234
|
+
if (newlineIdx === -1) return {
|
|
235
|
+
events: [],
|
|
236
|
+
offset: size,
|
|
237
|
+
carry: chunk
|
|
238
|
+
};
|
|
239
|
+
const complete = chunk.slice(0, newlineIdx);
|
|
240
|
+
const remainder = chunk.slice(newlineIdx + 1);
|
|
241
|
+
return {
|
|
242
|
+
events: complete.split("\n").map((l) => l.trim()).filter(Boolean),
|
|
243
|
+
offset: size,
|
|
244
|
+
carry: remainder
|
|
245
|
+
};
|
|
246
|
+
} finally {
|
|
247
|
+
await handle.close();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function delay(ms, signal) {
|
|
251
|
+
return new Promise((resolve) => {
|
|
252
|
+
const timer = setTimeout(() => {
|
|
253
|
+
if (signal) signal.removeEventListener("abort", onAbort);
|
|
254
|
+
resolve();
|
|
255
|
+
}, ms);
|
|
256
|
+
const onAbort = () => {
|
|
257
|
+
clearTimeout(timer);
|
|
258
|
+
resolve();
|
|
259
|
+
};
|
|
260
|
+
if (signal) {
|
|
261
|
+
if (signal.aborted) {
|
|
262
|
+
clearTimeout(timer);
|
|
263
|
+
resolve();
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Follow the local file system drain in real time. Yields existing events
|
|
272
|
+
* (unless `fromEnd: true`) then keeps yielding new events as they are
|
|
273
|
+
* appended. Automatically picks up newly created daily files.
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```ts
|
|
277
|
+
* import { tailFsLogs } from 'evlog/fs'
|
|
278
|
+
*
|
|
279
|
+
* const ac = new AbortController()
|
|
280
|
+
* setTimeout(() => ac.abort(), 60_000)
|
|
281
|
+
*
|
|
282
|
+
* for await (const event of tailFsLogs({ signal: ac.signal })) {
|
|
283
|
+
* console.log('live:', event.action ?? event.message)
|
|
284
|
+
* }
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
async function* tailFsLogs(options = {}) {
|
|
288
|
+
const dir = options.dir ?? ".evlog/logs";
|
|
289
|
+
const interval = Math.max(50, options.pollIntervalMs ?? 500);
|
|
290
|
+
const { signal } = options;
|
|
291
|
+
const predicate = buildFilter(options);
|
|
292
|
+
const offsets = /* @__PURE__ */ new Map();
|
|
293
|
+
const carries = /* @__PURE__ */ new Map();
|
|
294
|
+
if (options.fromEnd) {
|
|
295
|
+
const files = await listLogFiles(dir);
|
|
296
|
+
for (const filename of files) {
|
|
297
|
+
offsets.set(filename, await safeStatSize(join(dir, filename)));
|
|
298
|
+
carries.set(filename, "");
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
for await (const event of readFsLogs(options)) {
|
|
302
|
+
if (signal?.aborted) return;
|
|
303
|
+
yield event;
|
|
304
|
+
}
|
|
305
|
+
const files = await listLogFiles(dir);
|
|
306
|
+
for (const filename of files) if (!offsets.has(filename)) {
|
|
307
|
+
offsets.set(filename, await safeStatSize(join(dir, filename)));
|
|
308
|
+
carries.set(filename, "");
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
while (true) {
|
|
312
|
+
if (signal?.aborted) return;
|
|
313
|
+
await delay(interval, signal);
|
|
314
|
+
if (signal?.aborted) return;
|
|
315
|
+
const files = await listLogFiles(dir);
|
|
316
|
+
for (const filename of files) {
|
|
317
|
+
if (!offsets.has(filename)) {
|
|
318
|
+
offsets.set(filename, 0);
|
|
319
|
+
carries.set(filename, "");
|
|
320
|
+
}
|
|
321
|
+
const { events, offset, carry: newCarry } = await readAppendedLines(join(dir, filename), offsets.get(filename), carries.get(filename) ?? "");
|
|
322
|
+
offsets.set(filename, offset);
|
|
323
|
+
carries.set(filename, newCarry);
|
|
324
|
+
for (const line of events) {
|
|
325
|
+
if (signal?.aborted) return;
|
|
326
|
+
try {
|
|
327
|
+
const event = JSON.parse(line);
|
|
328
|
+
if (predicate(event)) yield event;
|
|
329
|
+
} catch {}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
115
334
|
//#endregion
|
|
116
|
-
export { createFsDrain, writeBatchToFs, writeToFs };
|
|
335
|
+
export { createFsDrain, readFsLogs, tailFsLogs, writeBatchToFs, writeToFs };
|
|
117
336
|
|
|
118
337
|
//# sourceMappingURL=fs.mjs.map
|
package/dist/adapters/fs.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.mjs","names":[],"sources":["../../src/adapters/fs.ts"],"sourcesContent":["import { appendFile, mkdir, readdir, stat, unlink, writeFile } from 'node:fs/promises'\nimport { join, sep } from 'node:path'\nimport type { WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { resolveAdapterConfig } from '../shared/config'\nimport { defineDrain } from '../shared/drain'\n\nexport interface FsConfig {\n /** Directory for log files. Default: `.evlog/logs` */\n dir: string\n /** Max number of log files to keep (auto-deletes oldest when exceeded) */\n maxFiles?: number\n /** Max bytes per file before rotating to a new suffixed file */\n maxSizePerFile?: number\n /** Pretty-print JSON instead of compact NDJSON */\n pretty: boolean\n}\n\nconst FS_FIELDS: ConfigField<FsConfig>[] = [\n { key: 'dir', env: ['NUXT_EVLOG_FS_DIR', 'EVLOG_FS_DIR'] },\n { key: 'maxFiles' },\n { key: 'maxSizePerFile' },\n { key: 'pretty' },\n]\n\nconst gitignoreWritten = new Set<string>()\n\nasync function ensureGitignore(dir: string): Promise<void> {\n const normalized = dir.replace(/[\\\\/]/g, sep)\n const segments = normalized.split(sep)\n const evlogIndex = segments.findIndex(s => s === '.evlog')\n const targetDir = evlogIndex !== -1 ? segments.slice(0, evlogIndex + 1).join(sep) : dir\n\n if (gitignoreWritten.has(targetDir)) return\n\n const gitignorePath = join(targetDir, '.gitignore')\n try {\n await stat(gitignorePath)\n } catch {\n await writeFile(gitignorePath, '*\\n', 'utf-8')\n }\n gitignoreWritten.add(targetDir)\n}\n\nfunction getDateString(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\nasync function resolveFilePath(dir: string, maxSizePerFile?: number): Promise<string> {\n const date = getDateString()\n const basePath = join(dir, `${date}.jsonl`)\n\n if (!maxSizePerFile) return basePath\n\n try {\n const stats = await stat(basePath)\n if (stats.size < maxSizePerFile) return basePath\n } catch {\n return basePath\n }\n\n for (let i = 1; i < 1000; i++) {\n const rotatedPath = join(dir, `${date}.${i}.jsonl`)\n try {\n const stats = await stat(rotatedPath)\n if (stats.size < maxSizePerFile) return rotatedPath\n } catch {\n return rotatedPath\n }\n }\n\n return join(dir, `${date}.999.jsonl`)\n}\n\nfunction parseLogFilename(filename: string): { date: string; index: number } {\n const match = filename.match(/^(\\d{4}-\\d{2}-\\d{2})(?:\\.(\\d+))?\\.jsonl$/)\n if (!match) return { date: '', index: 0 }\n return { date: match[1], index: match[2] ? Number.parseInt(match[2], 10) : 0 }\n}\n\nasync function cleanupOldFiles(dir: string, maxFiles: number): Promise<void> {\n const files = await readdir(dir)\n const jsonlFiles = files.filter(f => f.endsWith('.jsonl')).sort((a, b) => {\n const pa = parseLogFilename(a)\n const pb = parseLogFilename(b)\n return pa.date.localeCompare(pb.date) || pa.index - pb.index\n })\n\n if (jsonlFiles.length <= maxFiles) return\n\n const toDelete = jsonlFiles.slice(0, jsonlFiles.length - maxFiles)\n await Promise.allSettled(toDelete.map(f => unlink(join(dir, f))))\n}\n\nexport async function writeToFs(event: WideEvent, config: FsConfig): Promise<void> {\n await writeBatchToFs([event], config)\n}\n\nexport async function writeBatchToFs(events: WideEvent[], config: FsConfig): Promise<void> {\n if (events.length === 0) return\n\n await mkdir(config.dir, { recursive: true })\n await ensureGitignore(config.dir)\n\n const filePath = await resolveFilePath(config.dir, config.maxSizePerFile)\n const lines = `${events\n .map(e => config.pretty ? JSON.stringify(e, null, 2) : JSON.stringify(e))\n .join('\\n') }\\n`\n\n await appendFile(filePath, lines, 'utf-8')\n\n if (config.maxFiles) {\n await cleanupOldFiles(config.dir, config.maxFiles)\n }\n}\n\n/**\n * Create a drain function that writes logs to the local file system as NDJSON.\n *\n * Files are organized by date (`2026-03-14.jsonl`) with optional size-based\n * rotation and automatic cleanup of old files.\n *\n * @example\n * ```ts\n * // Default: writes to .evlog/logs/\n * nitroApp.hooks.hook('evlog:drain', createFsDrain())\n *\n * // With options\n * nitroApp.hooks.hook('evlog:drain', createFsDrain({\n * dir: '.evlog/logs',\n * maxFiles: 7,\n * pretty: true,\n * }))\n * ```\n */\nexport function createFsDrain(overrides?: Partial<FsConfig>) {\n return defineDrain<FsConfig>({\n name: 'fs',\n resolve: async () => {\n const resolved = await resolveAdapterConfig<FsConfig>('fs', FS_FIELDS, overrides)\n return {\n dir: resolved.dir ?? '.evlog/logs',\n pretty: resolved.pretty ?? false,\n maxFiles: resolved.maxFiles,\n maxSizePerFile: resolved.maxSizePerFile,\n }\n },\n send: writeBatchToFs,\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fs.mjs","names":[],"sources":["../../src/adapters/fs.ts"],"sourcesContent":["import { createReadStream } from 'node:fs'\nimport { appendFile, mkdir, open, readdir, stat, unlink, writeFile } from 'node:fs/promises'\nimport { join, sep } from 'node:path'\nimport { createInterface } from 'node:readline'\nimport type { LogLevel, WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { resolveAdapterConfig } from '../shared/config'\nimport { defineDrain } from '../shared/drain'\n\nexport interface FsConfig {\n /** Directory for log files. Default: `.evlog/logs` */\n dir: string\n /** Max number of log files to keep (auto-deletes oldest when exceeded) */\n maxFiles?: number\n /** Max bytes per file before rotating to a new suffixed file */\n maxSizePerFile?: number\n /** Pretty-print JSON instead of compact NDJSON */\n pretty: boolean\n}\n\nconst FS_FIELDS: ConfigField<FsConfig>[] = [\n { key: 'dir', env: ['NUXT_EVLOG_FS_DIR', 'EVLOG_FS_DIR'] },\n { key: 'maxFiles' },\n { key: 'maxSizePerFile' },\n { key: 'pretty' },\n]\n\nconst gitignoreWritten = new Set<string>()\n\nasync function ensureGitignore(dir: string): Promise<void> {\n const normalized = dir.replace(/[\\\\/]/g, sep)\n const segments = normalized.split(sep)\n const evlogIndex = segments.findIndex(s => s === '.evlog')\n const targetDir = evlogIndex !== -1 ? segments.slice(0, evlogIndex + 1).join(sep) : dir\n\n if (gitignoreWritten.has(targetDir)) return\n\n const gitignorePath = join(targetDir, '.gitignore')\n try {\n await stat(gitignorePath)\n } catch {\n await writeFile(gitignorePath, '*\\n', 'utf-8')\n }\n gitignoreWritten.add(targetDir)\n}\n\nfunction getDateString(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\nasync function resolveFilePath(dir: string, maxSizePerFile?: number): Promise<string> {\n const date = getDateString()\n const basePath = join(dir, `${date}.jsonl`)\n\n if (!maxSizePerFile) return basePath\n\n try {\n const stats = await stat(basePath)\n if (stats.size < maxSizePerFile) return basePath\n } catch {\n return basePath\n }\n\n for (let i = 1; i < 1000; i++) {\n const rotatedPath = join(dir, `${date}.${i}.jsonl`)\n try {\n const stats = await stat(rotatedPath)\n if (stats.size < maxSizePerFile) return rotatedPath\n } catch {\n return rotatedPath\n }\n }\n\n return join(dir, `${date}.999.jsonl`)\n}\n\nfunction parseLogFilename(filename: string): { date: string; index: number } {\n const match = filename.match(/^(\\d{4}-\\d{2}-\\d{2})(?:\\.(\\d+))?\\.jsonl$/)\n if (!match) return { date: '', index: 0 }\n return { date: match[1], index: match[2] ? Number.parseInt(match[2], 10) : 0 }\n}\n\nasync function cleanupOldFiles(dir: string, maxFiles: number): Promise<void> {\n const files = await readdir(dir)\n const jsonlFiles = files.filter(f => f.endsWith('.jsonl')).sort((a, b) => {\n const pa = parseLogFilename(a)\n const pb = parseLogFilename(b)\n return pa.date.localeCompare(pb.date) || pa.index - pb.index\n })\n\n if (jsonlFiles.length <= maxFiles) return\n\n const toDelete = jsonlFiles.slice(0, jsonlFiles.length - maxFiles)\n await Promise.allSettled(toDelete.map(f => unlink(join(dir, f))))\n}\n\nexport async function writeToFs(event: WideEvent, config: FsConfig): Promise<void> {\n await writeBatchToFs([event], config)\n}\n\nexport async function writeBatchToFs(events: WideEvent[], config: FsConfig): Promise<void> {\n if (events.length === 0) return\n\n await mkdir(config.dir, { recursive: true })\n await ensureGitignore(config.dir)\n\n const filePath = await resolveFilePath(config.dir, config.maxSizePerFile)\n const lines = `${events\n .map(e => config.pretty ? JSON.stringify(e, null, 2) : JSON.stringify(e))\n .join('\\n') }\\n`\n\n await appendFile(filePath, lines, 'utf-8')\n\n if (config.maxFiles) {\n await cleanupOldFiles(config.dir, config.maxFiles)\n }\n}\n\n/**\n * Create a drain function that writes logs to the local file system as NDJSON.\n *\n * Files are organized by date (`2026-03-14.jsonl`) with optional size-based\n * rotation and automatic cleanup of old files.\n *\n * @example\n * ```ts\n * // Default: writes to .evlog/logs/\n * nitroApp.hooks.hook('evlog:drain', createFsDrain())\n *\n * // With options\n * nitroApp.hooks.hook('evlog:drain', createFsDrain({\n * dir: '.evlog/logs',\n * maxFiles: 7,\n * pretty: true,\n * }))\n * ```\n */\nexport function createFsDrain(overrides?: Partial<FsConfig>) {\n return defineDrain<FsConfig>({\n name: 'fs',\n resolve: async () => {\n const resolved = await resolveAdapterConfig<FsConfig>('fs', FS_FIELDS, overrides)\n return {\n dir: resolved.dir ?? '.evlog/logs',\n pretty: resolved.pretty ?? false,\n maxFiles: resolved.maxFiles,\n maxSizePerFile: resolved.maxSizePerFile,\n }\n },\n send: writeBatchToFs,\n })\n}\n\n/** Options accepted by {@link readFsLogs}. */\nexport interface ReadFsLogsOptions {\n /** Directory to read from. Default: `.evlog/logs` */\n dir?: string\n /** Only yield events with `event.timestamp >= since`. */\n since?: Date | string\n /** Only yield events with `event.timestamp <= until`. */\n until?: Date | string\n /** Filter by event level. */\n level?: LogLevel | LogLevel[]\n /** Custom predicate — return `false` to skip the event. */\n filter?: (event: WideEvent) => boolean\n}\n\n/** Options accepted by {@link tailFsLogs}. */\nexport interface TailFsLogsOptions extends ReadFsLogsOptions {\n /**\n * Polling interval (ms) used to detect new bytes / new files.\n * @default 500\n */\n pollIntervalMs?: number\n /**\n * Skip existing events and only yield events appended after the tailer\n * starts. Useful for \"live tail\" UX.\n * @default false\n */\n fromEnd?: boolean\n /** Stop tailing when this signal aborts. */\n signal?: AbortSignal\n}\n\ninterface ParsedFilename {\n date: string\n index: number\n}\n\nfunction isLogFilename(filename: string): boolean {\n return /^\\d{4}-\\d{2}-\\d{2}(\\.\\d+)?\\.jsonl$/.test(filename)\n}\n\nfunction compareLogFiles(a: string, b: string): number {\n const pa = parseLogFilename(a)\n const pb = parseLogFilename(b)\n return pa.date.localeCompare(pb.date) || pa.index - pb.index\n}\n\nfunction normalizeTimestamp(value: Date | string | undefined): number | undefined {\n if (!value) return undefined\n const date = value instanceof Date ? value : new Date(value)\n const ts = date.getTime()\n return Number.isNaN(ts) ? undefined : ts\n}\n\nfunction buildFilter(options: ReadFsLogsOptions): (event: WideEvent) => boolean {\n const since = normalizeTimestamp(options.since)\n const until = normalizeTimestamp(options.until)\n const levels = options.level\n ? new Set<LogLevel>(Array.isArray(options.level) ? options.level : [options.level])\n : undefined\n const custom = options.filter\n\n return (event: WideEvent) => {\n if (levels && !levels.has(event.level)) return false\n if (since !== undefined || until !== undefined) {\n const ts = typeof event.timestamp === 'string' ? Date.parse(event.timestamp) : Number.NaN\n if (Number.isNaN(ts)) return false\n if (since !== undefined && ts < since) return false\n if (until !== undefined && ts > until) return false\n }\n if (custom && !custom(event)) return false\n return true\n }\n}\n\nasync function listLogFiles(dir: string): Promise<string[]> {\n let files: string[]\n try {\n files = await readdir(dir)\n } catch {\n return []\n }\n return files.filter(isLogFilename).sort(compareLogFiles)\n}\n\nfunction fileDateMs(filename: string): number {\n const { date } = parseLogFilename(filename)\n return date ? Date.parse(`${date}T00:00:00.000Z`) : Number.NaN\n}\n\nfunction fileWithinRange(filename: string, since?: number, until?: number): boolean {\n if (since === undefined && until === undefined) return true\n const dayStart = fileDateMs(filename)\n if (Number.isNaN(dayStart)) return true\n const dayEnd = dayStart + 24 * 60 * 60 * 1000 - 1\n if (since !== undefined && dayEnd < since) return false\n if (until !== undefined && dayStart > until) return false\n return true\n}\n\nasync function* iterateFile(filePath: string): AsyncGenerator<WideEvent> {\n const stream = createReadStream(filePath, { encoding: 'utf-8' })\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n try {\n for await (const line of rl) {\n const trimmed = line.trim()\n if (!trimmed) continue\n try {\n yield JSON.parse(trimmed) as WideEvent\n } catch {\n // Skip malformed lines (partial writes, manual edits) silently.\n }\n }\n } finally {\n rl.close()\n stream.destroy()\n }\n}\n\n/**\n * Read past events from the local file system drain (NDJSON). Files are\n * iterated in chronological order; events are yielded as they appear in\n * each file.\n *\n * @example\n * ```ts\n * import { readFsLogs } from 'evlog/fs'\n *\n * for await (const event of readFsLogs({ since: '2026-01-01', level: 'error' })) {\n * console.log(event)\n * }\n * ```\n */\nexport async function* readFsLogs(options: ReadFsLogsOptions = {}): AsyncGenerator<WideEvent> {\n const dir = options.dir ?? '.evlog/logs'\n const sinceMs = normalizeTimestamp(options.since)\n const untilMs = normalizeTimestamp(options.until)\n const predicate = buildFilter(options)\n\n const files = await listLogFiles(dir)\n for (const filename of files) {\n if (!fileWithinRange(filename, sinceMs, untilMs)) continue\n for await (const event of iterateFile(join(dir, filename))) {\n if (predicate(event)) yield event\n }\n }\n}\n\nasync function safeStatSize(filePath: string): Promise<number> {\n try {\n const s = await stat(filePath)\n return s.size\n } catch {\n return 0\n }\n}\n\nasync function readAppendedLines(\n filePath: string,\n fromOffset: number,\n carry: string,\n): Promise<{ events: string[]; offset: number; carry: string }> {\n const size = await safeStatSize(filePath)\n if (size <= fromOffset) return { events: [], offset: fromOffset, carry }\n\n const handle = await open(filePath, 'r')\n try {\n const length = size - fromOffset\n const buf = Buffer.alloc(length)\n await handle.read(buf, 0, length, fromOffset)\n const chunk = carry + buf.toString('utf-8')\n const newlineIdx = chunk.lastIndexOf('\\n')\n if (newlineIdx === -1) {\n return { events: [], offset: size, carry: chunk }\n }\n const complete = chunk.slice(0, newlineIdx)\n const remainder = chunk.slice(newlineIdx + 1)\n const lines = complete.split('\\n').map(l => l.trim()).filter(Boolean)\n return { events: lines, offset: size, carry: remainder }\n } finally {\n await handle.close()\n }\n}\n\nfunction delay(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n if (signal) signal.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n const onAbort = () => {\n clearTimeout(timer)\n resolve()\n }\n if (signal) {\n if (signal.aborted) {\n clearTimeout(timer)\n resolve()\n return\n }\n signal.addEventListener('abort', onAbort, { once: true })\n }\n })\n}\n\n/**\n * Follow the local file system drain in real time. Yields existing events\n * (unless `fromEnd: true`) then keeps yielding new events as they are\n * appended. Automatically picks up newly created daily files.\n *\n * @example\n * ```ts\n * import { tailFsLogs } from 'evlog/fs'\n *\n * const ac = new AbortController()\n * setTimeout(() => ac.abort(), 60_000)\n *\n * for await (const event of tailFsLogs({ signal: ac.signal })) {\n * console.log('live:', event.action ?? event.message)\n * }\n * ```\n */\nexport async function* tailFsLogs(options: TailFsLogsOptions = {}): AsyncGenerator<WideEvent> {\n const dir = options.dir ?? '.evlog/logs'\n const interval = Math.max(50, options.pollIntervalMs ?? 500)\n const { signal } = options\n const predicate = buildFilter(options)\n\n const offsets = new Map<string, number>()\n const carries = new Map<string, string>()\n\n if (options.fromEnd) {\n const files = await listLogFiles(dir)\n for (const filename of files) {\n offsets.set(filename, await safeStatSize(join(dir, filename)))\n carries.set(filename, '')\n }\n } else {\n for await (const event of readFsLogs(options)) {\n if (signal?.aborted) return\n yield event\n }\n const files = await listLogFiles(dir)\n for (const filename of files) {\n if (!offsets.has(filename)) {\n offsets.set(filename, await safeStatSize(join(dir, filename)))\n carries.set(filename, '')\n }\n }\n }\n\n while (true) {\n if (signal?.aborted) return\n await delay(interval, signal)\n if (signal?.aborted) return\n\n const files = await listLogFiles(dir)\n\n for (const filename of files) {\n if (!offsets.has(filename)) {\n offsets.set(filename, 0)\n carries.set(filename, '')\n }\n const filePath = join(dir, filename)\n const fromOffset = offsets.get(filename)!\n const carry = carries.get(filename) ?? ''\n const { events, offset, carry: newCarry } = await readAppendedLines(filePath, fromOffset, carry)\n offsets.set(filename, offset)\n carries.set(filename, newCarry)\n\n for (const line of events) {\n if (signal?.aborted) return\n try {\n const event = JSON.parse(line) as WideEvent\n if (predicate(event)) yield event\n } catch {\n // Skip malformed lines.\n }\n }\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { I as DrainContext, K as LogLevel, ct as WideEvent } from "../audit-DVdkntSO.mjs";
|
|
2
|
+
//#region src/adapters/memory.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for the in-memory drain.
|
|
5
|
+
*/
|
|
6
|
+
interface MemoryConfig {
|
|
7
|
+
/** Named store key. Multiple drains sharing the same key share the same buffer. Default: `'default'` */
|
|
8
|
+
store: string;
|
|
9
|
+
/** Maximum number of events to keep in the ring buffer. Oldest events are discarded when the limit is exceeded. Default: `1000` */
|
|
10
|
+
maxEvents: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Write events directly into the named store. Exported for direct use and
|
|
14
|
+
* easier testing without going through the drain pipeline.
|
|
15
|
+
*/
|
|
16
|
+
declare function writeToMemory(events: WideEvent[], config: MemoryConfig): void;
|
|
17
|
+
/**
|
|
18
|
+
* Create a drain that stores wide events in an in-memory ring buffer.
|
|
19
|
+
*
|
|
20
|
+
* Works in **any** runtime — including Cloudflare Workers (workerd) — where
|
|
21
|
+
* the filesystem (`evlog/fs`) is not available. Pair it with a dev-only HTTP
|
|
22
|
+
* endpoint to let agents retrieve the buffer over HTTP.
|
|
23
|
+
*
|
|
24
|
+
* Configuration priority (highest to lowest):
|
|
25
|
+
* 1. Overrides passed to `createMemoryDrain()`
|
|
26
|
+
* 2. `runtimeConfig.evlog.memory` / `runtimeConfig.memory` (Nitro)
|
|
27
|
+
* 3. Environment variables: `NUXT_EVLOG_MEMORY_STORE`, `EVLOG_MEMORY_STORE`,
|
|
28
|
+
* `NUXT_EVLOG_MEMORY_MAX_EVENTS`, `EVLOG_MEMORY_MAX_EVENTS`
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* // Hono + Cloudflare Workers
|
|
33
|
+
* import { createMemoryDrain, readMemoryLogs } from 'evlog/memory'
|
|
34
|
+
*
|
|
35
|
+
* app.use(evlog({ drain: createMemoryDrain() }))
|
|
36
|
+
*
|
|
37
|
+
* // Dev-only endpoint for agent retrieval
|
|
38
|
+
* if (env.NODE_ENV === 'development') {
|
|
39
|
+
* app.get('/_evlog/logs', (c) => c.json(readMemoryLogs()))
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
declare function createMemoryDrain(overrides?: Partial<MemoryConfig>): (ctx: DrainContext | DrainContext[]) => Promise<void>;
|
|
44
|
+
/** Options accepted by {@link readMemoryLogs}. */
|
|
45
|
+
interface ReadMemoryLogsOptions {
|
|
46
|
+
/** Named store to read from. Default: `'default'` */
|
|
47
|
+
store?: string;
|
|
48
|
+
/** Only include events with `timestamp >= since`. */
|
|
49
|
+
since?: Date | string;
|
|
50
|
+
/** Only include events with `timestamp <= until`. */
|
|
51
|
+
until?: Date | string;
|
|
52
|
+
/** Filter by log level. */
|
|
53
|
+
level?: LogLevel | LogLevel[];
|
|
54
|
+
/** Custom predicate — return `false` to skip the event. */
|
|
55
|
+
filter?: (event: WideEvent) => boolean;
|
|
56
|
+
/** Return at most this many of the most-recent matching events. */
|
|
57
|
+
limit?: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Read events from the named in-memory store. Returns a snapshot of the
|
|
61
|
+
* buffer with optional filtering, ordered oldest-first.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* import { readMemoryLogs } from 'evlog/memory'
|
|
66
|
+
*
|
|
67
|
+
* // All events
|
|
68
|
+
* const events = readMemoryLogs()
|
|
69
|
+
*
|
|
70
|
+
* // Errors in the last hour
|
|
71
|
+
* const errors = readMemoryLogs({
|
|
72
|
+
* level: 'error',
|
|
73
|
+
* since: new Date(Date.now() - 60 * 60 * 1000),
|
|
74
|
+
* })
|
|
75
|
+
*
|
|
76
|
+
* // Expose as a JSON endpoint
|
|
77
|
+
* app.get('/_evlog/logs', (c) => c.json(readMemoryLogs({ limit: 200 })))
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function readMemoryLogs(options?: ReadMemoryLogsOptions): WideEvent[];
|
|
81
|
+
/**
|
|
82
|
+
* Clear all events from a named store (or `'default'`).
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* clearMemoryLogs() // clears the default store
|
|
87
|
+
* clearMemoryLogs('my-store') // clears a named store
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare function clearMemoryLogs(store?: string): void;
|
|
91
|
+
/**
|
|
92
|
+
* Parse a flat query-string object (e.g. from `c.req.query()` in Hono, or
|
|
93
|
+
* `req.query` in Express) into {@link ReadMemoryLogsOptions} with proper type
|
|
94
|
+
* coercion.
|
|
95
|
+
*
|
|
96
|
+
* This lets agents discover and pass filter parameters through HTTP query
|
|
97
|
+
* strings directly:
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* // Hono — zero glue
|
|
102
|
+
* app.get('/_evlog/logs', (c) =>
|
|
103
|
+
* c.json(readMemoryLogs(parseReadMemoryLogsQuery(c.req.query()))))
|
|
104
|
+
*
|
|
105
|
+
* // Express
|
|
106
|
+
* app.get('/_evlog/logs', (req, res) =>
|
|
107
|
+
* res.json(readMemoryLogs(parseReadMemoryLogsQuery(req.query as Record<string, string>))))
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* Supported query params: `store`, `since`, `until`, `level` (comma-separated),
|
|
111
|
+
* `limit`. The `filter` predicate cannot be expressed as a query param.
|
|
112
|
+
*/
|
|
113
|
+
declare function parseReadMemoryLogsQuery(query: Record<string, string | string[] | undefined>): ReadMemoryLogsOptions;
|
|
114
|
+
//#endregion
|
|
115
|
+
export { MemoryConfig, ReadMemoryLogsOptions, clearMemoryLogs, createMemoryDrain, parseReadMemoryLogsQuery, readMemoryLogs, writeToMemory };
|
|
116
|
+
//# sourceMappingURL=memory.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.mts","names":[],"sources":["../../src/adapters/memory.ts"],"mappings":";;;;;UAQiB,YAAA;EAAY;EAE3B,KAAA;EAAA;EAEA,SAAA;AAAA;;;;;iBA2Cc,aAAA,CAAc,MAAA,EAAQ,SAAA,IAAa,MAAA,EAAQ,YAAA;;;;;AAmC3D;;;;;;;;;;;;;;;;;;;AAYA;;;iBAZgB,iBAAA,CAAkB,SAAA,GAAY,OAAA,CAAQ,YAAA,KAAa,GAAA,EAAd,YAAA,GAAc,YAAA,OAAA,OAAA;;UAYlD,qBAAA;EAQI;EANnB,KAAA;EAQ0B;EAN1B,KAAA,GAAQ,IAAA;EAFR;EAIA,KAAA,GAAQ,IAAA;EAFA;EAIR,KAAA,GAAQ,QAAA,GAAW,QAAA;EAFX;EAIR,MAAA,IAAU,KAAA,EAAO,SAAA;EAFT;EAIR,KAAA;AAAA;;;;;;AA+BF;;;;;;;;;AAuCA;;;;;AA6BA;;iBApEgB,cAAA,CAAe,OAAA,GAAS,qBAAA,GAA6B,SAAA;;;;;;;;;;iBAuCrD,eAAA,CAAgB,KAAA;;;;;;;;;;;;;;;;;;;;;;;iBA6BhB,wBAAA,CACd,KAAA,EAAO,MAAA,0CACN,qBAAA"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { i as resolveAdapterConfig, t as defineDrain } from "../drain-7n3K6kPe.mjs";
|
|
2
|
+
//#region src/adapters/memory.ts
|
|
3
|
+
const DEFAULT_STORE = "default";
|
|
4
|
+
const DEFAULT_MAX_EVENTS = 1e3;
|
|
5
|
+
const MEMORY_FIELDS = [{
|
|
6
|
+
key: "store",
|
|
7
|
+
env: ["NUXT_EVLOG_MEMORY_STORE", "EVLOG_MEMORY_STORE"]
|
|
8
|
+
}, {
|
|
9
|
+
key: "maxEvents",
|
|
10
|
+
env: ["NUXT_EVLOG_MEMORY_MAX_EVENTS", "EVLOG_MEMORY_MAX_EVENTS"]
|
|
11
|
+
}];
|
|
12
|
+
const stores = /* @__PURE__ */ new Map();
|
|
13
|
+
function getOrCreateStore(name) {
|
|
14
|
+
if (!stores.has(name)) stores.set(name, []);
|
|
15
|
+
return stores.get(name);
|
|
16
|
+
}
|
|
17
|
+
function parseMaxEvents(value) {
|
|
18
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
19
|
+
const n = Math.floor(value);
|
|
20
|
+
return n > 0 ? n : void 0;
|
|
21
|
+
}
|
|
22
|
+
if (typeof value === "string" && value) {
|
|
23
|
+
const parsed = Number.parseFloat(value);
|
|
24
|
+
if (!Number.isFinite(parsed)) return void 0;
|
|
25
|
+
const n = Math.floor(parsed);
|
|
26
|
+
return n > 0 ? n : void 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function resolveMemoryConfig(overrides) {
|
|
30
|
+
return {
|
|
31
|
+
store: overrides?.store ?? DEFAULT_STORE,
|
|
32
|
+
maxEvents: parseMaxEvents(overrides?.maxEvents) ?? DEFAULT_MAX_EVENTS
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Write events directly into the named store. Exported for direct use and
|
|
37
|
+
* easier testing without going through the drain pipeline.
|
|
38
|
+
*/
|
|
39
|
+
function writeToMemory(events, config) {
|
|
40
|
+
if (events.length === 0) return;
|
|
41
|
+
const store = getOrCreateStore(config.store);
|
|
42
|
+
store.push(...events);
|
|
43
|
+
if (store.length > config.maxEvents) store.splice(0, store.length - config.maxEvents);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create a drain that stores wide events in an in-memory ring buffer.
|
|
47
|
+
*
|
|
48
|
+
* Works in **any** runtime — including Cloudflare Workers (workerd) — where
|
|
49
|
+
* the filesystem (`evlog/fs`) is not available. Pair it with a dev-only HTTP
|
|
50
|
+
* endpoint to let agents retrieve the buffer over HTTP.
|
|
51
|
+
*
|
|
52
|
+
* Configuration priority (highest to lowest):
|
|
53
|
+
* 1. Overrides passed to `createMemoryDrain()`
|
|
54
|
+
* 2. `runtimeConfig.evlog.memory` / `runtimeConfig.memory` (Nitro)
|
|
55
|
+
* 3. Environment variables: `NUXT_EVLOG_MEMORY_STORE`, `EVLOG_MEMORY_STORE`,
|
|
56
|
+
* `NUXT_EVLOG_MEMORY_MAX_EVENTS`, `EVLOG_MEMORY_MAX_EVENTS`
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* // Hono + Cloudflare Workers
|
|
61
|
+
* import { createMemoryDrain, readMemoryLogs } from 'evlog/memory'
|
|
62
|
+
*
|
|
63
|
+
* app.use(evlog({ drain: createMemoryDrain() }))
|
|
64
|
+
*
|
|
65
|
+
* // Dev-only endpoint for agent retrieval
|
|
66
|
+
* if (env.NODE_ENV === 'development') {
|
|
67
|
+
* app.get('/_evlog/logs', (c) => c.json(readMemoryLogs()))
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
function createMemoryDrain(overrides) {
|
|
72
|
+
return defineDrain({
|
|
73
|
+
name: "memory",
|
|
74
|
+
resolve: async () => {
|
|
75
|
+
return resolveMemoryConfig(await resolveAdapterConfig("memory", MEMORY_FIELDS, overrides));
|
|
76
|
+
},
|
|
77
|
+
send: (events, cfg) => Promise.resolve(writeToMemory(events, cfg))
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function normalizeTimestamp(value) {
|
|
81
|
+
if (!value) return void 0;
|
|
82
|
+
const ts = (value instanceof Date ? value : new Date(value)).getTime();
|
|
83
|
+
return Number.isNaN(ts) ? void 0 : ts;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Read events from the named in-memory store. Returns a snapshot of the
|
|
87
|
+
* buffer with optional filtering, ordered oldest-first.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* import { readMemoryLogs } from 'evlog/memory'
|
|
92
|
+
*
|
|
93
|
+
* // All events
|
|
94
|
+
* const events = readMemoryLogs()
|
|
95
|
+
*
|
|
96
|
+
* // Errors in the last hour
|
|
97
|
+
* const errors = readMemoryLogs({
|
|
98
|
+
* level: 'error',
|
|
99
|
+
* since: new Date(Date.now() - 60 * 60 * 1000),
|
|
100
|
+
* })
|
|
101
|
+
*
|
|
102
|
+
* // Expose as a JSON endpoint
|
|
103
|
+
* app.get('/_evlog/logs', (c) => c.json(readMemoryLogs({ limit: 200 })))
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
function readMemoryLogs(options = {}) {
|
|
107
|
+
const storeName = options.store ?? DEFAULT_STORE;
|
|
108
|
+
const events = [...stores.get(storeName) ?? []];
|
|
109
|
+
const sinceMs = normalizeTimestamp(options.since);
|
|
110
|
+
const untilMs = normalizeTimestamp(options.until);
|
|
111
|
+
const levels = options.level ? new Set(Array.isArray(options.level) ? options.level : [options.level]) : void 0;
|
|
112
|
+
const custom = options.filter;
|
|
113
|
+
const filtered = events.filter((event) => {
|
|
114
|
+
if (levels && !levels.has(event.level)) return false;
|
|
115
|
+
if (sinceMs !== void 0 || untilMs !== void 0) {
|
|
116
|
+
const ts = typeof event.timestamp === "string" ? Date.parse(event.timestamp) : NaN;
|
|
117
|
+
if (Number.isNaN(ts)) return false;
|
|
118
|
+
if (sinceMs !== void 0 && ts < sinceMs) return false;
|
|
119
|
+
if (untilMs !== void 0 && ts > untilMs) return false;
|
|
120
|
+
}
|
|
121
|
+
if (custom && !custom(event)) return false;
|
|
122
|
+
return true;
|
|
123
|
+
});
|
|
124
|
+
if (options.limit !== void 0) {
|
|
125
|
+
if (options.limit <= 0) return [];
|
|
126
|
+
if (filtered.length > options.limit) return filtered.slice(-options.limit);
|
|
127
|
+
}
|
|
128
|
+
return filtered;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Clear all events from a named store (or `'default'`).
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* clearMemoryLogs() // clears the default store
|
|
136
|
+
* clearMemoryLogs('my-store') // clears a named store
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
function clearMemoryLogs(store = DEFAULT_STORE) {
|
|
140
|
+
const s = stores.get(store);
|
|
141
|
+
if (s) s.length = 0;
|
|
142
|
+
}
|
|
143
|
+
const VALID_LEVELS = new Set([
|
|
144
|
+
"info",
|
|
145
|
+
"error",
|
|
146
|
+
"warn",
|
|
147
|
+
"debug"
|
|
148
|
+
]);
|
|
149
|
+
/**
|
|
150
|
+
* Parse a flat query-string object (e.g. from `c.req.query()` in Hono, or
|
|
151
|
+
* `req.query` in Express) into {@link ReadMemoryLogsOptions} with proper type
|
|
152
|
+
* coercion.
|
|
153
|
+
*
|
|
154
|
+
* This lets agents discover and pass filter parameters through HTTP query
|
|
155
|
+
* strings directly:
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* // Hono — zero glue
|
|
160
|
+
* app.get('/_evlog/logs', (c) =>
|
|
161
|
+
* c.json(readMemoryLogs(parseReadMemoryLogsQuery(c.req.query()))))
|
|
162
|
+
*
|
|
163
|
+
* // Express
|
|
164
|
+
* app.get('/_evlog/logs', (req, res) =>
|
|
165
|
+
* res.json(readMemoryLogs(parseReadMemoryLogsQuery(req.query as Record<string, string>))))
|
|
166
|
+
* ```
|
|
167
|
+
*
|
|
168
|
+
* Supported query params: `store`, `since`, `until`, `level` (comma-separated),
|
|
169
|
+
* `limit`. The `filter` predicate cannot be expressed as a query param.
|
|
170
|
+
*/
|
|
171
|
+
function parseReadMemoryLogsQuery(query) {
|
|
172
|
+
const opts = {};
|
|
173
|
+
const { store, since, until, level, limit } = query;
|
|
174
|
+
if (typeof store === "string" && store) opts.store = store;
|
|
175
|
+
if (typeof since === "string" && since) opts.since = since;
|
|
176
|
+
if (typeof until === "string" && until) opts.until = until;
|
|
177
|
+
if (level !== void 0) {
|
|
178
|
+
const levels = (Array.isArray(level) ? level : level.split(",")).map((l) => l.trim()).filter((l) => VALID_LEVELS.has(l));
|
|
179
|
+
if (levels.length === 1) [opts.level] = levels;
|
|
180
|
+
else if (levels.length > 1) opts.level = levels;
|
|
181
|
+
}
|
|
182
|
+
if (typeof limit === "string") {
|
|
183
|
+
const n = Number.parseInt(limit, 10);
|
|
184
|
+
if (!Number.isNaN(n)) opts.limit = n;
|
|
185
|
+
}
|
|
186
|
+
return opts;
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
export { clearMemoryLogs, createMemoryDrain, parseReadMemoryLogsQuery, readMemoryLogs, writeToMemory };
|
|
190
|
+
|
|
191
|
+
//# sourceMappingURL=memory.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.mjs","names":[],"sources":["../../src/adapters/memory.ts"],"sourcesContent":["import type { LogLevel, WideEvent } from '../types'\nimport type { ConfigField } from '../shared/config'\nimport { resolveAdapterConfig } from '../shared/config'\nimport { defineDrain } from '../shared/drain'\n\n/**\n * Configuration for the in-memory drain.\n */\nexport interface MemoryConfig {\n /** Named store key. Multiple drains sharing the same key share the same buffer. Default: `'default'` */\n store: string\n /** Maximum number of events to keep in the ring buffer. Oldest events are discarded when the limit is exceeded. Default: `1000` */\n maxEvents: number\n}\n\nconst DEFAULT_STORE = 'default'\nconst DEFAULT_MAX_EVENTS = 1000\n\nconst MEMORY_FIELDS: ConfigField<Partial<MemoryConfig>>[] = [\n { key: 'store', env: ['NUXT_EVLOG_MEMORY_STORE', 'EVLOG_MEMORY_STORE'] },\n { key: 'maxEvents', env: ['NUXT_EVLOG_MEMORY_MAX_EVENTS', 'EVLOG_MEMORY_MAX_EVENTS'] },\n]\n\nconst stores = new Map<string, WideEvent[]>()\n\nfunction getOrCreateStore(name: string): WideEvent[] {\n if (!stores.has(name)) stores.set(name, [])\n return stores.get(name)!\n}\n\nfunction parseMaxEvents(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) {\n const n = Math.floor(value)\n return n > 0 ? n : undefined\n }\n if (typeof value === 'string' && value) {\n const parsed = Number.parseFloat(value)\n if (!Number.isFinite(parsed)) return undefined\n const n = Math.floor(parsed)\n return n > 0 ? n : undefined\n }\n return undefined\n}\n\nfunction resolveMemoryConfig(overrides?: Partial<MemoryConfig>): MemoryConfig {\n return {\n store: overrides?.store ?? DEFAULT_STORE,\n maxEvents: parseMaxEvents(overrides?.maxEvents) ?? DEFAULT_MAX_EVENTS,\n }\n}\n\n/**\n * Write events directly into the named store. Exported for direct use and\n * easier testing without going through the drain pipeline.\n */\nexport function writeToMemory(events: WideEvent[], config: MemoryConfig): void {\n if (events.length === 0) return\n const store = getOrCreateStore(config.store)\n store.push(...events)\n if (store.length > config.maxEvents) {\n store.splice(0, store.length - config.maxEvents)\n }\n}\n\n/**\n * Create a drain that stores wide events in an in-memory ring buffer.\n *\n * Works in **any** runtime — including Cloudflare Workers (workerd) — where\n * the filesystem (`evlog/fs`) is not available. Pair it with a dev-only HTTP\n * endpoint to let agents retrieve the buffer over HTTP.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to `createMemoryDrain()`\n * 2. `runtimeConfig.evlog.memory` / `runtimeConfig.memory` (Nitro)\n * 3. Environment variables: `NUXT_EVLOG_MEMORY_STORE`, `EVLOG_MEMORY_STORE`,\n * `NUXT_EVLOG_MEMORY_MAX_EVENTS`, `EVLOG_MEMORY_MAX_EVENTS`\n *\n * @example\n * ```ts\n * // Hono + Cloudflare Workers\n * import { createMemoryDrain, readMemoryLogs } from 'evlog/memory'\n *\n * app.use(evlog({ drain: createMemoryDrain() }))\n *\n * // Dev-only endpoint for agent retrieval\n * if (env.NODE_ENV === 'development') {\n * app.get('/_evlog/logs', (c) => c.json(readMemoryLogs()))\n * }\n * ```\n */\nexport function createMemoryDrain(overrides?: Partial<MemoryConfig>) {\n return defineDrain<MemoryConfig>({\n name: 'memory',\n resolve: async () => {\n const resolved = await resolveAdapterConfig<Partial<MemoryConfig>>('memory', MEMORY_FIELDS, overrides)\n return resolveMemoryConfig(resolved)\n },\n send: (events, cfg) => Promise.resolve(writeToMemory(events, cfg)),\n })\n}\n\n/** Options accepted by {@link readMemoryLogs}. */\nexport interface ReadMemoryLogsOptions {\n /** Named store to read from. Default: `'default'` */\n store?: string\n /** Only include events with `timestamp >= since`. */\n since?: Date | string\n /** Only include events with `timestamp <= until`. */\n until?: Date | string\n /** Filter by log level. */\n level?: LogLevel | LogLevel[]\n /** Custom predicate — return `false` to skip the event. */\n filter?: (event: WideEvent) => boolean\n /** Return at most this many of the most-recent matching events. */\n limit?: number\n}\n\nfunction normalizeTimestamp(value: Date | string | undefined): number | undefined {\n if (!value) return undefined\n const date = value instanceof Date ? value : new Date(value)\n const ts = date.getTime()\n return Number.isNaN(ts) ? undefined : ts\n}\n\n/**\n * Read events from the named in-memory store. Returns a snapshot of the\n * buffer with optional filtering, ordered oldest-first.\n *\n * @example\n * ```ts\n * import { readMemoryLogs } from 'evlog/memory'\n *\n * // All events\n * const events = readMemoryLogs()\n *\n * // Errors in the last hour\n * const errors = readMemoryLogs({\n * level: 'error',\n * since: new Date(Date.now() - 60 * 60 * 1000),\n * })\n *\n * // Expose as a JSON endpoint\n * app.get('/_evlog/logs', (c) => c.json(readMemoryLogs({ limit: 200 })))\n * ```\n */\nexport function readMemoryLogs(options: ReadMemoryLogsOptions = {}): WideEvent[] {\n const storeName = options.store ?? DEFAULT_STORE\n const events = [...(stores.get(storeName) ?? [])]\n\n const sinceMs = normalizeTimestamp(options.since)\n const untilMs = normalizeTimestamp(options.until)\n const levels = options.level\n ? new Set<LogLevel>(Array.isArray(options.level) ? options.level : [options.level])\n : undefined\n const custom = options.filter\n\n const filtered = events.filter((event) => {\n if (levels && !levels.has(event.level)) return false\n if (sinceMs !== undefined || untilMs !== undefined) {\n const ts = typeof event.timestamp === 'string' ? Date.parse(event.timestamp) : Number.NaN\n if (Number.isNaN(ts)) return false\n if (sinceMs !== undefined && ts < sinceMs) return false\n if (untilMs !== undefined && ts > untilMs) return false\n }\n if (custom && !custom(event)) return false\n return true\n })\n\n if (options.limit !== undefined) {\n if (options.limit <= 0) return []\n if (filtered.length > options.limit) return filtered.slice(-options.limit)\n }\n return filtered\n}\n\n/**\n * Clear all events from a named store (or `'default'`).\n *\n * @example\n * ```ts\n * clearMemoryLogs() // clears the default store\n * clearMemoryLogs('my-store') // clears a named store\n * ```\n */\nexport function clearMemoryLogs(store = DEFAULT_STORE): void {\n const s = stores.get(store)\n if (s) s.length = 0\n}\n\nconst VALID_LEVELS = new Set<LogLevel>(['info', 'error', 'warn', 'debug'])\n\n/**\n * Parse a flat query-string object (e.g. from `c.req.query()` in Hono, or\n * `req.query` in Express) into {@link ReadMemoryLogsOptions} with proper type\n * coercion.\n *\n * This lets agents discover and pass filter parameters through HTTP query\n * strings directly:\n *\n * @example\n * ```ts\n * // Hono — zero glue\n * app.get('/_evlog/logs', (c) =>\n * c.json(readMemoryLogs(parseReadMemoryLogsQuery(c.req.query()))))\n *\n * // Express\n * app.get('/_evlog/logs', (req, res) =>\n * res.json(readMemoryLogs(parseReadMemoryLogsQuery(req.query as Record<string, string>))))\n * ```\n *\n * Supported query params: `store`, `since`, `until`, `level` (comma-separated),\n * `limit`. The `filter` predicate cannot be expressed as a query param.\n */\nexport function parseReadMemoryLogsQuery(\n query: Record<string, string | string[] | undefined>,\n): ReadMemoryLogsOptions {\n const opts: ReadMemoryLogsOptions = {}\n const { store, since, until, level, limit } = query\n\n if (typeof store === 'string' && store) opts.store = store\n if (typeof since === 'string' && since) opts.since = since\n if (typeof until === 'string' && until) opts.until = until\n\n if (level !== undefined) {\n const raw = Array.isArray(level) ? level : level.split(',')\n const levels = raw.map((l) => l.trim()).filter((l): l is LogLevel => VALID_LEVELS.has(l as LogLevel))\n if (levels.length === 1) [opts.level] = levels\n else if (levels.length > 1) opts.level = levels\n }\n\n if (typeof limit === 'string') {\n const n = Number.parseInt(limit, 10)\n if (!Number.isNaN(n)) opts.limit = n\n }\n\n return opts\n}\n"],"mappings":"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"}
|
package/dist/adapters/otlp.d.mts
CHANGED