@tanngo11/log 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/CONTRACT.md +135 -0
  3. package/LICENSE +21 -0
  4. package/README.md +291 -0
  5. package/dist/bullmq.cjs +108 -0
  6. package/dist/bullmq.cjs.map +1 -0
  7. package/dist/bullmq.d.cts +14 -0
  8. package/dist/bullmq.d.ts +14 -0
  9. package/dist/bullmq.js +29 -0
  10. package/dist/bullmq.js.map +1 -0
  11. package/dist/chunk-BP264YAM.js +72 -0
  12. package/dist/chunk-BP264YAM.js.map +1 -0
  13. package/dist/chunk-BVKAY2OK.js +53 -0
  14. package/dist/chunk-BVKAY2OK.js.map +1 -0
  15. package/dist/chunk-DO5HNNTP.js +66 -0
  16. package/dist/chunk-DO5HNNTP.js.map +1 -0
  17. package/dist/chunk-KD5H5G6Y.js +209 -0
  18. package/dist/chunk-KD5H5G6Y.js.map +1 -0
  19. package/dist/chunk-KLBL7QEN.js +29 -0
  20. package/dist/chunk-KLBL7QEN.js.map +1 -0
  21. package/dist/chunk-QMC6BWGK.js +203 -0
  22. package/dist/chunk-QMC6BWGK.js.map +1 -0
  23. package/dist/chunk-UXKPPF4G.js +41 -0
  24. package/dist/chunk-UXKPPF4G.js.map +1 -0
  25. package/dist/express.cjs +316 -0
  26. package/dist/express.cjs.map +1 -0
  27. package/dist/express.d.cts +10 -0
  28. package/dist/express.d.ts +10 -0
  29. package/dist/express.js +12 -0
  30. package/dist/express.js.map +1 -0
  31. package/dist/fastify.cjs +309 -0
  32. package/dist/fastify.cjs.map +1 -0
  33. package/dist/fastify.d.cts +10 -0
  34. package/dist/fastify.d.ts +10 -0
  35. package/dist/fastify.js +10 -0
  36. package/dist/fastify.js.map +1 -0
  37. package/dist/http-BI6ARZlD.d.ts +25 -0
  38. package/dist/http-BXAiU-rN.d.cts +25 -0
  39. package/dist/index.cjs +677 -0
  40. package/dist/index.cjs.map +1 -0
  41. package/dist/index.d.cts +69 -0
  42. package/dist/index.d.ts +69 -0
  43. package/dist/index.js +214 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/logger-CFMTzjsm.d.cts +47 -0
  46. package/dist/logger-CFMTzjsm.d.ts +47 -0
  47. package/dist/nest.cjs +458 -0
  48. package/dist/nest.cjs.map +1 -0
  49. package/dist/nest.d.cts +41 -0
  50. package/dist/nest.d.ts +41 -0
  51. package/dist/nest.js +107 -0
  52. package/dist/nest.js.map +1 -0
  53. package/dist/next-edge.cjs +44 -0
  54. package/dist/next-edge.cjs.map +1 -0
  55. package/dist/next-edge.d.cts +7 -0
  56. package/dist/next-edge.d.ts +7 -0
  57. package/dist/next-edge.js +16 -0
  58. package/dist/next-edge.js.map +1 -0
  59. package/dist/next.cjs +423 -0
  60. package/dist/next.cjs.map +1 -0
  61. package/dist/next.d.cts +36 -0
  62. package/dist/next.d.ts +36 -0
  63. package/dist/next.js +138 -0
  64. package/dist/next.js.map +1 -0
  65. package/dist/prisma.cjs +63 -0
  66. package/dist/prisma.cjs.map +1 -0
  67. package/dist/prisma.d.cts +31 -0
  68. package/dist/prisma.d.ts +31 -0
  69. package/dist/prisma.js +38 -0
  70. package/dist/prisma.js.map +1 -0
  71. package/package.json +138 -0
