@safaricom-mxl/log 0.0.3

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 (131) hide show
  1. package/README.md +1040 -0
  2. package/dist/_http-DmaJ426Z.mjs +76 -0
  3. package/dist/_http-DmaJ426Z.mjs.map +1 -0
  4. package/dist/_severity-D_IU9-90.mjs +17 -0
  5. package/dist/_severity-D_IU9-90.mjs.map +1 -0
  6. package/dist/adapters/axiom.d.mts +64 -0
  7. package/dist/adapters/axiom.d.mts.map +1 -0
  8. package/dist/adapters/axiom.mjs +100 -0
  9. package/dist/adapters/axiom.mjs.map +1 -0
  10. package/dist/adapters/better-stack.d.mts +63 -0
  11. package/dist/adapters/better-stack.d.mts.map +1 -0
  12. package/dist/adapters/better-stack.mjs +98 -0
  13. package/dist/adapters/better-stack.mjs.map +1 -0
  14. package/dist/adapters/otlp.d.mts +85 -0
  15. package/dist/adapters/otlp.d.mts.map +1 -0
  16. package/dist/adapters/otlp.mjs +196 -0
  17. package/dist/adapters/otlp.mjs.map +1 -0
  18. package/dist/adapters/posthog.d.mts +107 -0
  19. package/dist/adapters/posthog.d.mts.map +1 -0
  20. package/dist/adapters/posthog.mjs +166 -0
  21. package/dist/adapters/posthog.mjs.map +1 -0
  22. package/dist/adapters/sentry.d.mts +80 -0
  23. package/dist/adapters/sentry.d.mts.map +1 -0
  24. package/dist/adapters/sentry.mjs +221 -0
  25. package/dist/adapters/sentry.mjs.map +1 -0
  26. package/dist/browser.d.mts +63 -0
  27. package/dist/browser.d.mts.map +1 -0
  28. package/dist/browser.mjs +95 -0
  29. package/dist/browser.mjs.map +1 -0
  30. package/dist/enrichers.d.mts +74 -0
  31. package/dist/enrichers.d.mts.map +1 -0
  32. package/dist/enrichers.mjs +172 -0
  33. package/dist/enrichers.mjs.map +1 -0
  34. package/dist/error.d.mts +65 -0
  35. package/dist/error.d.mts.map +1 -0
  36. package/dist/error.mjs +112 -0
  37. package/dist/error.mjs.map +1 -0
  38. package/dist/index.d.mts +6 -0
  39. package/dist/index.mjs +6 -0
  40. package/dist/logger.d.mts +46 -0
  41. package/dist/logger.d.mts.map +1 -0
  42. package/dist/logger.mjs +287 -0
  43. package/dist/logger.mjs.map +1 -0
  44. package/dist/next/client.d.mts +55 -0
  45. package/dist/next/client.d.mts.map +1 -0
  46. package/dist/next/client.mjs +44 -0
  47. package/dist/next/client.mjs.map +1 -0
  48. package/dist/next/index.d.mts +169 -0
  49. package/dist/next/index.d.mts.map +1 -0
  50. package/dist/next/index.mjs +280 -0
  51. package/dist/next/index.mjs.map +1 -0
  52. package/dist/nitro/errorHandler.d.mts +15 -0
  53. package/dist/nitro/errorHandler.d.mts.map +1 -0
  54. package/dist/nitro/errorHandler.mjs +41 -0
  55. package/dist/nitro/errorHandler.mjs.map +1 -0
  56. package/dist/nitro/module.d.mts +11 -0
  57. package/dist/nitro/module.d.mts.map +1 -0
  58. package/dist/nitro/module.mjs +23 -0
  59. package/dist/nitro/module.mjs.map +1 -0
  60. package/dist/nitro/plugin.d.mts +7 -0
  61. package/dist/nitro/plugin.d.mts.map +1 -0
  62. package/dist/nitro/plugin.mjs +145 -0
  63. package/dist/nitro/plugin.mjs.map +1 -0
  64. package/dist/nitro/v3/errorHandler.d.mts +24 -0
  65. package/dist/nitro/v3/errorHandler.d.mts.map +1 -0
  66. package/dist/nitro/v3/errorHandler.mjs +36 -0
  67. package/dist/nitro/v3/errorHandler.mjs.map +1 -0
  68. package/dist/nitro/v3/index.d.mts +5 -0
  69. package/dist/nitro/v3/index.mjs +5 -0
  70. package/dist/nitro/v3/middleware.d.mts +25 -0
  71. package/dist/nitro/v3/middleware.d.mts.map +1 -0
  72. package/dist/nitro/v3/middleware.mjs +45 -0
  73. package/dist/nitro/v3/middleware.mjs.map +1 -0
  74. package/dist/nitro/v3/module.d.mts +10 -0
  75. package/dist/nitro/v3/module.d.mts.map +1 -0
  76. package/dist/nitro/v3/module.mjs +22 -0
  77. package/dist/nitro/v3/module.mjs.map +1 -0
  78. package/dist/nitro/v3/plugin.d.mts +14 -0
  79. package/dist/nitro/v3/plugin.d.mts.map +1 -0
  80. package/dist/nitro/v3/plugin.mjs +162 -0
  81. package/dist/nitro/v3/plugin.mjs.map +1 -0
  82. package/dist/nitro/v3/useLogger.d.mts +24 -0
  83. package/dist/nitro/v3/useLogger.d.mts.map +1 -0
  84. package/dist/nitro/v3/useLogger.mjs +27 -0
  85. package/dist/nitro/v3/useLogger.mjs.map +1 -0
  86. package/dist/nitro-CrFBjY1Y.d.mts +42 -0
  87. package/dist/nitro-CrFBjY1Y.d.mts.map +1 -0
  88. package/dist/nitro-Dsv6dSzv.mjs +39 -0
  89. package/dist/nitro-Dsv6dSzv.mjs.map +1 -0
  90. package/dist/nuxt/module.d.mts +164 -0
  91. package/dist/nuxt/module.d.mts.map +1 -0
  92. package/dist/nuxt/module.mjs +84 -0
  93. package/dist/nuxt/module.mjs.map +1 -0
  94. package/dist/pipeline.d.mts +46 -0
  95. package/dist/pipeline.d.mts.map +1 -0
  96. package/dist/pipeline.mjs +122 -0
  97. package/dist/pipeline.mjs.map +1 -0
  98. package/dist/routes-BNbrnm14.mjs +39 -0
  99. package/dist/routes-BNbrnm14.mjs.map +1 -0
  100. package/dist/runtime/client/log.d.mts +15 -0
  101. package/dist/runtime/client/log.d.mts.map +1 -0
  102. package/dist/runtime/client/log.mjs +92 -0
  103. package/dist/runtime/client/log.mjs.map +1 -0
  104. package/dist/runtime/client/plugin.d.mts +5 -0
  105. package/dist/runtime/client/plugin.d.mts.map +1 -0
  106. package/dist/runtime/client/plugin.mjs +17 -0
  107. package/dist/runtime/client/plugin.mjs.map +1 -0
  108. package/dist/runtime/server/routes/_mxllog/ingest.post.d.mts +7 -0
  109. package/dist/runtime/server/routes/_mxllog/ingest.post.d.mts.map +1 -0
  110. package/dist/runtime/server/routes/_mxllog/ingest.post.mjs +123 -0
  111. package/dist/runtime/server/routes/_mxllog/ingest.post.mjs.map +1 -0
  112. package/dist/runtime/server/useLogger.d.mts +39 -0
  113. package/dist/runtime/server/useLogger.d.mts.map +1 -0
  114. package/dist/runtime/server/useLogger.mjs +43 -0
  115. package/dist/runtime/server/useLogger.mjs.map +1 -0
  116. package/dist/runtime/utils/parseError.d.mts +7 -0
  117. package/dist/runtime/utils/parseError.d.mts.map +1 -0
  118. package/dist/runtime/utils/parseError.mjs +29 -0
  119. package/dist/runtime/utils/parseError.mjs.map +1 -0
  120. package/dist/types.d.mts +496 -0
  121. package/dist/types.d.mts.map +1 -0
  122. package/dist/types.mjs +1 -0
  123. package/dist/utils.d.mts +34 -0
  124. package/dist/utils.d.mts.map +1 -0
  125. package/dist/utils.mjs +78 -0
  126. package/dist/utils.mjs.map +1 -0
  127. package/dist/workers.d.mts +46 -0
  128. package/dist/workers.d.mts.map +1 -0
  129. package/dist/workers.mjs +81 -0
  130. package/dist/workers.mjs.map +1 -0
  131. package/package.json +195 -0
