@blyp/core 0.1.2

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 (235) hide show
  1. package/README.md +533 -0
  2. package/dist/client.js +1132 -0
  3. package/dist/client.js.map +1 -0
  4. package/dist/client.mjs +1125 -0
  5. package/dist/client.mjs.map +1 -0
  6. package/dist/connectors/betterstack/index.d.ts +7 -0
  7. package/dist/connectors/betterstack/sender.d.ts +5 -0
  8. package/dist/connectors/betterstack.js +1508 -0
  9. package/dist/connectors/betterstack.js.map +1 -0
  10. package/dist/connectors/betterstack.mjs +1483 -0
  11. package/dist/connectors/betterstack.mjs.map +1 -0
  12. package/dist/connectors/otlp/index.d.ts +5 -0
  13. package/dist/connectors/otlp/sender.d.ts +7 -0
  14. package/dist/connectors/otlp.js +1347 -0
  15. package/dist/connectors/otlp.js.map +1 -0
  16. package/dist/connectors/otlp.mjs +1344 -0
  17. package/dist/connectors/otlp.mjs.map +1 -0
  18. package/dist/connectors/posthog/index.d.ts +7 -0
  19. package/dist/connectors/posthog/sender.d.ts +11 -0
  20. package/dist/connectors/posthog.js +1503 -0
  21. package/dist/connectors/posthog.js.map +1 -0
  22. package/dist/connectors/posthog.mjs +1498 -0
  23. package/dist/connectors/posthog.mjs.map +1 -0
  24. package/dist/connectors/sentry/index.d.ts +5 -0
  25. package/dist/connectors/sentry/sender.d.ts +5 -0
  26. package/dist/connectors/sentry.js +1356 -0
  27. package/dist/connectors/sentry.js.map +1 -0
  28. package/dist/connectors/sentry.mjs +1333 -0
  29. package/dist/connectors/sentry.mjs.map +1 -0
  30. package/dist/connectors/shared.d.ts +8 -0
  31. package/dist/core/colors.d.ts +30 -0
  32. package/dist/core/config.d.ts +18 -0
  33. package/dist/core/errors.d.ts +8 -0
  34. package/dist/core/file-logger.d.ts +19 -0
  35. package/dist/core/helpers.d.ts +5 -0
  36. package/dist/core/index.d.ts +8 -0
  37. package/dist/core/log-reader.d.ts +5 -0
  38. package/dist/core/log-record.d.ts +14 -0
  39. package/dist/core/logger.d.ts +20 -0
  40. package/dist/core/primary-sink.d.ts +10 -0
  41. package/dist/core/runtime.d.ts +4 -0
  42. package/dist/core/sinks/database-primary-sink.d.ts +25 -0
  43. package/dist/core/sinks/file-primary-sink.d.ts +14 -0
  44. package/dist/core/structured-log.d.ts +3 -0
  45. package/dist/database/adapters/drizzle.d.ts +7 -0
  46. package/dist/database/adapters/prisma.d.ts +9 -0
  47. package/dist/database/helpers.d.ts +5 -0
  48. package/dist/database/index.d.ts +3 -0
  49. package/dist/database.js +24 -0
  50. package/dist/database.js.map +1 -0
  51. package/dist/database.mjs +21 -0
  52. package/dist/database.mjs.map +1 -0
  53. package/dist/elysia.js +4180 -0
  54. package/dist/elysia.js.map +1 -0
  55. package/dist/elysia.mjs +4152 -0
  56. package/dist/elysia.mjs.map +1 -0
  57. package/dist/expo.js +719 -0
  58. package/dist/expo.js.map +1 -0
  59. package/dist/expo.mjs +717 -0
  60. package/dist/expo.mjs.map +1 -0
  61. package/dist/express.js +4170 -0
  62. package/dist/express.js.map +1 -0
  63. package/dist/express.mjs +4141 -0
  64. package/dist/express.mjs.map +1 -0
  65. package/dist/fastify.js +4187 -0
  66. package/dist/fastify.js.map +1 -0
  67. package/dist/fastify.mjs +4158 -0
  68. package/dist/fastify.mjs.map +1 -0
  69. package/dist/frameworks/client/index.d.ts +3 -0
  70. package/dist/frameworks/client/logger.d.ts +4 -0
  71. package/dist/frameworks/elysia/index.d.ts +2 -0
  72. package/dist/frameworks/elysia/logger.d.ts +35 -0
  73. package/dist/frameworks/expo/index.d.ts +2 -0
  74. package/dist/frameworks/expo/logger.d.ts +3 -0
  75. package/dist/frameworks/expo/network.d.ts +7 -0
  76. package/dist/frameworks/express/index.d.ts +2 -0
  77. package/dist/frameworks/express/logger.d.ts +5 -0
  78. package/dist/frameworks/fastify/index.d.ts +2 -0
  79. package/dist/frameworks/fastify/logger.d.ts +4 -0
  80. package/dist/frameworks/hono/index.d.ts +2 -0
  81. package/dist/frameworks/hono/logger.d.ts +4 -0
  82. package/dist/frameworks/nestjs/constants.d.ts +2 -0
  83. package/dist/frameworks/nestjs/filter.d.ts +8 -0
  84. package/dist/frameworks/nestjs/helpers.d.ts +25 -0
  85. package/dist/frameworks/nestjs/index.d.ts +3 -0
  86. package/dist/frameworks/nestjs/interceptor.d.ts +8 -0
  87. package/dist/frameworks/nestjs/logger.d.ts +6 -0
  88. package/dist/frameworks/nestjs/middleware.d.ts +8 -0
  89. package/dist/frameworks/nestjs/module.d.ts +5 -0
  90. package/dist/frameworks/nextjs/index.d.ts +2 -0
  91. package/dist/frameworks/nextjs/logger.d.ts +3 -0
  92. package/dist/frameworks/shared/http.d.ts +10 -0
  93. package/dist/frameworks/shared/index.d.ts +5 -0
  94. package/dist/frameworks/shared/logger.d.ts +35 -0
  95. package/dist/frameworks/shared/request-context.d.ts +12 -0
  96. package/dist/frameworks/shared/request-logger.d.ts +4 -0
  97. package/dist/frameworks/standalone/index.d.ts +3 -0
  98. package/dist/frameworks/standalone/logger.d.ts +5 -0
  99. package/dist/frameworks/sveltekit/index.d.ts +2 -0
  100. package/dist/frameworks/sveltekit/logger.d.ts +3 -0
  101. package/dist/frameworks/tanstack-start/index.d.ts +2 -0
  102. package/dist/frameworks/tanstack-start/logger.d.ts +3 -0
  103. package/dist/frameworks/workers/index.d.ts +2 -0
  104. package/dist/frameworks/workers/logger.d.ts +3 -0
  105. package/dist/hono.js +4156 -0
  106. package/dist/hono.js.map +1 -0
  107. package/dist/hono.mjs +4128 -0
  108. package/dist/hono.mjs.map +1 -0
  109. package/dist/index.d.ts +47 -0
  110. package/dist/index.js +6581 -0
  111. package/dist/index.js.map +1 -0
  112. package/dist/index.mjs +6494 -0
  113. package/dist/index.mjs.map +1 -0
  114. package/dist/nestjs.js +4649 -0
  115. package/dist/nestjs.js.map +1 -0
  116. package/dist/nestjs.mjs +4621 -0
  117. package/dist/nestjs.mjs.map +1 -0
  118. package/dist/nextjs.js +4183 -0
  119. package/dist/nextjs.js.map +1 -0
  120. package/dist/nextjs.mjs +4155 -0
  121. package/dist/nextjs.mjs.map +1 -0
  122. package/dist/shared/client-log.d.ts +14 -0
  123. package/dist/shared/errors.d.ts +296 -0
  124. package/dist/shared/log-value.d.ts +3 -0
  125. package/dist/shared/once.d.ts +4 -0
  126. package/dist/shared/remote-delivery.d.ts +6 -0
  127. package/dist/shared/validation.d.ts +7 -0
  128. package/dist/standalone.js +3353 -0
  129. package/dist/standalone.js.map +1 -0
  130. package/dist/standalone.mjs +3324 -0
  131. package/dist/standalone.mjs.map +1 -0
  132. package/dist/sveltekit.js +4182 -0
  133. package/dist/sveltekit.js.map +1 -0
  134. package/dist/sveltekit.mjs +4154 -0
  135. package/dist/sveltekit.mjs.map +1 -0
  136. package/dist/tanstack-start.js +4182 -0
  137. package/dist/tanstack-start.js.map +1 -0
  138. package/dist/tanstack-start.mjs +4154 -0
  139. package/dist/tanstack-start.mjs.map +1 -0
  140. package/dist/types/connectors/betterstack.d.ts +54 -0
  141. package/dist/types/connectors/mode.d.ts +2 -0
  142. package/dist/types/connectors/otlp.d.ts +50 -0
  143. package/dist/types/connectors/posthog.d.ts +75 -0
  144. package/dist/types/connectors/sentry.d.ts +48 -0
  145. package/dist/types/core/config.d.ts +152 -0
  146. package/dist/types/core/errors.d.ts +16 -0
  147. package/dist/types/core/file-logger.d.ts +29 -0
  148. package/dist/types/core/helpers.d.ts +8 -0
  149. package/dist/types/core/index.d.ts +8 -0
  150. package/dist/types/core/log-reader.d.ts +4 -0
  151. package/dist/types/core/log-record.d.ts +1 -0
  152. package/dist/types/core/logger.d.ts +40 -0
  153. package/dist/types/core/structured-log.d.ts +57 -0
  154. package/dist/types/database.d.ts +73 -0
  155. package/dist/types/frameworks/client.d.ts +32 -0
  156. package/dist/types/frameworks/elysia.d.ts +33 -0
  157. package/dist/types/frameworks/expo.d.ts +44 -0
  158. package/dist/types/frameworks/express.d.ts +24 -0
  159. package/dist/types/frameworks/fastify.d.ts +22 -0
  160. package/dist/types/frameworks/hono.d.ts +13 -0
  161. package/dist/types/frameworks/http.d.ts +47 -0
  162. package/dist/types/frameworks/nestjs.d.ts +37 -0
  163. package/dist/types/frameworks/nextjs.d.ts +27 -0
  164. package/dist/types/frameworks/request-context.d.ts +8 -0
  165. package/dist/types/frameworks/request-logger.d.ts +8 -0
  166. package/dist/types/frameworks/shared.d.ts +154 -0
  167. package/dist/types/frameworks/standalone.d.ts +64 -0
  168. package/dist/types/frameworks/sveltekit.d.ts +37 -0
  169. package/dist/types/frameworks/tanstack-start.d.ts +28 -0
  170. package/dist/types/frameworks/workers.d.ts +33 -0
  171. package/dist/types/shared/client-log.d.ts +91 -0
  172. package/dist/types/shared/errors.d.ts +75 -0
  173. package/dist/types/shared/index.d.ts +4 -0
  174. package/dist/types/shared/once.d.ts +2 -0
  175. package/dist/types/shared/remote-delivery.d.ts +32 -0
  176. package/dist/workers.js +626 -0
  177. package/dist/workers.js.map +1 -0
  178. package/dist/workers.mjs +623 -0
  179. package/dist/workers.mjs.map +1 -0
  180. package/exports/client.js +3 -0
  181. package/exports/client.mjs +3 -0
  182. package/exports/connectors/betterstack.js +1 -0
  183. package/exports/connectors/betterstack.mjs +1 -0
  184. package/exports/connectors/otlp.js +1 -0
  185. package/exports/connectors/otlp.mjs +1 -0
  186. package/exports/connectors/posthog.js +1 -0
  187. package/exports/connectors/posthog.mjs +1 -0
  188. package/exports/connectors/sentry.js +1 -0
  189. package/exports/connectors/sentry.mjs +1 -0
  190. package/exports/database.js +1 -0
  191. package/exports/database.mjs +1 -0
  192. package/exports/expo.js +1 -0
  193. package/exports/expo.mjs +1 -0
  194. package/exports/frameworks/elysia.js +1 -0
  195. package/exports/frameworks/elysia.mjs +1 -0
  196. package/exports/frameworks/express.js +1 -0
  197. package/exports/frameworks/express.mjs +1 -0
  198. package/exports/frameworks/fastify.js +1 -0
  199. package/exports/frameworks/fastify.mjs +1 -0
  200. package/exports/frameworks/hono.js +1 -0
  201. package/exports/frameworks/hono.mjs +1 -0
  202. package/exports/frameworks/nestjs.js +1 -0
  203. package/exports/frameworks/nestjs.mjs +1 -0
  204. package/exports/frameworks/nextjs.js +1 -0
  205. package/exports/frameworks/nextjs.mjs +1 -0
  206. package/exports/frameworks/standalone.js +1 -0
  207. package/exports/frameworks/standalone.mjs +1 -0
  208. package/exports/frameworks/sveltekit.js +1 -0
  209. package/exports/frameworks/sveltekit.mjs +1 -0
  210. package/exports/frameworks/tanstack-start.js +1 -0
  211. package/exports/frameworks/tanstack-start.mjs +1 -0
  212. package/exports/workers.js +1 -0
  213. package/exports/workers.mjs +1 -0
  214. package/package.json +291 -0
  215. package/types/client.d.ts +34 -0
  216. package/types/connectors/betterstack.d.ts +1 -0
  217. package/types/connectors/otlp.d.ts +1 -0
  218. package/types/connectors/posthog.d.ts +1 -0
  219. package/types/connectors/sentry.d.ts +1 -0
  220. package/types/database.d.ts +1 -0
  221. package/types/expo.d.ts +17 -0
  222. package/types/frameworks/client.d.ts +160 -0
  223. package/types/frameworks/elysia.d.ts +1 -0
  224. package/types/frameworks/expo.d.ts +50 -0
  225. package/types/frameworks/express.d.ts +1 -0
  226. package/types/frameworks/fastify.d.ts +1 -0
  227. package/types/frameworks/hono.d.ts +1 -0
  228. package/types/frameworks/nestjs.d.ts +1 -0
  229. package/types/frameworks/nextjs.d.ts +1 -0
  230. package/types/frameworks/standalone.d.ts +1 -0
  231. package/types/frameworks/sveltekit.d.ts +1 -0
  232. package/types/frameworks/tanstack-start.d.ts +1 -0
  233. package/types/frameworks/workers.d.ts +115 -0
  234. package/types/index.d.ts +1 -0
  235. package/types/workers.d.ts +13 -0