package/dist/bullmq.js ADDED
@@ -0,0 +1,29 @@
1
+ import {
2
+ runJob
3
+ } from "./chunk-UXKPPF4G.js";
4
+ import "./chunk-QMC6BWGK.js";
5
+
6
+ // src/bullmq.ts
7
+ function loggedProcessor(log, name, processor) {
8
+ return (job, ...rest) => {
9
+ const attempts = job.opts?.attempts ?? 1;
10
+ const attempt = job.attemptsMade + 1;
11
+ const requestId = job.data?.request_id;
12
+ return runJob(
13
+ log,
14
+ {
15
+ job_name: name,
16
+ job_id: job.id,
17
+ job_attempt: attempt,
18
+ // UnrecoverableError skips the remaining retries.
19
+ final_attempt: (err) => attempt >= attempts || err?.name === "UnrecoverableError",
20
+ request_id: typeof requestId === "string" ? requestId : void 0
21
+ },
22
+ () => processor(job, ...rest)
23
+ );
24
+ };
25
+ }
26
+ export {
27
+ loggedProcessor
28
+ };
29
+ //# sourceMappingURL=bullmq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bullmq.ts"],"sourcesContent":["import { runJob } from \"./job\";\nimport type { Logger } from \"./logger\";\n\n/** Minimal shape of a BullMQ Job; avoids depending on bullmq. */\nexport interface BullJobLike {\n id?: string;\n attemptsMade: number;\n opts?: { attempts?: number };\n data?: unknown;\n}\n\nexport function loggedProcessor<J extends BullJobLike, R, A extends unknown[] = [token?: string, signal?: AbortSignal]>(\n log: Logger,\n name: string,\n processor: (job: J, ...rest: A) => Promise<R>,\n): (job: J, ...rest: A) => Promise<R> {\n return (job, ...rest) => {\n const attempts = job.opts?.attempts ?? 1;\n const attempt = job.attemptsMade + 1;\n const requestId = (job.data as { request_id?: unknown } | undefined)?.request_id;\n return runJob(\n log,\n {\n job_name: name,\n job_id: job.id,\n job_attempt: attempt,\n // UnrecoverableError skips the remaining retries.\n final_attempt: (err) => attempt >= attempts || (err as { name?: unknown } | null)?.name === \"UnrecoverableError\",\n request_id: typeof requestId === \"string\" ? requestId : undefined,\n },\n () => processor(job, ...rest),\n );\n };\n}\n"],"mappings":";;;;;;AAWO,SAAS,gBACd,KACA,MACA,WACoC;AACpC,SAAO,CAAC,QAAQ,SAAS;AACvB,UAAM,WAAW,IAAI,MAAM,YAAY;AACvC,UAAM,UAAU,IAAI,eAAe;AACnC,UAAM,YAAa,IAAI,MAA+C;AACtE,WAAO;AAAA,MACL;AAAA,MACA;AAAA,QACE,UAAU;AAAA,QACV,QAAQ,IAAI;AAAA,QACZ,aAAa;AAAA;AAAA,QAEb,eAAe,CAAC,QAAQ,WAAW,YAAa,KAAmC,SAAS;AAAA,QAC5F,YAAY,OAAO,cAAc,WAAW,YAAY;AAAA,MAC1D;AAAA,MACA,MAAM,UAAU,KAAK,GAAG,IAAI;AAAA,IAC9B;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,72 @@
1
+ import {
2
+ logHttpRequest,
3
+ requestContextFields
4
+ } from "./chunk-KD5H5G6Y.js";
5
+ import {
6
+ attachStore,
7
+ recordErrorIn,
8
+ runWithStore,
9
+ storeOf
10
+ } from "./chunk-QMC6BWGK.js";
11
+
12
+ // src/express.ts
13
+ function joinRoute(baseUrl, path) {
14
+ return `${baseUrl ?? ""}${String(path)}` || "/";
15
+ }
16
+ function captureRoute(req, store) {
17
+ let value;
18
+ Object.defineProperty(req, "route", {
19
+ configurable: true,
20
+ enumerable: true,
21
+ get: () => value,
22
+ set: (route) => {
23
+ value = route;
24
+ if (route?.path !== void 0) store.route = joinRoute(req.baseUrl, route.path);
25
+ }
26
+ });
27
+ }
28
+ function requestLogger(log, opts = {}) {
29
+ return (req, res, next) => {
30
+ const ctx = requestContextFields(req.headers);
31
+ res.setHeader("x-request-id", ctx.request_id);
32
+ const start = performance.now();
33
+ runWithStore(ctx, (store) => {
34
+ attachStore(res, store);
35
+ captureRoute(req, store);
36
+ let done = false;
37
+ const finish = () => {
38
+ if (done) return;
39
+ done = true;
40
+ logHttpRequest(
41
+ log,
42
+ {
43
+ method: req.method,
44
+ route: store.route,
45
+ path: req.originalUrl,
46
+ status: res.writableFinished || res.headersSent ? res.statusCode : 499,
47
+ duration_ms: performance.now() - start,
48
+ err: store.error,
49
+ fields: store.fields
50
+ },
51
+ opts
52
+ );
53
+ };
54
+ res.once("finish", finish);
55
+ res.once("close", finish);
56
+ next();
57
+ });
58
+ };
59
+ }
60
+ function errorRecorder() {
61
+ return (err, _req, res, next) => {
62
+ const store = storeOf(res);
63
+ if (store) recordErrorIn(store, err);
64
+ next(err);
65
+ };
66
+ }
67
+
68
+ export {
69
+ requestLogger,
70
+ errorRecorder
71
+ };
72
+ //# sourceMappingURL=chunk-BP264YAM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/express.ts"],"sourcesContent":["import type { ErrorRequestHandler, RequestHandler } from \"express\";\nimport { attachStore, recordErrorIn, runWithStore, storeOf, type ContextStore } from \"./context\";\nimport { logHttpRequest, requestContextFields, type HttpLogOptions } from \"./http\";\nimport type { Logger } from \"./logger\";\n\nfunction joinRoute(baseUrl: string | undefined, path: unknown): string {\n return `${baseUrl ?? \"\"}${String(path)}` || \"/\";\n}\n\n// Express assigns req.route when a route matches, while req.baseUrl still holds the mount\n// path. It resets baseUrl before the response ends, so capture the full template here.\nfunction captureRoute(req: { baseUrl?: string }, store: ContextStore): void {\n let value: unknown;\n Object.defineProperty(req, \"route\", {\n configurable: true,\n enumerable: true,\n get: () => value,\n set: (route: { path?: unknown } | undefined) => {\n value = route;\n if (route?.path !== undefined) store.route = joinRoute(req.baseUrl, route.path);\n },\n });\n}\n\n/** Mount before routes. Opens the request context and writes the http.request line. */\nexport function requestLogger(log: Logger, opts: HttpLogOptions = {}): RequestHandler {\n return (req, res, next) => {\n const ctx = requestContextFields(req.headers);\n res.setHeader(\"x-request-id\", ctx.request_id);\n const start = performance.now();\n runWithStore(ctx, (store) => {\n attachStore(res, store);\n captureRoute(req, store);\n let done = false;\n const finish = () => {\n if (done) return;\n done = true;\n logHttpRequest(\n log,\n {\n method: req.method,\n route: store.route,\n path: req.originalUrl,\n status: res.writableFinished || res.headersSent ? res.statusCode : 499,\n duration_ms: performance.now() - start,\n err: store.error,\n fields: store.fields,\n },\n opts,\n );\n };\n res.once(\"finish\", finish);\n res.once(\"close\", finish);\n next();\n });\n };\n}\n\n/** Mount after routes, before your own error handler. Records the error for the summary line. */\nexport function errorRecorder(): ErrorRequestHandler {\n return (err, _req, res, next) => {\n const store = storeOf(res);\n if (store) recordErrorIn(store, err);\n next(err);\n };\n}\n"],"mappings":";;;;;;;;;;;;AAKA,SAAS,UAAU,SAA6B,MAAuB;AACrE,SAAO,GAAG,WAAW,EAAE,GAAG,OAAO,IAAI,CAAC,MAAM;AAC9C;AAIA,SAAS,aAAa,KAA2B,OAA2B;AAC1E,MAAI;AACJ,SAAO,eAAe,KAAK,SAAS;AAAA,IAClC,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,KAAK,MAAM;AAAA,IACX,KAAK,CAAC,UAA0C;AAC9C,cAAQ;AACR,UAAI,OAAO,SAAS,OAAW,OAAM,QAAQ,UAAU,IAAI,SAAS,MAAM,IAAI;AAAA,IAChF;AAAA,EACF,CAAC;AACH;AAGO,SAAS,cAAc,KAAa,OAAuB,CAAC,GAAmB;AACpF,SAAO,CAAC,KAAK,KAAK,SAAS;AACzB,UAAM,MAAM,qBAAqB,IAAI,OAAO;AAC5C,QAAI,UAAU,gBAAgB,IAAI,UAAU;AAC5C,UAAM,QAAQ,YAAY,IAAI;AAC9B,iBAAa,KAAK,CAAC,UAAU;AAC3B,kBAAY,KAAK,KAAK;AACtB,mBAAa,KAAK,KAAK;AACvB,UAAI,OAAO;AACX,YAAM,SAAS,MAAM;AACnB,YAAI,KAAM;AACV,eAAO;AACP;AAAA,UACE;AAAA,UACA;AAAA,YACE,QAAQ,IAAI;AAAA,YACZ,OAAO,MAAM;AAAA,YACb,MAAM,IAAI;AAAA,YACV,QAAQ,IAAI,oBAAoB,IAAI,cAAc,IAAI,aAAa;AAAA,YACnE,aAAa,YAAY,IAAI,IAAI;AAAA,YACjC,KAAK,MAAM;AAAA,YACX,QAAQ,MAAM;AAAA,UAChB;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,KAAK,UAAU,MAAM;AACzB,UAAI,KAAK,SAAS,MAAM;AACxB,WAAK;AAAA,IACP,CAAC;AAAA,EACH;AACF;AAGO,SAAS,gBAAqC;AACnD,SAAO,CAAC,KAAK,MAAM,KAAK,SAAS;AAC/B,UAAM,QAAQ,QAAQ,GAAG;AACzB,QAAI,MAAO,eAAc,OAAO,GAAG;AACnC,SAAK,GAAG;AAAA,EACV;AACF;","names":[]}
@@ -0,0 +1,53 @@
1
+ import {
2
+ globalSingleton
3
+ } from "./chunk-QMC6BWGK.js";
4
+
5
+ // src/process.ts
6
+ function logStartup(log, fields = {}) {
7
+ log.info("app started", {
8
+ event: "app.started",
9
+ runtime_version: `node ${process.versions.node}`,
10
+ log_level: log.level,
11
+ ...fields
12
+ });
13
+ }
14
+ function logShutdown(log, fields = {}) {
15
+ log.info("app stopping", { event: "app.stopping", ...fields });
16
+ }
17
+ function crashHandlers(log, opts = {}) {
18
+ const exitOnCrash = opts.exitOnCrash ?? true;
19
+ const exitDelayMs = opts.exitDelayMs ?? 1e3;
20
+ const exit = opts.exit ?? ((code) => process.exit(code));
21
+ let exiting = false;
22
+ const crash = (source, err) => {
23
+ if (!exitOnCrash) {
24
+ log.error("unhandled error", { event: "app.unhandled_error", crash_source: source, err });
25
+ return;
26
+ }
27
+ log.fatal("app crashed", { event: "app.crashed", crash_source: source, err });
28
+ if (exiting) return;
29
+ exiting = true;
30
+ if (typeof process !== "undefined") process.exitCode = 1;
31
+ const timer = setTimeout(() => exit(1), exitDelayMs);
32
+ timer.unref?.();
33
+ };
34
+ return {
35
+ onUncaught: (err) => crash("uncaughtException", err),
36
+ onRejection: (reason) => crash("unhandledRejection", reason)
37
+ };
38
+ }
39
+ var state = globalSingleton("process", () => ({ installed: false }));
40
+ function installProcessHandlers(log, opts = {}) {
41
+ if (state.installed || typeof process === "undefined" || typeof process.on !== "function") return;
42
+ state.installed = true;
43
+ const h = crashHandlers(log, opts);
44
+ process.on("uncaughtException", h.onUncaught);
45
+ process.on("unhandledRejection", h.onRejection);
46
+ }
47
+
48
+ export {
49
+ logStartup,
50
+ logShutdown,
51
+ installProcessHandlers
52
+ };
53
+ //# sourceMappingURL=chunk-BVKAY2OK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/process.ts"],"sourcesContent":["import { globalSingleton } from \"./global\";\nimport type { Logger } from \"./logger\";\nimport type { Fields } from \"./normalize\";\n\nexport function logStartup(log: Logger, fields: Fields = {}): void {\n log.info(\"app started\", {\n event: \"app.started\",\n runtime_version: `node ${process.versions.node}`,\n log_level: log.level,\n ...fields,\n });\n}\n\n/** Call at the start of your own shutdown handler (e.g. on SIGTERM). The library never handles signals. */\nexport function logShutdown(log: Logger, fields: Fields = {}): void {\n log.info(\"app stopping\", { event: \"app.stopping\", ...fields });\n}\n\nexport interface ProcessHandlerOptions {\n /** Exit with code 1 after an uncaught error. Next.js keeps serving, so its adapter passes false. */\n exitOnCrash?: boolean;\n /** Time other crash handlers (Sentry, APM) get to flush before exit. Default 1000 ms. */\n exitDelayMs?: number;\n exit?: (code: number) => void;\n}\n\nexport function crashHandlers(log: Logger, opts: ProcessHandlerOptions = {}) {\n const exitOnCrash = opts.exitOnCrash ?? true;\n const exitDelayMs = opts.exitDelayMs ?? 1000;\n const exit = opts.exit ?? ((code: number) => process.exit(code));\n let exiting = false;\n const crash = (source: string, err: unknown) => {\n if (!exitOnCrash) {\n log.error(\"unhandled error\", { event: \"app.unhandled_error\", crash_source: source, err });\n return;\n }\n log.fatal(\"app crashed\", { event: \"app.crashed\", crash_source: source, err });\n if (exiting) return;\n exiting = true;\n if (typeof process !== \"undefined\") process.exitCode = 1;\n // Deferred so listeners registered after ours still run; unref so a process with nothing\n // left to do exits on its own (with exitCode 1) without waiting.\n const timer = setTimeout(() => exit(1), exitDelayMs);\n (timer as { unref?: () => void }).unref?.();\n };\n return {\n onUncaught: (err: unknown) => crash(\"uncaughtException\", err),\n onRejection: (reason: unknown) => crash(\"unhandledRejection\", reason),\n };\n}\n\nconst state = globalSingleton(\"process\", () => ({ installed: false }));\n\n/** Logs uncaught exceptions and unhandled rejections. Does not touch SIGTERM/SIGINT. */\nexport function installProcessHandlers(log: Logger, opts: ProcessHandlerOptions = {}): void {\n if (state.installed || typeof process === \"undefined\" || typeof process.on !== \"function\") return;\n state.installed = true;\n const h = crashHandlers(log, opts);\n process.on(\"uncaughtException\", h.onUncaught);\n process.on(\"unhandledRejection\", h.onRejection);\n}\n"],"mappings":";;;;;AAIO,SAAS,WAAW,KAAa,SAAiB,CAAC,GAAS;AACjE,MAAI,KAAK,eAAe;AAAA,IACtB,OAAO;AAAA,IACP,iBAAiB,QAAQ,QAAQ,SAAS,IAAI;AAAA,IAC9C,WAAW,IAAI;AAAA,IACf,GAAG;AAAA,EACL,CAAC;AACH;AAGO,SAAS,YAAY,KAAa,SAAiB,CAAC,GAAS;AAClE,MAAI,KAAK,gBAAgB,EAAE,OAAO,gBAAgB,GAAG,OAAO,CAAC;AAC/D;AAUO,SAAS,cAAc,KAAa,OAA8B,CAAC,GAAG;AAC3E,QAAM,cAAc,KAAK,eAAe;AACxC,QAAM,cAAc,KAAK,eAAe;AACxC,QAAM,OAAO,KAAK,SAAS,CAAC,SAAiB,QAAQ,KAAK,IAAI;AAC9D,MAAI,UAAU;AACd,QAAM,QAAQ,CAAC,QAAgB,QAAiB;AAC9C,QAAI,CAAC,aAAa;AAChB,UAAI,MAAM,mBAAmB,EAAE,OAAO,uBAAuB,cAAc,QAAQ,IAAI,CAAC;AACxF;AAAA,IACF;AACA,QAAI,MAAM,eAAe,EAAE,OAAO,eAAe,cAAc,QAAQ,IAAI,CAAC;AAC5E,QAAI,QAAS;AACb,cAAU;AACV,QAAI,OAAO,YAAY,YAAa,SAAQ,WAAW;AAGvD,UAAM,QAAQ,WAAW,MAAM,KAAK,CAAC,GAAG,WAAW;AACnD,IAAC,MAAiC,QAAQ;AAAA,EAC5C;AACA,SAAO;AAAA,IACL,YAAY,CAAC,QAAiB,MAAM,qBAAqB,GAAG;AAAA,IAC5D,aAAa,CAAC,WAAoB,MAAM,sBAAsB,MAAM;AAAA,EACtE;AACF;AAEA,IAAM,QAAQ,gBAAgB,WAAW,OAAO,EAAE,WAAW,MAAM,EAAE;AAG9D,SAAS,uBAAuB,KAAa,OAA8B,CAAC,GAAS;AAC1F,MAAI,MAAM,aAAa,OAAO,YAAY,eAAe,OAAO,QAAQ,OAAO,WAAY;AAC3F,QAAM,YAAY;AAClB,QAAM,IAAI,cAAc,KAAK,IAAI;AACjC,UAAQ,GAAG,qBAAqB,EAAE,UAAU;AAC5C,UAAQ,GAAG,sBAAsB,EAAE,WAAW;AAChD;","names":[]}
@@ -0,0 +1,66 @@
1
+ import {
2
+ logHttpRequest,
3
+ requestContextFields
4
+ } from "./chunk-KD5H5G6Y.js";
5
+ import {
6
+ attachStore,
7
+ recordErrorIn,
8
+ runWithStore,
9
+ storeOf
10
+ } from "./chunk-QMC6BWGK.js";
11
+
12
+ // src/fastify.ts
13
+ var starts = /* @__PURE__ */ new WeakMap();
14
+ var finished = /* @__PURE__ */ new WeakSet();
15
+ var plugin = (app, opts, done) => {
16
+ const summary = (req, status) => {
17
+ if (finished.has(req)) return;
18
+ finished.add(req);
19
+ const store = storeOf(req);
20
+ const start = starts.get(req);
21
+ logHttpRequest(
22
+ opts.log,
23
+ {
24
+ method: req.method,
25
+ route: req.routeOptions?.url,
26
+ path: req.url,
27
+ status,
28
+ duration_ms: start === void 0 ? void 0 : performance.now() - start,
29
+ err: store?.error,
30
+ fields: store?.fields
31
+ },
32
+ opts
33
+ );
34
+ };
35
+ app.addHook("onRequest", (req, reply, next) => {
36
+ const ctx = requestContextFields(req.headers);
37
+ reply.header("x-request-id", ctx.request_id);
38
+ starts.set(req, performance.now());
39
+ runWithStore(ctx, (store) => {
40
+ attachStore(req, store);
41
+ attachStore(reply, store);
42
+ next();
43
+ });
44
+ });
45
+ app.addHook("onError", (_req, reply, err, next) => {
46
+ const store = storeOf(reply);
47
+ if (store) recordErrorIn(store, err);
48
+ next();
49
+ });
50
+ app.addHook("onResponse", (req, reply, next) => {
51
+ summary(req, reply.statusCode);
52
+ next();
53
+ });
54
+ app.addHook("onRequestAbort", (req, next) => {
55
+ summary(req, 499);
56
+ next();
57
+ });
58
+ done();
59
+ };
60
+ plugin[/* @__PURE__ */ Symbol.for("skip-override")] = true;
61
+ var fastifyLogger = plugin;
62
+
63
+ export {
64
+ fastifyLogger
65
+ };
66
+ //# sourceMappingURL=chunk-DO5HNNTP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/fastify.ts"],"sourcesContent":["import type { FastifyPluginCallback, FastifyRequest } from \"fastify\";\nimport { attachStore, recordErrorIn, runWithStore, storeOf } from \"./context\";\nimport { logHttpRequest, requestContextFields, type HttpLogOptions } from \"./http\";\nimport type { Logger } from \"./logger\";\n\nexport interface FastifyLoggerOptions extends HttpLogOptions {\n log: Logger;\n}\n\nconst starts = new WeakMap<object, number>();\nconst finished = new WeakSet<object>();\n\nconst plugin: FastifyPluginCallback<FastifyLoggerOptions> = (app, opts, done) => {\n const summary = (req: FastifyRequest, status: number) => {\n if (finished.has(req)) return;\n finished.add(req);\n const store = storeOf(req);\n const start = starts.get(req);\n logHttpRequest(\n opts.log,\n {\n method: req.method,\n route: req.routeOptions?.url,\n path: req.url,\n status,\n duration_ms: start === undefined ? undefined : performance.now() - start,\n err: store?.error,\n fields: store?.fields,\n },\n opts,\n );\n };\n\n app.addHook(\"onRequest\", (req, reply, next) => {\n const ctx = requestContextFields(req.headers);\n reply.header(\"x-request-id\", ctx.request_id);\n starts.set(req, performance.now());\n runWithStore(ctx, (store) => {\n attachStore(req, store);\n attachStore(reply, store);\n next();\n });\n });\n app.addHook(\"onError\", (_req, reply, err, next) => {\n const store = storeOf(reply);\n if (store) recordErrorIn(store, err);\n next();\n });\n app.addHook(\"onResponse\", (req, reply, next) => {\n summary(req, reply.statusCode);\n next();\n });\n // Client closed the connection before the response (Fastify >= 4.21).\n app.addHook(\"onRequestAbort\", (req, next) => {\n summary(req, 499);\n next();\n });\n done();\n};\n\n// Same effect as fastify-plugin: hooks apply to the whole app, not an encapsulated child.\n(plugin as unknown as Record<symbol, boolean>)[Symbol.for(\"skip-override\")] = true;\n\nexport const fastifyLogger = plugin;\n"],"mappings":";;;;;;;;;;;;AASA,IAAM,SAAS,oBAAI,QAAwB;AAC3C,IAAM,WAAW,oBAAI,QAAgB;AAErC,IAAM,SAAsD,CAAC,KAAK,MAAM,SAAS;AAC/E,QAAM,UAAU,CAAC,KAAqB,WAAmB;AACvD,QAAI,SAAS,IAAI,GAAG,EAAG;AACvB,aAAS,IAAI,GAAG;AAChB,UAAM,QAAQ,QAAQ,GAAG;AACzB,UAAM,QAAQ,OAAO,IAAI,GAAG;AAC5B;AAAA,MACE,KAAK;AAAA,MACL;AAAA,QACE,QAAQ,IAAI;AAAA,QACZ,OAAO,IAAI,cAAc;AAAA,QACzB,MAAM,IAAI;AAAA,QACV;AAAA,QACA,aAAa,UAAU,SAAY,SAAY,YAAY,IAAI,IAAI;AAAA,QACnE,KAAK,OAAO;AAAA,QACZ,QAAQ,OAAO;AAAA,MACjB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,aAAa,CAAC,KAAK,OAAO,SAAS;AAC7C,UAAM,MAAM,qBAAqB,IAAI,OAAO;AAC5C,UAAM,OAAO,gBAAgB,IAAI,UAAU;AAC3C,WAAO,IAAI,KAAK,YAAY,IAAI,CAAC;AACjC,iBAAa,KAAK,CAAC,UAAU;AAC3B,kBAAY,KAAK,KAAK;AACtB,kBAAY,OAAO,KAAK;AACxB,WAAK;AAAA,IACP,CAAC;AAAA,EACH,CAAC;AACD,MAAI,QAAQ,WAAW,CAAC,MAAM,OAAO,KAAK,SAAS;AACjD,UAAM,QAAQ,QAAQ,KAAK;AAC3B,QAAI,MAAO,eAAc,OAAO,GAAG;AACnC,SAAK;AAAA,EACP,CAAC;AACD,MAAI,QAAQ,cAAc,CAAC,KAAK,OAAO,SAAS;AAC9C,YAAQ,KAAK,MAAM,UAAU;AAC7B,SAAK;AAAA,EACP,CAAC;AAED,MAAI,QAAQ,kBAAkB,CAAC,KAAK,SAAS;AAC3C,YAAQ,KAAK,GAAG;AAChB,SAAK;AAAA,EACP,CAAC;AACD,OAAK;AACP;AAGC,OAA8C,uBAAO,IAAI,eAAe,CAAC,IAAI;AAEvE,IAAM,gBAAgB;","names":[]}
@@ -0,0 +1,209 @@
1
+ import {
2
+ parseTraceparent,
3
+ resolveRequestId
4
+ } from "./chunk-KLBL7QEN.js";
5
+ import {
6
+ REDACTED,
7
+ getContext,
8
+ isErrorLike,
9
+ markLogged,
10
+ serializeError,
11
+ toSnakeCase
12
+ } from "./chunk-QMC6BWGK.js";
13
+
14
+ // src/normalize.ts
15
+ var HOOK_EXEMPT = /* @__PURE__ */ new Set(["level", "message", "event"]);
16
+ var RESERVED_KEYS = /* @__PURE__ */ new Set([
17
+ "project",
18
+ "service",
19
+ "vps",
20
+ "version",
21
+ "container_name",
22
+ "container_id",
23
+ "image",
24
+ "stream",
25
+ "_timestamp",
26
+ "label",
27
+ "host",
28
+ "source_type",
29
+ "msg",
30
+ "lvl",
31
+ "severity",
32
+ "level",
33
+ "message"
34
+ ]);
35
+ var MAX_LINE_BYTES = 16e3;
36
+ var MAX_MESSAGE = 500;
37
+ var MAX_STACK = 4e3;
38
+ var MAX_STRING = 1e3;
39
+ var MAX_DEPTH = 3;
40
+ var TRUNCATED = "\u2026[truncated]";
41
+ var KEEP_ON_SHRINK = /* @__PURE__ */ new Set([
42
+ "level",
43
+ "message",
44
+ "event",
45
+ "request_id",
46
+ "trace_id",
47
+ "span_id",
48
+ "job_name",
49
+ "job_id",
50
+ "job_attempt",
51
+ "user_id",
52
+ "tenant_id",
53
+ "err_type",
54
+ "err_message",
55
+ "err_code"
56
+ ]);
57
+ function stripUrl(url) {
58
+ const noQuery = url.split(/[?#]/, 1)[0] ?? "";
59
+ return noQuery.replace(/^([a-z][a-z0-9+.-]*:\/\/)[^/@\s]*@/i, "$1");
60
+ }
61
+ function truncate(s, max) {
62
+ return s.length > max ? s.slice(0, max - TRUNCATED.length) + TRUNCATED : s;
63
+ }
64
+ function isPlainObject(v) {
65
+ if (typeof v !== "object" || v === null) return false;
66
+ const proto = Object.getPrototypeOf(v);
67
+ return proto === Object.prototype || proto === null;
68
+ }
69
+ function isUrlKey(key) {
70
+ return key === "http_path" || key === "http_url" || key.endsWith("_url");
71
+ }
72
+ function flattenInto(out, prefix, obj, depth, opts) {
73
+ for (const [rawKey, value] of Object.entries(obj)) {
74
+ const key = opts.snakeCase ? toSnakeCase(rawKey) : rawKey;
75
+ const full = prefix ? `${prefix}_${key}` : key;
76
+ if (value === void 0 || typeof value === "function" || typeof value === "symbol") continue;
77
+ if (value !== null && (opts.redactor.isSensitive(rawKey) || opts.redactor.isSensitive(full))) {
78
+ out[full] = REDACTED;
79
+ continue;
80
+ }
81
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
82
+ out[full] = value;
83
+ } else if (typeof value === "number") {
84
+ out[full] = Number.isFinite(value) ? value : String(value);
85
+ } else if (typeof value === "bigint") {
86
+ out[full] = value.toString();
87
+ } else if (value instanceof Date) {
88
+ out[full] = Number.isNaN(value.getTime()) ? "Invalid Date" : value.toISOString();
89
+ } else if (isErrorLike(value)) {
90
+ out[full] = `${value.name}: ${value.message}`;
91
+ } else if (isPlainObject(value) && depth < MAX_DEPTH - 1) {
92
+ flattenInto(out, full, value, depth + 1, opts);
93
+ } else {
94
+ out[full] = opts.redactor.json(value);
95
+ }
96
+ }
97
+ }
98
+ function finalize(key, value, opts) {
99
+ if (typeof value !== "string") return value;
100
+ const v = opts.redactor.scrub(isUrlKey(key) ? stripUrl(value) : value);
101
+ return truncate(v, key === "err_stack" ? MAX_STACK : MAX_STRING);
102
+ }
103
+ function buildRecord(level, message, sources, opts) {
104
+ const merged = {};
105
+ for (const source of sources) if (source) Object.assign(merged, source);
106
+ let err;
107
+ if (merged.err !== void 0 && merged.err !== null) {
108
+ err = merged.err;
109
+ delete merged.err;
110
+ } else if (isErrorLike(merged.error)) {
111
+ err = merged.error;
112
+ delete merged.error;
113
+ }
114
+ const flat = {};
115
+ flattenInto(flat, "", merged, 0, opts);
116
+ if (err !== void 0) Object.assign(flat, serializeError(err));
117
+ const text = typeof message === "string" ? message : opts.redactor.json(message);
118
+ const out = { level, message: truncate(opts.redactor.scrub(text), MAX_MESSAGE) };
119
+ for (const [k, v] of Object.entries(flat)) {
120
+ const key = RESERVED_KEYS.has(k) ? `app_${k}` : k;
121
+ let value = finalize(key, v, opts);
122
+ if (opts.hook && !HOOK_EXEMPT.has(key)) {
123
+ const replaced = opts.hook(key, value);
124
+ if (replaced === void 0) continue;
125
+ value = typeof replaced === "object" && replaced !== null ? opts.redactor.json(replaced) : replaced;
126
+ }
127
+ out[key] = value;
128
+ }
129
+ return out;
130
+ }
131
+ function byteLength(s) {
132
+ if (s.length * 3 <= MAX_LINE_BYTES) return s.length;
133
+ return new TextEncoder().encode(s).length;
134
+ }
135
+ function serializeRecord(record) {
136
+ const line = JSON.stringify(record);
137
+ if (byteLength(line) <= MAX_LINE_BYTES) return line;
138
+ const small = {};
139
+ for (const [k, v] of Object.entries(record)) {
140
+ if (KEEP_ON_SHRINK.has(k) || k.startsWith("http_")) small[k] = v;
141
+ }
142
+ small.log_truncated = true;
143
+ return JSON.stringify(small);
144
+ }
145
+
146
+ // src/http.ts
147
+ function header(headers, name) {
148
+ if (typeof headers.get === "function") return headers.get(name) ?? void 0;
149
+ return headers[name];
150
+ }
151
+ function requestContextFields(headers) {
152
+ const out = {
153
+ request_id: resolveRequestId(header(headers, "x-request-id"))
154
+ };
155
+ const tp = parseTraceparent(header(headers, "traceparent"));
156
+ if (tp) Object.assign(out, tp);
157
+ return out;
158
+ }
159
+ function propagationHeaders() {
160
+ const ctx = getContext();
161
+ const out = {};
162
+ if (typeof ctx.request_id === "string") out["x-request-id"] = ctx.request_id;
163
+ if (typeof ctx.trace_id === "string" && typeof ctx.span_id === "string") {
164
+ out.traceparent = `00-${ctx.trace_id}-${ctx.span_id}-01`;
165
+ }
166
+ return out;
167
+ }
168
+ var DEFAULT_SKIP_PATHS = [
169
+ /^\/(health|healthz|ready|readyz|livez)\/?$/,
170
+ "/favicon.ico",
171
+ /^\/_next\/static\//
172
+ ];
173
+ function shouldSkip(method, path, skipPaths = DEFAULT_SKIP_PATHS) {
174
+ if (method.toUpperCase() === "OPTIONS") return true;
175
+ const p = stripUrl(path);
176
+ return skipPaths.some((s) => typeof s === "string" ? p === s : s.test(p));
177
+ }
178
+ function logHttpRequest(log, info, opts = {}) {
179
+ if (shouldSkip(info.method, info.path, opts.skipPaths)) return;
180
+ const level = info.status >= 500 ? "error" : info.status >= 400 ? "warn" : "info";
181
+ const path = stripUrl(info.path);
182
+ const errFields = {};
183
+ if (info.err !== void 0 && info.err !== null) {
184
+ Object.assign(errFields, serializeError(info.err));
185
+ if (info.status < 500) delete errFields.err_stack;
186
+ markLogged(info.err);
187
+ }
188
+ const message = info.route ? `${info.method} ${info.route} ${info.status}` : `${info.method} ${info.status}`;
189
+ log[level](message, {
190
+ ...info.fields,
191
+ event: "http.request",
192
+ http_method: info.method,
193
+ http_route: info.route,
194
+ http_path: path,
195
+ http_status: info.status,
196
+ duration_ms: info.duration_ms === void 0 ? void 0 : Math.round(info.duration_ms),
197
+ ...errFields
198
+ });
199
+ }
200
+
201
+ export {
202
+ buildRecord,
203
+ serializeRecord,
204
+ requestContextFields,
205
+ propagationHeaders,
206
+ DEFAULT_SKIP_PATHS,
207
+ logHttpRequest
208
+ };
209
+ //# sourceMappingURL=chunk-KD5H5G6Y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/normalize.ts","../src/http.ts"],"sourcesContent":["import { isErrorLike, serializeError } from \"./error\";\nimport type { Level } from \"./levels\";\nimport { REDACTED, toSnakeCase, type Redactor } from \"./redact\";\n\nexport { DEFAULT_REDACT_KEYS, toSnakeCase } from \"./redact\";\n\n/** Final per-field hook: return a replacement, or undefined to drop the field. */\nexport type RedactHook = (key: string, value: Primitive) => unknown;\n\nexport type Fields = Record<string, unknown>;\nexport type Primitive = string | number | boolean | null;\nexport type LogRecord = Record<string, Primitive>;\n\nexport interface NormalizeOptions {\n snakeCase: boolean;\n redactor: Redactor;\n hook?: RedactHook;\n}\n\n// Fields the redact hook never sees, so every line keeps its level, message and event.\nconst HOOK_EXEMPT = new Set([\"level\", \"message\", \"event\"]);\n\n// Keys owned by Vector (overwritten or deleted on ingest) or by the logger itself.\nexport const RESERVED_KEYS = new Set([\n \"project\", \"service\", \"vps\", \"version\", \"container_name\", \"container_id\", \"image\", \"stream\",\n \"_timestamp\", \"label\", \"host\", \"source_type\", \"msg\", \"lvl\", \"severity\", \"level\", \"message\",\n]);\n\nexport const MAX_LINE_BYTES = 16000;\nconst MAX_MESSAGE = 500;\nconst MAX_STACK = 4000;\nconst MAX_STRING = 1000;\nconst MAX_DEPTH = 3;\nconst TRUNCATED = \"…[truncated]\";\n\n// Fields kept when a line is too large.\nconst KEEP_ON_SHRINK = new Set([\n \"level\", \"message\", \"event\", \"request_id\", \"trace_id\", \"span_id\", \"job_name\", \"job_id\", \"job_attempt\",\n \"user_id\", \"tenant_id\", \"err_type\", \"err_message\", \"err_code\",\n]);\n\nexport function stripUrl(url: string): string {\n const noQuery = url.split(/[?#]/, 1)[0] ?? \"\";\n return noQuery.replace(/^([a-z][a-z0-9+.-]*:\\/\\/)[^/@\\s]*@/i, \"$1\");\n}\n\nexport function truncate(s: string, max: number): string {\n return s.length > max ? s.slice(0, max - TRUNCATED.length) + TRUNCATED : s;\n}\n\nfunction isPlainObject(v: unknown): v is Fields {\n if (typeof v !== \"object\" || v === null) return false;\n const proto = Object.getPrototypeOf(v);\n return proto === Object.prototype || proto === null;\n}\n\nfunction isUrlKey(key: string): boolean {\n return key === \"http_path\" || key === \"http_url\" || key.endsWith(\"_url\");\n}\n\nfunction flattenInto(out: LogRecord, prefix: string, obj: Fields, depth: number, opts: NormalizeOptions): void {\n for (const [rawKey, value] of Object.entries(obj)) {\n const key = opts.snakeCase ? toSnakeCase(rawKey) : rawKey;\n const full = prefix ? `${prefix}_${key}` : key;\n if (value === undefined || typeof value === \"function\" || typeof value === \"symbol\") continue;\n if (value !== null && (opts.redactor.isSensitive(rawKey) || opts.redactor.isSensitive(full))) {\n out[full] = REDACTED;\n continue;\n }\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") {\n out[full] = value;\n } else if (typeof value === \"number\") {\n out[full] = Number.isFinite(value) ? value : String(value);\n } else if (typeof value === \"bigint\") {\n out[full] = value.toString();\n } else if (value instanceof Date) {\n out[full] = Number.isNaN(value.getTime()) ? \"Invalid Date\" : value.toISOString();\n } else if (isErrorLike(value)) {\n out[full] = `${value.name}: ${value.message}`;\n } else if (isPlainObject(value) && depth < MAX_DEPTH - 1) {\n flattenInto(out, full, value, depth + 1, opts);\n } else {\n // Arrays, deep objects, class instances: stringified with sensitive keys redacted.\n out[full] = opts.redactor.json(value);\n }\n }\n}\n\nfunction finalize(key: string, value: Primitive, opts: NormalizeOptions): Primitive {\n if (typeof value !== \"string\") return value;\n const v = opts.redactor.scrub(isUrlKey(key) ? stripUrl(value) : value);\n return truncate(v, key === \"err_stack\" ? MAX_STACK : MAX_STRING);\n}\n\nexport function buildRecord(\n level: Level,\n message: unknown,\n sources: (Fields | undefined)[],\n opts: NormalizeOptions,\n): LogRecord {\n const merged: Fields = {};\n for (const source of sources) if (source) Object.assign(merged, source);\n\n let err: unknown;\n if (merged.err !== undefined && merged.err !== null) {\n err = merged.err;\n delete merged.err;\n } else if (isErrorLike(merged.error)) {\n err = merged.error;\n delete merged.error;\n }\n\n const flat: LogRecord = {};\n flattenInto(flat, \"\", merged, 0, opts);\n if (err !== undefined) Object.assign(flat, serializeError(err));\n\n const text = typeof message === \"string\" ? message : opts.redactor.json(message);\n const out: LogRecord = { level, message: truncate(opts.redactor.scrub(text), MAX_MESSAGE) };\n for (const [k, v] of Object.entries(flat)) {\n const key = RESERVED_KEYS.has(k) ? `app_${k}` : k;\n let value = finalize(key, v, opts);\n if (opts.hook && !HOOK_EXEMPT.has(key)) {\n const replaced = opts.hook(key, value);\n if (replaced === undefined) continue;\n value = typeof replaced === \"object\" && replaced !== null ? opts.redactor.json(replaced) : (replaced as Primitive);\n }\n out[key] = value;\n }\n return out;\n}\n\nfunction byteLength(s: string): number {\n // UTF-8 uses at most 3 bytes per UTF-16 code unit: skip encoding short lines.\n if (s.length * 3 <= MAX_LINE_BYTES) return s.length;\n return new TextEncoder().encode(s).length;\n}\n\nexport function serializeRecord(record: LogRecord): string {\n const line = JSON.stringify(record);\n if (byteLength(line) <= MAX_LINE_BYTES) return line;\n const small: LogRecord = {};\n for (const [k, v] of Object.entries(record)) {\n if (KEEP_ON_SHRINK.has(k) || k.startsWith(\"http_\")) small[k] = v;\n }\n small.log_truncated = true;\n return JSON.stringify(small);\n}\n","import { getContext } from \"./context\";\nimport { markLogged, serializeError } from \"./error\";\nimport type { Logger } from \"./logger\";\nimport { stripUrl, type Fields } from \"./normalize\";\nimport { parseTraceparent, resolveRequestId } from \"./request-id\";\n\nexport { newRequestId, parseTraceparent, REQUEST_ID_RE, resolveRequestId } from \"./request-id\";\n\nexport type HeaderSource = Headers | Record<string, string | string[] | undefined>;\n\nfunction header(headers: HeaderSource, name: string): string | string[] | undefined {\n if (typeof (headers as Headers).get === \"function\") return (headers as Headers).get(name) ?? undefined;\n return (headers as Record<string, string | string[] | undefined>)[name];\n}\n\nexport function requestContextFields(headers: HeaderSource): { request_id: string; trace_id?: string; span_id?: string } {\n const out: { request_id: string; trace_id?: string; span_id?: string } = {\n request_id: resolveRequestId(header(headers, \"x-request-id\")),\n };\n const tp = parseTraceparent(header(headers, \"traceparent\"));\n if (tp) Object.assign(out, tp);\n return out;\n}\n\n// Headers to forward to services we own, so their logs share request_id / trace_id.\nexport function propagationHeaders(): Record<string, string> {\n const ctx = getContext();\n const out: Record<string, string> = {};\n if (typeof ctx.request_id === \"string\") out[\"x-request-id\"] = ctx.request_id;\n if (typeof ctx.trace_id === \"string\" && typeof ctx.span_id === \"string\") {\n out.traceparent = `00-${ctx.trace_id}-${ctx.span_id}-01`;\n }\n return out;\n}\n\nexport const DEFAULT_SKIP_PATHS: (string | RegExp)[] = [\n /^\\/(health|healthz|ready|readyz|livez)\\/?$/,\n \"/favicon.ico\",\n /^\\/_next\\/static\\//,\n];\n\nexport interface HttpLogOptions {\n skipPaths?: (string | RegExp)[];\n}\n\nexport interface HttpRequestInfo {\n method: string;\n route?: string;\n path: string;\n status: number;\n duration_ms?: number;\n err?: unknown;\n fields?: Fields;\n}\n\nexport function shouldSkip(method: string, path: string, skipPaths: (string | RegExp)[] = DEFAULT_SKIP_PATHS): boolean {\n if (method.toUpperCase() === \"OPTIONS\") return true;\n const p = stripUrl(path);\n return skipPaths.some((s) => (typeof s === \"string\" ? p === s : s.test(p)));\n}\n\n// Writes the one `http.request` summary line for an inbound request.\nexport function logHttpRequest(log: Logger, info: HttpRequestInfo, opts: HttpLogOptions = {}): void {\n if (shouldSkip(info.method, info.path, opts.skipPaths)) return;\n const level = info.status >= 500 ? \"error\" : info.status >= 400 ? \"warn\" : \"info\";\n const path = stripUrl(info.path);\n const errFields: Fields = {};\n if (info.err !== undefined && info.err !== null) {\n Object.assign(errFields, serializeError(info.err));\n if (info.status < 500) delete errFields.err_stack;\n markLogged(info.err);\n }\n // Route templates keep the message bounded; the raw path would make one message per URL.\n const message = info.route ? `${info.method} ${info.route} ${info.status}` : `${info.method} ${info.status}`;\n log[level](message, {\n ...info.fields,\n event: \"http.request\",\n http_method: info.method,\n http_route: info.route,\n http_path: path,\n http_status: info.status,\n duration_ms: info.duration_ms === undefined ? undefined : Math.round(info.duration_ms),\n ...errFields,\n });\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,29 @@
1
+ // src/request-id.ts
2
+ var REQUEST_ID_RE = /^[A-Za-z0-9._-]{1,64}$/;
3
+ var TRACEPARENT_RE = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;
4
+ function newRequestId() {
5
+ return globalThis.crypto.randomUUID();
6
+ }
7
+ function first(header) {
8
+ return Array.isArray(header) ? header[0] : header ?? void 0;
9
+ }
10
+ function resolveRequestId(header) {
11
+ const value = first(header);
12
+ return value && REQUEST_ID_RE.test(value) ? value : newRequestId();
13
+ }
14
+ function parseTraceparent(header) {
15
+ const value = first(header)?.trim().toLowerCase();
16
+ const m = value ? TRACEPARENT_RE.exec(value) : null;
17
+ if (!m) return void 0;
18
+ const [, version, traceId, spanId] = m;
19
+ if (version === "ff" || /^0+$/.test(traceId) || /^0+$/.test(spanId)) return void 0;
20
+ return { trace_id: traceId, span_id: spanId };
21
+ }
22
+
23
+ export {
24
+ REQUEST_ID_RE,
25
+ newRequestId,
26
+ resolveRequestId,
27
+ parseTraceparent
28
+ };
29
+ //# sourceMappingURL=chunk-KLBL7QEN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/request-id.ts"],"sourcesContent":["// No imports: this module is shared with the edge entry (next-edge).\nexport const REQUEST_ID_RE = /^[A-Za-z0-9._-]{1,64}$/;\nconst TRACEPARENT_RE = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;\n\nexport function newRequestId(): string {\n return globalThis.crypto.randomUUID();\n}\n\nfunction first(header?: string | string[] | null): string | undefined {\n return Array.isArray(header) ? header[0] : (header ?? undefined);\n}\n\nexport function resolveRequestId(header?: string | string[] | null): string {\n const value = first(header);\n return value && REQUEST_ID_RE.test(value) ? value : newRequestId();\n}\n\nexport function parseTraceparent(header?: string | string[] | null): { trace_id: string; span_id: string } | undefined {\n const value = first(header)?.trim().toLowerCase();\n const m = value ? TRACEPARENT_RE.exec(value) : null;\n if (!m) return undefined;\n const [, version, traceId, spanId] = m as unknown as [string, string, string, string];\n if (version === \"ff\" || /^0+$/.test(traceId) || /^0+$/.test(spanId)) return undefined;\n return { trace_id: traceId, span_id: spanId };\n}\n"],"mappings":";AACO,IAAM,gBAAgB;AAC7B,IAAM,iBAAiB;AAEhB,SAAS,eAAuB;AACrC,SAAO,WAAW,OAAO,WAAW;AACtC;AAEA,SAAS,MAAM,QAAuD;AACpE,SAAO,MAAM,QAAQ,MAAM,IAAI,OAAO,CAAC,IAAK,UAAU;AACxD;AAEO,SAAS,iBAAiB,QAA2C;AAC1E,QAAM,QAAQ,MAAM,MAAM;AAC1B,SAAO,SAAS,cAAc,KAAK,KAAK,IAAI,QAAQ,aAAa;AACnE;AAEO,SAAS,iBAAiB,QAAsF;AACrH,QAAM,QAAQ,MAAM,MAAM,GAAG,KAAK,EAAE,YAAY;AAChD,QAAM,IAAI,QAAQ,eAAe,KAAK,KAAK,IAAI;AAC/C,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,CAAC,EAAE,SAAS,SAAS,MAAM,IAAI;AACrC,MAAI,YAAY,QAAQ,OAAO,KAAK,OAAO,KAAK,OAAO,KAAK,MAAM,EAAG,QAAO;AAC5E,SAAO,EAAE,UAAU,SAAS,SAAS,OAAO;AAC9C;","names":[]}