@@ -0,0 +1,11 @@
1
+ import { useLogger } from "../runtime/server/useLogger.mjs";
2
+ import { t as NitroModuleOptions } from "../nitro-CrFBjY1Y.mjs";
3
+
4
+ //#region src/nitro/module.d.ts
5
+ declare function mxllog(options?: NitroModuleOptions): {
6
+ name: string;
7
+ setup(nitro: any): void;
8
+ };
9
+ //#endregion
10
+ export { type NitroModuleOptions, mxllog as default, useLogger };
11
+ //# sourceMappingURL=module.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.d.mts","names":[],"sources":["../../src/nitro/module.ts"],"mappings":";;;;iBAQwB,MAAA,CAAO,OAAA,GAAU,kBAAA"}
@@ -0,0 +1,23 @@
1
+ import { useLogger } from "../runtime/server/useLogger.mjs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ //#region src/nitro/module.ts
6
+ const _dir = dirname(fileURLToPath(import.meta.url));
7
+ function mxllog(options) {
8
+ return {
9
+ name: "@safaricom-mxl/log",
10
+ setup(nitro) {
11
+ nitro.options.plugins = nitro.options.plugins || [];
12
+ nitro.options.plugins.push(resolve(_dir, "plugin"));
13
+ if (!nitro.options.errorHandler) nitro.options.errorHandler = resolve(_dir, "errorHandler");
14
+ nitro.options.runtimeConfig = nitro.options.runtimeConfig || {};
15
+ nitro.options.runtimeConfig.mxllog = options || {};
16
+ process.env.__MXLLOG_CONFIG = JSON.stringify(options || {});
17
+ }
18
+ };
19
+ }
20
+
21
+ //#endregion
22
+ export { mxllog as default, useLogger };
23
+ //# sourceMappingURL=module.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.mjs","names":[],"sources":["../../src/nitro/module.ts"],"sourcesContent":["import { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { NitroModuleOptions } from '../nitro'\n\nexport type { NitroModuleOptions }\n\nconst _dir = dirname(fileURLToPath(import.meta.url))\n\nexport default function mxllog(options?: NitroModuleOptions) {\n return {\n name: '@safaricom-mxl/log',\n setup(nitro: any) {\n // Push the plugin (no extension — Nitro's bundler resolves it)\n nitro.options.plugins = nitro.options.plugins || []\n nitro.options.plugins.push(resolve(_dir, 'plugin'))\n\n // Set error handler only if not already configured by user\n if (!nitro.options.errorHandler) {\n nitro.options.errorHandler = resolve(_dir, 'errorHandler')\n }\n\n // Inject config into runtimeConfig — works in production where the\n // plugin is bundled through Nitro's builder and the virtual\n // runtime-config module resolves correctly.\n nitro.options.runtimeConfig = nitro.options.runtimeConfig || {}\n nitro.options.runtimeConfig.mxllog = options || {}\n\n // In dev mode, Nitro loads plugins externally (not bundled), so the\n // virtual runtime-config module is unreachable and useRuntimeConfig()\n // returns a stub without our values. process.env is inherited by the\n // Worker Threads that run the dev server, making it a reliable bridge.\n // The plugin reads: useRuntimeConfig().mxllog ?? process.env.__MXLLOG_CONFIG\n process.env.__MXLLOG_CONFIG = JSON.stringify(options || {})\n },\n }\n}\n\nexport { useLogger } from '../runtime/server/useLogger'\n"],"mappings":";;;;;AAMA,MAAM,OAAO,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAEpD,SAAwB,OAAO,SAA8B;AAC3D,QAAO;EACL,MAAM;EACN,MAAM,OAAY;AAEhB,SAAM,QAAQ,UAAU,MAAM,QAAQ,WAAW,EAAE;AACnD,SAAM,QAAQ,QAAQ,KAAK,QAAQ,MAAM,SAAS,CAAC;AAGnD,OAAI,CAAC,MAAM,QAAQ,aACjB,OAAM,QAAQ,eAAe,QAAQ,MAAM,eAAe;AAM5D,SAAM,QAAQ,gBAAgB,MAAM,QAAQ,iBAAiB,EAAE;AAC/D,SAAM,QAAQ,cAAc,SAAS,WAAW,EAAE;AAOlD,WAAQ,IAAI,kBAAkB,KAAK,UAAU,WAAW,EAAE,CAAC;;EAE9D"}
@@ -0,0 +1,7 @@
1
+ import * as nitropack from "nitropack";
2
+
3
+ //#region src/nitro/plugin.d.ts
4
+ declare const _default: nitropack.NitroAppPlugin;
5
+ //#endregion
6
+ export { _default as default };
7
+ //# sourceMappingURL=plugin.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.mts","names":[],"sources":["../../src/nitro/plugin.ts"],"mappings":""}
@@ -0,0 +1,145 @@
1
+ import { filterSafeHeaders } from "../utils.mjs";
2
+ import { createRequestLogger, initLogger, isEnabled } from "../logger.mjs";
3
+ import { n as shouldLog, t as getServiceForPath } from "../routes-BNbrnm14.mjs";
4
+ import { t as extractErrorStatus } from "../nitro-Dsv6dSzv.mjs";
5
+ import { defineNitroPlugin } from "nitropack/runtime/internal/plugin";
6
+ import { getHeaders } from "h3";
7
+
8
+ //#region src/nitro/plugin.ts
9
+ function getSafeHeaders(event) {
10
+ return filterSafeHeaders(getHeaders(event));
11
+ }
12
+ function getSafeResponseHeaders(event) {
13
+ const headers = {};
14
+ const nodeRes = event.node?.res;
15
+ if (nodeRes?.getHeaders) for (const [key, value] of Object.entries(nodeRes.getHeaders())) {
16
+ if (value === void 0) continue;
17
+ headers[key] = Array.isArray(value) ? value.join(", ") : String(value);
18
+ }
19
+ if (event.response?.headers) event.response.headers.forEach((value, key) => {
20
+ headers[key] = value;
21
+ });
22
+ if (Object.keys(headers).length === 0) return void 0;
23
+ return filterSafeHeaders(headers);
24
+ }
25
+ function getResponseStatus(event) {
26
+ if (event.node?.res?.statusCode) return event.node.res.statusCode;
27
+ if (event.response?.status) return event.response.status;
28
+ if (typeof event.context.status === "number") return event.context.status;
29
+ return 200;
30
+ }
31
+ function buildHookContext(event) {
32
+ const responseHeaders = getSafeResponseHeaders(event);
33
+ return {
34
+ request: {
35
+ method: event.method,
36
+ path: event.path
37
+ },
38
+ headers: getSafeHeaders(event),
39
+ response: {
40
+ status: getResponseStatus(event),
41
+ headers: responseHeaders
42
+ }
43
+ };
44
+ }
45
+ async function callEnrichAndDrain(nitroApp, emittedEvent, event) {
46
+ if (!emittedEvent) return;
47
+ const hookContext = buildHookContext(event);
48
+ try {
49
+ await nitroApp.hooks.callHook("@safaricom-mxl/log:enrich", {
50
+ event: emittedEvent,
51
+ ...hookContext
52
+ });
53
+ } catch (err) {
54
+ console.error("[mxllog] enrich failed:", err);
55
+ }
56
+ const drainPromise = nitroApp.hooks.callHook("@safaricom-mxl/log:drain", {
57
+ event: emittedEvent,
58
+ request: hookContext.request,
59
+ headers: hookContext.headers
60
+ }).catch((err) => {
61
+ console.error("[mxllog] drain failed:", err);
62
+ });
63
+ const waitUntilCtx = event.context.cloudflare?.context ?? event.context;
64
+ if (typeof waitUntilCtx?.waitUntil === "function") waitUntilCtx.waitUntil(drainPromise);
65
+ else await drainPromise;
66
+ }
67
+ var plugin_default = defineNitroPlugin(async (nitroApp) => {
68
+ let mxllogConfig;
69
+ if (process.env.__MXLLOG_CONFIG) mxllogConfig = JSON.parse(process.env.__MXLLOG_CONFIG);
70
+ else try {
71
+ const { useRuntimeConfig } = await import("nitropack/runtime/internal/config");
72
+ mxllogConfig = useRuntimeConfig().mxllog;
73
+ } catch {}
74
+ initLogger({
75
+ enabled: mxllogConfig?.enabled,
76
+ env: mxllogConfig?.env,
77
+ pretty: mxllogConfig?.pretty,
78
+ sampling: mxllogConfig?.sampling
79
+ });
80
+ if (!isEnabled()) return;
81
+ nitroApp.hooks.hook("request", (event) => {
82
+ const e = event;
83
+ if (!shouldLog(e.path, mxllogConfig?.include, mxllogConfig?.exclude)) return;
84
+ e.context._mxllogStartTime = Date.now();
85
+ let requestIdOverride = void 0;
86
+ if (globalThis.navigator?.userAgent === "Cloudflare-Workers") {
87
+ const cfRay = getSafeHeaders(e)?.["cf-ray"];
88
+ if (cfRay) requestIdOverride = cfRay;
89
+ }
90
+ const requestLog = createRequestLogger({
91
+ method: e.method,
92
+ path: e.path,
93
+ requestId: requestIdOverride || e.context.requestId || crypto.randomUUID()
94
+ });
95
+ const routeService = getServiceForPath(e.path, mxllogConfig?.routes);
96
+ if (routeService) requestLog.set({ service: routeService });
97
+ e.context.log = requestLog;
98
+ });
99
+ nitroApp.hooks.hook("error", async (error, { event }) => {
100
+ const e = event;
101
+ if (!e) return;
102
+ const requestLog = e.context.log;
103
+ if (requestLog) {
104
+ requestLog.error(error);
105
+ const errorStatus = extractErrorStatus(error);
106
+ requestLog.set({ status: errorStatus });
107
+ const startTime = e.context._mxllogStartTime;
108
+ const tailCtx = {
109
+ status: errorStatus,
110
+ duration: startTime ? Date.now() - startTime : void 0,
111
+ path: e.path,
112
+ method: e.method,
113
+ context: requestLog.getContext(),
114
+ shouldKeep: false
115
+ };
116
+ await nitroApp.hooks.callHook("@safaricom-mxl/log:emit:keep", tailCtx);
117
+ e.context._mxllogEmitted = true;
118
+ await callEnrichAndDrain(nitroApp, requestLog.emit({ _forceKeep: tailCtx.shouldKeep }), e);
119
+ }
120
+ });
121
+ nitroApp.hooks.hook("afterResponse", async (event) => {
122
+ const e = event;
123
+ if (e.context._mxllogEmitted) return;
124
+ const requestLog = e.context.log;
125
+ if (requestLog) {
126
+ const status = getResponseStatus(e);
127
+ requestLog.set({ status });
128
+ const startTime = e.context._mxllogStartTime;
129
+ const tailCtx = {
130
+ status,
131
+ duration: startTime ? Date.now() - startTime : void 0,
132
+ path: e.path,
133
+ method: e.method,
134
+ context: requestLog.getContext(),
135
+ shouldKeep: false
136
+ };
137
+ await nitroApp.hooks.callHook("@safaricom-mxl/log:emit:keep", tailCtx);
138
+ await callEnrichAndDrain(nitroApp, requestLog.emit({ _forceKeep: tailCtx.shouldKeep }), e);
139
+ }
140
+ });
141
+ });
142
+
143
+ //#endregion
144
+ export { plugin_default as default };
145
+ //# sourceMappingURL=plugin.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.mjs","names":[],"sources":["../../src/nitro/plugin.ts"],"sourcesContent":["import type { NitroApp } from 'nitropack/types'\n// Import from specific subpaths to avoid the barrel 'nitropack/runtime' which\n// re-exports from internal/app.mjs — that file imports #nitro-internal-virtual/*\n// modules that only exist inside rollup builds and crash when loaded externally\n// (nitropack dev loads plugins outside the bundle via Worker threads).\nimport { defineNitroPlugin } from 'nitropack/runtime/internal/plugin'\nimport { getHeaders } from 'h3'\nimport { createRequestLogger, initLogger, isEnabled } from '../logger'\nimport { shouldLog, getServiceForPath, extractErrorStatus } from '../nitro'\nimport type { MxllogConfig } from '../nitro'\nimport type { EnrichContext, RequestLogger, ServerEvent, TailSamplingContext, WideEvent } from '../types'\nimport { filterSafeHeaders } from '../utils'\n\nfunction getSafeHeaders(event: ServerEvent): Record<string, string> {\n const allHeaders = getHeaders(event as Parameters<typeof getHeaders>[0])\n return filterSafeHeaders(allHeaders)\n}\n\nfunction getSafeResponseHeaders(event: ServerEvent): Record<string, string> | undefined {\n const headers: Record<string, string> = {}\n const nodeRes = event.node?.res as { getHeaders?: () => Record<string, unknown> } | undefined\n\n if (nodeRes?.getHeaders) {\n for (const [key, value] of Object.entries(nodeRes.getHeaders())) {\n if (value === undefined) continue\n headers[key] = Array.isArray(value) ? value.join(', ') : String(value)\n }\n }\n\n if (event.response?.headers) {\n event.response.headers.forEach((value, key) => {\n headers[key] = value\n })\n }\n\n if (Object.keys(headers).length === 0) return undefined\n return filterSafeHeaders(headers)\n}\n\nfunction getResponseStatus(event: ServerEvent): number {\n // Node.js style\n if (event.node?.res?.statusCode) {\n return event.node.res.statusCode\n }\n\n // Web Standard\n if (event.response?.status) {\n return event.response.status\n }\n\n // Context-based\n if (typeof event.context.status === 'number') {\n return event.context.status\n }\n\n return 200\n}\n\nfunction buildHookContext(event: ServerEvent): Omit<EnrichContext, 'event'> {\n const responseHeaders = getSafeResponseHeaders(event)\n return {\n request: { method: event.method, path: event.path },\n headers: getSafeHeaders(event),\n response: {\n status: getResponseStatus(event),\n headers: responseHeaders,\n },\n }\n}\n\nasync function callEnrichAndDrain(\n nitroApp: NitroApp,\n emittedEvent: WideEvent | null,\n event: ServerEvent,\n): Promise<void> {\n if (!emittedEvent) return\n\n const hookContext = buildHookContext(event)\n\n try {\n await nitroApp.hooks.callHook('@safaricom-mxl/log:enrich', { event: emittedEvent, ...hookContext })\n } catch (err) {\n console.error('[mxllog] enrich failed:', err)\n }\n\n const drainPromise = nitroApp.hooks.callHook('@safaricom-mxl/log:drain', {\n event: emittedEvent,\n request: hookContext.request,\n headers: hookContext.headers,\n }).catch((err) => {\n console.error('[mxllog] drain failed:', err)\n })\n\n // Use waitUntil if available (Cloudflare Workers, Vercel Edge, etc.)\n // This keeps the runtime alive for background work without blocking the response\n const waitUntilCtx = event.context.cloudflare?.context ?? event.context\n if (typeof waitUntilCtx?.waitUntil === 'function') {\n waitUntilCtx.waitUntil(drainPromise)\n } else {\n // Fallback: await drain to prevent lost logs in serverless environments\n // (e.g. Vercel Fluid Compute). On the normal path this runs from\n // afterResponse (response already sent); on the error path it may run\n // before the error response is finalized.\n await drainPromise\n }\n}\n\nexport default defineNitroPlugin(async (nitroApp) => {\n // Config resolution: process.env bridge first (always set by the module),\n // then lazy useRuntimeConfig() for production builds where env may not persist.\n let mxllogConfig: MxllogConfig | undefined\n if (process.env.__MXLLOG_CONFIG) {\n mxllogConfig = JSON.parse(process.env.__MXLLOG_CONFIG)\n } else {\n try {\n // nitropack/runtime/internal/config imports virtual modules —\n // only works inside rollup-bundled output (production builds).\n const { useRuntimeConfig } = await import('nitropack/runtime/internal/config')\n mxllogConfig = (useRuntimeConfig() as Record<string, any>).mxllog\n } catch {\n // Expected in dev mode — virtual modules unavailable outside rollup\n }\n }\n\n initLogger({\n enabled: mxllogConfig?.enabled,\n env: mxllogConfig?.env,\n pretty: mxllogConfig?.pretty,\n sampling: mxllogConfig?.sampling,\n })\n\n if (!isEnabled()) return\n\n nitroApp.hooks.hook('request', (event) => {\n const e = event as ServerEvent\n\n // Skip logging for routes not matching include/exclude patterns\n if (!shouldLog(e.path, mxllogConfig?.include, mxllogConfig?.exclude)) {\n return\n }\n\n // Store start time for duration calculation in tail sampling\n e.context._mxllogStartTime = Date.now()\n\n let requestIdOverride: string | undefined = undefined\n if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') {\n const cfRay = getSafeHeaders(e)?.['cf-ray']\n if (cfRay) requestIdOverride = cfRay\n }\n\n const requestLog = createRequestLogger({\n method: e.method,\n path: e.path,\n requestId: requestIdOverride || e.context.requestId || crypto.randomUUID(),\n })\n\n // Apply route-based service configuration if a matching route is found\n const routeService = getServiceForPath(e.path, mxllogConfig?.routes)\n if (routeService) {\n requestLog.set({ service: routeService })\n }\n\n e.context.log = requestLog\n })\n\n nitroApp.hooks.hook('error', async (error, { event }) => {\n const e = event as ServerEvent | undefined\n if (!e) return\n\n const requestLog = e.context.log as RequestLogger | undefined\n if (requestLog) {\n requestLog.error(error as Error)\n\n const errorStatus = extractErrorStatus(error)\n requestLog.set({ status: errorStatus })\n\n // Build tail sampling context\n const startTime = e.context._mxllogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status: errorStatus,\n duration: durationMs,\n path: e.path,\n method: e.method,\n context: requestLog.getContext(),\n shouldKeep: false,\n }\n\n // Call mxllog:emit:keep hook\n await nitroApp.hooks.callHook('@safaricom-mxl/log:emit:keep', tailCtx)\n\n e.context._mxllogEmitted = true\n\n const emittedEvent = requestLog.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(nitroApp, emittedEvent, e)\n }\n })\n\n nitroApp.hooks.hook('afterResponse', async (event) => {\n const e = event as ServerEvent\n // Skip if already emitted by error hook\n if (e.context._mxllogEmitted) return\n\n const requestLog = e.context.log as RequestLogger | undefined\n if (requestLog) {\n const status = getResponseStatus(e)\n requestLog.set({ status })\n\n const startTime = e.context._mxllogStartTime as number | undefined\n const durationMs = startTime ? Date.now() - startTime : undefined\n\n const tailCtx: TailSamplingContext = {\n status,\n duration: durationMs,\n path: e.path,\n method: e.method,\n context: requestLog.getContext(),\n shouldKeep: false,\n }\n\n await nitroApp.hooks.callHook('@safaricom-mxl/log:emit:keep', tailCtx)\n\n const emittedEvent = requestLog.emit({ _forceKeep: tailCtx.shouldKeep })\n await callEnrichAndDrain(nitroApp, emittedEvent, e)\n }\n })\n})\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import * as nitro_types0 from "nitro/types";
2
+
3
+ //#region src/nitro-v3/errorHandler.d.ts
4
+ /**
5
+ * Custom Nitro v3 error handler that properly serializes MxllogError.
6
+ * This ensures that 'data' (containing 'why', 'fix', 'link') is preserved
7
+ * in the JSON response regardless of the underlying HTTP framework.
8
+ *
9
+ * For non-MxllogError, returns undefined to let Nitro's default handler take over.
10
+ *
11
+ * Usage in nitro.config.ts:
12
+ * ```ts
13
+ * // errorHandler.ts
14
+ * export { default } from '@safaricom-mxl/log/nitro/v3/errorHandler'
15
+ * // nitro.config.ts
16
+ * export default defineConfig({
17
+ * errorHandler: './errorHandler',
18
+ * })
19
+ * ```
20
+ */
21
+ declare const _default: nitro_types0.NitroErrorHandler;
22
+ //#endregion
23
+ export { _default as default };
24
+ //# sourceMappingURL=errorHandler.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorHandler.d.mts","names":[],"sources":["../../../src/nitro-v3/errorHandler.ts"],"mappings":""}
@@ -0,0 +1,36 @@
1
+ import { n as resolveMxllogError, r as serializeMxllogErrorResponse, t as extractErrorStatus } from "../../nitro-Dsv6dSzv.mjs";
2
+ import { defineErrorHandler } from "nitro";
3
+ import { parseURL } from "ufo";
4
+
5
+ //#region src/nitro-v3/errorHandler.ts
6
+ /**
7
+ * Custom Nitro v3 error handler that properly serializes MxllogError.
8
+ * This ensures that 'data' (containing 'why', 'fix', 'link') is preserved
9
+ * in the JSON response regardless of the underlying HTTP framework.
10
+ *
11
+ * For non-MxllogError, returns undefined to let Nitro's default handler take over.
12
+ *
13
+ * Usage in nitro.config.ts:
14
+ * ```ts
15
+ * // errorHandler.ts
16
+ * export { default } from '@safaricom-mxl/log/nitro/v3/errorHandler'
17
+ * // nitro.config.ts
18
+ * export default defineConfig({
19
+ * errorHandler: './errorHandler',
20
+ * })
21
+ * ```
22
+ */
23
+ var errorHandler_default = defineErrorHandler((error, event) => {
24
+ const mxllogError = resolveMxllogError(error);
25
+ if (!mxllogError) return;
26
+ const url = parseURL(event.req.url).pathname;
27
+ const status = extractErrorStatus(mxllogError);
28
+ return new Response(JSON.stringify(serializeMxllogErrorResponse(mxllogError, url)), {
29
+ status,
30
+ headers: { "Content-Type": "application/json" }
31
+ });
32
+ });
33
+
34
+ //#endregion
35
+ export { errorHandler_default as default };
36
+ //# sourceMappingURL=errorHandler.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorHandler.mjs","names":[],"sources":["../../../src/nitro-v3/errorHandler.ts"],"sourcesContent":["import { parseURL } from 'ufo'\nimport { defineErrorHandler } from 'nitro'\nimport { resolveMxllogError, extractErrorStatus, serializeMxllogErrorResponse } from '../nitro'\n\n/**\n * Custom Nitro v3 error handler that properly serializes MxllogError.\n * This ensures that 'data' (containing 'why', 'fix', 'link') is preserved\n * in the JSON response regardless of the underlying HTTP framework.\n *\n * For non-MxllogError, returns undefined to let Nitro's default handler take over.\n *\n * Usage in nitro.config.ts:\n * ```ts\n * // errorHandler.ts\n * export { default } from '@safaricom-mxl/log/nitro/v3/errorHandler'\n * // nitro.config.ts\n * export default defineConfig({\n * errorHandler: './errorHandler',\n * })\n * ```\n */\nexport default defineErrorHandler((error, event) => {\n const mxllogError = resolveMxllogError(error)\n\n if (!mxllogError) return\n\n const url = parseURL(event.req.url).pathname\n const status = extractErrorStatus(mxllogError)\n\n return new Response(JSON.stringify(serializeMxllogErrorResponse(mxllogError, url)), {\n status,\n headers: { 'Content-Type': 'application/json' },\n })\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAqBA,2BAAe,oBAAoB,OAAO,UAAU;CAClD,MAAM,cAAc,mBAAmB,MAAM;AAE7C,KAAI,CAAC,YAAa;CAElB,MAAM,MAAM,SAAS,MAAM,IAAI,IAAI,CAAC;CACpC,MAAM,SAAS,mBAAmB,YAAY;AAE9C,QAAO,IAAI,SAAS,KAAK,UAAU,6BAA6B,aAAa,IAAI,CAAC,EAAE;EAClF;EACA,SAAS,EAAE,gBAAgB,oBAAoB;EAChD,CAAC;EACF"}
@@ -0,0 +1,5 @@
1
+ import "../../nitro-CrFBjY1Y.mjs";
2
+ import mxllog from "./module.mjs";
3
+ import { useLogger } from "./useLogger.mjs";
4
+ import { mxllogErrorHandler } from "./middleware.mjs";
5
+ export { mxllog as default, mxllogErrorHandler, useLogger };
@@ -0,0 +1,5 @@
1
+ import mxllog from "./module.mjs";
2
+ import { useLogger } from "./useLogger.mjs";
3
+ import { mxllogErrorHandler } from "./middleware.mjs";
4
+
5
+ export { mxllog as default, mxllogErrorHandler, useLogger };
@@ -0,0 +1,25 @@
1
+ //#region src/nitro-v3/middleware.d.ts
2
+ /**
3
+ * Server middleware handler that catches MxllogError and returns a structured JSON response.
4
+ *
5
+ * Frameworks like TanStack Start catch thrown errors before Nitro's error handler,
6
+ * stripping the `data` field (containing `why`, `fix`, `link`). This middleware
7
+ * intercepts MxllogErrors first, attaches them to the wide event, and throws a
8
+ * `Response` that the framework passes through directly.
9
+ *
10
+ * @example TanStack Start
11
+ * ```ts
12
+ * import { createMiddleware } from '@tanstack/react-start'
13
+ * import { mxllogErrorHandler } from '@safaricom-mxl/log/nitro/v3'
14
+ *
15
+ * const mxllogMiddleware = createMiddleware().server(mxllogErrorHandler)
16
+ *
17
+ * export const Route = createRootRoute({
18
+ * server: { middleware: [mxllogMiddleware] },
19
+ * })
20
+ * ```
21
+ */
22
+ declare function mxllogErrorHandler<T>(next: (...args: any[]) => Promise<T>): Promise<T>;
23
+ //#endregion
24
+ export { mxllogErrorHandler };
25
+ //# sourceMappingURL=middleware.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.mts","names":[],"sources":["../../../src/nitro-v3/middleware.ts"],"mappings":";;AAyBA;;;;;;;;;;;;;;;;;;;iBAAsB,kBAAA,GAAA,CAAsB,IAAA,MAAU,IAAA,YAAgB,OAAA,CAAQ,CAAA,IAAK,OAAA,CAAQ,CAAA"}
@@ -0,0 +1,45 @@
1
+ import { MxllogError } from "../../error.mjs";
2
+
3
+ //#region src/nitro-v3/middleware.ts
4
+ /**
5
+ * Server middleware handler that catches MxllogError and returns a structured JSON response.
6
+ *
7
+ * Frameworks like TanStack Start catch thrown errors before Nitro's error handler,
8
+ * stripping the `data` field (containing `why`, `fix`, `link`). This middleware
9
+ * intercepts MxllogErrors first, attaches them to the wide event, and throws a
10
+ * `Response` that the framework passes through directly.
11
+ *
12
+ * @example TanStack Start
13
+ * ```ts
14
+ * import { createMiddleware } from '@tanstack/react-start'
15
+ * import { mxllogErrorHandler } from '@safaricom-mxl/log/nitro/v3'
16
+ *
17
+ * const mxllogMiddleware = createMiddleware().server(mxllogErrorHandler)
18
+ *
19
+ * export const Route = createRootRoute({
20
+ * server: { middleware: [mxllogMiddleware] },
21
+ * })
22
+ * ```
23
+ */
24
+ async function mxllogErrorHandler(next) {
25
+ try {
26
+ return await next();
27
+ } catch (error) {
28
+ if (error instanceof MxllogError || error && typeof error === "object" && error.name === "MxllogError") {
29
+ const mxllogError = error;
30
+ try {
31
+ const { useRequest } = await import("nitro/context");
32
+ (useRequest().context?.log)?.error(mxllogError);
33
+ } catch {}
34
+ throw new Response(JSON.stringify(mxllogError.toJSON()), {
35
+ status: mxllogError.status || 500,
36
+ headers: { "Content-Type": "application/json" }
37
+ });
38
+ }
39
+ throw error;
40
+ }
41
+ }
42
+
43
+ //#endregion
44
+ export { mxllogErrorHandler };
45
+ //# sourceMappingURL=middleware.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.mjs","names":[],"sources":["../../../src/nitro-v3/middleware.ts"],"sourcesContent":["import type { RequestLogger } from '../types'\nimport { MxllogError } from '../error'\nimport { serializeMxllogErrorResponse } from '../nitro'\n\n/**\n * Server middleware handler that catches MxllogError and returns a structured JSON response.\n *\n * Frameworks like TanStack Start catch thrown errors before Nitro's error handler,\n * stripping the `data` field (containing `why`, `fix`, `link`). This middleware\n * intercepts MxllogErrors first, attaches them to the wide event, and throws a\n * `Response` that the framework passes through directly.\n *\n * @example TanStack Start\n * ```ts\n * import { createMiddleware } from '@tanstack/react-start'\n * import { mxllogErrorHandler } from '@safaricom-mxl/log/nitro/v3'\n *\n * const mxllogMiddleware = createMiddleware().server(mxllogErrorHandler)\n *\n * export const Route = createRootRoute({\n * server: { middleware: [mxllogMiddleware] },\n * })\n * ```\n */\n\nexport async function mxllogErrorHandler<T>(next: (...args: any[]) => Promise<T>): Promise<T> {\n try {\n return await next()\n } catch (error: unknown) {\n if (error instanceof MxllogError || (error && typeof error === 'object' && (error as Error).name === 'MxllogError')) {\n const mxllogError = error as MxllogError\n\n try {\n const { useRequest } = await import('nitro/context')\n const req = useRequest()\n const log = req.context?.log as RequestLogger | undefined\n log?.error(mxllogError)\n } catch {\n // ignore\n }\n\n // Throw as Response so frameworks (TanStack Start, SolidStart, etc.) pass it through\n throw new Response(JSON.stringify(mxllogError.toJSON()), {\n status: mxllogError.status || 500,\n headers: { 'Content-Type': 'application/json' },\n })\n }\n throw error\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAyBA,eAAsB,mBAAsB,MAAkD;AAC5F,KAAI;AACF,SAAO,MAAM,MAAM;UACZ,OAAgB;AACvB,MAAI,iBAAiB,eAAgB,SAAS,OAAO,UAAU,YAAa,MAAgB,SAAS,eAAgB;GACnH,MAAM,cAAc;AAEpB,OAAI;IACF,MAAM,EAAE,eAAe,MAAM,OAAO;AAGpC,KAFY,YAAY,CACR,SAAS,MACpB,MAAM,YAAY;WACjB;AAKR,SAAM,IAAI,SAAS,KAAK,UAAU,YAAY,QAAQ,CAAC,EAAE;IACvD,QAAQ,YAAY,UAAU;IAC9B,SAAS,EAAE,gBAAgB,oBAAoB;IAChD,CAAC;;AAEJ,QAAM"}
@@ -0,0 +1,10 @@
1
+ import { t as NitroModuleOptions } from "../../nitro-CrFBjY1Y.mjs";
2
+
3
+ //#region src/nitro-v3/module.d.ts
4
+ declare function mxllog(options?: NitroModuleOptions): {
5
+ name: string;
6
+ setup(nitro: any): void;
7
+ };
8
+ //#endregion
9
+ export { type NitroModuleOptions, mxllog as default };
10
+ //# sourceMappingURL=module.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.d.mts","names":[],"sources":["../../../src/nitro-v3/module.ts"],"mappings":";;;iBAQwB,MAAA,CAAO,OAAA,GAAU,kBAAA"}
@@ -0,0 +1,22 @@
1
+ import { dirname, resolve } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+
4
+ //#region src/nitro-v3/module.ts
5
+ const _dir = dirname(fileURLToPath(import.meta.url));
6
+ function mxllog(options) {
7
+ return {
8
+ name: "@safaricom-mxl/log",
9
+ setup(nitro) {
10
+ nitro.options.plugins = nitro.options.plugins || [];
11
+ nitro.options.plugins.push(resolve(_dir, "plugin"));
12
+ if (!nitro.options.errorHandler) nitro.options.errorHandler = resolve(_dir, "errorHandler");
13
+ nitro.options.runtimeConfig = nitro.options.runtimeConfig || {};
14
+ nitro.options.runtimeConfig.mxllog = options || {};
15
+ process.env.__MXLLOG_CONFIG = JSON.stringify(options || {});
16
+ }
17
+ };
18
+ }
19
+
20
+ //#endregion
21
+ export { mxllog as default };
22
+ //# sourceMappingURL=module.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.mjs","names":[],"sources":["../../../src/nitro-v3/module.ts"],"sourcesContent":["import { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { NitroModuleOptions } from '../nitro'\n\nexport type { NitroModuleOptions }\n\nconst _dir = dirname(fileURLToPath(import.meta.url))\n\nexport default function mxllog(options?: NitroModuleOptions) {\n return {\n name: '@safaricom-mxl/log',\n setup(nitro: any) {\n // Push the plugin (no extension — Nitro's bundler resolves it)\n nitro.options.plugins = nitro.options.plugins || []\n nitro.options.plugins.push(resolve(_dir, 'plugin'))\n\n // Set error handler only if not already configured by user\n if (!nitro.options.errorHandler) {\n nitro.options.errorHandler = resolve(_dir, 'errorHandler')\n }\n\n // Inject config into runtimeConfig — works in production where the\n // plugin is bundled through Nitro's builder and the virtual\n // runtime-config module resolves correctly.\n nitro.options.runtimeConfig = nitro.options.runtimeConfig || {}\n nitro.options.runtimeConfig.mxllog = options || {}\n\n // In dev mode, Nitro loads plugins externally (not bundled), so the\n // virtual runtime-config module is unreachable and useRuntimeConfig()\n // returns a stub without our values. process.env is inherited by the\n // Worker Threads that run the dev server, making it a reliable bridge.\n // The plugin reads: useRuntimeConfig().mxllog ?? process.env.__MXLLOG_CONFIG\n process.env.__MXLLOG_CONFIG = JSON.stringify(options || {})\n },\n }\n}\n"],"mappings":";;;;AAMA,MAAM,OAAO,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAEpD,SAAwB,OAAO,SAA8B;AAC3D,QAAO;EACL,MAAM;EACN,MAAM,OAAY;AAEhB,SAAM,QAAQ,UAAU,MAAM,QAAQ,WAAW,EAAE;AACnD,SAAM,QAAQ,QAAQ,KAAK,QAAQ,MAAM,SAAS,CAAC;AAGnD,OAAI,CAAC,MAAM,QAAQ,aACjB,OAAM,QAAQ,eAAe,QAAQ,MAAM,eAAe;AAM5D,SAAM,QAAQ,gBAAgB,MAAM,QAAQ,iBAAiB,EAAE;AAC/D,SAAM,QAAQ,cAAc,SAAS,WAAW,EAAE;AAOlD,WAAQ,IAAI,kBAAkB,KAAK,UAAU,WAAW,EAAE,CAAC;;EAE9D"}
@@ -0,0 +1,14 @@
1
+ //#region src/nitro-v3/plugin.d.ts
2
+ /**
3
+ * Nitro v3 plugin entry point.
4
+ *
5
+ * Usage in Nitro v3:
6
+ * ```ts
7
+ * // plugins/mxllog.ts
8
+ * export { default } from '@safaricom-mxl/log/nitro/v3'
9
+ * ```
10
+ */
11
+ declare const _default: any;
12
+ //#endregion
13
+ export { _default as default };
14
+ //# sourceMappingURL=plugin.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.mts","names":[],"sources":["../../../src/nitro-v3/plugin.ts"],"mappings":""}
@@ -0,0 +1,162 @@
1
+ import { filterSafeHeaders } from "../../utils.mjs";
2
+ import { createRequestLogger, initLogger, isEnabled } from "../../logger.mjs";
3
+ import { n as shouldLog, t as getServiceForPath } from "../../routes-BNbrnm14.mjs";
4
+ import { t as extractErrorStatus } from "../../nitro-Dsv6dSzv.mjs";
5
+ import { definePlugin } from "nitro";
6
+ import { useRuntimeConfig } from "nitro/runtime-config";
7
+ import { parseURL } from "ufo";
8
+
9
+ //#region src/nitro-v3/plugin.ts
10
+ function getContext(event) {
11
+ if (!event.req.context) event.req.context = {};
12
+ return event.req.context;
13
+ }
14
+ function getSafeRequestHeaders(event) {
15
+ const headers = {};
16
+ event.req.headers.forEach((value, key) => {
17
+ headers[key] = value;
18
+ });
19
+ return filterSafeHeaders(headers);
20
+ }
21
+ function getSafeResponseHeaders(res) {
22
+ const headers = {};
23
+ res.headers.forEach((value, key) => {
24
+ headers[key] = value;
25
+ });
26
+ if (Object.keys(headers).length === 0) return void 0;
27
+ return filterSafeHeaders(headers);
28
+ }
29
+ function buildHookContext(event, res) {
30
+ const { pathname } = parseURL(event.req.url);
31
+ const responseHeaders = res ? getSafeResponseHeaders(res) : void 0;
32
+ return {
33
+ request: {
34
+ method: event.req.method,
35
+ path: pathname
36
+ },
37
+ headers: getSafeRequestHeaders(event),
38
+ response: {
39
+ status: res?.status ?? 200,
40
+ headers: responseHeaders
41
+ }
42
+ };
43
+ }
44
+ async function callDrainHook(hooks, emittedEvent, event, hookContext) {
45
+ if (!emittedEvent) return;
46
+ let drainPromise;
47
+ try {
48
+ drainPromise = hooks.callHook("@safaricom-mxl/log:drain", {
49
+ event: emittedEvent,
50
+ request: hookContext.request,
51
+ headers: hookContext.headers
52
+ })?.catch?.((err) => {
53
+ console.error("[mxllog] drain failed:", err);
54
+ });
55
+ } catch (err) {
56
+ console.error("[mxllog] drain failed:", err);
57
+ }
58
+ if (!drainPromise) return;
59
+ if (typeof event.req.waitUntil === "function") event.req.waitUntil(drainPromise);
60
+ else await drainPromise;
61
+ }
62
+ async function callEnrichAndDrain(hooks, emittedEvent, event, res) {
63
+ if (!emittedEvent) return;
64
+ const hookContext = buildHookContext(event, res);
65
+ try {
66
+ await hooks.callHook("@safaricom-mxl/log:enrich", {
67
+ event: emittedEvent,
68
+ ...hookContext
69
+ });
70
+ } catch (err) {
71
+ console.error("[mxllog] enrich failed:", err);
72
+ }
73
+ await callDrainHook(hooks, emittedEvent, event, hookContext);
74
+ }
75
+ /**
76
+ * Nitro v3 plugin entry point.
77
+ *
78
+ * Usage in Nitro v3:
79
+ * ```ts
80
+ * // plugins/mxllog.ts
81
+ * export { default } from '@safaricom-mxl/log/nitro/v3'
82
+ * ```
83
+ */
84
+ var plugin_default = definePlugin((nitroApp) => {
85
+ const mxllogConfig = useRuntimeConfig().mxllog ?? (process.env.__MXLLOG_CONFIG ? JSON.parse(process.env.__MXLLOG_CONFIG) : void 0);
86
+ initLogger({
87
+ enabled: mxllogConfig?.enabled,
88
+ env: mxllogConfig?.env,
89
+ pretty: mxllogConfig?.pretty,
90
+ sampling: mxllogConfig?.sampling
91
+ });
92
+ if (!isEnabled()) return;
93
+ const hooks = nitroApp.hooks;
94
+ hooks.hook("request", (event) => {
95
+ const { pathname } = parseURL(event.req.url);
96
+ if (!shouldLog(pathname, mxllogConfig?.include, mxllogConfig?.exclude)) return;
97
+ const ctx = getContext(event);
98
+ ctx._mxllogStartTime = Date.now();
99
+ let requestIdOverride = void 0;
100
+ if (globalThis.navigator?.userAgent === "Cloudflare-Workers") {
101
+ const cfRay = event.req.headers.get("cf-ray");
102
+ if (cfRay) requestIdOverride = cfRay;
103
+ }
104
+ const log = createRequestLogger({
105
+ method: event.req.method,
106
+ path: pathname,
107
+ requestId: requestIdOverride || ctx.requestId || crypto.randomUUID()
108
+ });
109
+ const routeService = getServiceForPath(pathname, mxllogConfig?.routes);
110
+ if (routeService) log.set({ service: routeService });
111
+ ctx.log = log;
112
+ });
113
+ hooks.hook("response", async (res, event) => {
114
+ const ctx = event.req.context;
115
+ if (ctx?._mxllogEmitted) return;
116
+ const log = ctx?.log;
117
+ if (!log || !ctx) return;
118
+ const { status } = res;
119
+ log.set({ status });
120
+ const startTime = ctx._mxllogStartTime;
121
+ const durationMs = startTime ? Date.now() - startTime : void 0;
122
+ const { pathname } = parseURL(event.req.url);
123
+ const tailCtx = {
124
+ status,
125
+ duration: durationMs,
126
+ path: pathname,
127
+ method: event.req.method,
128
+ context: log.getContext(),
129
+ shouldKeep: false
130
+ };
131
+ await hooks.callHook("@safaricom-mxl/log:emit:keep", tailCtx);
132
+ await callEnrichAndDrain(hooks, log.emit({ _forceKeep: tailCtx.shouldKeep }), event, res);
133
+ });
134
+ hooks.hook("error", async (error, { event }) => {
135
+ if (!event) return;
136
+ const e = event;
137
+ const ctx = e.req.context;
138
+ const log = ctx?.log;
139
+ if (!log || !ctx) return;
140
+ const actualError = error.cause?.name === "MxllogError" ? error.cause : error;
141
+ log.error(actualError);
142
+ const errorStatus = extractErrorStatus(actualError);
143
+ log.set({ status: errorStatus });
144
+ const { pathname } = parseURL(e.req.url);
145
+ const startTime = ctx._mxllogStartTime;
146
+ const tailCtx = {
147
+ status: errorStatus,
148
+ duration: startTime ? Date.now() - startTime : void 0,
149
+ path: pathname,
150
+ method: e.req.method,
151
+ context: log.getContext(),
152
+ shouldKeep: false
153
+ };
154
+ await hooks.callHook("@safaricom-mxl/log:emit:keep", tailCtx);
155
+ ctx._mxllogEmitted = true;
156
+ await callEnrichAndDrain(hooks, log.emit({ _forceKeep: tailCtx.shouldKeep }), e);
157
+ });
158
+ });
159
+
160
+ //#endregion
161
+ export { plugin_default as default };
162
+ //# sourceMappingURL=plugin.mjs.map