@@ -0,0 +1,4621 @@
1
+ import { z } from 'zod';
2
+ import fs, { existsSync, readFileSync, writeFileSync, appendFileSync } from 'fs';
3
+ import { createJiti } from 'jiti';
4
+ import path, { resolve, dirname } from 'path';
5
+ import { SeverityNumber } from '@opentelemetry/api-logs';
6
+ import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
7
+ import { resourceFromAttributes } from '@opentelemetry/resources';
8
+ import { LoggerProvider, BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';
9
+ import { PostHog } from 'posthog-node';
10
+ import { gzipSync } from 'fflate';
11
+ import pino from 'pino';
12
+ import { AsyncLocalStorage } from 'async_hooks';
13
+ import { randomUUID } from 'crypto';
14
+ import * as Sentry from '@sentry/node';
15
+ import { Logtail } from '@logtail/node';
16
+ import { Catch, Inject, Injectable, Global, Module, RequestMethod, HttpException } from '@nestjs/common';
17
+ import { APP_INTERCEPTOR, APP_FILTER, BaseExceptionFilter } from '@nestjs/core';
18
+ import { tap } from 'rxjs';
19
+
20
+ var __defProp = Object.defineProperty;
21
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
22
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
23
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
24
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
25
+ }) : x)(function(x) {
26
+ if (typeof require !== "undefined") return require.apply(this, arguments);
27
+ throw Error('Dynamic require of "' + x + '" is not supported');
28
+ });
29
+ var __decorateClass = (decorators, target, key, kind) => {
30
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
31
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
32
+ if (decorator = decorators[i])
33
+ result = (decorator(result)) || result;
34
+ return result;
35
+ };
36
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
37
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
38
+
39
+ // src/core/colors.ts
40
+ function getMethodColor(method) {
41
+ const colors = {
42
+ GET: "\x1B[32m",
43
+ POST: "\x1B[36m",
44
+ PUT: "\x1B[33m",
45
+ PATCH: "\x1B[34m",
46
+ DELETE: "\x1B[31m"
47
+ };
48
+ const reset = "\x1B[0m";
49
+ return `${colors[method.toUpperCase()] || ""}${method}${reset}`;
50
+ }
51
+ function getStatusColor(statusCode) {
52
+ const reset = "\x1B[0m";
53
+ if (statusCode >= 500) return `\x1B[31m${statusCode}${reset}`;
54
+ if (statusCode >= 400) return `\x1B[33m${statusCode}${reset}`;
55
+ if (statusCode >= 300) return `\x1B[36m${statusCode}${reset}`;
56
+ if (statusCode >= 200) return `\x1B[32m${statusCode}${reset}`;
57
+ return `\x1B[37m${statusCode}${reset}`;
58
+ }
59
+ function getArrowForMethod(method) {
60
+ const arrows = {
61
+ GET: "\u2192",
62
+ POST: "\u2191",
63
+ PUT: "\u21D1",
64
+ PATCH: "\u2197",
65
+ DELETE: "\u2715"
66
+ };
67
+ return arrows[method.toUpperCase()] || "\u2022";
68
+ }
69
+ function getResponseTimeColor(ms) {
70
+ const reset = "\x1B[0m";
71
+ if (ms < 100) return `\x1B[32m${ms}ms${reset}`;
72
+ if (ms < 300) return `\x1B[33m${ms}ms${reset}`;
73
+ if (ms < 1e3) return `\x1B[31m${ms}ms${reset}`;
74
+ return `\x1B[41m\x1B[37m${ms}ms${reset}`;
75
+ }
76
+
77
+ // src/frameworks/shared/http.ts
78
+ function getHeaderValue(headers, name) {
79
+ if (!headers) {
80
+ return void 0;
81
+ }
82
+ if (headers instanceof Headers) {
83
+ return headers.get(name) ?? headers.get(name.toLowerCase()) ?? void 0;
84
+ }
85
+ if (typeof headers.get === "function") {
86
+ const direct2 = headers.get(name);
87
+ return direct2 ?? headers.get(name.toLowerCase()) ?? void 0;
88
+ }
89
+ const record = headers;
90
+ const direct = record[name] ?? record[name.toLowerCase()];
91
+ if (Array.isArray(direct)) {
92
+ return direct[0];
93
+ }
94
+ return direct;
95
+ }
96
+ function parseForwardedHeader(value) {
97
+ if (!value) {
98
+ return [];
99
+ }
100
+ return value.split(",").map((entry) => entry.trim()).filter(Boolean).map((entry) => {
101
+ const match = entry.match(/for="?(\[[^\]]+\]|[^;,\s"]+)/i);
102
+ return match?.[1]?.replace(/^"|"$/g, "") ?? "";
103
+ }).map((entry) => entry.replace(/^\[|\]$/g, "")).filter(Boolean);
104
+ }
105
+ function parseForwardedFor(value) {
106
+ if (!value) {
107
+ return [];
108
+ }
109
+ return value.split(",").map((entry) => entry.trim()).filter(Boolean);
110
+ }
111
+ function stripPort(host) {
112
+ if (host.startsWith("[")) {
113
+ const endIndex = host.indexOf("]");
114
+ return endIndex >= 0 ? host.slice(1, endIndex) : host;
115
+ }
116
+ return host.replace(/:\d+$/, "");
117
+ }
118
+ function detectBrowser(userAgent) {
119
+ if (/edg\//i.test(userAgent)) return "Edge";
120
+ if (/opr\//i.test(userAgent) || /opera/i.test(userAgent)) return "Opera";
121
+ if (/chrome\//i.test(userAgent) && !/edg\//i.test(userAgent)) return "Chrome";
122
+ if (/firefox\//i.test(userAgent)) return "Firefox";
123
+ if (/safari\//i.test(userAgent) && !/chrome\//i.test(userAgent)) return "Safari";
124
+ if (/curl\//i.test(userAgent)) return "curl";
125
+ if (/postmanruntime/i.test(userAgent)) return "Postman";
126
+ return "Unknown";
127
+ }
128
+ function detectOperatingSystem(userAgent) {
129
+ if (/windows/i.test(userAgent)) return "Windows";
130
+ if (/android/i.test(userAgent)) return "Android";
131
+ if (/iphone|ipad|ipod/i.test(userAgent)) return "iOS";
132
+ if (/mac os x|macintosh/i.test(userAgent)) return "macOS";
133
+ if (/linux/i.test(userAgent)) return "Linux";
134
+ return "Unknown";
135
+ }
136
+ function detectDeviceType(userAgent) {
137
+ if (!userAgent) return "unknown";
138
+ if (/bot|crawler|spider|curl|wget|postmanruntime/i.test(userAgent)) return "bot";
139
+ if (/ipad|tablet/i.test(userAgent)) return "tablet";
140
+ if (/mobi|iphone|android/i.test(userAgent)) return "mobile";
141
+ return "desktop";
142
+ }
143
+ function extractPathname(requestUrl, fallbackPath = "/") {
144
+ if (!requestUrl) {
145
+ return fallbackPath;
146
+ }
147
+ if (requestUrl.startsWith("http://") || requestUrl.startsWith("https://")) {
148
+ try {
149
+ return new URL(requestUrl).pathname || fallbackPath;
150
+ } catch {
151
+ return fallbackPath;
152
+ }
153
+ }
154
+ if (requestUrl.startsWith("/")) {
155
+ const queryIndex = requestUrl.indexOf("?");
156
+ return queryIndex >= 0 ? requestUrl.slice(0, queryIndex) : requestUrl;
157
+ }
158
+ try {
159
+ return new URL(requestUrl, "http://localhost").pathname || fallbackPath;
160
+ } catch {
161
+ return fallbackPath;
162
+ }
163
+ }
164
+ function createRequestLike(method, url, headers) {
165
+ return { method, url, headers };
166
+ }
167
+ function buildClientDetails(request, fallbackPath) {
168
+ const pathname = fallbackPath ?? extractPathname(request.url);
169
+ const urlObject = (() => {
170
+ try {
171
+ return new URL(request.url);
172
+ } catch {
173
+ try {
174
+ return new URL(pathname, "http://localhost");
175
+ } catch {
176
+ return null;
177
+ }
178
+ }
179
+ })();
180
+ const hostHeader = getHeaderValue(request.headers, "x-forwarded-host") ?? getHeaderValue(request.headers, "host") ?? urlObject?.host ?? void 0;
181
+ const hostname = hostHeader ? stripPort(hostHeader) : urlObject?.hostname;
182
+ const port = hostHeader?.match(/:(\d+)$/)?.[1] ?? (urlObject?.port || void 0);
183
+ const xForwardedFor = parseForwardedFor(getHeaderValue(request.headers, "x-forwarded-for"));
184
+ const forwardedFor = parseForwardedHeader(getHeaderValue(request.headers, "forwarded"));
185
+ const ipCandidates = [
186
+ getHeaderValue(request.headers, "cf-connecting-ip"),
187
+ getHeaderValue(request.headers, "true-client-ip"),
188
+ getHeaderValue(request.headers, "fly-client-ip"),
189
+ getHeaderValue(request.headers, "x-real-ip"),
190
+ getHeaderValue(request.headers, "x-client-ip"),
191
+ xForwardedFor[0],
192
+ forwardedFor[0]
193
+ ].filter((value) => Boolean(value));
194
+ const userAgent = getHeaderValue(request.headers, "user-agent");
195
+ const platform = getHeaderValue(request.headers, "sec-ch-ua-platform")?.replace(/^"|"$/g, "") ?? void 0;
196
+ const deviceType = detectDeviceType(userAgent ?? "");
197
+ return {
198
+ hostname,
199
+ ip: ipCandidates[0],
200
+ forwardedFor: [...xForwardedFor, ...forwardedFor].filter((value, index, values) => {
201
+ return values.indexOf(value) === index;
202
+ }),
203
+ protocol: getHeaderValue(request.headers, "x-forwarded-proto") ?? (urlObject?.protocol ? urlObject.protocol.replace(/:$/, "") : void 0),
204
+ port,
205
+ userAgent,
206
+ origin: getHeaderValue(request.headers, "origin"),
207
+ referer: getHeaderValue(request.headers, "referer"),
208
+ acceptLanguage: getHeaderValue(request.headers, "accept-language"),
209
+ client: {
210
+ ip: ipCandidates[0],
211
+ hostname,
212
+ browser: userAgent ? detectBrowser(userAgent) : void 0,
213
+ os: userAgent ? detectOperatingSystem(userAgent) : void 0,
214
+ deviceType,
215
+ platform,
216
+ isMobile: deviceType === "mobile"
217
+ }
218
+ };
219
+ }
220
+ function buildRequestLogData(request, type, path3, statusCode, responseTime, extra = {}) {
221
+ return {
222
+ type,
223
+ method: request.method,
224
+ url: path3,
225
+ statusCode,
226
+ responseTime,
227
+ ...buildClientDetails(request, path3),
228
+ ...extra
229
+ };
230
+ }
231
+ function buildInfoLogMessage(method, statusCode, url, responseTime) {
232
+ const methodColor = getMethodColor(method);
233
+ const statusColor = getStatusColor(statusCode);
234
+ const timeColor = getResponseTimeColor(responseTime);
235
+ const arrow = getArrowForMethod(method);
236
+ return `${methodColor} ${arrow} ${statusColor} ${url} ${timeColor}`;
237
+ }
238
+ function toErrorLike(error, fallbackStatusCode) {
239
+ if (error === void 0 || error === null) {
240
+ return fallbackStatusCode === void 0 ? void 0 : { statusCode: fallbackStatusCode, message: `HTTP ${fallbackStatusCode}` };
241
+ }
242
+ if (error instanceof Error) {
243
+ const errorWithStatus = error;
244
+ return {
245
+ status: errorWithStatus.status,
246
+ statusCode: errorWithStatus.statusCode ?? fallbackStatusCode,
247
+ code: errorWithStatus.code,
248
+ message: error.message,
249
+ stack: error.stack,
250
+ why: errorWithStatus.why,
251
+ fix: errorWithStatus.fix,
252
+ link: errorWithStatus.link,
253
+ details: errorWithStatus.details,
254
+ cause: errorWithStatus.cause
255
+ };
256
+ }
257
+ if (typeof error === "object") {
258
+ const record = error;
259
+ return {
260
+ status: typeof record.status === "number" ? record.status : void 0,
261
+ statusCode: typeof record.statusCode === "number" ? record.statusCode : fallbackStatusCode,
262
+ code: typeof record.code === "string" || typeof record.code === "number" ? record.code : void 0,
263
+ message: typeof record.message === "string" ? record.message : `HTTP ${fallbackStatusCode ?? 500}`,
264
+ stack: typeof record.stack === "string" ? record.stack : void 0,
265
+ why: typeof record.why === "string" ? record.why : void 0,
266
+ fix: typeof record.fix === "string" ? record.fix : void 0,
267
+ link: typeof record.link === "string" ? record.link : void 0,
268
+ details: record.details !== null && typeof record.details === "object" && !Array.isArray(record.details) ? record.details : void 0,
269
+ cause: record.cause
270
+ };
271
+ }
272
+ return {
273
+ statusCode: fallbackStatusCode,
274
+ message: typeof error === "string" ? error : `HTTP ${fallbackStatusCode ?? 500}`
275
+ };
276
+ }
277
+ function isErrorStatus(statusCode) {
278
+ return statusCode >= 400;
279
+ }
280
+
281
+ // src/shared/log-value.ts
282
+ function normalizeError(error) {
283
+ const normalized = {
284
+ name: error.name,
285
+ message: error.message
286
+ };
287
+ if (error.stack) {
288
+ normalized.stack = error.stack;
289
+ }
290
+ const errorWithCause = error;
291
+ if (errorWithCause.cause !== void 0) {
292
+ normalized.cause = normalizeLogValue(errorWithCause.cause);
293
+ }
294
+ return normalized;
295
+ }
296
+ function normalizeLogValue(value, seen = /* @__PURE__ */ new WeakSet()) {
297
+ if (value instanceof Error) {
298
+ return normalizeError(value);
299
+ }
300
+ if (typeof value === "function") {
301
+ return `[Function: ${value.name || "anonymous"}]`;
302
+ }
303
+ if (typeof value === "symbol") {
304
+ return value.toString();
305
+ }
306
+ if (value === void 0 || value === null) {
307
+ return value;
308
+ }
309
+ if (Array.isArray(value)) {
310
+ return value.map((entry) => normalizeLogValue(entry, seen));
311
+ }
312
+ if (typeof value === "object") {
313
+ if (seen.has(value)) {
314
+ return "[Circular]";
315
+ }
316
+ seen.add(value);
317
+ const normalized = {};
318
+ for (const [key, entry] of Object.entries(value)) {
319
+ normalized[key] = normalizeLogValue(entry, seen);
320
+ }
321
+ seen.delete(value);
322
+ return normalized;
323
+ }
324
+ return value;
325
+ }
326
+ function serializeLogMessage(message) {
327
+ if (typeof message === "string") {
328
+ return message;
329
+ }
330
+ if (message instanceof Error) {
331
+ return message.message || message.name;
332
+ }
333
+ const normalized = normalizeLogValue(message);
334
+ if (typeof normalized === "string") {
335
+ return normalized;
336
+ }
337
+ try {
338
+ const serialized = JSON.stringify(normalized, null, 2);
339
+ return serialized ?? String(normalized);
340
+ } catch {
341
+ return String(normalized);
342
+ }
343
+ }
344
+ var absoluteHttpUrlSchema = z.string().url().refine((value) => {
345
+ try {
346
+ const url = new URL(value);
347
+ return url.protocol === "http:" || url.protocol === "https:";
348
+ } catch {
349
+ return false;
350
+ }
351
+ }, {
352
+ message: "Expected an absolute http(s) URL"
353
+ });
354
+ var plainObjectSchema = z.custom(
355
+ (value) => {
356
+ return value !== null && typeof value === "object" && !Array.isArray(value);
357
+ },
358
+ {
359
+ message: "Expected a plain object"
360
+ }
361
+ );
362
+ var nonEmptyStringSchema = z.string().trim().min(1);
363
+ function isAbsoluteHttpUrl(value) {
364
+ return absoluteHttpUrlSchema.safeParse(value).success;
365
+ }
366
+ function isPlainObject(value) {
367
+ return plainObjectSchema.safeParse(value).success;
368
+ }
369
+ function hasNonEmptyString(value) {
370
+ return nonEmptyStringSchema.safeParse(value).success;
371
+ }
372
+
373
+ // src/shared/client-log.ts
374
+ var DEFAULT_CLIENT_LOG_ENDPOINT = "/inngest";
375
+ var CLIENT_LOG_LEVELS = [
376
+ "debug",
377
+ "info",
378
+ "warning",
379
+ "error",
380
+ "critical",
381
+ "success",
382
+ "table"
383
+ ];
384
+ var clientConnectorRequestSchema = z.union([
385
+ z.literal("betterstack"),
386
+ z.literal("posthog"),
387
+ z.literal("sentry"),
388
+ z.undefined(),
389
+ z.object({
390
+ type: z.literal("otlp"),
391
+ name: nonEmptyStringSchema
392
+ })
393
+ ]);
394
+ function isClientLogLevel(value) {
395
+ return typeof value === "string" && CLIENT_LOG_LEVELS.includes(value);
396
+ }
397
+ function isClientConnectorRequest(value) {
398
+ return clientConnectorRequestSchema.safeParse(value).success;
399
+ }
400
+ function isClientLogEvent(payload) {
401
+ if (!isPlainObject(payload)) {
402
+ return false;
403
+ }
404
+ if (payload.type !== "client_log" || payload.source !== "client" || !isClientLogLevel(payload.level) || typeof payload.id !== "string" || typeof payload.message !== "string" || typeof payload.clientTimestamp !== "string") {
405
+ return false;
406
+ }
407
+ const pageResult = plainObjectSchema.safeParse(payload.page);
408
+ const browserResult = plainObjectSchema.safeParse(payload.browser);
409
+ const sessionResult = plainObjectSchema.safeParse(payload.session);
410
+ if (!pageResult.success || !browserResult.success || !sessionResult.success) {
411
+ return false;
412
+ }
413
+ if (!isClientConnectorRequest(payload.connector)) {
414
+ return false;
415
+ }
416
+ return typeof sessionResult.data.pageId === "string" && typeof sessionResult.data.sessionId === "string";
417
+ }
418
+ function normalizeEndpointPath(path3) {
419
+ if (!path3) {
420
+ return DEFAULT_CLIENT_LOG_ENDPOINT;
421
+ }
422
+ return path3.startsWith("/") ? path3 : `/${path3}`;
423
+ }
424
+
425
+ // src/shared/once.ts
426
+ function createConsoleOnceLogger(method, warnedKeys6 = /* @__PURE__ */ new Set()) {
427
+ return (key, message, error) => {
428
+ if (warnedKeys6.has(key) || typeof console === "undefined") {
429
+ return;
430
+ }
431
+ const writer = console[method];
432
+ if (typeof writer !== "function") {
433
+ return;
434
+ }
435
+ warnedKeys6.add(key);
436
+ if (error === void 0) {
437
+ writer.call(console, message);
438
+ return;
439
+ }
440
+ writer.call(console, message, error);
441
+ };
442
+ }
443
+ function createWarnOnceLogger(warnedKeys6) {
444
+ return createConsoleOnceLogger("warn", warnedKeys6);
445
+ }
446
+ function createErrorOnceLogger(warnedKeys6) {
447
+ return createConsoleOnceLogger("error", warnedKeys6);
448
+ }
449
+
450
+ // src/core/config.ts
451
+ var PACKAGE_NAME = "@blyp/core";
452
+ var GITIGNORE_FILE_NAME = ".gitignore";
453
+ var CONFIG_FILE_NAMES = [
454
+ "blyp.config.ts",
455
+ "blyp.config.mts",
456
+ "blyp.config.cts",
457
+ "blyp.config.js",
458
+ "blyp.config.mjs",
459
+ "blyp.config.cjs",
460
+ "blyp.config.json"
461
+ ];
462
+ var CONFIG_FILE_NAME = "blyp.config.json";
463
+ var DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com";
464
+ var DEFAULT_CONNECTOR_SERVICE_NAME = "blyp-app";
465
+ var DEFAULT_POSTHOG_SERVICE_NAME = DEFAULT_CONNECTOR_SERVICE_NAME;
466
+ var warnedKeys = /* @__PURE__ */ new Set();
467
+ var warnOnce = createWarnOnceLogger(warnedKeys);
468
+ var DEFAULT_ROTATION_CONFIG = {
469
+ enabled: true,
470
+ maxSizeBytes: 10 * 1024 * 1024,
471
+ maxArchives: 5,
472
+ compress: true
473
+ };
474
+ var DEFAULT_FILE_CONFIG = {
475
+ enabled: true,
476
+ dir: "",
477
+ archiveDir: "",
478
+ format: "ndjson",
479
+ rotation: DEFAULT_ROTATION_CONFIG
480
+ };
481
+ var DEFAULT_CLIENT_LOGGING_CONFIG = {
482
+ enabled: true,
483
+ path: DEFAULT_CLIENT_LOG_ENDPOINT
484
+ };
485
+ var DEFAULT_DATABASE_RETRY_CONFIG = {
486
+ maxRetries: 1,
487
+ backoffMs: 100
488
+ };
489
+ var DEFAULT_DATABASE_DELIVERY_CONFIG = {
490
+ strategy: "immediate",
491
+ batchSize: 1,
492
+ flushIntervalMs: 250,
493
+ maxQueueSize: 1e3,
494
+ overflowStrategy: "drop-oldest",
495
+ flushTimeoutMs: 5e3,
496
+ retry: DEFAULT_DATABASE_RETRY_CONFIG
497
+ };
498
+ var DEFAULT_CONFIG = {
499
+ pretty: true,
500
+ level: "info",
501
+ destination: "file",
502
+ file: DEFAULT_FILE_CONFIG,
503
+ clientLogging: DEFAULT_CLIENT_LOGGING_CONFIG,
504
+ connectors: {}
505
+ };
506
+ var cachedConfig = null;
507
+ function findNearestPackageName(startDir) {
508
+ let currentDir = startDir;
509
+ while (true) {
510
+ const packageJsonPath = resolve(currentDir, "package.json");
511
+ if (existsSync(packageJsonPath)) {
512
+ try {
513
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
514
+ if (hasNonEmptyString(packageJson.name)) {
515
+ return packageJson.name;
516
+ }
517
+ } catch {
518
+ }
519
+ }
520
+ const parentDir = dirname(currentDir);
521
+ if (parentDir === currentDir) {
522
+ return void 0;
523
+ }
524
+ currentDir = parentDir;
525
+ }
526
+ }
527
+ function resolveDefaultConnectorServiceName(cwd = process.cwd()) {
528
+ return findNearestPackageName(cwd) ?? DEFAULT_POSTHOG_SERVICE_NAME;
529
+ }
530
+ function getBootstrapConfig() {
531
+ return {
532
+ pretty: true,
533
+ level: "info",
534
+ destination: "file",
535
+ file: {
536
+ enabled: true,
537
+ format: "ndjson",
538
+ rotation: {
539
+ enabled: true,
540
+ maxSizeBytes: 10 * 1024 * 1024,
541
+ maxArchives: 5,
542
+ compress: true
543
+ }
544
+ },
545
+ clientLogging: {
546
+ enabled: true,
547
+ path: DEFAULT_CLIENT_LOG_ENDPOINT
548
+ },
549
+ connectors: {}
550
+ };
551
+ }
552
+ function shouldBootstrapProjectFiles(cwd) {
553
+ const packageJsonPath = resolve(cwd, "package.json");
554
+ if (!existsSync(packageJsonPath)) {
555
+ return true;
556
+ }
557
+ try {
558
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
559
+ return packageJson.name !== PACKAGE_NAME;
560
+ } catch {
561
+ return true;
562
+ }
563
+ }
564
+ function ensureConfigFile(cwd) {
565
+ if (CONFIG_FILE_NAMES.some((fileName) => existsSync(resolve(cwd, fileName)))) {
566
+ return;
567
+ }
568
+ const configPath = resolve(cwd, CONFIG_FILE_NAME);
569
+ if (existsSync(configPath)) {
570
+ return;
571
+ }
572
+ try {
573
+ writeFileSync(configPath, `${JSON.stringify(getBootstrapConfig(), null, 2)}
574
+ `);
575
+ } catch (error) {
576
+ console.error("[Blyp] Warning: Failed to create blyp.config.json:", error);
577
+ }
578
+ }
579
+ function ensureLogsIgnored(cwd) {
580
+ const gitignorePath = resolve(cwd, GITIGNORE_FILE_NAME);
581
+ if (!existsSync(gitignorePath)) {
582
+ try {
583
+ writeFileSync(gitignorePath, "logs\n");
584
+ } catch (error) {
585
+ console.error("[Blyp] Warning: Failed to create .gitignore:", error);
586
+ }
587
+ return;
588
+ }
589
+ try {
590
+ const currentContent = readFileSync(gitignorePath, "utf-8");
591
+ if (/^(?:\/?logs\/?)\s*$/m.test(currentContent)) {
592
+ return;
593
+ }
594
+ const separator = currentContent.endsWith("\n") ? "" : "\n";
595
+ appendFileSync(gitignorePath, `${separator}logs
596
+ `);
597
+ } catch (error) {
598
+ console.error("[Blyp] Warning: Failed to update .gitignore:", error);
599
+ }
600
+ }
601
+ function bootstrapProjectFiles() {
602
+ const cwd = process.cwd();
603
+ if (!shouldBootstrapProjectFiles(cwd)) {
604
+ return;
605
+ }
606
+ ensureConfigFile(cwd);
607
+ ensureLogsIgnored(cwd);
608
+ }
609
+ function findConfigFile() {
610
+ const cwd = process.cwd();
611
+ const matches = CONFIG_FILE_NAMES.map((fileName) => resolve(cwd, fileName)).filter((filePath) => existsSync(filePath));
612
+ if (matches.length === 0) {
613
+ return null;
614
+ }
615
+ if (matches.length > 1) {
616
+ const preferred = matches[0];
617
+ warnOnce(
618
+ `config-multiple:${preferred}`,
619
+ `[Blyp] Warning: Multiple config files found. Using ${preferred} and ignoring ${matches.slice(1).join(", ")}.`
620
+ );
621
+ }
622
+ const selectedPath = matches[0];
623
+ return {
624
+ path: selectedPath,
625
+ type: selectedPath.endsWith(".json") ? "json" : "jiti"
626
+ };
627
+ }
628
+ function normalizeLoadedConfig(value, configPath) {
629
+ const normalized = value && typeof value === "object" && "default" in value && value.default !== void 0 ? value.default : value;
630
+ if (!normalized || typeof normalized !== "object" || Array.isArray(normalized)) {
631
+ warnOnce(
632
+ `config-invalid:${configPath}`,
633
+ `[Blyp] Warning: Config file ${configPath} did not export an object. Falling back to defaults.`
634
+ );
635
+ return {};
636
+ }
637
+ return normalized;
638
+ }
639
+ function parseJsonConfigFile(configPath) {
640
+ try {
641
+ const content = readFileSync(configPath, "utf-8");
642
+ return normalizeLoadedConfig(JSON.parse(content), configPath);
643
+ } catch (error) {
644
+ console.error("[Blyp] Warning: Failed to parse blyp.config.json:", error);
645
+ return {};
646
+ }
647
+ }
648
+ function parseExecutableConfigFile(configPath) {
649
+ try {
650
+ const jiti = createJiti(process.cwd(), {
651
+ interopDefault: true,
652
+ moduleCache: false,
653
+ fsCache: false
654
+ });
655
+ return normalizeLoadedConfig(jiti(configPath), configPath);
656
+ } catch (error) {
657
+ console.error(`[Blyp] Warning: Failed to load ${configPath}:`, error);
658
+ return {};
659
+ }
660
+ }
661
+ function parseConfigFile(config) {
662
+ return config.type === "json" ? parseJsonConfigFile(config.path) : parseExecutableConfigFile(config.path);
663
+ }
664
+ function isPrismaAdapter(value) {
665
+ return !!value && typeof value === "object" && value.type === "prisma";
666
+ }
667
+ function isDrizzleAdapter(value) {
668
+ return !!value && typeof value === "object" && value.type === "drizzle";
669
+ }
670
+ function mergeDatabaseRetryConfig(base, override) {
671
+ return {
672
+ ...DEFAULT_DATABASE_RETRY_CONFIG,
673
+ ...base,
674
+ ...override
675
+ };
676
+ }
677
+ function mergeDatabaseDeliveryConfig(base, override) {
678
+ return {
679
+ ...DEFAULT_DATABASE_DELIVERY_CONFIG,
680
+ ...base,
681
+ ...override,
682
+ retry: mergeDatabaseRetryConfig(base?.retry, override?.retry)
683
+ };
684
+ }
685
+ function hasPrismaDelegate(adapter) {
686
+ const model = adapter.model ?? "blypLog";
687
+ const client = adapter.client;
688
+ const delegate = client?.[model];
689
+ return !!delegate && typeof delegate.create === "function";
690
+ }
691
+ function hasDrizzleAdapterShape(adapter) {
692
+ const db = adapter.db;
693
+ return !!db && typeof db.insert === "function" && adapter.table !== void 0;
694
+ }
695
+ function resolveDatabaseLoggerConfig(config, sourceType) {
696
+ if (!config) {
697
+ return void 0;
698
+ }
699
+ const adapter = config.adapter;
700
+ let ready = false;
701
+ if (sourceType === "json") {
702
+ warnOnce(
703
+ "database-json-config",
704
+ "[Blyp] Warning: Database logging requires an executable blyp config file. Database destination remains disabled until you move this config to blyp.config.ts/js."
705
+ );
706
+ } else if (config.dialect !== "postgres" && config.dialect !== "mysql") {
707
+ warnOnce(
708
+ `database-dialect:${String(config.dialect)}`,
709
+ `[Blyp] Warning: Unsupported database dialect "${String(config.dialect)}". Database logging is disabled.`
710
+ );
711
+ } else if (!adapter) {
712
+ warnOnce(
713
+ "database-adapter-missing",
714
+ "[Blyp] Warning: Database logging is enabled without an adapter. Database logging is disabled."
715
+ );
716
+ } else if (isPrismaAdapter(adapter)) {
717
+ ready = hasPrismaDelegate({
718
+ ...adapter,
719
+ model: adapter.model ?? "blypLog"
720
+ });
721
+ if (!ready) {
722
+ warnOnce(
723
+ "database-prisma-missing",
724
+ `[Blyp] Warning: Prisma database adapter is missing the "${adapter.model ?? "blypLog"}" delegate or its create method. Database logging is disabled.`
725
+ );
726
+ }
727
+ } else if (isDrizzleAdapter(adapter)) {
728
+ ready = hasDrizzleAdapterShape(adapter);
729
+ if (!ready) {
730
+ warnOnce(
731
+ "database-drizzle-missing",
732
+ "[Blyp] Warning: Drizzle database adapter is missing a db.insert function or table reference. Database logging is disabled."
733
+ );
734
+ }
735
+ }
736
+ const normalizedAdapter = isPrismaAdapter(adapter) ? {
737
+ ...adapter,
738
+ model: adapter.model ?? "blypLog"
739
+ } : adapter;
740
+ return {
741
+ dialect: config.dialect,
742
+ adapter: normalizedAdapter,
743
+ delivery: mergeDatabaseDeliveryConfig(void 0, config.delivery),
744
+ ready,
745
+ status: ready ? "enabled" : "missing"
746
+ };
747
+ }
748
+ function mergeRotationConfig(base, override) {
749
+ return {
750
+ ...DEFAULT_ROTATION_CONFIG,
751
+ ...base,
752
+ ...override
753
+ };
754
+ }
755
+ function mergeFileConfig(base, override) {
756
+ return {
757
+ ...DEFAULT_FILE_CONFIG,
758
+ ...base,
759
+ ...override,
760
+ rotation: mergeRotationConfig(base?.rotation, override?.rotation)
761
+ };
762
+ }
763
+ function mergeClientLoggingConfig(base, override) {
764
+ return {
765
+ ...DEFAULT_CLIENT_LOGGING_CONFIG,
766
+ ...base,
767
+ ...override,
768
+ path: override?.path ?? base?.path ?? DEFAULT_CLIENT_LOGGING_CONFIG.path
769
+ };
770
+ }
771
+ function mergeDatabaseLoggerConfig(base, override, sourceType) {
772
+ if (!base && !override) {
773
+ return void 0;
774
+ }
775
+ return resolveDatabaseLoggerConfig(
776
+ {
777
+ dialect: override?.dialect ?? base?.dialect,
778
+ adapter: override?.adapter ?? base?.adapter,
779
+ delivery: {
780
+ ...base?.delivery ?? {},
781
+ ...override?.delivery ?? {},
782
+ retry: {
783
+ ...base?.delivery?.retry ?? {},
784
+ ...override?.delivery?.retry ?? {}
785
+ }
786
+ }
787
+ },
788
+ sourceType
789
+ );
790
+ }
791
+ function mergePostHogConnectorConfig(base, override) {
792
+ const enabled = override?.enabled ?? base?.enabled ?? false;
793
+ const projectKey = override?.projectKey ?? base?.projectKey;
794
+ const baseErrorTracking = base?.enabled === true ? base?.errorTracking : void 0;
795
+ const errorTrackingMode = override?.errorTracking?.mode ?? baseErrorTracking?.mode ?? "auto";
796
+ const errorTrackingEnabled = override?.errorTracking?.enabled ?? baseErrorTracking?.enabled ?? enabled;
797
+ const errorTrackingReady = enabled && errorTrackingEnabled && typeof projectKey === "string" && projectKey.trim().length > 0;
798
+ return {
799
+ enabled,
800
+ mode: override?.mode ?? base?.mode ?? "auto",
801
+ projectKey,
802
+ host: override?.host ?? base?.host ?? DEFAULT_POSTHOG_HOST,
803
+ serviceName: override?.serviceName ?? base?.serviceName ?? resolveDefaultConnectorServiceName(),
804
+ errorTracking: {
805
+ enabled: errorTrackingEnabled,
806
+ mode: errorTrackingMode,
807
+ enableExceptionAutocapture: override?.errorTracking?.enableExceptionAutocapture ?? baseErrorTracking?.enableExceptionAutocapture ?? errorTrackingMode === "auto",
808
+ ready: errorTrackingReady,
809
+ status: errorTrackingReady ? "enabled" : "missing"
810
+ }
811
+ };
812
+ }
813
+ function mergeBetterStackConnectorConfig(base, override) {
814
+ const sourceToken = override?.sourceToken ?? base?.sourceToken;
815
+ const ingestingHost = override?.ingestingHost ?? base?.ingestingHost;
816
+ const enabled = override?.enabled ?? base?.enabled ?? false;
817
+ const baseErrorTracking = base?.enabled === true ? base?.errorTracking : void 0;
818
+ const errorTracking = mergeBetterStackErrorTrackingConfig(
819
+ enabled,
820
+ baseErrorTracking,
821
+ override?.errorTracking
822
+ );
823
+ const ready = enabled && hasNonEmptyString(sourceToken) && isAbsoluteHttpUrl(ingestingHost);
824
+ return {
825
+ enabled,
826
+ mode: override?.mode ?? base?.mode ?? "auto",
827
+ sourceToken,
828
+ ingestingHost,
829
+ serviceName: override?.serviceName ?? base?.serviceName ?? resolveDefaultConnectorServiceName(),
830
+ errorTracking,
831
+ ready,
832
+ status: ready ? "enabled" : "missing"
833
+ };
834
+ }
835
+ function mergeBetterStackErrorTrackingConfig(connectorEnabled, base, override) {
836
+ const dsn = override?.dsn ?? base?.dsn;
837
+ const enabled = override?.enabled ?? base?.enabled ?? connectorEnabled;
838
+ const ready = enabled && hasNonEmptyString(dsn);
839
+ return {
840
+ enabled,
841
+ dsn,
842
+ tracesSampleRate: override?.tracesSampleRate ?? base?.tracesSampleRate ?? 1,
843
+ environment: override?.environment ?? base?.environment,
844
+ release: override?.release ?? base?.release,
845
+ ready,
846
+ status: ready ? "enabled" : "missing"
847
+ };
848
+ }
849
+ function mergeSentryConnectorConfig(base, override) {
850
+ const dsn = override?.dsn ?? base?.dsn;
851
+ const enabled = override?.enabled ?? base?.enabled ?? false;
852
+ const ready = enabled && typeof dsn === "string" && dsn.trim().length > 0;
853
+ return {
854
+ enabled,
855
+ mode: override?.mode ?? base?.mode ?? "auto",
856
+ dsn,
857
+ environment: override?.environment ?? base?.environment,
858
+ release: override?.release ?? base?.release,
859
+ ready,
860
+ status: ready ? "enabled" : "missing"
861
+ };
862
+ }
863
+ function mergeOTLPConnectorConfig(base, override) {
864
+ const endpoint = override?.endpoint ?? base?.endpoint;
865
+ const enabled = override?.enabled ?? base?.enabled ?? false;
866
+ const resolvedHeaders = {
867
+ ...{},
868
+ ...override?.headers ?? {}
869
+ };
870
+ const ready = enabled && isAbsoluteHttpUrl(endpoint);
871
+ return {
872
+ name: override?.name ?? base?.name ?? "",
873
+ enabled,
874
+ mode: override?.mode ?? base?.mode ?? "auto",
875
+ endpoint,
876
+ headers: resolvedHeaders,
877
+ auth: override?.auth ?? base?.auth,
878
+ serviceName: override?.serviceName ?? base?.serviceName ?? resolveDefaultConnectorServiceName(),
879
+ ready,
880
+ status: ready ? "enabled" : "missing"
881
+ };
882
+ }
883
+ function mergeOTLPConnectorsConfig(base, override) {
884
+ const source = override ?? base ?? [];
885
+ const deduped = /* @__PURE__ */ new Map();
886
+ for (const connector of source) {
887
+ if (!connector || typeof connector.name !== "string" || connector.name.length === 0) {
888
+ continue;
889
+ }
890
+ if (deduped.has(connector.name)) {
891
+ warnOnce(
892
+ `otlp-duplicate:${connector.name}`,
893
+ `[Blyp] Warning: Duplicate OTLP connector name "${connector.name}" found. Using the last definition.`
894
+ );
895
+ }
896
+ deduped.set(connector.name, mergeOTLPConnectorConfig(void 0, connector));
897
+ }
898
+ return Array.from(deduped.values());
899
+ }
900
+ function mergeConnectorsConfig(base, override) {
901
+ return {
902
+ betterstack: mergeBetterStackConnectorConfig(base?.betterstack, override?.betterstack),
903
+ posthog: mergePostHogConnectorConfig(base?.posthog, override?.posthog),
904
+ sentry: mergeSentryConnectorConfig(base?.sentry, override?.sentry),
905
+ otlp: mergeOTLPConnectorsConfig(base?.otlp, override?.otlp)
906
+ };
907
+ }
908
+ function mergeBlypConfig(base, override = {}, options = {}) {
909
+ return {
910
+ ...base,
911
+ ...override,
912
+ destination: override.destination ?? base.destination ?? "file",
913
+ file: mergeFileConfig(base.file, override.file),
914
+ database: mergeDatabaseLoggerConfig(base.database, override.database, options.configFileType),
915
+ clientLogging: mergeClientLoggingConfig(base.clientLogging, override.clientLogging),
916
+ connectors: mergeConnectorsConfig(base.connectors, override.connectors)
917
+ };
918
+ }
919
+ function loadConfig() {
920
+ if (cachedConfig !== null) {
921
+ return cachedConfig;
922
+ }
923
+ bootstrapProjectFiles();
924
+ const configFile = findConfigFile();
925
+ if (configFile) {
926
+ const userConfig = parseConfigFile(configFile);
927
+ cachedConfig = mergeBlypConfig(DEFAULT_CONFIG, userConfig, {
928
+ configFileType: configFile.type
929
+ });
930
+ } else {
931
+ cachedConfig = mergeBlypConfig(DEFAULT_CONFIG);
932
+ }
933
+ return cachedConfig;
934
+ }
935
+ function resolveConfig(overrides = {}) {
936
+ return mergeBlypConfig(loadConfig(), overrides);
937
+ }
938
+
939
+ // src/core/helpers.ts
940
+ function normalizePath(path3) {
941
+ const queryIndex = path3.indexOf("?");
942
+ let withoutQuery = queryIndex >= 0 ? path3.substring(0, queryIndex) : path3;
943
+ if (withoutQuery.endsWith("/") && withoutQuery.length > 1) {
944
+ withoutQuery = withoutQuery.slice(0, -1);
945
+ }
946
+ if (!withoutQuery.startsWith("/")) {
947
+ withoutQuery = "/" + withoutQuery;
948
+ }
949
+ return withoutQuery;
950
+ }
951
+ function normalizePattern(pattern) {
952
+ const queryIndex = pattern.indexOf("?");
953
+ let withoutQuery = queryIndex >= 0 ? pattern.substring(0, queryIndex) : pattern;
954
+ if (withoutQuery.endsWith("/") && withoutQuery.length > 1) {
955
+ withoutQuery = withoutQuery.slice(0, -1);
956
+ }
957
+ if (!withoutQuery.startsWith("/")) {
958
+ withoutQuery = "/" + withoutQuery;
959
+ }
960
+ return withoutQuery;
961
+ }
962
+ function shouldIgnorePath(path3, ignorePaths) {
963
+ if (!ignorePaths || ignorePaths.length === 0) {
964
+ return false;
965
+ }
966
+ const normalizedPath = normalizePath(path3);
967
+ return ignorePaths.some((ignoredPattern) => {
968
+ const normalizedPattern = normalizePattern(ignoredPattern);
969
+ if (normalizedPattern === normalizedPath) {
970
+ return true;
971
+ }
972
+ if (normalizedPattern === "/**" || normalizedPattern === "**") {
973
+ return true;
974
+ }
975
+ if (normalizedPattern === "/*") {
976
+ const segments = normalizedPath.split("/").filter((s) => s.length > 0);
977
+ return segments.length === 1;
978
+ }
979
+ if (normalizedPattern.endsWith("/*") && !normalizedPattern.includes("**")) {
980
+ const prefix = normalizedPattern.slice(0, -1);
981
+ if (normalizedPath.startsWith(prefix)) {
982
+ const rest = normalizedPath.slice(prefix.length);
983
+ const restSegments = rest.split("/").filter((s) => s.length > 0);
984
+ return restSegments.length === 1;
985
+ }
986
+ return false;
987
+ }
988
+ if (normalizedPattern.includes("**")) {
989
+ if (normalizedPattern === "/**") {
990
+ return true;
991
+ }
992
+ if (normalizedPattern.startsWith("/") && normalizedPattern.endsWith("**")) {
993
+ let prefix2 = normalizedPattern.slice(0, -2);
994
+ if (prefix2.endsWith("/") && prefix2.length > 1) {
995
+ prefix2 = prefix2.slice(0, -1);
996
+ }
997
+ if (prefix2 === normalizedPath) {
998
+ return true;
999
+ }
1000
+ return normalizedPath.startsWith(prefix2 + "/");
1001
+ }
1002
+ const starIndex = normalizedPattern.indexOf("**");
1003
+ let prefix = normalizedPattern.substring(0, starIndex);
1004
+ const suffix = normalizedPattern.substring(starIndex + 2);
1005
+ if (prefix.endsWith("/") && prefix.length > 1) {
1006
+ prefix = prefix.slice(0, -1);
1007
+ }
1008
+ if (prefix === "" && suffix === "") {
1009
+ return true;
1010
+ }
1011
+ if (prefix !== "" && suffix === "") {
1012
+ return normalizedPath.startsWith(prefix + "/");
1013
+ }
1014
+ if (prefix === "" && suffix !== "") {
1015
+ return normalizedPath.endsWith(suffix) || normalizedPath.includes(suffix + "/");
1016
+ }
1017
+ if (prefix !== "" && suffix !== "") {
1018
+ return normalizedPath.startsWith(prefix) && (normalizedPath.endsWith(suffix) || normalizedPath.includes(suffix + "/"));
1019
+ }
1020
+ return false;
1021
+ }
1022
+ if (normalizedPattern.includes("*")) {
1023
+ const lastDotIndex = normalizedPattern.lastIndexOf(".");
1024
+ const lastStarIndex = normalizedPattern.lastIndexOf("*");
1025
+ if (lastDotIndex > lastStarIndex && lastStarIndex > 0) {
1026
+ const charBeforeStar = normalizedPattern[lastStarIndex - 1];
1027
+ if (charBeforeStar === "/") {
1028
+ const extPattern = normalizedPattern.slice(lastStarIndex);
1029
+ const filePart = normalizedPath.slice(normalizedPath.lastIndexOf("/") + 1);
1030
+ const extIndex = filePart.lastIndexOf(".");
1031
+ if (extIndex > 0) {
1032
+ const actualExt = filePart.slice(extIndex);
1033
+ return actualExt === extPattern;
1034
+ }
1035
+ }
1036
+ }
1037
+ const regexPattern = normalizedPattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*");
1038
+ const regex = new RegExp("^" + regexPattern + "$");
1039
+ return regex.test(normalizedPath);
1040
+ }
1041
+ return false;
1042
+ });
1043
+ }
1044
+ function gzipBuffer(buf) {
1045
+ return Buffer.from(gzipSync(buf));
1046
+ }
1047
+ function warnWithConsole(message, error) {
1048
+ console.warn(`[Blyp] Warning: ${message}`, error);
1049
+ }
1050
+ function ensureDirectory(dirPath) {
1051
+ fs.mkdirSync(dirPath, { recursive: true });
1052
+ }
1053
+ function getFileSize(filePath) {
1054
+ try {
1055
+ return fs.statSync(filePath).size;
1056
+ } catch {
1057
+ return 0;
1058
+ }
1059
+ }
1060
+ function formatArchiveTimestamp(timestamp) {
1061
+ const year = timestamp.getUTCFullYear();
1062
+ const month = String(timestamp.getUTCMonth() + 1).padStart(2, "0");
1063
+ const day = String(timestamp.getUTCDate()).padStart(2, "0");
1064
+ const hours = String(timestamp.getUTCHours()).padStart(2, "0");
1065
+ const minutes = String(timestamp.getUTCMinutes()).padStart(2, "0");
1066
+ const seconds = String(timestamp.getUTCSeconds()).padStart(2, "0");
1067
+ return `${year}${month}${day}T${hours}${minutes}${seconds}Z`;
1068
+ }
1069
+ function getUniqueArchivePath(basePath, extension) {
1070
+ let candidate = `${basePath}${extension}`;
1071
+ let suffix = 1;
1072
+ while (fs.existsSync(candidate)) {
1073
+ candidate = `${basePath}-${suffix}${extension}`;
1074
+ suffix += 1;
1075
+ }
1076
+ return candidate;
1077
+ }
1078
+ function pruneArchives(archiveDir, archivePrefix, maxArchives, warn) {
1079
+ const prefix = `${archivePrefix}.`;
1080
+ try {
1081
+ const archivePaths = fs.readdirSync(archiveDir).filter(
1082
+ (name) => name.startsWith(prefix) && (name.endsWith(".ndjson") || name.endsWith(".ndjson.gz"))
1083
+ ).map((name) => path.join(archiveDir, name)).sort((left, right) => {
1084
+ return fs.statSync(left).mtimeMs - fs.statSync(right).mtimeMs;
1085
+ });
1086
+ const deleteCount = Math.max(archivePaths.length - maxArchives, 0);
1087
+ for (let index = 0; index < deleteCount; index += 1) {
1088
+ fs.rmSync(archivePaths[index]);
1089
+ }
1090
+ } catch (error) {
1091
+ warn(`Failed to prune archives for ${archivePrefix}`, error);
1092
+ }
1093
+ }
1094
+ function createSafeReplacer() {
1095
+ const seen = /* @__PURE__ */ new WeakSet();
1096
+ return (_key, value) => {
1097
+ if (typeof value === "function") {
1098
+ return `[Function: ${value.name || "anonymous"}]`;
1099
+ }
1100
+ if (value === void 0) {
1101
+ return "[undefined]";
1102
+ }
1103
+ if (typeof value === "symbol") {
1104
+ return value.toString();
1105
+ }
1106
+ if (value !== null && typeof value === "object") {
1107
+ if (seen.has(value)) {
1108
+ return "[Circular]";
1109
+ }
1110
+ seen.add(value);
1111
+ }
1112
+ return value;
1113
+ };
1114
+ }
1115
+ function serializeLogRecord(record) {
1116
+ return JSON.stringify(record, createSafeReplacer());
1117
+ }
1118
+ function resolveFileLoggerConfig(config) {
1119
+ const fileConfig = config.file;
1120
+ const dir = fileConfig?.dir || config.logDir || path.join(process.cwd(), "logs");
1121
+ const archiveDir = fileConfig?.archiveDir || path.join(dir, "archive");
1122
+ const rotation = fileConfig?.rotation;
1123
+ return {
1124
+ enabled: fileConfig?.enabled ?? true,
1125
+ dir,
1126
+ archiveDir,
1127
+ rotationEnabled: rotation?.enabled ?? true,
1128
+ maxSizeBytes: rotation?.maxSizeBytes ?? 10 * 1024 * 1024,
1129
+ maxArchives: rotation?.maxArchives ?? 5,
1130
+ compress: rotation?.compress ?? true
1131
+ };
1132
+ }
1133
+ var RotatingFileLogger = class {
1134
+ constructor(config, dependencies = {}) {
1135
+ __publicField(this, "config");
1136
+ __publicField(this, "gzip");
1137
+ __publicField(this, "warn");
1138
+ __publicField(this, "combined");
1139
+ __publicField(this, "error");
1140
+ this.config = resolveFileLoggerConfig(config);
1141
+ this.gzip = dependencies.gzip ?? gzipBuffer;
1142
+ this.warn = dependencies.warn ?? warnWithConsole;
1143
+ this.combined = {
1144
+ activePath: path.join(this.config.dir, "log.ndjson"),
1145
+ archivePrefix: "log",
1146
+ bytes: 0,
1147
+ queue: [],
1148
+ processing: false
1149
+ };
1150
+ this.error = {
1151
+ activePath: path.join(this.config.dir, "log.error.ndjson"),
1152
+ archivePrefix: "log.error",
1153
+ bytes: 0,
1154
+ queue: [],
1155
+ processing: false
1156
+ };
1157
+ if (!this.config.enabled) {
1158
+ return;
1159
+ }
1160
+ ensureDirectory(this.config.dir);
1161
+ ensureDirectory(this.config.archiveDir);
1162
+ this.seedStream(this.combined);
1163
+ this.seedStream(this.error);
1164
+ }
1165
+ write(record) {
1166
+ if (!this.config.enabled) {
1167
+ return;
1168
+ }
1169
+ const line = `${serializeLogRecord(record)}
1170
+ `;
1171
+ this.enqueue(this.combined, line);
1172
+ if (record.level === "error" || record.level === "critical") {
1173
+ this.enqueue(this.error, line);
1174
+ }
1175
+ }
1176
+ enqueue(stream, line) {
1177
+ stream.queue.push(line);
1178
+ this.processQueue(stream);
1179
+ }
1180
+ processQueue(stream) {
1181
+ if (stream.processing) {
1182
+ return;
1183
+ }
1184
+ stream.processing = true;
1185
+ try {
1186
+ while (stream.queue.length > 0) {
1187
+ const queuedLine = stream.queue.shift();
1188
+ if (queuedLine === void 0) {
1189
+ continue;
1190
+ }
1191
+ try {
1192
+ this.append(stream, queuedLine);
1193
+ } catch (error) {
1194
+ this.warn(`Failed writing log line for ${stream.archivePrefix}`, error);
1195
+ }
1196
+ }
1197
+ } finally {
1198
+ stream.processing = false;
1199
+ }
1200
+ }
1201
+ seedStream(stream) {
1202
+ stream.bytes = getFileSize(stream.activePath);
1203
+ if (this.config.rotationEnabled && stream.bytes > this.config.maxSizeBytes && stream.bytes > 0) {
1204
+ this.rotate(stream);
1205
+ fs.closeSync(fs.openSync(stream.activePath, "a"));
1206
+ stream.bytes = 0;
1207
+ }
1208
+ }
1209
+ append(stream, line) {
1210
+ ensureDirectory(this.config.dir);
1211
+ const lineBytes = Buffer.byteLength(line, "utf8");
1212
+ if (this.config.rotationEnabled && stream.bytes > 0 && stream.bytes + lineBytes > this.config.maxSizeBytes) {
1213
+ this.rotate(stream);
1214
+ }
1215
+ fs.appendFileSync(stream.activePath, line, "utf8");
1216
+ stream.bytes += lineBytes;
1217
+ }
1218
+ rotate(stream) {
1219
+ ensureDirectory(this.config.archiveDir);
1220
+ if (!fs.existsSync(stream.activePath) || stream.bytes === 0) {
1221
+ stream.bytes = 0;
1222
+ return;
1223
+ }
1224
+ const archiveTimestamp = formatArchiveTimestamp(/* @__PURE__ */ new Date());
1225
+ const archiveBasePath = path.join(
1226
+ this.config.archiveDir,
1227
+ `${stream.archivePrefix}.${archiveTimestamp}`
1228
+ );
1229
+ const archivePath = getUniqueArchivePath(archiveBasePath, ".ndjson");
1230
+ fs.renameSync(stream.activePath, archivePath);
1231
+ if (this.config.compress) {
1232
+ try {
1233
+ const compressedPath = `${archivePath}.gz`;
1234
+ const gzipped = this.gzip(fs.readFileSync(archivePath));
1235
+ fs.writeFileSync(compressedPath, gzipped);
1236
+ fs.rmSync(archivePath);
1237
+ } catch (error) {
1238
+ this.warn(`Failed to gzip archive ${archivePath}`, error);
1239
+ }
1240
+ }
1241
+ stream.bytes = 0;
1242
+ pruneArchives(this.config.archiveDir, stream.archivePrefix, this.config.maxArchives, this.warn);
1243
+ }
1244
+ };
1245
+ function createFileLogger(config) {
1246
+ return new RotatingFileLogger(config);
1247
+ }
1248
+
1249
+ // src/connectors/shared.ts
1250
+ function isBlypConfig(config) {
1251
+ return isPlainObject(config) && ("connectors" in config || "pretty" in config || "level" in config);
1252
+ }
1253
+ function getPrimaryPayload(record) {
1254
+ return isPlainObject(record.data) ? record.data : record;
1255
+ }
1256
+ function getField(record, key) {
1257
+ if (key in record) {
1258
+ const direct = record[key];
1259
+ if (typeof direct === "string" || typeof direct === "number") {
1260
+ return direct;
1261
+ }
1262
+ }
1263
+ const payload = getPrimaryPayload(record);
1264
+ const nested = payload[key];
1265
+ if (typeof nested === "string" || typeof nested === "number") {
1266
+ return nested;
1267
+ }
1268
+ return void 0;
1269
+ }
1270
+ function getClientPageField(record, key) {
1271
+ const payload = getPrimaryPayload(record);
1272
+ const page = isPlainObject(payload.page) ? payload.page : void 0;
1273
+ const value = page?.[key];
1274
+ return typeof value === "string" ? value : void 0;
1275
+ }
1276
+ function getClientSessionField(record, key) {
1277
+ const payload = getPrimaryPayload(record);
1278
+ const session = isPlainObject(payload.session) ? payload.session : void 0;
1279
+ const value = session?.[key];
1280
+ return typeof value === "string" ? value : void 0;
1281
+ }
1282
+ function getRecordType(record) {
1283
+ return getField(record, "type");
1284
+ }
1285
+
1286
+ // src/connectors/posthog/sender.ts
1287
+ var PREVIOUSLY_CAPTURED_ERROR_KEY = "__posthog_previously_captured_error";
1288
+ var warnedKeys2 = /* @__PURE__ */ new Set();
1289
+ var testHooks = {};
1290
+ var warnOnce2 = createErrorOnceLogger(warnedKeys2);
1291
+ function normalizeHost(host) {
1292
+ const trimmed = (host || "https://us.i.posthog.com").trim();
1293
+ return trimmed.replace(/\/+$/, "");
1294
+ }
1295
+ function buildRecordAttributes(record, source) {
1296
+ const recordType = getRecordType(record);
1297
+ const caller = typeof record.caller === "string" ? record.caller : void 0;
1298
+ const groupId = getField(record, "groupId");
1299
+ const method = getField(record, "method");
1300
+ const path3 = getField(record, "path");
1301
+ const status = getField(record, "status");
1302
+ const duration = getField(record, "duration");
1303
+ const pagePath = getClientPageField(record, "pathname");
1304
+ const pageUrl = getClientPageField(record, "url");
1305
+ const sessionId = getClientSessionField(record, "sessionId");
1306
+ const pageId = getClientSessionField(record, "pageId");
1307
+ const attributes = {
1308
+ "blyp.level": record.level,
1309
+ "blyp.source": source,
1310
+ "blyp.payload": serializeLogRecord(record)
1311
+ };
1312
+ const ifTruthy = [
1313
+ ["blyp.type", recordType],
1314
+ ["blyp.caller", caller],
1315
+ ["blyp.group_id", groupId],
1316
+ ["http.method", method],
1317
+ ["url.path", path3],
1318
+ ["client.page_path", pagePath],
1319
+ ["client.page_url", pageUrl],
1320
+ ["client.session_id", sessionId],
1321
+ ["client.page_id", pageId]
1322
+ ];
1323
+ const ifDefined = [
1324
+ ["http.status_code", status],
1325
+ ["blyp.duration_ms", duration]
1326
+ ];
1327
+ for (const [k, v] of ifTruthy) if (v) attributes[k] = v;
1328
+ for (const [k, v] of ifDefined) if (v !== void 0) attributes[k] = v;
1329
+ return attributes;
1330
+ }
1331
+ function normalizeExceptionProperties(value) {
1332
+ if (!isPlainObject(value)) {
1333
+ return {};
1334
+ }
1335
+ return normalizeLogValue(value);
1336
+ }
1337
+ function assignExceptionField(target, key, value) {
1338
+ if (value === void 0) {
1339
+ return;
1340
+ }
1341
+ try {
1342
+ target[key] = value;
1343
+ } catch {
1344
+ }
1345
+ }
1346
+ function createSyntheticError(message, source) {
1347
+ const error = new Error(message);
1348
+ const name = hasNonEmptyString(source.name) ? source.name : "Error";
1349
+ error.name = name;
1350
+ if (hasNonEmptyString(source.stack)) {
1351
+ error.stack = source.stack;
1352
+ }
1353
+ assignExceptionField(error, "cause", source.cause);
1354
+ assignExceptionField(error, "status", source.status);
1355
+ assignExceptionField(error, "statusCode", source.statusCode);
1356
+ assignExceptionField(error, "code", source.code);
1357
+ assignExceptionField(error, "why", source.why);
1358
+ assignExceptionField(error, "fix", source.fix);
1359
+ assignExceptionField(error, "link", source.link);
1360
+ assignExceptionField(error, "details", source.details);
1361
+ return error;
1362
+ }
1363
+ function normalizeExceptionInput(input, fallbackMessage = "Unknown error") {
1364
+ if (input instanceof Error) {
1365
+ return {
1366
+ error: input,
1367
+ properties: normalizeExceptionProperties(input)
1368
+ };
1369
+ }
1370
+ if (isPlainObject(input)) {
1371
+ const message = hasNonEmptyString(input.message) ? input.message : hasNonEmptyString(input.error) ? input.error : fallbackMessage;
1372
+ return {
1373
+ error: createSyntheticError(message, input),
1374
+ properties: normalizeExceptionProperties(input)
1375
+ };
1376
+ }
1377
+ if (typeof input === "string") {
1378
+ return {
1379
+ error: new Error(input),
1380
+ properties: {
1381
+ message: input
1382
+ }
1383
+ };
1384
+ }
1385
+ return {
1386
+ error: new Error(fallbackMessage),
1387
+ properties: {
1388
+ value: normalizeLogValue(input)
1389
+ }
1390
+ };
1391
+ }
1392
+ function createExceptionPropertiesFromRecord(record, source) {
1393
+ return buildRecordAttributes(record, source);
1394
+ }
1395
+ function isPreviouslyCapturedPostHogError(value) {
1396
+ return isPlainObject(value) && value[PREVIOUSLY_CAPTURED_ERROR_KEY] === true;
1397
+ }
1398
+ function markPostHogCapturedError(value) {
1399
+ if (!isPlainObject(value) || isPreviouslyCapturedPostHogError(value)) {
1400
+ return;
1401
+ }
1402
+ try {
1403
+ Object.defineProperty(value, PREVIOUSLY_CAPTURED_ERROR_KEY, {
1404
+ value: true,
1405
+ enumerable: false,
1406
+ configurable: true,
1407
+ writable: true
1408
+ });
1409
+ } catch {
1410
+ try {
1411
+ value[PREVIOUSLY_CAPTURED_ERROR_KEY] = true;
1412
+ } catch {
1413
+ }
1414
+ }
1415
+ }
1416
+ function isClientLogRecord(record) {
1417
+ return getRecordType(record) === "client_log";
1418
+ }
1419
+ function normalizePostHogRecord(record, connector, source = "server") {
1420
+ const severity = resolveSeverity(record.level);
1421
+ const body = typeof record.message === "string" ? record.message : String(record.message);
1422
+ return {
1423
+ body,
1424
+ severityText: severity.text,
1425
+ severityNumber: severity.number,
1426
+ attributes: buildRecordAttributes(record, source),
1427
+ resourceAttributes: {
1428
+ "service.name": connector.serviceName
1429
+ }
1430
+ };
1431
+ }
1432
+ function resolveSeverity(level) {
1433
+ switch (level) {
1434
+ case "debug":
1435
+ return { text: "debug", number: SeverityNumber.DEBUG };
1436
+ case "warning":
1437
+ case "warn":
1438
+ return { text: "warn", number: SeverityNumber.WARN };
1439
+ case "error":
1440
+ return { text: "error", number: SeverityNumber.ERROR };
1441
+ case "critical":
1442
+ return { text: "fatal", number: SeverityNumber.FATAL };
1443
+ case "success":
1444
+ case "table":
1445
+ case "info":
1446
+ default:
1447
+ return { text: "info", number: SeverityNumber.INFO };
1448
+ }
1449
+ }
1450
+ function registerShutdownHooks(key, shutdown) {
1451
+ const handlers = ["beforeExit", "SIGINT", "SIGTERM"];
1452
+ for (const event of handlers) {
1453
+ process.once(event, () => {
1454
+ void shutdown().catch((error) => {
1455
+ warnOnce2(
1456
+ `${key}:shutdown`,
1457
+ "[Blyp] Failed to flush PostHog telemetry during shutdown.",
1458
+ error
1459
+ );
1460
+ });
1461
+ });
1462
+ }
1463
+ }
1464
+ function createDefaultTransport(connector) {
1465
+ const exporter = new OTLPLogExporter({
1466
+ url: `${normalizeHost(connector.host)}/i/v1/logs`,
1467
+ headers: {
1468
+ Authorization: `Bearer ${connector.projectKey}`
1469
+ }
1470
+ });
1471
+ const provider = new LoggerProvider({
1472
+ resource: resourceFromAttributes({
1473
+ "service.name": connector.serviceName
1474
+ }),
1475
+ processors: [new BatchLogRecordProcessor(exporter)]
1476
+ });
1477
+ const logger3 = provider.getLogger("blyp-posthog");
1478
+ return {
1479
+ emit(payload) {
1480
+ logger3.emit({
1481
+ body: payload.body,
1482
+ severityText: payload.severityText,
1483
+ severityNumber: payload.severityNumber,
1484
+ attributes: payload.attributes
1485
+ });
1486
+ },
1487
+ flush() {
1488
+ return provider.forceFlush();
1489
+ },
1490
+ shutdown() {
1491
+ return provider.shutdown();
1492
+ }
1493
+ };
1494
+ }
1495
+ function createDefaultExceptionClient(connector) {
1496
+ const client = new PostHog(connector.projectKey ?? "", {
1497
+ host: connector.host,
1498
+ enableExceptionAutocapture: connector.errorTracking.enableExceptionAutocapture
1499
+ });
1500
+ return {
1501
+ captureException(error, distinctId, additionalProperties) {
1502
+ return client.captureExceptionImmediate(error, distinctId, additionalProperties);
1503
+ },
1504
+ shutdown() {
1505
+ return client._shutdown();
1506
+ }
1507
+ };
1508
+ }
1509
+ function resolveConnectorConfig(config) {
1510
+ const connector = isBlypConfig(config) ? config.connectors?.posthog : config;
1511
+ const enabled = connector?.enabled ?? false;
1512
+ const projectKey = connector?.projectKey;
1513
+ const errorTrackingEnabled = connector?.errorTracking?.enabled ?? enabled;
1514
+ const errorTrackingMode = connector?.errorTracking?.mode ?? "auto";
1515
+ const errorTrackingReady = enabled && errorTrackingEnabled && hasNonEmptyString(projectKey);
1516
+ return {
1517
+ enabled,
1518
+ mode: connector?.mode ?? "auto",
1519
+ projectKey,
1520
+ host: normalizeHost(connector?.host),
1521
+ serviceName: connector?.serviceName ?? "blyp-app",
1522
+ errorTracking: {
1523
+ enabled: errorTrackingEnabled,
1524
+ mode: errorTrackingMode,
1525
+ enableExceptionAutocapture: connector?.errorTracking?.enableExceptionAutocapture ?? errorTrackingMode === "auto",
1526
+ ready: errorTrackingReady,
1527
+ status: errorTrackingReady ? "enabled" : "missing"
1528
+ }
1529
+ };
1530
+ }
1531
+ function createPostHogSender(config) {
1532
+ const connector = resolveConnectorConfig(config);
1533
+ const key = `${connector.serviceName}:${connector.host}:${connector.mode}`;
1534
+ const ready = connector.enabled === true && hasNonEmptyString(connector.projectKey);
1535
+ const transport = ready ? testHooks.createTransport?.(connector) ?? createDefaultTransport(connector) : void 0;
1536
+ const exceptionClient = connector.errorTracking.ready ? testHooks.createExceptionClient?.(connector) ?? createDefaultExceptionClient(connector) : void 0;
1537
+ const shutdown = async () => {
1538
+ if (transport?.shutdown) {
1539
+ await transport.shutdown();
1540
+ } else if (transport?.flush) {
1541
+ await transport.flush();
1542
+ }
1543
+ if (exceptionClient?.shutdown) {
1544
+ await exceptionClient.shutdown();
1545
+ }
1546
+ };
1547
+ if (transport || exceptionClient) {
1548
+ registerShutdownHooks(key, shutdown);
1549
+ }
1550
+ const emitUnavailableWarning = () => {
1551
+ warnOnce2(
1552
+ `posthog-unavailable:${key}`,
1553
+ "[Blyp] PostHog connector is not configured. Skipping PostHog delivery."
1554
+ );
1555
+ };
1556
+ const emitExceptionUnavailableWarning = () => {
1557
+ warnOnce2(
1558
+ `posthog-exception-unavailable:${key}`,
1559
+ "[Blyp] PostHog error tracking is not configured. Skipping PostHog exception capture."
1560
+ );
1561
+ };
1562
+ return {
1563
+ enabled: connector.enabled,
1564
+ ready,
1565
+ mode: connector.mode,
1566
+ serviceName: connector.serviceName,
1567
+ host: connector.host,
1568
+ status: ready ? "enabled" : "missing",
1569
+ errorTracking: {
1570
+ enabled: connector.errorTracking.enabled,
1571
+ ready: connector.errorTracking.ready,
1572
+ mode: connector.errorTracking.mode,
1573
+ status: connector.errorTracking.status,
1574
+ enableExceptionAutocapture: connector.errorTracking.enableExceptionAutocapture
1575
+ },
1576
+ shouldAutoForwardServerLogs() {
1577
+ return ready && connector.mode === "auto";
1578
+ },
1579
+ shouldAutoCaptureExceptions() {
1580
+ return connector.errorTracking.ready && connector.errorTracking.mode === "auto";
1581
+ },
1582
+ send(record, options = {}) {
1583
+ const source = options.source ?? "server";
1584
+ if (!ready || !transport) {
1585
+ if (options.warnIfUnavailable) {
1586
+ emitUnavailableWarning();
1587
+ }
1588
+ return;
1589
+ }
1590
+ const normalized = normalizePostHogRecord(record, connector, source);
1591
+ try {
1592
+ const result = transport.emit(normalized);
1593
+ if (result && typeof result.catch === "function") {
1594
+ void result.catch((error) => {
1595
+ warnOnce2(
1596
+ `posthog-emit:${key}`,
1597
+ "[Blyp] Failed to deliver log to PostHog.",
1598
+ error
1599
+ );
1600
+ });
1601
+ }
1602
+ } catch (error) {
1603
+ warnOnce2(
1604
+ `posthog-emit:${key}`,
1605
+ "[Blyp] Failed to deliver log to PostHog.",
1606
+ error
1607
+ );
1608
+ }
1609
+ },
1610
+ captureException(error, options = {}) {
1611
+ if (!connector.errorTracking.ready || !exceptionClient) {
1612
+ if (options.warnIfUnavailable) {
1613
+ emitExceptionUnavailableWarning();
1614
+ }
1615
+ return;
1616
+ }
1617
+ if (isPreviouslyCapturedPostHogError(error)) {
1618
+ return;
1619
+ }
1620
+ const normalized = normalizeExceptionInput(
1621
+ error,
1622
+ options.source === "client" ? "Client error" : "Server error"
1623
+ );
1624
+ const properties = {
1625
+ ...normalized.properties,
1626
+ ...options.properties ?? {},
1627
+ "blyp.source": options.source ?? "server"
1628
+ };
1629
+ try {
1630
+ const result = exceptionClient.captureException(
1631
+ normalized.error,
1632
+ options.distinctId,
1633
+ properties
1634
+ );
1635
+ markPostHogCapturedError(error);
1636
+ markPostHogCapturedError(normalized.error);
1637
+ if (result && typeof result.catch === "function") {
1638
+ void result.catch((captureError) => {
1639
+ warnOnce2(
1640
+ `posthog-capture:${key}`,
1641
+ "[Blyp] Failed to capture exception in PostHog.",
1642
+ captureError
1643
+ );
1644
+ });
1645
+ }
1646
+ } catch (captureError) {
1647
+ warnOnce2(
1648
+ `posthog-capture:${key}`,
1649
+ "[Blyp] Failed to capture exception in PostHog.",
1650
+ captureError
1651
+ );
1652
+ }
1653
+ },
1654
+ async flush() {
1655
+ try {
1656
+ if (transport?.flush) {
1657
+ await transport.flush();
1658
+ }
1659
+ } catch (error) {
1660
+ warnOnce2(
1661
+ `posthog-flush:${key}`,
1662
+ "[Blyp] Failed to flush PostHog telemetry.",
1663
+ error
1664
+ );
1665
+ }
1666
+ }
1667
+ };
1668
+ }
1669
+ function buildPostHogExceptionProperties(record, source, properties = {}) {
1670
+ return {
1671
+ ...createExceptionPropertiesFromRecord(record, source),
1672
+ ...properties
1673
+ };
1674
+ }
1675
+ var requestContextStorage = new AsyncLocalStorage();
1676
+ function createStore() {
1677
+ return {
1678
+ requestScopedLoggerActive: true,
1679
+ structuredCollectorActive: false,
1680
+ structuredLogEmitted: false,
1681
+ mixedLoggerWarningShown: false
1682
+ };
1683
+ }
1684
+ function enterRequestContext() {
1685
+ const store = createStore();
1686
+ requestContextStorage.enterWith(store);
1687
+ return store;
1688
+ }
1689
+ function getRequestContextStore() {
1690
+ return requestContextStorage.getStore();
1691
+ }
1692
+ function setActiveRequestLogger(logger3) {
1693
+ const store = getRequestContextStore();
1694
+ if (store) {
1695
+ store.activeLogger = logger3;
1696
+ }
1697
+ }
1698
+ function markStructuredCollectorActive() {
1699
+ const store = getRequestContextStore();
1700
+ if (store) {
1701
+ store.structuredCollectorActive = true;
1702
+ }
1703
+ }
1704
+ function markStructuredLogEmitted() {
1705
+ const store = getRequestContextStore();
1706
+ if (store) {
1707
+ store.structuredLogEmitted = true;
1708
+ }
1709
+ }
1710
+ function shouldDropRootLogWrite() {
1711
+ const store = getRequestContextStore();
1712
+ if (!store || !store.requestScopedLoggerActive || !store.structuredCollectorActive) {
1713
+ return false;
1714
+ }
1715
+ if (!store.mixedLoggerWarningShown) {
1716
+ store.mixedLoggerWarningShown = true;
1717
+ console.warn(
1718
+ "[Blyp] Warning: Mixed logger usage detected for this request. The root logger call was ignored because a request-scoped structured logger is active."
1719
+ );
1720
+ }
1721
+ return true;
1722
+ }
1723
+
1724
+ // src/core/log-record.ts
1725
+ var RECORD_LEVELS = {
1726
+ success: "success",
1727
+ critical: "critical",
1728
+ warning: "warning",
1729
+ info: "info",
1730
+ debug: "debug",
1731
+ error: "error",
1732
+ warn: "warning",
1733
+ table: "table"
1734
+ };
1735
+ function normalizePath2(filePath) {
1736
+ return filePath.replace(/\\/g, "/");
1737
+ }
1738
+ function isInternalLoggerFrame(filePath) {
1739
+ const normalizedPath = normalizePath2(filePath);
1740
+ return normalizedPath.startsWith("node:") || normalizedPath.includes("/node_modules/pino") || normalizedPath.includes("/node_modules/pino-pretty") || normalizedPath.includes("/node_modules/@blyp/core/") || normalizedPath.includes("/blyp/src/core/") || normalizedPath.includes("/blyp/src/frameworks/") || normalizedPath.includes("/blyp/src/posthog/") || normalizedPath.includes("/blyp/dist/");
1741
+ }
1742
+ function formatCallerPath(filePath) {
1743
+ const normalizedPath = normalizePath2(filePath);
1744
+ const normalizedCwd = normalizePath2(process.cwd());
1745
+ return normalizedPath.startsWith(`${normalizedCwd}/`) ? normalizedPath.slice(normalizedCwd.length + 1) : normalizedPath;
1746
+ }
1747
+ function getCallerLocation() {
1748
+ try {
1749
+ const stack = new Error().stack;
1750
+ if (!stack) {
1751
+ return { file: null, line: null };
1752
+ }
1753
+ const lines = stack.split("\n");
1754
+ let fallback = null;
1755
+ for (let index = 2; index < lines.length; index += 1) {
1756
+ const line = lines[index];
1757
+ if (!line) {
1758
+ continue;
1759
+ }
1760
+ const match = line.match(/\((.*):(\d+):\d+\)/) || line.match(/at\s+(.*):(\d+):(\d+)/);
1761
+ if (!match) {
1762
+ continue;
1763
+ }
1764
+ const fileName = match[1] || "";
1765
+ const lineNumber = parseInt(match[2] || "0", 10) || null;
1766
+ if (fileName && !fileName.includes("node_modules") && !isInternalLoggerFrame(fileName)) {
1767
+ const formattedPath = formatCallerPath(fileName);
1768
+ const normalizedFormattedPath = normalizePath2(formattedPath);
1769
+ if (!normalizedFormattedPath.startsWith("dist/")) {
1770
+ return { file: formattedPath, line: lineNumber };
1771
+ }
1772
+ fallback ?? (fallback = { file: formattedPath, line: lineNumber });
1773
+ }
1774
+ }
1775
+ if (fallback) {
1776
+ return fallback;
1777
+ }
1778
+ } catch {
1779
+ return { file: null, line: null };
1780
+ }
1781
+ return { file: null, line: null };
1782
+ }
1783
+ var serializeMessage = serializeLogMessage;
1784
+ function stripAnsi(value) {
1785
+ return value.replace(/\u001b\[[0-9;]*m/g, "");
1786
+ }
1787
+ function buildRecord(level, message, args, bindings) {
1788
+ const { file, line } = getCallerLocation();
1789
+ const serializedMessage = serializeMessage(message);
1790
+ const record = {
1791
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1792
+ level: RECORD_LEVELS[level],
1793
+ message: stripAnsi(serializedMessage)
1794
+ };
1795
+ if (message instanceof Error) {
1796
+ record.error = normalizeError(message);
1797
+ }
1798
+ if (file) {
1799
+ record.caller = line !== null ? `${file}:${line}` : file;
1800
+ }
1801
+ if (args.length === 1) {
1802
+ record.data = normalizeLogValue(args[0]);
1803
+ } else if (args.length > 1) {
1804
+ record.data = normalizeLogValue(args);
1805
+ }
1806
+ if (Object.keys(bindings).length > 0) {
1807
+ record.bindings = normalizeLogValue(bindings);
1808
+ }
1809
+ return record;
1810
+ }
1811
+ function buildStructuredRecord(level, message, payload, bindings) {
1812
+ const { file, line } = getCallerLocation();
1813
+ const normalizedPayload = normalizeLogValue(payload);
1814
+ const record = {
1815
+ message: stripAnsi(message),
1816
+ ...normalizedPayload
1817
+ };
1818
+ if (file) {
1819
+ record.caller = line !== null ? `${file}:${line}` : file;
1820
+ }
1821
+ if (Object.keys(bindings).length > 0) {
1822
+ record.bindings = normalizeLogValue(bindings);
1823
+ }
1824
+ record.level = typeof normalizedPayload.level === "string" && normalizedPayload.level.length > 0 ? normalizedPayload.level : RECORD_LEVELS[level];
1825
+ record.timestamp = typeof normalizedPayload.timestamp === "string" && normalizedPayload.timestamp.length > 0 ? normalizedPayload.timestamp : (/* @__PURE__ */ new Date()).toISOString();
1826
+ return record;
1827
+ }
1828
+ function resolveStructuredWriteLevel(level) {
1829
+ switch (level) {
1830
+ case "debug":
1831
+ return "debug";
1832
+ case "warning":
1833
+ return "warning";
1834
+ case "warn":
1835
+ return "warn";
1836
+ case "error":
1837
+ return "error";
1838
+ case "success":
1839
+ return "success";
1840
+ case "critical":
1841
+ return "critical";
1842
+ case "table":
1843
+ return "table";
1844
+ case "info":
1845
+ default:
1846
+ return "info";
1847
+ }
1848
+ }
1849
+
1850
+ // src/core/sinks/file-primary-sink.ts
1851
+ var FilePrimarySink = class {
1852
+ constructor(logger3) {
1853
+ this.logger = logger3;
1854
+ __publicField(this, "isAsync", false);
1855
+ __publicField(this, "isReady", true);
1856
+ }
1857
+ write(record) {
1858
+ this.logger.write(record);
1859
+ }
1860
+ async flush() {
1861
+ }
1862
+ async shutdown() {
1863
+ }
1864
+ };
1865
+ function createFilePrimarySink(config) {
1866
+ return new FilePrimarySink(createFileLogger(config));
1867
+ }
1868
+
1869
+ // src/database/adapters/drizzle.ts
1870
+ function createDrizzleRowWriter(adapter) {
1871
+ const db = adapter.db;
1872
+ if (typeof db?.insert !== "function" || adapter.table === void 0) {
1873
+ throw new Error(
1874
+ "[Blyp] Drizzle database adapter is missing a db.insert function or table reference."
1875
+ );
1876
+ }
1877
+ return {
1878
+ async insert(rows) {
1879
+ if (rows.length === 0) {
1880
+ return;
1881
+ }
1882
+ await db.insert(adapter.table).values(rows);
1883
+ }
1884
+ };
1885
+ }
1886
+
1887
+ // src/database/adapters/prisma.ts
1888
+ function shouldFallbackFromCreateMany(error) {
1889
+ const message = String(error ?? "");
1890
+ return message.includes("createMany") || message.includes("Unknown argument") || message.includes("not supported") || message.includes("is not a function");
1891
+ }
1892
+ function createPrismaRowWriter(adapter) {
1893
+ const client = adapter.client;
1894
+ const model = adapter.model ?? "blypLog";
1895
+ const delegateCandidate = client[model];
1896
+ if (!delegateCandidate || typeof delegateCandidate.create !== "function") {
1897
+ throw new Error(
1898
+ `[Blyp] Prisma database adapter is missing the "${model}" delegate or its create method.`
1899
+ );
1900
+ }
1901
+ const delegate = delegateCandidate;
1902
+ let useCreateMany = typeof delegate.createMany === "function";
1903
+ async function fallbackInsert(rows) {
1904
+ if (typeof client.$transaction === "function") {
1905
+ await client.$transaction(
1906
+ rows.map((row) => delegate.create({ data: row }))
1907
+ );
1908
+ return;
1909
+ }
1910
+ for (const row of rows) {
1911
+ await delegate.create({ data: row });
1912
+ }
1913
+ }
1914
+ return {
1915
+ async insert(rows) {
1916
+ if (rows.length === 0) {
1917
+ return;
1918
+ }
1919
+ if (rows.length === 1) {
1920
+ await delegate.create({ data: rows[0] });
1921
+ return;
1922
+ }
1923
+ if (!useCreateMany || typeof delegate.createMany !== "function") {
1924
+ await fallbackInsert(rows);
1925
+ return;
1926
+ }
1927
+ try {
1928
+ await delegate.createMany({ data: rows });
1929
+ } catch (error) {
1930
+ if (!shouldFallbackFromCreateMany(error)) {
1931
+ throw error;
1932
+ }
1933
+ useCreateMany = false;
1934
+ await fallbackInsert(rows);
1935
+ }
1936
+ }
1937
+ };
1938
+ }
1939
+
1940
+ // src/database/helpers.ts
1941
+ function normalizeNullableNumber(value) {
1942
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
1943
+ }
1944
+ function normalizeNullableString(value) {
1945
+ return typeof value === "string" && value.length > 0 ? value : null;
1946
+ }
1947
+ function parseTimestamp(value) {
1948
+ if (typeof value === "string") {
1949
+ const timestamp = new Date(value);
1950
+ if (!Number.isNaN(timestamp.getTime())) {
1951
+ return timestamp;
1952
+ }
1953
+ }
1954
+ return /* @__PURE__ */ new Date();
1955
+ }
1956
+ function toDatabaseLogRow(record) {
1957
+ const normalizedRecord = normalizeLogValue(record);
1958
+ return {
1959
+ id: randomUUID(),
1960
+ timestamp: parseTimestamp(record.timestamp),
1961
+ level: record.level,
1962
+ message: record.message,
1963
+ caller: normalizeNullableString(record.caller),
1964
+ type: normalizeNullableString(record.type),
1965
+ groupId: normalizeNullableString(record.groupId),
1966
+ method: normalizeNullableString(record.method),
1967
+ path: normalizeNullableString(record.path),
1968
+ status: normalizeNullableNumber(record.status),
1969
+ duration: normalizeNullableNumber(record.duration),
1970
+ hasError: normalizedRecord.error != null,
1971
+ data: normalizedRecord.data ?? null,
1972
+ bindings: normalizedRecord.bindings ?? null,
1973
+ error: normalizedRecord.error ?? null,
1974
+ events: normalizedRecord.events ?? null,
1975
+ record: normalizedRecord,
1976
+ createdAt: /* @__PURE__ */ new Date()
1977
+ };
1978
+ }
1979
+ function isPrismaAdapter2(adapter) {
1980
+ return !!adapter && adapter.type === "prisma";
1981
+ }
1982
+ function isDrizzleAdapter2(adapter) {
1983
+ return !!adapter && adapter.type === "drizzle";
1984
+ }
1985
+ function createDatabaseRowWriter(config) {
1986
+ if (isPrismaAdapter2(config.adapter)) {
1987
+ return createPrismaRowWriter(config.adapter);
1988
+ }
1989
+ if (isDrizzleAdapter2(config.adapter)) {
1990
+ return createDrizzleRowWriter(config.adapter);
1991
+ }
1992
+ throw new Error("[Blyp] Unsupported database adapter configuration.");
1993
+ }
1994
+
1995
+ // src/core/sinks/database-primary-sink.ts
1996
+ function delay(ms) {
1997
+ return new Promise((resolve2) => {
1998
+ setTimeout(resolve2, ms);
1999
+ });
2000
+ }
2001
+ var DatabasePrimarySink = class {
2002
+ constructor(config) {
2003
+ this.config = config;
2004
+ __publicField(this, "isAsync", true);
2005
+ __publicField(this, "isReady", true);
2006
+ __publicField(this, "warnOnce", createWarnOnceLogger(/* @__PURE__ */ new Set()));
2007
+ __publicField(this, "queue", []);
2008
+ __publicField(this, "writer");
2009
+ __publicField(this, "timer", null);
2010
+ __publicField(this, "processing", false);
2011
+ __publicField(this, "closed", false);
2012
+ __publicField(this, "terminalError", null);
2013
+ __publicField(this, "activeDispatch", null);
2014
+ this.writer = createDatabaseRowWriter(config);
2015
+ }
2016
+ write(record) {
2017
+ if (this.closed) {
2018
+ return;
2019
+ }
2020
+ this.enqueue(toDatabaseLogRow(record));
2021
+ this.scheduleDispatch();
2022
+ }
2023
+ async flush() {
2024
+ if (this.timer) {
2025
+ clearTimeout(this.timer);
2026
+ this.timer = null;
2027
+ }
2028
+ const flushPromise = (async () => {
2029
+ await this.drain();
2030
+ if (this.terminalError) {
2031
+ throw this.terminalError;
2032
+ }
2033
+ })();
2034
+ let timeoutHandle = null;
2035
+ try {
2036
+ await Promise.race([
2037
+ flushPromise,
2038
+ new Promise((_, reject) => {
2039
+ timeoutHandle = setTimeout(() => {
2040
+ this.warnOnce(
2041
+ "database-flush-timeout",
2042
+ `[Blyp] Warning: Timed out flushing database logs after ${this.config.delivery.flushTimeoutMs}ms.`
2043
+ );
2044
+ reject(new Error("[Blyp] Timed out flushing database logs."));
2045
+ }, this.config.delivery.flushTimeoutMs);
2046
+ })
2047
+ ]);
2048
+ } finally {
2049
+ if (timeoutHandle) {
2050
+ clearTimeout(timeoutHandle);
2051
+ }
2052
+ }
2053
+ }
2054
+ async shutdown() {
2055
+ this.closed = true;
2056
+ await this.flush();
2057
+ }
2058
+ enqueue(row) {
2059
+ this.queue.push(row);
2060
+ const overflow = this.queue.length - this.config.delivery.maxQueueSize;
2061
+ if (overflow <= 0) {
2062
+ return;
2063
+ }
2064
+ this.warnOnce(
2065
+ "database-overflow",
2066
+ `[Blyp] Warning: Database log queue exceeded ${this.config.delivery.maxQueueSize} entries. Applying ${this.config.delivery.overflowStrategy} overflow handling.`
2067
+ );
2068
+ if (this.config.delivery.overflowStrategy === "drop-new") {
2069
+ this.queue.splice(this.config.delivery.maxQueueSize);
2070
+ return;
2071
+ }
2072
+ this.queue.splice(0, overflow);
2073
+ }
2074
+ scheduleDispatch() {
2075
+ if (this.processing) {
2076
+ return;
2077
+ }
2078
+ if (this.config.delivery.strategy === "immediate") {
2079
+ void this.drain();
2080
+ return;
2081
+ }
2082
+ if (this.queue.length >= this.config.delivery.batchSize) {
2083
+ void this.drain();
2084
+ return;
2085
+ }
2086
+ if (this.timer) {
2087
+ return;
2088
+ }
2089
+ this.timer = setTimeout(() => {
2090
+ this.timer = null;
2091
+ void this.drain();
2092
+ }, this.config.delivery.flushIntervalMs);
2093
+ }
2094
+ async drain() {
2095
+ if (this.processing) {
2096
+ if (this.activeDispatch) {
2097
+ await this.activeDispatch;
2098
+ }
2099
+ return;
2100
+ }
2101
+ this.processing = true;
2102
+ this.activeDispatch = this.processQueue();
2103
+ try {
2104
+ await this.activeDispatch;
2105
+ } finally {
2106
+ this.processing = false;
2107
+ this.activeDispatch = null;
2108
+ }
2109
+ }
2110
+ async processQueue() {
2111
+ while (this.queue.length > 0) {
2112
+ const batchSize = this.config.delivery.strategy === "batch" ? Math.max(1, this.config.delivery.batchSize) : 1;
2113
+ const batch = this.queue.splice(0, batchSize);
2114
+ try {
2115
+ await this.insertWithRetry(batch);
2116
+ } catch (error) {
2117
+ const failure = error instanceof Error ? error : new Error(String(error ?? "Unknown database logging failure"));
2118
+ this.terminalError = failure;
2119
+ this.warnOnce(
2120
+ "database-insert-failure",
2121
+ `[Blyp] Warning: Failed to persist logs to the ${this.config.dialect ?? "database"} database.`,
2122
+ failure
2123
+ );
2124
+ throw failure;
2125
+ }
2126
+ }
2127
+ }
2128
+ async insertWithRetry(batch) {
2129
+ const maxAttempts = Math.max(1, this.config.delivery.retry.maxRetries + 1);
2130
+ let attempt = 0;
2131
+ while (attempt < maxAttempts) {
2132
+ attempt += 1;
2133
+ try {
2134
+ await this.writer.insert(batch);
2135
+ return;
2136
+ } catch (error) {
2137
+ if (attempt >= maxAttempts) {
2138
+ throw error;
2139
+ }
2140
+ await delay(this.config.delivery.retry.backoffMs);
2141
+ }
2142
+ }
2143
+ }
2144
+ };
2145
+
2146
+ // src/core/primary-sink.ts
2147
+ var NoopPrimarySink = class {
2148
+ constructor() {
2149
+ __publicField(this, "isAsync", false);
2150
+ __publicField(this, "isReady", false);
2151
+ }
2152
+ write(_record) {
2153
+ }
2154
+ async flush() {
2155
+ }
2156
+ async shutdown() {
2157
+ }
2158
+ };
2159
+ var warnOnce3 = createWarnOnceLogger(/* @__PURE__ */ new Set());
2160
+ function createPrimarySink(config) {
2161
+ if (config.destination !== "database") {
2162
+ return createFilePrimarySink(config);
2163
+ }
2164
+ const databaseConfig = config.database;
2165
+ if (!databaseConfig?.ready) {
2166
+ warnOnce3(
2167
+ "database-sink-disabled",
2168
+ "[Blyp] Warning: Database destination is configured but not ready. Falling back to a no-op primary sink."
2169
+ );
2170
+ return new NoopPrimarySink();
2171
+ }
2172
+ return new DatabasePrimarySink(databaseConfig);
2173
+ }
2174
+ var PREVIOUSLY_CAPTURED_ERROR_KEY2 = "__betterstack_previously_captured_error";
2175
+ var warnedKeys3 = /* @__PURE__ */ new Set();
2176
+ var testHooks2 = {};
2177
+ var warnOnce4 = createErrorOnceLogger(warnedKeys3);
2178
+ function getSentryModule() {
2179
+ return testHooks2.module ?? Sentry;
2180
+ }
2181
+ function resolveConnectorConfig2(config) {
2182
+ const connector = isBlypConfig(config) ? config.connectors?.betterstack : config;
2183
+ const enabled = connector?.enabled ?? false;
2184
+ const sourceToken = connector?.sourceToken;
2185
+ const ingestingHost = connector?.ingestingHost;
2186
+ const errorTrackingEnabled = connector?.errorTracking?.enabled ?? enabled;
2187
+ const errorTrackingDsn = connector?.errorTracking?.dsn;
2188
+ const errorTrackingReady = enabled && errorTrackingEnabled && hasNonEmptyString(errorTrackingDsn);
2189
+ const ready = enabled && hasNonEmptyString(sourceToken) && isAbsoluteHttpUrl(ingestingHost);
2190
+ return {
2191
+ enabled,
2192
+ mode: connector?.mode ?? "auto",
2193
+ sourceToken,
2194
+ ingestingHost,
2195
+ serviceName: connector?.serviceName ?? "blyp-app",
2196
+ errorTracking: {
2197
+ enabled: errorTrackingEnabled,
2198
+ dsn: errorTrackingDsn,
2199
+ tracesSampleRate: connector?.errorTracking?.tracesSampleRate ?? 1,
2200
+ environment: connector?.errorTracking?.environment,
2201
+ release: connector?.errorTracking?.release,
2202
+ ready: errorTrackingReady,
2203
+ status: errorTrackingReady ? "enabled" : "missing"
2204
+ },
2205
+ ready,
2206
+ status: ready ? "enabled" : "missing"
2207
+ };
2208
+ }
2209
+ function resolveBetterStackLevel(level) {
2210
+ switch (level) {
2211
+ case "debug":
2212
+ return "debug";
2213
+ case "warning":
2214
+ case "warn":
2215
+ return "warn";
2216
+ case "error":
2217
+ return "error";
2218
+ case "critical":
2219
+ return "fatal";
2220
+ case "success":
2221
+ case "table":
2222
+ case "info":
2223
+ default:
2224
+ return "info";
2225
+ }
2226
+ }
2227
+ function parseCaller(caller) {
2228
+ if (typeof caller !== "string" || caller.trim().length === 0) {
2229
+ return {};
2230
+ }
2231
+ const match = caller.match(/^(.*):(\d+)$/);
2232
+ if (!match) {
2233
+ return {};
2234
+ }
2235
+ const file = match[1]?.trim();
2236
+ const line = Number.parseInt(match[2] ?? "", 10);
2237
+ return {
2238
+ ...file ? { file } : {},
2239
+ ...Number.isFinite(line) ? { line } : {}
2240
+ };
2241
+ }
2242
+ function buildContext(record, connector, source) {
2243
+ const recordType = getRecordType(record);
2244
+ const groupId = getField(record, "groupId");
2245
+ const method = getField(record, "method");
2246
+ const path3 = getField(record, "path");
2247
+ const status = getField(record, "status");
2248
+ const duration = getField(record, "duration");
2249
+ const pagePath = getClientPageField(record, "pathname");
2250
+ const pageUrl = getClientPageField(record, "url");
2251
+ const sessionId = getClientSessionField(record, "sessionId");
2252
+ const pageId = getClientSessionField(record, "pageId");
2253
+ const runtime2 = parseCaller(record.caller);
2254
+ return {
2255
+ service: connector.serviceName,
2256
+ context: {
2257
+ blyp: {
2258
+ level: record.level,
2259
+ source,
2260
+ ...recordType ? { type: recordType } : {},
2261
+ ...groupId ? { group_id: groupId } : {},
2262
+ ...record.caller ? { caller: record.caller } : {},
2263
+ ...duration !== void 0 ? { duration_ms: duration } : {},
2264
+ ...record.bindings ? { bindings: record.bindings } : {},
2265
+ payload: serializeLogRecord(record)
2266
+ },
2267
+ ...method || path3 || status !== void 0 ? {
2268
+ http: {
2269
+ ...method ? { method } : {},
2270
+ ...path3 ? { path: path3 } : {},
2271
+ ...status !== void 0 ? { status_code: status } : {}
2272
+ }
2273
+ } : {},
2274
+ ...pagePath || pageUrl || sessionId || pageId ? {
2275
+ client: {
2276
+ ...pagePath ? { page_path: pagePath } : {},
2277
+ ...pageUrl ? { page_url: pageUrl } : {},
2278
+ ...sessionId ? { session_id: sessionId } : {},
2279
+ ...pageId ? { page_id: pageId } : {}
2280
+ }
2281
+ } : {},
2282
+ ...Object.keys(runtime2).length > 0 ? { runtime: runtime2 } : {},
2283
+ ...record.data !== void 0 ? { data: record.data } : {},
2284
+ ...record.error !== void 0 ? { error: record.error } : {}
2285
+ }
2286
+ };
2287
+ }
2288
+ function toExceptionCandidate(value) {
2289
+ if (!isPlainObject(value)) {
2290
+ return void 0;
2291
+ }
2292
+ const message = typeof value.message === "string" ? value.message : void 0;
2293
+ const name = typeof value.name === "string" ? value.name : void 0;
2294
+ const stack = typeof value.stack === "string" ? value.stack : void 0;
2295
+ if (!message && !name && !stack) {
2296
+ return void 0;
2297
+ }
2298
+ const error = new Error(message ?? name ?? "Unknown error");
2299
+ error.name = name ?? "Error";
2300
+ if (stack) {
2301
+ error.stack = stack;
2302
+ }
2303
+ for (const [key, entry] of Object.entries(value)) {
2304
+ if (key === "message" || key === "name" || key === "stack") {
2305
+ continue;
2306
+ }
2307
+ error[key] = entry;
2308
+ }
2309
+ return error;
2310
+ }
2311
+ function normalizeScopeLevel(level) {
2312
+ switch (level) {
2313
+ case "debug":
2314
+ return "debug";
2315
+ case "warning":
2316
+ case "warn":
2317
+ return "warning";
2318
+ case "critical":
2319
+ return "fatal";
2320
+ case "error":
2321
+ return "error";
2322
+ case "success":
2323
+ case "table":
2324
+ case "info":
2325
+ default:
2326
+ return "info";
2327
+ }
2328
+ }
2329
+ function normalizeExceptionInput2(input) {
2330
+ if (input instanceof Error) {
2331
+ return input;
2332
+ }
2333
+ const direct = toExceptionCandidate(input);
2334
+ if (direct) {
2335
+ return direct;
2336
+ }
2337
+ if (typeof input === "string") {
2338
+ return new Error(input);
2339
+ }
2340
+ return new Error("Unknown Better Stack exception");
2341
+ }
2342
+ function isPreviouslyCapturedError(value) {
2343
+ return isPlainObject(value) && value[PREVIOUSLY_CAPTURED_ERROR_KEY2] === true;
2344
+ }
2345
+ function markCapturedError(value) {
2346
+ if (!isPlainObject(value) || isPreviouslyCapturedError(value)) {
2347
+ return;
2348
+ }
2349
+ try {
2350
+ Object.defineProperty(value, PREVIOUSLY_CAPTURED_ERROR_KEY2, {
2351
+ value: true,
2352
+ enumerable: false,
2353
+ configurable: true,
2354
+ writable: true
2355
+ });
2356
+ } catch {
2357
+ try {
2358
+ value[PREVIOUSLY_CAPTURED_ERROR_KEY2] = true;
2359
+ } catch {
2360
+ }
2361
+ }
2362
+ }
2363
+ function createDefaultClient(connector) {
2364
+ return new Logtail(connector.sourceToken ?? "", {
2365
+ endpoint: connector.ingestingHost,
2366
+ captureStackContext: false
2367
+ });
2368
+ }
2369
+ function getClientOptions(client) {
2370
+ return client?.getOptions?.() ?? {};
2371
+ }
2372
+ function registerShutdownHooks2(key, flush) {
2373
+ const handlers = ["beforeExit", "SIGINT", "SIGTERM"];
2374
+ for (const event of handlers) {
2375
+ process.once(event, () => {
2376
+ void flush().catch((error) => {
2377
+ warnOnce4(
2378
+ `${key}:shutdown`,
2379
+ "[Blyp] Failed to flush Better Stack logs during shutdown.",
2380
+ error
2381
+ );
2382
+ });
2383
+ });
2384
+ }
2385
+ }
2386
+ function createBetterStackSender(config) {
2387
+ const connector = resolveConnectorConfig2(config);
2388
+ const key = `${connector.serviceName}:${connector.ingestingHost ?? "missing"}:${connector.mode}`;
2389
+ const sentryModule = getSentryModule();
2390
+ const client = connector.ready ? testHooks2.createClient?.(connector) ?? createDefaultClient(connector) : void 0;
2391
+ let sentryClient = connector.errorTracking.enabled ? sentryModule?.getClient?.() : void 0;
2392
+ if (sentryClient) {
2393
+ const options = getClientOptions(sentryClient);
2394
+ if (hasNonEmptyString(connector.errorTracking.dsn) && connector.errorTracking.dsn !== options.dsn || hasNonEmptyString(connector.errorTracking.environment) && connector.errorTracking.environment !== options.environment || hasNonEmptyString(connector.errorTracking.release) && connector.errorTracking.release !== options.release) {
2395
+ warnOnce4(
2396
+ `betterstack-error-mismatch:${key}`,
2397
+ "[Blyp] Sentry is already initialized with different options. Reusing the existing Sentry client for Better Stack error tracking."
2398
+ );
2399
+ }
2400
+ }
2401
+ if (!sentryClient && connector.errorTracking.enabled && hasNonEmptyString(connector.errorTracking.dsn) && sentryModule) {
2402
+ try {
2403
+ sentryModule.init({
2404
+ dsn: connector.errorTracking.dsn,
2405
+ tracesSampleRate: connector.errorTracking.tracesSampleRate,
2406
+ environment: connector.errorTracking.environment,
2407
+ release: connector.errorTracking.release
2408
+ });
2409
+ sentryClient = sentryModule.getClient();
2410
+ } catch (error) {
2411
+ warnOnce4(
2412
+ `betterstack-error-init:${key}`,
2413
+ "[Blyp] Failed to initialize Better Stack error tracking.",
2414
+ error
2415
+ );
2416
+ }
2417
+ }
2418
+ const errorTrackingReady = connector.errorTracking.enabled && sentryClient !== void 0;
2419
+ if (client || errorTrackingReady) {
2420
+ registerShutdownHooks2(key, async () => {
2421
+ if (client) {
2422
+ await client.flush();
2423
+ }
2424
+ if (errorTrackingReady) {
2425
+ await sentryModule.flush(2e3);
2426
+ }
2427
+ });
2428
+ }
2429
+ const emitUnavailableWarning = () => {
2430
+ warnOnce4(
2431
+ `betterstack-unavailable:${key}`,
2432
+ "[Blyp] Better Stack connector is not configured or not ready. Skipping Better Stack delivery."
2433
+ );
2434
+ };
2435
+ const emitExceptionUnavailableWarning = () => {
2436
+ warnOnce4(
2437
+ `betterstack-exception-unavailable:${key}`,
2438
+ "[Blyp] Better Stack error tracking is not configured. Skipping Better Stack exception capture."
2439
+ );
2440
+ };
2441
+ return {
2442
+ enabled: connector.enabled,
2443
+ ready: connector.ready,
2444
+ mode: connector.mode,
2445
+ serviceName: connector.serviceName,
2446
+ ingestingHost: connector.ingestingHost,
2447
+ status: connector.status,
2448
+ errorTracking: {
2449
+ enabled: connector.errorTracking.enabled,
2450
+ ready: errorTrackingReady,
2451
+ status: errorTrackingReady ? "enabled" : "missing",
2452
+ dsn: connector.errorTracking.dsn,
2453
+ tracesSampleRate: connector.errorTracking.tracesSampleRate,
2454
+ environment: connector.errorTracking.environment,
2455
+ release: connector.errorTracking.release
2456
+ },
2457
+ shouldAutoForwardServerLogs() {
2458
+ return connector.ready && connector.mode === "auto";
2459
+ },
2460
+ shouldAutoCaptureExceptions() {
2461
+ return errorTrackingReady;
2462
+ },
2463
+ send(record, options = {}) {
2464
+ if (!connector.ready || !client) {
2465
+ if (options.warnIfUnavailable) {
2466
+ emitUnavailableWarning();
2467
+ }
2468
+ return;
2469
+ }
2470
+ const source = options.source ?? "server";
2471
+ void client.log(
2472
+ record.message,
2473
+ resolveBetterStackLevel(record.level),
2474
+ buildContext(record, connector, source)
2475
+ ).catch((error) => {
2476
+ warnOnce4(
2477
+ `betterstack-send:${key}`,
2478
+ "[Blyp] Failed to deliver log to Better Stack.",
2479
+ error
2480
+ );
2481
+ });
2482
+ },
2483
+ captureException(error, options = {}) {
2484
+ if (!errorTrackingReady || !sentryModule) {
2485
+ if (options.warnIfUnavailable) {
2486
+ emitExceptionUnavailableWarning();
2487
+ }
2488
+ return;
2489
+ }
2490
+ if (isPreviouslyCapturedError(error)) {
2491
+ return;
2492
+ }
2493
+ try {
2494
+ const exception = normalizeExceptionInput2(error);
2495
+ sentryModule.withScope((scope) => {
2496
+ scope.setLevel(
2497
+ normalizeScopeLevel(
2498
+ options.source === "client" ? "error" : "error"
2499
+ )
2500
+ );
2501
+ scope.setContext("blyp", {
2502
+ source: options.source ?? "server",
2503
+ ...options.context ? { context: options.context } : {}
2504
+ });
2505
+ sentryModule.captureException(exception);
2506
+ });
2507
+ markCapturedError(error);
2508
+ markCapturedError(exception);
2509
+ } catch (captureError) {
2510
+ warnOnce4(
2511
+ `betterstack-manual-capture:${key}`,
2512
+ "[Blyp] Failed to capture exception in Better Stack error tracking.",
2513
+ captureError
2514
+ );
2515
+ }
2516
+ },
2517
+ async flush() {
2518
+ if (!client) {
2519
+ if (!errorTrackingReady || !sentryModule) {
2520
+ return;
2521
+ }
2522
+ }
2523
+ try {
2524
+ if (client) {
2525
+ await client.flush();
2526
+ }
2527
+ if (errorTrackingReady && sentryModule) {
2528
+ await sentryModule.flush(2e3);
2529
+ }
2530
+ } catch (error) {
2531
+ warnOnce4(
2532
+ `betterstack-flush:${key}`,
2533
+ "[Blyp] Failed to flush Better Stack logs.",
2534
+ error
2535
+ );
2536
+ }
2537
+ }
2538
+ };
2539
+ }
2540
+ var warnedKeys4 = /* @__PURE__ */ new Set();
2541
+ var testHooks3 = {};
2542
+ var warnOnce5 = createErrorOnceLogger(warnedKeys4);
2543
+ function getSentryModule2() {
2544
+ return testHooks3.module ?? Sentry;
2545
+ }
2546
+ function resolveConnectorConfig3(config) {
2547
+ const connector = isBlypConfig(config) ? config.connectors?.sentry : config;
2548
+ const enabled = connector?.enabled ?? false;
2549
+ const dsn = connector?.dsn;
2550
+ const ready = enabled && hasNonEmptyString(dsn);
2551
+ return {
2552
+ enabled,
2553
+ mode: connector?.mode ?? "auto",
2554
+ dsn,
2555
+ environment: connector?.environment,
2556
+ release: connector?.release,
2557
+ ready,
2558
+ status: ready ? "enabled" : "missing"
2559
+ };
2560
+ }
2561
+ function normalizeAttributes(record, source) {
2562
+ const attributes = {
2563
+ "blyp.level": record.level,
2564
+ "blyp.source": source,
2565
+ "blyp.payload": serializeLogRecord(record)
2566
+ };
2567
+ const recordType = getRecordType(record);
2568
+ const caller = typeof record.caller === "string" ? record.caller : void 0;
2569
+ const groupId = getField(record, "groupId");
2570
+ const method = getField(record, "method");
2571
+ const path3 = getField(record, "path");
2572
+ const status = getField(record, "status");
2573
+ const duration = getField(record, "duration");
2574
+ const pagePath = getClientPageField(record, "pathname");
2575
+ const pageUrl = getClientPageField(record, "url");
2576
+ const sessionId = getClientSessionField(record, "sessionId");
2577
+ const pageId = getClientSessionField(record, "pageId");
2578
+ const ifTruthy = [
2579
+ ["blyp.type", recordType],
2580
+ ["blyp.caller", caller],
2581
+ ["blyp.group_id", groupId],
2582
+ ["http.method", method],
2583
+ ["url.path", path3],
2584
+ ["client.page_path", pagePath],
2585
+ ["client.page_url", pageUrl],
2586
+ ["client.session_id", sessionId],
2587
+ ["client.page_id", pageId]
2588
+ ];
2589
+ const ifDefined = [
2590
+ ["http.status_code", status],
2591
+ ["blyp.duration_ms", duration]
2592
+ ];
2593
+ for (const [k, v] of ifTruthy) if (v) attributes[k] = v;
2594
+ for (const [k, v] of ifDefined) if (v !== void 0) attributes[k] = v;
2595
+ return attributes;
2596
+ }
2597
+ function resolveLogMethod(module, level) {
2598
+ switch (level) {
2599
+ case "debug":
2600
+ return module.logger.debug;
2601
+ case "warning":
2602
+ case "warn":
2603
+ return module.logger.warn;
2604
+ case "error":
2605
+ return module.logger.error;
2606
+ case "critical":
2607
+ return module.logger.fatal;
2608
+ case "success":
2609
+ case "table":
2610
+ case "info":
2611
+ default:
2612
+ return module.logger.info;
2613
+ }
2614
+ }
2615
+ function normalizeScopeLevel2(level) {
2616
+ switch (level) {
2617
+ case "debug":
2618
+ return "debug";
2619
+ case "warning":
2620
+ case "warn":
2621
+ return "warning";
2622
+ case "critical":
2623
+ return "fatal";
2624
+ case "error":
2625
+ return "error";
2626
+ case "success":
2627
+ case "table":
2628
+ case "info":
2629
+ default:
2630
+ return "info";
2631
+ }
2632
+ }
2633
+ function toExceptionCandidate2(value) {
2634
+ if (!isPlainObject(value)) {
2635
+ return void 0;
2636
+ }
2637
+ const message = typeof value.message === "string" ? value.message : void 0;
2638
+ const name = typeof value.name === "string" ? value.name : void 0;
2639
+ const stack = typeof value.stack === "string" ? value.stack : void 0;
2640
+ if (!message && !name && !stack) {
2641
+ return void 0;
2642
+ }
2643
+ const error = new Error(message ?? name ?? "Unknown error");
2644
+ error.name = name ?? "Error";
2645
+ if (stack) {
2646
+ error.stack = stack;
2647
+ }
2648
+ for (const [key, entry] of Object.entries(value)) {
2649
+ if (key === "message" || key === "name" || key === "stack") {
2650
+ continue;
2651
+ }
2652
+ error[key] = entry;
2653
+ }
2654
+ return error;
2655
+ }
2656
+ function extractExceptionCandidate(record) {
2657
+ if (record.level !== "error" && record.level !== "critical") {
2658
+ return void 0;
2659
+ }
2660
+ const direct = toExceptionCandidate2(record.error);
2661
+ if (direct) {
2662
+ return direct;
2663
+ }
2664
+ if (isPlainObject(record.data)) {
2665
+ const directData = toExceptionCandidate2(record.data);
2666
+ if (directData) {
2667
+ return directData;
2668
+ }
2669
+ const nested = toExceptionCandidate2(record.data.error);
2670
+ if (nested) {
2671
+ return nested;
2672
+ }
2673
+ }
2674
+ const payload = getPrimaryPayload(record);
2675
+ if (isPlainObject(payload)) {
2676
+ const nested = toExceptionCandidate2(payload.error);
2677
+ if (nested) {
2678
+ return nested;
2679
+ }
2680
+ }
2681
+ return void 0;
2682
+ }
2683
+ function getClientOptions2(client) {
2684
+ return client?.getOptions?.() ?? {};
2685
+ }
2686
+ function hasConfigMismatch(connector, client) {
2687
+ const options = getClientOptions2(client);
2688
+ return hasNonEmptyString(connector.dsn) && connector.dsn !== options.dsn || hasNonEmptyString(connector.environment) && connector.environment !== options.environment || hasNonEmptyString(connector.release) && connector.release !== options.release;
2689
+ }
2690
+ function createSentrySender(config) {
2691
+ const connector = resolveConnectorConfig3(config);
2692
+ const key = `${connector.mode}:${connector.dsn ?? "missing"}`;
2693
+ const module = getSentryModule2();
2694
+ let client = connector.enabled ? module.getClient() : void 0;
2695
+ if (!client && connector.enabled && hasNonEmptyString(connector.dsn)) {
2696
+ try {
2697
+ module.init({
2698
+ dsn: connector.dsn,
2699
+ environment: connector.environment,
2700
+ release: connector.release,
2701
+ enableLogs: true
2702
+ });
2703
+ client = module.getClient();
2704
+ } catch (error) {
2705
+ warnOnce5(
2706
+ `sentry-init:${key}`,
2707
+ "[Blyp] Failed to initialize Sentry. Skipping Sentry delivery.",
2708
+ error
2709
+ );
2710
+ }
2711
+ }
2712
+ if (client && hasConfigMismatch(connector, client)) {
2713
+ warnOnce5(
2714
+ `sentry-mismatch:${key}`,
2715
+ "[Blyp] Sentry is already initialized with different options. Reusing the existing Sentry client."
2716
+ );
2717
+ }
2718
+ const ready = connector.enabled && client !== void 0;
2719
+ const emitUnavailableWarning = () => {
2720
+ warnOnce5(
2721
+ `sentry-unavailable:${key}`,
2722
+ "[Blyp] Sentry connector is not configured. Skipping Sentry delivery."
2723
+ );
2724
+ };
2725
+ return {
2726
+ enabled: connector.enabled,
2727
+ ready,
2728
+ mode: connector.mode,
2729
+ status: ready ? "enabled" : "missing",
2730
+ shouldAutoForwardServerLogs() {
2731
+ return ready && connector.mode === "auto";
2732
+ },
2733
+ send(record, options = {}) {
2734
+ if (!ready) {
2735
+ if (options.warnIfUnavailable) {
2736
+ emitUnavailableWarning();
2737
+ }
2738
+ return;
2739
+ }
2740
+ const source = options.source ?? "server";
2741
+ const attributes = normalizeAttributes(record, source);
2742
+ const logMethod = resolveLogMethod(module, record.level);
2743
+ try {
2744
+ logMethod(record.message, attributes);
2745
+ } catch (error) {
2746
+ warnOnce5(
2747
+ `sentry-log:${key}`,
2748
+ "[Blyp] Failed to deliver log to Sentry.",
2749
+ error
2750
+ );
2751
+ }
2752
+ const exception = extractExceptionCandidate(record);
2753
+ if (!exception) {
2754
+ return;
2755
+ }
2756
+ try {
2757
+ module.withScope((scope) => {
2758
+ scope.setLevel(normalizeScopeLevel2(record.level));
2759
+ scope.setContext("blyp", attributes);
2760
+ scope.setExtra("blyp.payload", serializeLogRecord(record));
2761
+ module.captureException(exception);
2762
+ });
2763
+ } catch (error) {
2764
+ warnOnce5(
2765
+ `sentry-exception:${key}`,
2766
+ "[Blyp] Failed to capture exception in Sentry.",
2767
+ error
2768
+ );
2769
+ }
2770
+ },
2771
+ async flush() {
2772
+ try {
2773
+ await module.flush(2e3);
2774
+ } catch (error) {
2775
+ warnOnce5(
2776
+ `sentry-flush:${key}`,
2777
+ "[Blyp] Failed to flush Sentry logs.",
2778
+ error
2779
+ );
2780
+ }
2781
+ }
2782
+ };
2783
+ }
2784
+ var warnedKeys5 = /* @__PURE__ */ new Set();
2785
+ var testHooks4 = {};
2786
+ var warnOnce6 = createErrorOnceLogger(warnedKeys5);
2787
+ function normalizeOTLPRecord(record, connector, source = "server") {
2788
+ const severity = resolveSeverity2(record.level);
2789
+ const body = typeof record.message === "string" ? record.message : String(record.message);
2790
+ const recordType = getRecordType(record);
2791
+ const caller = typeof record.caller === "string" ? record.caller : void 0;
2792
+ const groupId = getField(record, "groupId");
2793
+ const method = getField(record, "method");
2794
+ const path3 = getField(record, "path");
2795
+ const status = getField(record, "status");
2796
+ const duration = getField(record, "duration");
2797
+ const pagePath = getClientPageField(record, "pathname");
2798
+ const pageUrl = getClientPageField(record, "url");
2799
+ const sessionId = getClientSessionField(record, "sessionId");
2800
+ const pageId = getClientSessionField(record, "pageId");
2801
+ const attributes = {
2802
+ "blyp.level": record.level,
2803
+ "blyp.source": source,
2804
+ "blyp.payload": serializeLogRecord(record)
2805
+ };
2806
+ const ifTruthy = [
2807
+ ["blyp.type", recordType],
2808
+ ["blyp.caller", caller],
2809
+ ["blyp.group_id", groupId],
2810
+ ["http.method", method],
2811
+ ["url.path", path3],
2812
+ ["client.page_path", pagePath],
2813
+ ["client.page_url", pageUrl],
2814
+ ["client.session_id", sessionId],
2815
+ ["client.page_id", pageId]
2816
+ ];
2817
+ const ifDefined = [
2818
+ ["http.status_code", status],
2819
+ ["blyp.duration_ms", duration]
2820
+ ];
2821
+ for (const [k, v] of ifTruthy) if (v) attributes[k] = v;
2822
+ for (const [k, v] of ifDefined) if (v !== void 0) attributes[k] = v;
2823
+ return {
2824
+ body,
2825
+ severityText: severity.text,
2826
+ severityNumber: severity.number,
2827
+ attributes,
2828
+ resourceAttributes: {
2829
+ "service.name": connector.serviceName
2830
+ }
2831
+ };
2832
+ }
2833
+ function resolveSeverity2(level) {
2834
+ switch (level) {
2835
+ case "debug":
2836
+ return { text: "debug", number: SeverityNumber.DEBUG };
2837
+ case "warning":
2838
+ case "warn":
2839
+ return { text: "warn", number: SeverityNumber.WARN };
2840
+ case "error":
2841
+ return { text: "error", number: SeverityNumber.ERROR };
2842
+ case "critical":
2843
+ return { text: "fatal", number: SeverityNumber.FATAL };
2844
+ case "success":
2845
+ case "table":
2846
+ case "info":
2847
+ default:
2848
+ return { text: "info", number: SeverityNumber.INFO };
2849
+ }
2850
+ }
2851
+ function registerShutdownHooks3(key, shutdown) {
2852
+ const handlers = ["beforeExit", "SIGINT", "SIGTERM"];
2853
+ for (const event of handlers) {
2854
+ process.once(event, async () => {
2855
+ try {
2856
+ await shutdown();
2857
+ } catch (error) {
2858
+ warnOnce6(
2859
+ `${key}:shutdown`,
2860
+ "[Blyp] Failed to flush OTLP logs during shutdown.",
2861
+ error
2862
+ );
2863
+ }
2864
+ if (event !== "beforeExit") {
2865
+ process.exit(0);
2866
+ }
2867
+ });
2868
+ }
2869
+ }
2870
+ function resolveTransportHeaders(connector) {
2871
+ const headers = {
2872
+ ...connector.headers ?? {}
2873
+ };
2874
+ if (headers.Authorization === void 0 && connector.auth) {
2875
+ headers.Authorization = connector.auth;
2876
+ }
2877
+ return headers;
2878
+ }
2879
+ function createDefaultTransport2(connector) {
2880
+ const exporter = new OTLPLogExporter({
2881
+ url: connector.endpoint,
2882
+ headers: resolveTransportHeaders(connector)
2883
+ });
2884
+ const provider = new LoggerProvider({
2885
+ resource: resourceFromAttributes({
2886
+ "service.name": connector.serviceName
2887
+ }),
2888
+ processors: [new BatchLogRecordProcessor(exporter)]
2889
+ });
2890
+ const logger3 = provider.getLogger(`blyp-otlp:${connector.name}`);
2891
+ return {
2892
+ emit(payload) {
2893
+ logger3.emit({
2894
+ body: payload.body,
2895
+ severityText: payload.severityText,
2896
+ severityNumber: payload.severityNumber,
2897
+ attributes: payload.attributes
2898
+ });
2899
+ },
2900
+ flush() {
2901
+ return provider.forceFlush();
2902
+ },
2903
+ shutdown() {
2904
+ return provider.shutdown();
2905
+ }
2906
+ };
2907
+ }
2908
+ function resolveConnectors(config) {
2909
+ const connectors = isBlypConfig(config) ? config.connectors?.otlp ?? [] : config;
2910
+ return connectors.map((connector) => {
2911
+ const headers = {
2912
+ ...connector.headers ?? {}
2913
+ };
2914
+ const enabled = connector.enabled ?? false;
2915
+ const endpoint = connector.endpoint;
2916
+ const explicitReady = "ready" in connector && typeof connector.ready === "boolean" ? connector.ready : void 0;
2917
+ const ready = (explicitReady ?? (enabled && isAbsoluteHttpUrl(endpoint))) && isAbsoluteHttpUrl(endpoint);
2918
+ return {
2919
+ name: connector.name,
2920
+ enabled,
2921
+ mode: connector.mode ?? "auto",
2922
+ endpoint,
2923
+ headers,
2924
+ auth: connector.auth,
2925
+ serviceName: connector.serviceName ?? "blyp-app",
2926
+ ready,
2927
+ status: ready ? "enabled" : "missing"
2928
+ };
2929
+ });
2930
+ }
2931
+ function createUnavailableSender(name, connector) {
2932
+ const senderName = name || connector?.name || "otlp";
2933
+ const key = `${senderName}:${connector?.serviceName ?? "blyp-app"}:${connector?.endpoint ?? "missing"}`;
2934
+ const emitUnavailableWarning = () => {
2935
+ warnOnce6(
2936
+ `otlp-unavailable:${key}`,
2937
+ `[Blyp] OTLP target "${senderName}" is not configured or not ready. Skipping OTLP delivery.`
2938
+ );
2939
+ };
2940
+ return {
2941
+ name: senderName,
2942
+ enabled: connector?.enabled ?? false,
2943
+ ready: false,
2944
+ mode: connector?.mode ?? "auto",
2945
+ serviceName: connector?.serviceName ?? "blyp-app",
2946
+ endpoint: connector?.endpoint,
2947
+ status: "missing",
2948
+ send(_record, options = {}) {
2949
+ if (options.warnIfUnavailable) {
2950
+ emitUnavailableWarning();
2951
+ }
2952
+ },
2953
+ async flush() {
2954
+ }
2955
+ };
2956
+ }
2957
+ function createSender(connector) {
2958
+ if (!connector.ready || !connector.endpoint) {
2959
+ return createUnavailableSender(connector.name, connector);
2960
+ }
2961
+ const key = `${connector.name}:${connector.serviceName}:${connector.endpoint}:${connector.mode}`;
2962
+ const transportConnector = {
2963
+ ...connector,
2964
+ headers: resolveTransportHeaders(connector)
2965
+ };
2966
+ const transport = testHooks4.createTransport?.(transportConnector) ?? createDefaultTransport2(transportConnector);
2967
+ return {
2968
+ name: connector.name,
2969
+ enabled: connector.enabled,
2970
+ ready: connector.ready,
2971
+ mode: connector.mode,
2972
+ serviceName: connector.serviceName,
2973
+ endpoint: connector.endpoint,
2974
+ status: connector.status,
2975
+ send(record, options = {}) {
2976
+ const source = options.source ?? "server";
2977
+ const normalized = normalizeOTLPRecord(record, connector, source);
2978
+ try {
2979
+ const result = transport.emit(normalized);
2980
+ if (result && typeof result.catch === "function") {
2981
+ void result.catch((error) => {
2982
+ warnOnce6(
2983
+ `otlp-emit:${key}`,
2984
+ `[Blyp] Failed to deliver log to OTLP target "${connector.name}".`,
2985
+ error
2986
+ );
2987
+ });
2988
+ }
2989
+ } catch (error) {
2990
+ warnOnce6(
2991
+ `otlp-emit:${key}`,
2992
+ `[Blyp] Failed to deliver log to OTLP target "${connector.name}".`,
2993
+ error
2994
+ );
2995
+ }
2996
+ },
2997
+ async flush() {
2998
+ try {
2999
+ if (transport.flush) {
3000
+ await transport.flush();
3001
+ }
3002
+ } catch (error) {
3003
+ warnOnce6(
3004
+ `otlp-flush:${key}`,
3005
+ `[Blyp] Failed to flush OTLP logs for target "${connector.name}".`,
3006
+ error
3007
+ );
3008
+ }
3009
+ }
3010
+ };
3011
+ }
3012
+ function createOTLPRegistry(config) {
3013
+ const senders = /* @__PURE__ */ new Map();
3014
+ for (const connector of resolveConnectors(config)) {
3015
+ senders.set(connector.name, createSender(connector));
3016
+ }
3017
+ const registry = {
3018
+ get(name) {
3019
+ return senders.get(name) ?? createUnavailableSender(name);
3020
+ },
3021
+ getAutoForwardTargets() {
3022
+ return Array.from(senders.values()).filter((sender) => sender.ready && sender.mode === "auto");
3023
+ },
3024
+ send(name, record, options = {}) {
3025
+ const sender = senders.get(name) ?? createUnavailableSender(name);
3026
+ sender.send(record, options);
3027
+ },
3028
+ async flush() {
3029
+ await Promise.all(Array.from(senders.values()).map((sender) => sender.flush()));
3030
+ }
3031
+ };
3032
+ registerShutdownHooks3("otlp-registry", () => registry.flush());
3033
+ return registry;
3034
+ }
3035
+ var _RuntimeDetector = class _RuntimeDetector {
3036
+ constructor() {
3037
+ __publicField(this, "_type", null);
3038
+ }
3039
+ static getInstance() {
3040
+ if (!_RuntimeDetector.instance) {
3041
+ _RuntimeDetector.instance = new _RuntimeDetector();
3042
+ }
3043
+ return _RuntimeDetector.instance;
3044
+ }
3045
+ get type() {
3046
+ if (this._type === null) {
3047
+ this._type = this.detectRuntime();
3048
+ }
3049
+ return this._type;
3050
+ }
3051
+ get isBun() {
3052
+ return this.type === "bun";
3053
+ }
3054
+ get isNode() {
3055
+ return this.type === "node";
3056
+ }
3057
+ detectRuntime() {
3058
+ if (typeof Bun !== "undefined" && typeof Bun.file === "function") {
3059
+ return "bun";
3060
+ }
3061
+ return "node";
3062
+ }
3063
+ };
3064
+ __publicField(_RuntimeDetector, "instance");
3065
+ var RuntimeDetector = _RuntimeDetector;
3066
+ var BunAdapter = class {
3067
+ constructor() {
3068
+ __publicField(this, "type", "bun");
3069
+ __publicField(this, "isBun", true);
3070
+ __publicField(this, "isNode", false);
3071
+ __publicField(this, "file", {
3072
+ existsSync: (filePath) => {
3073
+ try {
3074
+ const file = Bun.file(filePath);
3075
+ return file.size > 0 || file.name !== "";
3076
+ } catch {
3077
+ return false;
3078
+ }
3079
+ },
3080
+ mkdirSync: (filePath, options) => {
3081
+ try {
3082
+ fs.mkdirSync(filePath, options);
3083
+ } catch {
3084
+ }
3085
+ },
3086
+ writeFileSync: (filePath, data) => {
3087
+ Bun.write(filePath, data);
3088
+ }
3089
+ });
3090
+ __publicField(this, "path", {
3091
+ join: (...paths) => {
3092
+ return path.join(...paths);
3093
+ }
3094
+ });
3095
+ __publicField(this, "env", {
3096
+ get: (key) => Bun.env[key]
3097
+ });
3098
+ __publicField(this, "cwd", () => {
3099
+ return process.cwd();
3100
+ });
3101
+ }
3102
+ };
3103
+ var NodeAdapter = class {
3104
+ constructor() {
3105
+ __publicField(this, "type", "node");
3106
+ __publicField(this, "isBun", false);
3107
+ __publicField(this, "isNode", true);
3108
+ __publicField(this, "file", {
3109
+ existsSync: (filePath) => fs.existsSync(filePath),
3110
+ mkdirSync: (filePath, options) => {
3111
+ fs.mkdirSync(filePath, options);
3112
+ },
3113
+ writeFileSync: (filePath, data) => {
3114
+ fs.writeFileSync(filePath, data);
3115
+ }
3116
+ });
3117
+ __publicField(this, "path", {
3118
+ join: (...paths) => path.join(...paths)
3119
+ });
3120
+ __publicField(this, "env", {
3121
+ get: (key) => process.env[key]
3122
+ });
3123
+ __publicField(this, "cwd", () => process.cwd());
3124
+ }
3125
+ };
3126
+ function createRuntimeAdapter() {
3127
+ const detector = RuntimeDetector.getInstance();
3128
+ if (detector.isBun) {
3129
+ return new BunAdapter();
3130
+ }
3131
+ return new NodeAdapter();
3132
+ }
3133
+ var runtime = createRuntimeAdapter();
3134
+
3135
+ // src/core/structured-log.ts
3136
+ function serializeMessage2(message) {
3137
+ if (typeof message === "string") {
3138
+ return message;
3139
+ }
3140
+ if (message !== null && typeof message === "object") {
3141
+ try {
3142
+ return JSON.stringify(
3143
+ message,
3144
+ (_key, value) => {
3145
+ if (typeof value === "function") {
3146
+ return `[Function: ${value.name || "anonymous"}]`;
3147
+ }
3148
+ if (value === void 0) {
3149
+ return "[undefined]";
3150
+ }
3151
+ if (typeof value === "symbol") {
3152
+ return value.toString();
3153
+ }
3154
+ return value;
3155
+ },
3156
+ 2
3157
+ );
3158
+ } catch {
3159
+ return "[Object]";
3160
+ }
3161
+ }
3162
+ return String(message);
3163
+ }
3164
+ function normalizeEventData(message, args) {
3165
+ if (typeof message === "string") {
3166
+ if (args.length === 0) {
3167
+ return void 0;
3168
+ }
3169
+ return args.length === 1 ? args[0] : args;
3170
+ }
3171
+ const values = [message, ...args];
3172
+ return values.length === 1 ? values[0] : values;
3173
+ }
3174
+ function normalizeDetails(value) {
3175
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
3176
+ return void 0;
3177
+ }
3178
+ return value;
3179
+ }
3180
+ function normalizeError2(error, fallbackStatus) {
3181
+ if (error === void 0 || error === null) {
3182
+ return fallbackStatus === void 0 || fallbackStatus < 400 ? void 0 : {
3183
+ message: `HTTP ${fallbackStatus}`,
3184
+ code: fallbackStatus,
3185
+ type: "HttpError"
3186
+ };
3187
+ }
3188
+ if (error instanceof Error) {
3189
+ const errorLike = error;
3190
+ return {
3191
+ message: error.message,
3192
+ code: errorLike.code,
3193
+ type: errorLike.type ?? error.name ?? error.constructor?.name,
3194
+ stack: error.stack,
3195
+ why: errorLike.why,
3196
+ fix: errorLike.fix,
3197
+ link: errorLike.link,
3198
+ details: normalizeDetails(errorLike.details),
3199
+ cause: errorLike.cause
3200
+ };
3201
+ }
3202
+ if (typeof error === "object") {
3203
+ const record = error;
3204
+ const statusCode = typeof record.statusCode === "number" ? record.statusCode : typeof record.status === "number" ? record.status : fallbackStatus;
3205
+ return {
3206
+ message: typeof record.message === "string" ? record.message : `HTTP ${statusCode ?? 500}`,
3207
+ code: typeof record.code === "string" || typeof record.code === "number" ? record.code : statusCode,
3208
+ type: typeof record.type === "string" ? record.type : typeof record.name === "string" ? record.name : "Error",
3209
+ stack: typeof record.stack === "string" ? record.stack : void 0,
3210
+ why: typeof record.why === "string" ? record.why : void 0,
3211
+ fix: typeof record.fix === "string" ? record.fix : void 0,
3212
+ link: typeof record.link === "string" ? record.link : void 0,
3213
+ details: normalizeDetails(record.details),
3214
+ cause: record.cause
3215
+ };
3216
+ }
3217
+ return {
3218
+ message: String(error),
3219
+ code: fallbackStatus,
3220
+ type: typeof error
3221
+ };
3222
+ }
3223
+ function resolveEmitStatus(options) {
3224
+ if (options.response && typeof options.response.status === "number") {
3225
+ return options.response.status;
3226
+ }
3227
+ if (typeof options.status === "number") {
3228
+ return options.status;
3229
+ }
3230
+ if (options.error && typeof options.error === "object" && options.error !== null && typeof options.error.statusCode === "number") {
3231
+ return options.error.statusCode;
3232
+ }
3233
+ if (options.error && typeof options.error === "object" && options.error !== null && typeof options.error.status === "number") {
3234
+ return options.error.status;
3235
+ }
3236
+ return options.error ? 500 : void 0;
3237
+ }
3238
+ function createStructuredLog(groupId, options) {
3239
+ const startedAt = performance.now();
3240
+ const fields = { ...options.initialFields ?? {} };
3241
+ const events = [];
3242
+ let emittedPayload;
3243
+ options.onCreate?.();
3244
+ const appendEvent = (level, message, args) => {
3245
+ events.push({
3246
+ level,
3247
+ message: serializeMessage2(message),
3248
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3249
+ ...normalizeEventData(message, args) === void 0 ? {} : { data: normalizeEventData(message, args) }
3250
+ });
3251
+ return structuredLog;
3252
+ };
3253
+ const structuredLog = {
3254
+ set(extraFields) {
3255
+ Object.assign(fields, extraFields);
3256
+ return structuredLog;
3257
+ },
3258
+ debug(message, ...args) {
3259
+ return appendEvent("debug", message, args);
3260
+ },
3261
+ info(message, ...args) {
3262
+ return appendEvent("info", message, args);
3263
+ },
3264
+ warn(message, ...args) {
3265
+ return appendEvent("warn", message, args);
3266
+ },
3267
+ warning(message, ...args) {
3268
+ return appendEvent("warning", message, args);
3269
+ },
3270
+ error(message, ...args) {
3271
+ return appendEvent("error", message, args);
3272
+ },
3273
+ success(message, ...args) {
3274
+ return appendEvent("success", message, args);
3275
+ },
3276
+ critical(message, ...args) {
3277
+ return appendEvent("critical", message, args);
3278
+ },
3279
+ table(message, data) {
3280
+ return appendEvent("table", message, data === void 0 ? [] : [data]);
3281
+ },
3282
+ emit(emitOptions = {}) {
3283
+ if (emittedPayload) {
3284
+ return emittedPayload;
3285
+ }
3286
+ const defaultFields = options.resolveDefaultFields?.() ?? {};
3287
+ const status = resolveEmitStatus(emitOptions);
3288
+ const error = normalizeError2(emitOptions.error, status);
3289
+ const level = emitOptions.level ?? (error ? "error" : "info");
3290
+ const payload = {
3291
+ ...defaultFields,
3292
+ ...fields,
3293
+ groupId,
3294
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3295
+ level,
3296
+ duration: Math.round(performance.now() - startedAt),
3297
+ ...typeof status === "number" ? { status } : {},
3298
+ ...events.length > 0 ? { events: [...events] } : {},
3299
+ ...error ? { error } : {}
3300
+ };
3301
+ options.write(payload, emitOptions.message ?? "structured_log");
3302
+ emittedPayload = payload;
3303
+ options.onEmit?.(payload);
3304
+ return payload;
3305
+ }
3306
+ };
3307
+ return structuredLog;
3308
+ }
3309
+
3310
+ // src/core/logger.ts
3311
+ var LOGGER_FACTORY = /* @__PURE__ */ Symbol("blyp.logger.factory");
3312
+ var CUSTOM_LEVELS = {
3313
+ success: 25,
3314
+ info: 30,
3315
+ debug: 35,
3316
+ table: 37,
3317
+ warning: 40,
3318
+ error: 50,
3319
+ critical: 60
3320
+ };
3321
+ var CONSOLE_LEVELS = {
3322
+ success: "success",
3323
+ critical: "critical",
3324
+ warning: "warning",
3325
+ info: "info",
3326
+ debug: "debug",
3327
+ error: "error",
3328
+ warn: "warn",
3329
+ table: "debug"
3330
+ };
3331
+ var MAGENTA = "\x1B[35m";
3332
+ var RESET = "\x1B[0m";
3333
+ function summarizeClientConsoleData(data) {
3334
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
3335
+ return null;
3336
+ }
3337
+ const record = data;
3338
+ const summary = {};
3339
+ if (record.data !== void 0) {
3340
+ summary.data = record.data;
3341
+ }
3342
+ const pathname = typeof record.page?.pathname === "string" ? record.page.pathname : void 0;
3343
+ const url = typeof record.page?.url === "string" ? record.page.url : void 0;
3344
+ if (pathname || url) {
3345
+ summary.page = pathname ?? url;
3346
+ }
3347
+ if (record.metadata !== void 0) {
3348
+ summary.metadata = record.metadata;
3349
+ }
3350
+ return Object.keys(summary).length > 0 ? summary : null;
3351
+ }
3352
+ function getConsoleDataPayload(data) {
3353
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
3354
+ return { hidden: false, value: data };
3355
+ }
3356
+ const record = data;
3357
+ if (record.type === "http_request" || record.type === "http_error") {
3358
+ return { hidden: true };
3359
+ }
3360
+ if (record.type === "client_log") {
3361
+ const summary = summarizeClientConsoleData(data);
3362
+ if (!summary) {
3363
+ return { hidden: true };
3364
+ }
3365
+ return {
3366
+ hidden: false,
3367
+ value: summary
3368
+ };
3369
+ }
3370
+ return { hidden: false, value: data };
3371
+ }
3372
+ function createPinoLogger(config) {
3373
+ if (config.pretty) {
3374
+ const pinoPretty = __require("pino-pretty");
3375
+ const pretty = pinoPretty.default({
3376
+ colorize: true,
3377
+ translateTime: "SYS:HH:MM:ss",
3378
+ ignore: "pid,hostname,caller",
3379
+ customColors: {
3380
+ success: "green",
3381
+ critical: "red bold",
3382
+ info: "blue",
3383
+ warning: "yellow",
3384
+ error: "red",
3385
+ debug: "cyan",
3386
+ table: "cyan"
3387
+ },
3388
+ messageFormat: (log, messageKey) => {
3389
+ const message = String(log[messageKey] ?? "");
3390
+ const caller = typeof log.caller === "string" ? log.caller.trim() : "";
3391
+ if (!caller) {
3392
+ return message;
3393
+ }
3394
+ return `${message} ${MAGENTA}${caller}${RESET}`;
3395
+ }
3396
+ });
3397
+ return pino(
3398
+ {
3399
+ level: config.level,
3400
+ customLevels: CUSTOM_LEVELS
3401
+ },
3402
+ pretty
3403
+ );
3404
+ }
3405
+ return pino({
3406
+ level: config.level,
3407
+ customLevels: CUSTOM_LEVELS
3408
+ });
3409
+ }
3410
+ function getLoggerFactory(logger3) {
3411
+ const factory = logger3[LOGGER_FACTORY];
3412
+ if (!factory) {
3413
+ throw new Error("Unsupported Blyp logger instance");
3414
+ }
3415
+ return factory;
3416
+ }
3417
+ function getPostHogSender(logger3) {
3418
+ return getLoggerFactory(logger3).posthog;
3419
+ }
3420
+ function getBetterStackSender(logger3) {
3421
+ return getLoggerFactory(logger3).betterstack;
3422
+ }
3423
+ function tryGetPostHogSender(logger3) {
3424
+ try {
3425
+ return getPostHogSender(logger3);
3426
+ } catch {
3427
+ return null;
3428
+ }
3429
+ }
3430
+ function tryGetBetterStackSender(logger3) {
3431
+ try {
3432
+ return getBetterStackSender(logger3);
3433
+ } catch {
3434
+ return null;
3435
+ }
3436
+ }
3437
+ function getSentrySender(logger3) {
3438
+ return getLoggerFactory(logger3).sentry;
3439
+ }
3440
+ function getOtlpRegistry(logger3) {
3441
+ return getLoggerFactory(logger3).otlp;
3442
+ }
3443
+ function attachLoggerInternals(target, source) {
3444
+ const factory = getLoggerFactory(source);
3445
+ Object.defineProperty(target, LOGGER_FACTORY, {
3446
+ value: factory,
3447
+ enumerable: false,
3448
+ configurable: false,
3449
+ writable: false
3450
+ });
3451
+ return target;
3452
+ }
3453
+ function createLoggerWithSource(logger3, source) {
3454
+ const factory = getLoggerFactory(logger3);
3455
+ return factory.create(source, factory.bindings);
3456
+ }
3457
+ function createStructuredLogForLogger(logger3, groupId, options = {}) {
3458
+ const factory = getLoggerFactory(logger3);
3459
+ return createStructuredLog(groupId, {
3460
+ initialFields: options.initialFields,
3461
+ resolveDefaultFields: () => ({
3462
+ ...factory.bindings,
3463
+ ...options.resolveDefaultFields?.() ?? {}
3464
+ }),
3465
+ write: (payload, message) => {
3466
+ factory.writeStructured(payload, message, "structured-flush");
3467
+ },
3468
+ onCreate: options.onCreate,
3469
+ onEmit: options.onEmit
3470
+ });
3471
+ }
3472
+ function maybeSendToPostHog(posthog, record) {
3473
+ if (isClientLogRecord(record)) {
3474
+ return;
3475
+ }
3476
+ if (!posthog.shouldAutoForwardServerLogs()) {
3477
+ if (posthog.enabled && !posthog.ready) {
3478
+ posthog.send(record, { source: "server", warnIfUnavailable: true });
3479
+ }
3480
+ return;
3481
+ }
3482
+ posthog.send(record, { source: "server", warnIfUnavailable: true });
3483
+ }
3484
+ function maybeSendToBetterStack(betterstack, record) {
3485
+ if (isClientLogRecord(record)) {
3486
+ return;
3487
+ }
3488
+ if (!betterstack.shouldAutoForwardServerLogs()) {
3489
+ if (betterstack.enabled && !betterstack.ready) {
3490
+ betterstack.send(record, { source: "server", warnIfUnavailable: true });
3491
+ }
3492
+ return;
3493
+ }
3494
+ betterstack.send(record, { source: "server", warnIfUnavailable: true });
3495
+ }
3496
+ function maybeSendToSentry(sentry, record) {
3497
+ if (isClientLogRecord(record)) {
3498
+ return;
3499
+ }
3500
+ if (!sentry.shouldAutoForwardServerLogs()) {
3501
+ if (sentry.enabled && !sentry.ready) {
3502
+ sentry.send(record, { source: "server", warnIfUnavailable: true });
3503
+ }
3504
+ return;
3505
+ }
3506
+ sentry.send(record, { source: "server", warnIfUnavailable: true });
3507
+ }
3508
+ function maybeSendToOTLP(otlp, record) {
3509
+ if (isClientLogRecord(record)) {
3510
+ return;
3511
+ }
3512
+ for (const sender of otlp.getAutoForwardTargets()) {
3513
+ sender.send(record, { source: "server", warnIfUnavailable: true });
3514
+ }
3515
+ }
3516
+ function createLoggerInstance(rootRawLogger, sink, betterstack, posthog, sentry, otlp, bindings = {}, source = "root") {
3517
+ const rawLogger = Object.keys(bindings).length > 0 ? rootRawLogger.child(bindings) : rootRawLogger;
3518
+ const writeRecord = (level, message, args, writeSource = source) => {
3519
+ if (writeSource === "root" && shouldDropRootLogWrite()) {
3520
+ return;
3521
+ }
3522
+ const record = buildRecord(level, message, args, bindings);
3523
+ const consoleMessage = serializeMessage(message);
3524
+ const payload = {
3525
+ caller: record.caller
3526
+ };
3527
+ const consoleData = getConsoleDataPayload(record.data);
3528
+ if (!consoleData.hidden && consoleData.value !== void 0) {
3529
+ payload.data = consoleData.value;
3530
+ }
3531
+ const consoleMethod = CONSOLE_LEVELS[level];
3532
+ const boundLogger = rawLogger;
3533
+ const logMethod = boundLogger[consoleMethod] ?? boundLogger.info ?? ((_payload, _message) => {
3534
+ });
3535
+ logMethod.call(
3536
+ rawLogger,
3537
+ payload,
3538
+ consoleMessage
3539
+ );
3540
+ sink.write(record);
3541
+ maybeSendToBetterStack(betterstack, record);
3542
+ maybeSendToPostHog(posthog, record);
3543
+ maybeSendToSentry(sentry, record);
3544
+ maybeSendToOTLP(otlp, record);
3545
+ };
3546
+ const writeStructuredRecord = (payload, message, writeSource = "structured-flush") => {
3547
+ const level = resolveStructuredWriteLevel(payload.level);
3548
+ const record = buildStructuredRecord(level, message, payload, bindings);
3549
+ const consoleMethod = CONSOLE_LEVELS[level];
3550
+ const boundLogger = rawLogger;
3551
+ const logMethod = boundLogger[consoleMethod] ?? boundLogger.info ?? ((_payload, _message) => {
3552
+ });
3553
+ logMethod.call(
3554
+ rawLogger,
3555
+ {
3556
+ caller: record.caller,
3557
+ ...payload
3558
+ },
3559
+ message
3560
+ );
3561
+ if (writeSource !== "root" || !shouldDropRootLogWrite()) {
3562
+ sink.write(record);
3563
+ }
3564
+ maybeSendToBetterStack(betterstack, record);
3565
+ maybeSendToPostHog(posthog, record);
3566
+ maybeSendToSentry(sentry, record);
3567
+ maybeSendToOTLP(otlp, record);
3568
+ };
3569
+ const logger3 = {
3570
+ success: (message, ...args) => {
3571
+ writeRecord("success", message, args);
3572
+ },
3573
+ critical: (message, ...args) => {
3574
+ writeRecord("critical", message, args);
3575
+ },
3576
+ warning: (message, ...args) => {
3577
+ writeRecord("warning", message, args);
3578
+ },
3579
+ info: (message, ...args) => {
3580
+ writeRecord("info", message, args);
3581
+ },
3582
+ debug: (message, ...args) => {
3583
+ writeRecord("debug", message, args);
3584
+ },
3585
+ error: (message, ...args) => {
3586
+ writeRecord("error", message, args);
3587
+ },
3588
+ warn: (message, ...args) => {
3589
+ writeRecord("warn", message, args);
3590
+ },
3591
+ table: (message, data) => {
3592
+ if (data && typeof data === "object" && runtime.env.get("NODE_ENV") !== "production") {
3593
+ console.log("TABLE:", message);
3594
+ console.table(data);
3595
+ }
3596
+ writeRecord("table", message, data === void 0 ? [] : [data]);
3597
+ },
3598
+ flush: () => sink.flush(),
3599
+ shutdown: () => sink.shutdown(),
3600
+ createStructuredLog: (groupId, initial) => {
3601
+ return createStructuredLogForLogger(logger3, groupId, {
3602
+ initialFields: initial
3603
+ });
3604
+ },
3605
+ child: (childBindings) => {
3606
+ const mergedBindings = { ...bindings, ...childBindings };
3607
+ return createLoggerInstance(
3608
+ rootRawLogger,
3609
+ sink,
3610
+ betterstack,
3611
+ posthog,
3612
+ sentry,
3613
+ otlp,
3614
+ mergedBindings,
3615
+ source
3616
+ );
3617
+ },
3618
+ [LOGGER_FACTORY]: {
3619
+ bindings,
3620
+ betterstack,
3621
+ posthog,
3622
+ sentry,
3623
+ otlp,
3624
+ sink,
3625
+ create: (nextSource, nextBindings = bindings) => {
3626
+ return createLoggerInstance(
3627
+ rootRawLogger,
3628
+ sink,
3629
+ betterstack,
3630
+ posthog,
3631
+ sentry,
3632
+ otlp,
3633
+ nextBindings,
3634
+ nextSource
3635
+ );
3636
+ },
3637
+ writeStructured: (payload, message, nextSource = "structured-flush") => {
3638
+ writeStructuredRecord(payload, message, nextSource);
3639
+ }
3640
+ }
3641
+ };
3642
+ return logger3;
3643
+ }
3644
+ var loggerInstance = null;
3645
+ function createBaseLogger(config) {
3646
+ if (config === void 0 && loggerInstance) {
3647
+ return loggerInstance;
3648
+ }
3649
+ const resolvedConfig = resolveConfig(config);
3650
+ const rawLogger = createPinoLogger(resolvedConfig);
3651
+ const sink = createPrimarySink(resolvedConfig);
3652
+ const betterstack = createBetterStackSender(resolvedConfig);
3653
+ const posthog = createPostHogSender(resolvedConfig);
3654
+ const sentry = createSentrySender(resolvedConfig);
3655
+ const otlp = createOTLPRegistry(resolvedConfig);
3656
+ const instance = createLoggerInstance(
3657
+ rawLogger,
3658
+ sink,
3659
+ betterstack,
3660
+ posthog,
3661
+ sentry,
3662
+ otlp
3663
+ );
3664
+ if (config === void 0) {
3665
+ loggerInstance = instance;
3666
+ }
3667
+ return instance;
3668
+ }
3669
+ createBaseLogger();
3670
+
3671
+ // src/frameworks/shared/logger.ts
3672
+ function buildVerboseLogMessage(method, statusCode, url, responseTime) {
3673
+ const methodColor = getMethodColor(method);
3674
+ const statusColor = getStatusColor(statusCode);
3675
+ const timeColor = getResponseTimeColor(responseTime);
3676
+ return `${methodColor} ${url} ${statusColor} ${timeColor}`;
3677
+ }
3678
+ function resolveClientLoggingConfig(clientLogging, defaultClientLogging) {
3679
+ const defaultPath = normalizeEndpointPath(
3680
+ defaultClientLogging?.path ?? DEFAULT_CLIENT_LOG_ENDPOINT
3681
+ );
3682
+ const defaultConfig = defaultClientLogging?.enabled === false ? null : { path: defaultPath };
3683
+ if (clientLogging === false) {
3684
+ return null;
3685
+ }
3686
+ if (clientLogging === void 0) {
3687
+ return defaultConfig;
3688
+ }
3689
+ if (clientLogging === true) {
3690
+ return {
3691
+ path: defaultPath
3692
+ };
3693
+ }
3694
+ return {
3695
+ ...defaultConfig,
3696
+ ...clientLogging,
3697
+ path: normalizeEndpointPath(clientLogging.path ?? defaultPath)
3698
+ };
3699
+ }
3700
+ function resolveServerLogger(config = {}, loggerOverride) {
3701
+ const resolvedConfig = resolveConfig({
3702
+ ...config.level !== void 0 ? { level: config.level } : {},
3703
+ ...config.pretty !== void 0 ? { pretty: config.pretty } : {},
3704
+ ...config.destination !== void 0 ? { destination: config.destination } : {},
3705
+ ...config.logDir !== void 0 ? { logDir: config.logDir } : {},
3706
+ ...config.file !== void 0 ? { file: config.file } : {},
3707
+ ...config.database !== void 0 ? { database: config.database } : {},
3708
+ ...config.connectors !== void 0 ? { connectors: config.connectors } : {}
3709
+ });
3710
+ const {
3711
+ level = resolvedConfig.level,
3712
+ pretty = resolvedConfig.pretty,
3713
+ destination = resolvedConfig.destination,
3714
+ logDir = resolvedConfig.logDir,
3715
+ file = resolvedConfig.file,
3716
+ database = resolvedConfig.database,
3717
+ autoLogging = true,
3718
+ customProps,
3719
+ logErrors = true,
3720
+ ignorePaths,
3721
+ clientLogging,
3722
+ connectors
3723
+ } = config;
3724
+ const logger3 = loggerOverride ?? createBaseLogger({
3725
+ level,
3726
+ pretty,
3727
+ destination,
3728
+ logDir,
3729
+ file,
3730
+ database,
3731
+ connectors
3732
+ });
3733
+ const resolvedClientLogging = resolveClientLoggingConfig(
3734
+ clientLogging,
3735
+ resolvedConfig.clientLogging
3736
+ );
3737
+ const ingestionPath = resolvedClientLogging?.path ?? DEFAULT_CLIENT_LOG_ENDPOINT;
3738
+ const resolvedIgnorePaths = resolvedClientLogging ? Array.from(/* @__PURE__ */ new Set([...ignorePaths ?? [], ingestionPath])) : ignorePaths;
3739
+ return {
3740
+ logger: logger3,
3741
+ betterstack: getBetterStackSender(logger3),
3742
+ posthog: getPostHogSender(logger3),
3743
+ sentry: getSentrySender(logger3),
3744
+ otlp: getOtlpRegistry(logger3),
3745
+ resolvedConfig,
3746
+ level,
3747
+ pretty,
3748
+ logDir,
3749
+ file,
3750
+ autoLogging,
3751
+ customProps,
3752
+ logErrors,
3753
+ resolvedIgnorePaths,
3754
+ resolvedClientLogging,
3755
+ ingestionPath
3756
+ };
3757
+ }
3758
+ function shouldSkipAutoLogging(config, ctx, path3) {
3759
+ if (config.autoLogging === false) {
3760
+ return true;
3761
+ }
3762
+ if (typeof config.autoLogging === "object" && config.autoLogging.ignore?.(ctx)) {
3763
+ return true;
3764
+ }
3765
+ return shouldIgnorePath(path3, config.resolvedIgnorePaths);
3766
+ }
3767
+ function shouldSkipErrorLogging(config, path3) {
3768
+ if (!config.logErrors) {
3769
+ return true;
3770
+ }
3771
+ return shouldIgnorePath(path3, config.resolvedIgnorePaths);
3772
+ }
3773
+ function resolveAdditionalProps(config, ctx) {
3774
+ return config.customProps ? config.customProps(ctx) : {};
3775
+ }
3776
+ function emitHttpRequestLog(logger3, level, request, path3, statusCode, responseTime, additionalProps = {}) {
3777
+ const requestLogData = buildRequestLogData(
3778
+ request,
3779
+ "http_request",
3780
+ path3,
3781
+ statusCode,
3782
+ responseTime,
3783
+ additionalProps
3784
+ );
3785
+ if (level === "info") {
3786
+ logger3.info(
3787
+ buildInfoLogMessage(request.method, statusCode, path3, responseTime),
3788
+ requestLogData
3789
+ );
3790
+ } else {
3791
+ logger3.info(
3792
+ buildVerboseLogMessage(request.method, statusCode, path3, responseTime),
3793
+ requestLogData
3794
+ );
3795
+ if (Object.keys(additionalProps).length > 0) {
3796
+ logger3.debug("Request context", additionalProps);
3797
+ }
3798
+ }
3799
+ return requestLogData;
3800
+ }
3801
+ function emitHttpErrorLog(logger3, level, request, path3, statusCode, responseTime, error, additionalProps = {}, captureContext = {}) {
3802
+ const errorLogData = buildRequestLogData(
3803
+ request,
3804
+ "http_error",
3805
+ path3,
3806
+ statusCode,
3807
+ responseTime,
3808
+ {
3809
+ error: error?.message ?? `HTTP ${statusCode}`,
3810
+ stack: error?.stack,
3811
+ code: error?.code,
3812
+ why: error?.why,
3813
+ fix: error?.fix,
3814
+ link: error?.link,
3815
+ details: error?.details,
3816
+ ...additionalProps
3817
+ }
3818
+ );
3819
+ const message = level === "info" ? buildInfoLogMessage(request.method, statusCode, path3, responseTime) : buildVerboseLogMessage(request.method, statusCode, path3, responseTime);
3820
+ logger3.error(message, errorLogData);
3821
+ const posthog = tryGetPostHogSender(logger3);
3822
+ if (posthog?.shouldAutoCaptureExceptions()) {
3823
+ posthog.captureException(captureContext.error ?? error ?? message, {
3824
+ source: "server",
3825
+ warnIfUnavailable: true,
3826
+ distinctId: captureContext.distinctId ?? getHeaderValue(request.headers, "x-posthog-distinct-id"),
3827
+ properties: buildPostHogExceptionProperties(
3828
+ {
3829
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3830
+ level: "error",
3831
+ message,
3832
+ data: errorLogData
3833
+ },
3834
+ "server",
3835
+ {
3836
+ $request_method: request.method,
3837
+ $request_path: path3,
3838
+ $current_url: request.url,
3839
+ $response_status_code: statusCode,
3840
+ ...getHeaderValue(request.headers, "user-agent") ? { $user_agent: getHeaderValue(request.headers, "user-agent") } : {},
3841
+ ...errorLogData.ip ? { $ip: errorLogData.ip } : {}
3842
+ }
3843
+ )
3844
+ });
3845
+ }
3846
+ const betterstack = tryGetBetterStackSender(logger3);
3847
+ if (betterstack?.shouldAutoCaptureExceptions()) {
3848
+ betterstack.captureException(captureContext.error ?? error ?? message, {
3849
+ source: "server",
3850
+ warnIfUnavailable: true,
3851
+ context: {
3852
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3853
+ level: "error",
3854
+ message,
3855
+ status: statusCode,
3856
+ path: path3,
3857
+ data: errorLogData
3858
+ }
3859
+ });
3860
+ }
3861
+ return errorLogData;
3862
+ }
3863
+ async function parseClientLogPayload(request, body) {
3864
+ if (body !== void 0) {
3865
+ if (typeof body === "string") {
3866
+ return JSON.parse(body);
3867
+ }
3868
+ return body;
3869
+ }
3870
+ if (typeof request.json === "function") {
3871
+ return await request.json();
3872
+ }
3873
+ throw new Error("Unable to parse client log payload");
3874
+ }
3875
+ function getClientLogMethod(logger3, level) {
3876
+ switch (level) {
3877
+ case "debug":
3878
+ return logger3.debug;
3879
+ case "info":
3880
+ return logger3.info;
3881
+ case "warning":
3882
+ return logger3.warning;
3883
+ case "error":
3884
+ return logger3.error;
3885
+ case "critical":
3886
+ return logger3.critical;
3887
+ case "success":
3888
+ return logger3.success;
3889
+ }
3890
+ }
3891
+ async function handleClientLogIngestion(options) {
3892
+ const { config, ctx, request, body, deliveryPath } = options;
3893
+ if (!config.resolvedClientLogging) {
3894
+ return { status: 404 };
3895
+ }
3896
+ let payload;
3897
+ try {
3898
+ payload = await parseClientLogPayload(request, body);
3899
+ } catch {
3900
+ return { status: 400 };
3901
+ }
3902
+ if (!isClientLogEvent(payload)) {
3903
+ return { status: 400 };
3904
+ }
3905
+ const isAllowed = config.resolvedClientLogging.validate ? await config.resolvedClientLogging.validate(ctx, payload) : true;
3906
+ if (!isAllowed) {
3907
+ return { status: 403 };
3908
+ }
3909
+ const serverContext = config.resolvedClientLogging.enrich ? await config.resolvedClientLogging.enrich(ctx, payload) : void 0;
3910
+ const structuredPayload = {
3911
+ ...payload,
3912
+ receivedAt: (/* @__PURE__ */ new Date()).toISOString(),
3913
+ delivery: buildClientDetails(request, deliveryPath ?? extractPathname(request.url))
3914
+ };
3915
+ if (serverContext !== void 0) {
3916
+ structuredPayload.serverContext = serverContext;
3917
+ }
3918
+ if (payload.level === "table") {
3919
+ config.logger.table(`[client] ${payload.message}`, structuredPayload);
3920
+ } else {
3921
+ const logMethod = getClientLogMethod(config.logger, payload.level);
3922
+ logMethod(`[client] ${payload.message}`, structuredPayload);
3923
+ }
3924
+ const headers = {};
3925
+ if (payload.connector === "betterstack") {
3926
+ headers["x-blyp-betterstack-status"] = config.betterstack.ready ? "enabled" : "missing";
3927
+ if (config.betterstack.ready) {
3928
+ const forwardedRecord = {
3929
+ timestamp: structuredPayload.receivedAt,
3930
+ level: payload.level,
3931
+ message: `[client] ${payload.message}`,
3932
+ data: structuredPayload
3933
+ };
3934
+ config.betterstack.send(forwardedRecord, {
3935
+ source: "client"
3936
+ });
3937
+ if ((payload.level === "error" || payload.level === "critical") && config.betterstack.shouldAutoCaptureExceptions()) {
3938
+ const clientErrorCandidate = payload.data && typeof payload.data === "object" && !Array.isArray(payload.data) && typeof payload.data.message === "string" ? payload.data : payload.message;
3939
+ config.betterstack.captureException(clientErrorCandidate, {
3940
+ source: "client",
3941
+ warnIfUnavailable: true,
3942
+ context: {
3943
+ sessionId: payload.session.sessionId,
3944
+ pageUrl: payload.page.url,
3945
+ pagePath: payload.page.pathname,
3946
+ metadata: payload.metadata,
3947
+ payload: structuredPayload
3948
+ }
3949
+ });
3950
+ }
3951
+ }
3952
+ } else if (payload.connector === "posthog") {
3953
+ headers["x-blyp-posthog-status"] = config.posthog.ready ? "enabled" : "missing";
3954
+ if (config.posthog.ready) {
3955
+ const forwardedRecord = {
3956
+ timestamp: structuredPayload.receivedAt,
3957
+ level: payload.level,
3958
+ message: `[client] ${payload.message}`,
3959
+ data: structuredPayload
3960
+ };
3961
+ config.posthog.send(forwardedRecord, {
3962
+ source: "client"
3963
+ });
3964
+ if ((payload.level === "error" || payload.level === "critical") && config.posthog.shouldAutoCaptureExceptions()) {
3965
+ const metadata = structuredPayload.metadata;
3966
+ const posthogDistinctId = metadata && typeof metadata === "object" && !Array.isArray(metadata) && typeof metadata.posthogDistinctId === "string" && metadata.posthogDistinctId ? String(metadata.posthogDistinctId) : void 0;
3967
+ const clientErrorCandidate = payload.data && typeof payload.data === "object" && !Array.isArray(payload.data) && typeof payload.data.message === "string" ? payload.data : payload.message;
3968
+ config.posthog.captureException(clientErrorCandidate, {
3969
+ source: "client",
3970
+ warnIfUnavailable: true,
3971
+ distinctId: posthogDistinctId,
3972
+ properties: buildPostHogExceptionProperties(forwardedRecord, "client", {
3973
+ $session_id: payload.session.sessionId,
3974
+ $current_url: payload.page.url,
3975
+ $request_path: payload.page.pathname,
3976
+ "client.runtime": payload.device?.runtime,
3977
+ "client.metadata": payload.metadata
3978
+ })
3979
+ });
3980
+ }
3981
+ }
3982
+ } else if (payload.connector === "sentry") {
3983
+ headers["x-blyp-sentry-status"] = config.sentry.ready ? "enabled" : "missing";
3984
+ if (config.sentry.ready) {
3985
+ config.sentry.send({
3986
+ timestamp: structuredPayload.receivedAt,
3987
+ level: payload.level,
3988
+ message: `[client] ${payload.message}`,
3989
+ data: structuredPayload
3990
+ }, {
3991
+ source: "client"
3992
+ });
3993
+ }
3994
+ } else if (payload.connector?.type === "otlp") {
3995
+ const sender = config.otlp.get(payload.connector.name);
3996
+ headers["x-blyp-otlp-status"] = sender.ready ? "enabled" : "missing";
3997
+ if (sender.ready) {
3998
+ sender.send({
3999
+ timestamp: structuredPayload.receivedAt,
4000
+ level: payload.level,
4001
+ message: `[client] ${payload.message}`,
4002
+ data: structuredPayload
4003
+ }, {
4004
+ source: "client"
4005
+ });
4006
+ }
4007
+ }
4008
+ return Object.keys(headers).length > 0 ? { status: 204, headers } : { status: 204 };
4009
+ }
4010
+ async function readNodeRequestBody(stream) {
4011
+ const chunks = [];
4012
+ for await (const chunk of stream) {
4013
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
4014
+ }
4015
+ return Buffer.concat(chunks).toString("utf8");
4016
+ }
4017
+ function buildAbsoluteUrl(path3, headers) {
4018
+ if (path3.startsWith("http://") || path3.startsWith("https://")) {
4019
+ return path3;
4020
+ }
4021
+ const protocol = getHeaderValue(headers, "x-forwarded-proto") ?? "http";
4022
+ const host = getHeaderValue(headers, "host") ?? "localhost";
4023
+ return `${protocol}://${host}${path3.startsWith("/") ? path3 : `/${path3}`}`;
4024
+ }
4025
+
4026
+ // src/frameworks/shared/request-logger.ts
4027
+ function createRequestScopedLogger(logger3, options = {}) {
4028
+ const scopedLogger = createLoggerWithSource(logger3, "request-scoped");
4029
+ const requestScopedLogger = attachLoggerInternals({
4030
+ ...scopedLogger,
4031
+ createStructuredLog: (groupId, initial) => {
4032
+ return createStructuredLogForLogger(requestScopedLogger, groupId, {
4033
+ initialFields: initial,
4034
+ resolveDefaultFields: options.resolveStructuredFields,
4035
+ onCreate: () => {
4036
+ markStructuredCollectorActive();
4037
+ },
4038
+ onEmit: () => {
4039
+ markStructuredLogEmitted();
4040
+ options.onStructuredEmit?.();
4041
+ }
4042
+ });
4043
+ },
4044
+ child(bindings) {
4045
+ return createRequestScopedLogger(scopedLogger.child(bindings), options);
4046
+ }
4047
+ }, scopedLogger);
4048
+ setActiveRequestLogger(requestScopedLogger);
4049
+ return requestScopedLogger;
4050
+ }
4051
+
4052
+ // src/frameworks/standalone/logger.ts
4053
+ function buildStructuredArgs(message, args) {
4054
+ const text = serializeMessage3(message);
4055
+ if (typeof message === "string") {
4056
+ return { text, data: args };
4057
+ }
4058
+ return { text, data: [message, ...args] };
4059
+ }
4060
+ function serializeMessage3(message) {
4061
+ return serializeLogMessage(message);
4062
+ }
4063
+ function wrapBaseLogger(baseLogger, config) {
4064
+ return attachLoggerInternals({
4065
+ debug: (message, ...args) => {
4066
+ const { text, data } = buildStructuredArgs(message, args);
4067
+ baseLogger.debug(text, ...data);
4068
+ },
4069
+ info: (message, ...args) => {
4070
+ const { text, data } = buildStructuredArgs(message, args);
4071
+ baseLogger.info(text, ...data);
4072
+ },
4073
+ error: (message, ...args) => {
4074
+ const { text, data } = buildStructuredArgs(message, args);
4075
+ baseLogger.error(text, ...data);
4076
+ },
4077
+ warn: (message, ...args) => {
4078
+ const { text, data } = buildStructuredArgs(message, args);
4079
+ baseLogger.warn(text, ...data);
4080
+ },
4081
+ warning: (message, ...args) => {
4082
+ const { text, data } = buildStructuredArgs(message, args);
4083
+ baseLogger.warning(text, ...data);
4084
+ },
4085
+ success: (message, meta) => {
4086
+ const { text, data } = buildStructuredArgs(message, meta === void 0 ? [] : [meta]);
4087
+ if (meta) {
4088
+ baseLogger.success(text, ...data);
4089
+ } else {
4090
+ baseLogger.success(text);
4091
+ }
4092
+ },
4093
+ critical: (message, meta) => {
4094
+ const { text, data } = buildStructuredArgs(message, meta === void 0 ? [] : [meta]);
4095
+ if (meta) {
4096
+ baseLogger.critical(text, ...data);
4097
+ } else {
4098
+ baseLogger.critical(text);
4099
+ }
4100
+ },
4101
+ table: (message, data) => {
4102
+ baseLogger.table(message, data);
4103
+ },
4104
+ flush: () => baseLogger.flush(),
4105
+ shutdown: () => baseLogger.shutdown(),
4106
+ createStructuredLog: (groupId, initial) => {
4107
+ return baseLogger.createStructuredLog(groupId, initial);
4108
+ },
4109
+ child: (bindings) => {
4110
+ return wrapBaseLogger(baseLogger.child(bindings));
4111
+ }
4112
+ }, baseLogger);
4113
+ }
4114
+ function createStandaloneLogger(config = {}) {
4115
+ const baseLogger = createBaseLogger(config);
4116
+ return wrapBaseLogger(baseLogger);
4117
+ }
4118
+ var defaultLoggerInstance = createStandaloneLogger();
4119
+ function getDefaultLogger() {
4120
+ return defaultLoggerInstance;
4121
+ }
4122
+ function createLoggerProxy() {
4123
+ return attachLoggerInternals({
4124
+ debug: (message, ...args) => {
4125
+ getDefaultLogger().debug(message, ...args);
4126
+ },
4127
+ info: (message, ...args) => {
4128
+ getDefaultLogger().info(message, ...args);
4129
+ },
4130
+ error: (message, ...args) => {
4131
+ getDefaultLogger().error(message, ...args);
4132
+ },
4133
+ warn: (message, ...args) => {
4134
+ getDefaultLogger().warn(message, ...args);
4135
+ },
4136
+ warning: (message, ...args) => {
4137
+ getDefaultLogger().warning(message, ...args);
4138
+ },
4139
+ success: (message, meta) => {
4140
+ if (meta === void 0) {
4141
+ getDefaultLogger().success(message);
4142
+ return;
4143
+ }
4144
+ getDefaultLogger().success(message, meta);
4145
+ },
4146
+ critical: (message, meta) => {
4147
+ if (meta === void 0) {
4148
+ getDefaultLogger().critical(message);
4149
+ return;
4150
+ }
4151
+ getDefaultLogger().critical(message, meta);
4152
+ },
4153
+ table: (message, data) => {
4154
+ getDefaultLogger().table(message, data);
4155
+ },
4156
+ flush: () => getDefaultLogger().flush(),
4157
+ shutdown: () => getDefaultLogger().shutdown(),
4158
+ createStructuredLog: (groupId, initial) => {
4159
+ return getDefaultLogger().createStructuredLog(groupId, initial);
4160
+ },
4161
+ child: (bindings) => {
4162
+ return getDefaultLogger().child(bindings);
4163
+ }
4164
+ }, getDefaultLogger());
4165
+ }
4166
+ function configureDefaultStandaloneLogger(config = {}) {
4167
+ defaultLoggerInstance = createStandaloneLogger(config);
4168
+ return defaultLoggerInstance;
4169
+ }
4170
+ createLoggerProxy();
4171
+
4172
+ // src/frameworks/nestjs/constants.ts
4173
+ var BLYP_NEST_LOGGER = /* @__PURE__ */ Symbol("BLYP_NEST_LOGGER");
4174
+ var BLYP_NEST_LOGGER_INIT_ERROR = "BlypModule.forRoot() requires createLogger(...) to run before NestFactory.create(AppModule).";
4175
+
4176
+ // src/frameworks/nestjs/logger.ts
4177
+ var nestLoggerState = null;
4178
+ function toStandaloneLoggerConfig(config) {
4179
+ const clientLogging = config.clientLogging === void 0 ? void 0 : config.clientLogging === false ? { enabled: false } : config.clientLogging === true ? { enabled: true } : {
4180
+ enabled: true,
4181
+ path: config.clientLogging.path
4182
+ };
4183
+ return {
4184
+ ...config.level !== void 0 ? { level: config.level } : {},
4185
+ ...config.pretty !== void 0 ? { pretty: config.pretty } : {},
4186
+ ...config.destination !== void 0 ? { destination: config.destination } : {},
4187
+ ...config.logDir !== void 0 ? { logDir: config.logDir } : {},
4188
+ ...config.file !== void 0 ? { file: config.file } : {},
4189
+ ...config.database !== void 0 ? { database: config.database } : {},
4190
+ ...clientLogging !== void 0 ? { clientLogging } : {},
4191
+ ...config.connectors !== void 0 ? { connectors: config.connectors } : {}
4192
+ };
4193
+ }
4194
+ function createNestLogger(config = {}) {
4195
+ const logger3 = configureDefaultStandaloneLogger(toStandaloneLoggerConfig(config));
4196
+ const shared = resolveServerLogger(config, logger3);
4197
+ nestLoggerState = {
4198
+ ...shared,
4199
+ logger: logger3
4200
+ };
4201
+ return logger3;
4202
+ }
4203
+ var createLogger = createNestLogger;
4204
+ function getNestLoggerStateOrThrow() {
4205
+ if (!nestLoggerState) {
4206
+ throw new Error(BLYP_NEST_LOGGER_INIT_ERROR);
4207
+ }
4208
+ return nestLoggerState;
4209
+ }
4210
+
4211
+ // src/frameworks/nestjs/helpers.ts
4212
+ function resolveNestAdapterType(request, response) {
4213
+ if (isPlainObject(response) && "raw" in response && response.raw !== void 0) {
4214
+ return "fastify";
4215
+ }
4216
+ if (isPlainObject(request) && "raw" in request && request.raw !== void 0) {
4217
+ return "fastify";
4218
+ }
4219
+ return "express";
4220
+ }
4221
+ function getNestRequestMethod(request) {
4222
+ if (!isPlainObject(request)) {
4223
+ return "GET";
4224
+ }
4225
+ if (typeof request.method === "string") {
4226
+ return request.method;
4227
+ }
4228
+ if (isPlainObject(request.raw) && typeof request.raw.method === "string") {
4229
+ return request.raw.method;
4230
+ }
4231
+ return "GET";
4232
+ }
4233
+ function getNestRequestHeaders(request) {
4234
+ if (!isPlainObject(request)) {
4235
+ return void 0;
4236
+ }
4237
+ if (isPlainObject(request.headers)) {
4238
+ return request.headers;
4239
+ }
4240
+ if (isPlainObject(request.raw) && isPlainObject(request.raw.headers)) {
4241
+ return request.raw.headers;
4242
+ }
4243
+ return void 0;
4244
+ }
4245
+ function getNestRequestUrl(request) {
4246
+ if (!isPlainObject(request)) {
4247
+ return "/";
4248
+ }
4249
+ if (typeof request.originalUrl === "string" && request.originalUrl.length > 0) {
4250
+ return request.originalUrl;
4251
+ }
4252
+ if (typeof request.url === "string" && request.url.length > 0) {
4253
+ return request.url;
4254
+ }
4255
+ if (isPlainObject(request.raw) && typeof request.raw.url === "string" && request.raw.url.length > 0) {
4256
+ return request.raw.url;
4257
+ }
4258
+ return "/";
4259
+ }
4260
+ function getNestRequestPath(request) {
4261
+ return extractPathname(getNestRequestUrl(request));
4262
+ }
4263
+ async function readNestRequestBody(request) {
4264
+ if (!isPlainObject(request)) {
4265
+ return void 0;
4266
+ }
4267
+ if ("body" in request && request.body !== void 0) {
4268
+ return request.body;
4269
+ }
4270
+ if (isPlainObject(request.raw) && "body" in request.raw && request.raw.body !== void 0) {
4271
+ return request.raw.body;
4272
+ }
4273
+ if (Symbol.asyncIterator in request) {
4274
+ return await readNodeRequestBody(
4275
+ request
4276
+ );
4277
+ }
4278
+ if (isPlainObject(request.raw) && Symbol.asyncIterator in request.raw) {
4279
+ return await readNodeRequestBody(
4280
+ request.raw
4281
+ );
4282
+ }
4283
+ return void 0;
4284
+ }
4285
+ function setNestRequestStartTime(request, startTime) {
4286
+ if (!isPlainObject(request)) {
4287
+ return;
4288
+ }
4289
+ request.blypStartTime = startTime;
4290
+ }
4291
+ function getNestRequestStartTime(request) {
4292
+ if (!isPlainObject(request)) {
4293
+ return void 0;
4294
+ }
4295
+ return typeof request.blypStartTime === "number" ? request.blypStartTime : void 0;
4296
+ }
4297
+ function setNestStructuredLogEmitted(request, emitted) {
4298
+ if (!isPlainObject(request)) {
4299
+ return;
4300
+ }
4301
+ request.blypStructuredLogEmitted = emitted;
4302
+ }
4303
+ function getNestStructuredLogEmitted(request) {
4304
+ if (!isPlainObject(request)) {
4305
+ return false;
4306
+ }
4307
+ return request.blypStructuredLogEmitted === true;
4308
+ }
4309
+ function attachNestRequestLogger(request, logger3) {
4310
+ if (!isPlainObject(request)) {
4311
+ return;
4312
+ }
4313
+ request.blypLog = logger3;
4314
+ }
4315
+ function buildNestRequestLike(request) {
4316
+ const method = getNestRequestMethod(request);
4317
+ const headers = getNestRequestHeaders(request);
4318
+ const path3 = getNestRequestUrl(request);
4319
+ return createRequestLike(method, buildAbsoluteUrl(path3, headers), headers);
4320
+ }
4321
+ function getNestResponseStatus(response) {
4322
+ if (!isPlainObject(response)) {
4323
+ return 200;
4324
+ }
4325
+ if (typeof response.statusCode === "number") {
4326
+ return response.statusCode;
4327
+ }
4328
+ if (isPlainObject(response.raw) && typeof response.raw.statusCode === "number") {
4329
+ return response.raw.statusCode;
4330
+ }
4331
+ return 200;
4332
+ }
4333
+ function setRawStatus(target, statusCode) {
4334
+ target.statusCode = statusCode;
4335
+ }
4336
+ function setNestResponseHeaders(response, headers) {
4337
+ if (!isPlainObject(response)) {
4338
+ return;
4339
+ }
4340
+ if (typeof response.setHeader === "function") {
4341
+ for (const [key, value] of Object.entries(headers)) {
4342
+ response.setHeader(key, value);
4343
+ }
4344
+ return;
4345
+ }
4346
+ if (typeof response.header === "function") {
4347
+ for (const [key, value] of Object.entries(headers)) {
4348
+ response.header(key, value);
4349
+ }
4350
+ return;
4351
+ }
4352
+ if (isPlainObject(response.raw) && typeof response.raw.setHeader === "function") {
4353
+ for (const [key, value] of Object.entries(headers)) {
4354
+ response.raw.setHeader(key, value);
4355
+ }
4356
+ }
4357
+ }
4358
+ function sendNestStatusResponse(response, statusCode) {
4359
+ if (!isPlainObject(response)) {
4360
+ return;
4361
+ }
4362
+ if (typeof response.status === "function") {
4363
+ const expressResponse = response.status(statusCode);
4364
+ expressResponse.end?.();
4365
+ return;
4366
+ }
4367
+ if (typeof response.code === "function") {
4368
+ const fastifyReply = response.code(statusCode);
4369
+ fastifyReply.send?.();
4370
+ return;
4371
+ }
4372
+ if (isPlainObject(response.raw)) {
4373
+ setRawStatus(response.raw, statusCode);
4374
+ if (typeof response.raw.end === "function") {
4375
+ response.raw.end();
4376
+ }
4377
+ return;
4378
+ }
4379
+ setRawStatus(response, statusCode);
4380
+ if (typeof response.end === "function") {
4381
+ response.end();
4382
+ }
4383
+ }
4384
+ function getControllerName(context) {
4385
+ const controller = context.getClass();
4386
+ return controller?.name || void 0;
4387
+ }
4388
+ function getHandlerName(context) {
4389
+ const handler = context.getHandler();
4390
+ return handler?.name || void 0;
4391
+ }
4392
+ function createNestLoggerContext(options) {
4393
+ const { request, response, executionContext, error } = options;
4394
+ const adapterType = resolveNestAdapterType(request, response);
4395
+ return {
4396
+ request,
4397
+ response,
4398
+ adapterType,
4399
+ executionContext,
4400
+ error,
4401
+ controllerName: executionContext ? getControllerName(executionContext) : void 0,
4402
+ handlerName: executionContext ? getHandlerName(executionContext) : void 0
4403
+ };
4404
+ }
4405
+
4406
+ // src/frameworks/nestjs/filter.ts
4407
+ var BlypNestExceptionFilter = class extends BaseExceptionFilter {
4408
+ constructor(state, httpAdapterHost) {
4409
+ super(httpAdapterHost.httpAdapter);
4410
+ this.state = state;
4411
+ }
4412
+ catch(exception, host) {
4413
+ if (host.getType() === "http") {
4414
+ const http = host.switchToHttp();
4415
+ const request = http.getRequest();
4416
+ const response = http.getResponse();
4417
+ const loggerContext = createNestLoggerContext({
4418
+ request,
4419
+ response,
4420
+ error: exception
4421
+ });
4422
+ const path3 = getNestRequestPath(request);
4423
+ if (getNestStructuredLogEmitted(request)) {
4424
+ super.catch(exception, host);
4425
+ return;
4426
+ }
4427
+ if (!shouldSkipErrorLogging(this.state, path3)) {
4428
+ const statusCode = exception instanceof HttpException ? exception.getStatus() : 500;
4429
+ const responseTime = Math.round(
4430
+ performance.now() - (getNestRequestStartTime(request) ?? performance.now())
4431
+ );
4432
+ emitHttpErrorLog(
4433
+ this.state.logger,
4434
+ this.state.level,
4435
+ buildNestRequestLike(request),
4436
+ path3,
4437
+ statusCode,
4438
+ responseTime,
4439
+ toErrorLike(exception, statusCode),
4440
+ resolveAdditionalProps(this.state, loggerContext),
4441
+ {
4442
+ error: exception
4443
+ }
4444
+ );
4445
+ }
4446
+ }
4447
+ super.catch(exception, host);
4448
+ }
4449
+ };
4450
+ BlypNestExceptionFilter = __decorateClass([
4451
+ Catch(),
4452
+ __decorateParam(0, Inject(BLYP_NEST_LOGGER))
4453
+ ], BlypNestExceptionFilter);
4454
+ var BlypNestInterceptor = class {
4455
+ constructor(state) {
4456
+ this.state = state;
4457
+ }
4458
+ intercept(context, next) {
4459
+ if (context.getType() !== "http") {
4460
+ return next.handle();
4461
+ }
4462
+ const http = context.switchToHttp();
4463
+ const request = http.getRequest();
4464
+ const response = http.getResponse();
4465
+ const loggerContext = createNestLoggerContext({
4466
+ request,
4467
+ response,
4468
+ executionContext: context
4469
+ });
4470
+ if (!request.blypLog) {
4471
+ attachNestRequestLogger(request, this.state.logger);
4472
+ }
4473
+ if (getNestRequestStartTime(request) === void 0) {
4474
+ setNestRequestStartTime(request, performance.now());
4475
+ }
4476
+ return next.handle().pipe(
4477
+ tap({
4478
+ complete: () => {
4479
+ const path3 = getNestRequestPath(request);
4480
+ const statusCode = getNestResponseStatus(response);
4481
+ const responseTime = Math.round(
4482
+ performance.now() - (getNestRequestStartTime(request) ?? performance.now())
4483
+ );
4484
+ const requestLike = buildNestRequestLike(request);
4485
+ const additionalProps = resolveAdditionalProps(this.state, loggerContext);
4486
+ if (getNestStructuredLogEmitted(request)) {
4487
+ return;
4488
+ }
4489
+ if (isErrorStatus(statusCode)) {
4490
+ if (!shouldSkipErrorLogging(this.state, path3)) {
4491
+ emitHttpErrorLog(
4492
+ this.state.logger,
4493
+ this.state.level,
4494
+ requestLike,
4495
+ path3,
4496
+ statusCode,
4497
+ responseTime,
4498
+ toErrorLike(void 0, statusCode),
4499
+ additionalProps
4500
+ );
4501
+ }
4502
+ return;
4503
+ }
4504
+ if (!shouldSkipAutoLogging(this.state, loggerContext, path3)) {
4505
+ emitHttpRequestLog(
4506
+ this.state.logger,
4507
+ this.state.level,
4508
+ requestLike,
4509
+ path3,
4510
+ statusCode,
4511
+ responseTime,
4512
+ additionalProps
4513
+ );
4514
+ }
4515
+ }
4516
+ })
4517
+ );
4518
+ }
4519
+ };
4520
+ BlypNestInterceptor = __decorateClass([
4521
+ Injectable(),
4522
+ __decorateParam(0, Inject(BLYP_NEST_LOGGER))
4523
+ ], BlypNestInterceptor);
4524
+ var BlypNestMiddleware = class {
4525
+ constructor(state) {
4526
+ this.state = state;
4527
+ }
4528
+ use(request, response, next) {
4529
+ enterRequestContext();
4530
+ setNestStructuredLogEmitted(request, false);
4531
+ attachNestRequestLogger(
4532
+ request,
4533
+ createRequestScopedLogger(this.state.logger, {
4534
+ resolveStructuredFields: () => {
4535
+ const loggerContext = createNestLoggerContext({
4536
+ request,
4537
+ response
4538
+ });
4539
+ return {
4540
+ method: buildNestRequestLike(request).method,
4541
+ path: getNestRequestPath(request),
4542
+ ...resolveAdditionalProps(this.state, loggerContext)
4543
+ };
4544
+ },
4545
+ onStructuredEmit: () => {
4546
+ setNestStructuredLogEmitted(request, true);
4547
+ }
4548
+ })
4549
+ );
4550
+ setNestRequestStartTime(request, performance.now());
4551
+ const path3 = getNestRequestPath(request);
4552
+ const method = getNestRequestMethod(request).toUpperCase();
4553
+ if (this.state.resolvedClientLogging && method === "POST" && path3 === this.state.ingestionPath) {
4554
+ void this.handleClientLogRequest(request, response, next);
4555
+ return;
4556
+ }
4557
+ next();
4558
+ }
4559
+ async handleClientLogRequest(request, response, next) {
4560
+ try {
4561
+ const body = await readNestRequestBody(request);
4562
+ const result = await handleClientLogIngestion({
4563
+ config: this.state,
4564
+ ctx: createNestLoggerContext({
4565
+ request,
4566
+ response
4567
+ }),
4568
+ request: buildNestRequestLike(request),
4569
+ body,
4570
+ deliveryPath: this.state.ingestionPath
4571
+ });
4572
+ if (result.headers) {
4573
+ setNestResponseHeaders(response, result.headers);
4574
+ }
4575
+ sendNestStatusResponse(response, result.status);
4576
+ } catch (error) {
4577
+ next(error);
4578
+ }
4579
+ }
4580
+ };
4581
+ BlypNestMiddleware = __decorateClass([
4582
+ Injectable(),
4583
+ __decorateParam(0, Inject(BLYP_NEST_LOGGER))
4584
+ ], BlypNestMiddleware);
4585
+
4586
+ // src/frameworks/nestjs/module.ts
4587
+ var BlypModule = class {
4588
+ static forRoot() {
4589
+ return {
4590
+ global: true,
4591
+ module: BlypModule,
4592
+ providers: [
4593
+ BlypNestMiddleware,
4594
+ {
4595
+ provide: BLYP_NEST_LOGGER,
4596
+ useFactory: () => getNestLoggerStateOrThrow()
4597
+ },
4598
+ {
4599
+ provide: APP_INTERCEPTOR,
4600
+ useClass: BlypNestInterceptor
4601
+ },
4602
+ {
4603
+ provide: APP_FILTER,
4604
+ useClass: BlypNestExceptionFilter
4605
+ }
4606
+ ],
4607
+ exports: [BLYP_NEST_LOGGER]
4608
+ };
4609
+ }
4610
+ configure(consumer) {
4611
+ consumer.apply(BlypNestMiddleware).forRoutes({ path: "*", method: RequestMethod.ALL });
4612
+ }
4613
+ };
4614
+ BlypModule = __decorateClass([
4615
+ Global(),
4616
+ Module({})
4617
+ ], BlypModule);
4618
+
4619
+ export { BlypModule, createLogger, createNestLogger };
4620
+ //# sourceMappingURL=nestjs.mjs.map
4621
+ //# sourceMappingURL=nestjs.mjs.map