@brizz/sdk 0.1.0 → 0.1.2-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +339 -19
  2. package/dist/index.cjs +2936 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +178 -0
  5. package/dist/index.d.ts +177 -12
  6. package/dist/index.js +2895 -9
  7. package/dist/index.js.map +1 -1
  8. package/dist/loader.mjs +72 -0
  9. package/dist/preload.cjs +2786 -0
  10. package/dist/preload.cjs.map +1 -0
  11. package/dist/preload.d.cts +2 -0
  12. package/dist/preload.d.ts +2 -0
  13. package/dist/preload.js +2777 -0
  14. package/dist/preload.js.map +1 -0
  15. package/package.json +35 -13
  16. package/dist/index.d.ts.map +0 -1
  17. package/dist/internal/config.d.ts +0 -17
  18. package/dist/internal/config.d.ts.map +0 -1
  19. package/dist/internal/config.js +0 -90
  20. package/dist/internal/config.js.map +0 -1
  21. package/dist/internal/instrumentation/auto-init.d.ts +0 -3
  22. package/dist/internal/instrumentation/auto-init.d.ts.map +0 -1
  23. package/dist/internal/instrumentation/auto-init.js +0 -82
  24. package/dist/internal/instrumentation/auto-init.js.map +0 -1
  25. package/dist/internal/instrumentation/index.d.ts +0 -2
  26. package/dist/internal/instrumentation/index.d.ts.map +0 -1
  27. package/dist/internal/instrumentation/index.js +0 -2
  28. package/dist/internal/instrumentation/index.js.map +0 -1
  29. package/dist/internal/instrumentation/registry.d.ts +0 -29
  30. package/dist/internal/instrumentation/registry.d.ts.map +0 -1
  31. package/dist/internal/instrumentation/registry.js +0 -88
  32. package/dist/internal/instrumentation/registry.js.map +0 -1
  33. package/dist/internal/log/index.d.ts +0 -2
  34. package/dist/internal/log/index.d.ts.map +0 -1
  35. package/dist/internal/log/index.js +0 -2
  36. package/dist/internal/log/index.js.map +0 -1
  37. package/dist/internal/log/logging.d.ts +0 -21
  38. package/dist/internal/log/logging.d.ts.map +0 -1
  39. package/dist/internal/log/logging.js +0 -149
  40. package/dist/internal/log/logging.js.map +0 -1
  41. package/dist/internal/logger.d.ts +0 -23
  42. package/dist/internal/logger.d.ts.map +0 -1
  43. package/dist/internal/logger.js +0 -155
  44. package/dist/internal/logger.js.map +0 -1
  45. package/dist/internal/masking/index.d.ts +0 -4
  46. package/dist/internal/masking/index.d.ts.map +0 -1
  47. package/dist/internal/masking/index.js +0 -3
  48. package/dist/internal/masking/index.js.map +0 -1
  49. package/dist/internal/masking/patterns.d.ts +0 -3
  50. package/dist/internal/masking/patterns.d.ts.map +0 -1
  51. package/dist/internal/masking/patterns.js +0 -375
  52. package/dist/internal/masking/patterns.js.map +0 -1
  53. package/dist/internal/masking/types.d.ts +0 -33
  54. package/dist/internal/masking/types.d.ts.map +0 -1
  55. package/dist/internal/masking/types.js +0 -2
  56. package/dist/internal/masking/types.js.map +0 -1
  57. package/dist/internal/masking/utils.d.ts +0 -6
  58. package/dist/internal/masking/utils.d.ts.map +0 -1
  59. package/dist/internal/masking/utils.js +0 -226
  60. package/dist/internal/masking/utils.js.map +0 -1
  61. package/dist/internal/metric/index.d.ts +0 -2
  62. package/dist/internal/metric/index.d.ts.map +0 -1
  63. package/dist/internal/metric/index.js +0 -2
  64. package/dist/internal/metric/index.js.map +0 -1
  65. package/dist/internal/metric/metrics.d.ts +0 -18
  66. package/dist/internal/metric/metrics.d.ts.map +0 -1
  67. package/dist/internal/metric/metrics.js +0 -82
  68. package/dist/internal/metric/metrics.js.map +0 -1
  69. package/dist/internal/sdk.d.ts +0 -36
  70. package/dist/internal/sdk.d.ts.map +0 -1
  71. package/dist/internal/sdk.js +0 -155
  72. package/dist/internal/sdk.js.map +0 -1
  73. package/dist/internal/trace/index.d.ts +0 -3
  74. package/dist/internal/trace/index.d.ts.map +0 -1
  75. package/dist/internal/trace/index.js +0 -3
  76. package/dist/internal/trace/index.js.map +0 -1
  77. package/dist/internal/trace/processors/log-masked.d.ts +0 -16
  78. package/dist/internal/trace/processors/log-masked.d.ts.map +0 -1
  79. package/dist/internal/trace/processors/log-masked.js +0 -75
  80. package/dist/internal/trace/processors/log-masked.js.map +0 -1
  81. package/dist/internal/trace/processors/span-masked.d.ts +0 -16
  82. package/dist/internal/trace/processors/span-masked.d.ts.map +0 -1
  83. package/dist/internal/trace/processors/span-masked.js +0 -81
  84. package/dist/internal/trace/processors/span-masked.js.map +0 -1
  85. package/dist/internal/trace/tracing.d.ts +0 -18
  86. package/dist/internal/trace/tracing.d.ts.map +0 -1
  87. package/dist/internal/trace/tracing.js +0 -97
  88. package/dist/internal/trace/tracing.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,10 +1,2896 @@
1
- import './internal/instrumentation/auto-init';
2
- export { Brizz } from './internal/sdk';
3
- export { emitEvent } from './internal/log';
4
- export { getSpanExporter, getSpanProcessor } from './internal/trace';
5
- export { getMetricsExporter, getMetricsReader } from './internal/metric';
6
- export { DEFAULT_PII_PATTERNS } from './internal/masking/patterns';
7
- export { maskValue, maskAttributes } from './internal/masking/utils';
8
- export { LogLevel, logger, setLogLevel, getLogLevel } from './internal/logger';
9
- export { SeverityNumber } from '@opentelemetry/api-logs';
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/internal/instrumentation/auto-init.ts
9
+ import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
10
+ import { registerInstrumentations } from "@opentelemetry/instrumentation";
11
+ import { AnthropicInstrumentation } from "@traceloop/instrumentation-anthropic";
12
+ import { BedrockInstrumentation } from "@traceloop/instrumentation-bedrock";
13
+ import { ChromaDBInstrumentation } from "@traceloop/instrumentation-chromadb";
14
+ import { CohereInstrumentation } from "@traceloop/instrumentation-cohere";
15
+ import { LangChainInstrumentation } from "@traceloop/instrumentation-langchain";
16
+ import { LlamaIndexInstrumentation } from "@traceloop/instrumentation-llamaindex";
17
+ import { OpenAIInstrumentation } from "@traceloop/instrumentation-openai";
18
+ import { PineconeInstrumentation } from "@traceloop/instrumentation-pinecone";
19
+ import { QdrantInstrumentation } from "@traceloop/instrumentation-qdrant";
20
+ import { TogetherInstrumentation } from "@traceloop/instrumentation-together";
21
+ import { VertexAIInstrumentation } from "@traceloop/instrumentation-vertexai";
22
+
23
+ // src/internal/logger.ts
24
+ import { DiagLogLevel } from "@opentelemetry/api";
25
+ import pino from "pino";
26
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
27
+ LogLevel2[LogLevel2["NONE"] = 0] = "NONE";
28
+ LogLevel2[LogLevel2["ERROR"] = 1] = "ERROR";
29
+ LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
30
+ LogLevel2[LogLevel2["INFO"] = 3] = "INFO";
31
+ LogLevel2[LogLevel2["DEBUG"] = 4] = "DEBUG";
32
+ return LogLevel2;
33
+ })(LogLevel || {});
34
+ var DEFAULT_LOG_LEVEL = 2 /* WARN */;
35
+ var PinoLogger = class {
36
+ _level = DEFAULT_LOG_LEVEL;
37
+ _pinoLogger = null;
38
+ constructor() {
39
+ const envLevel = this.getLogLevelFromEnv();
40
+ this._level = envLevel;
41
+ }
42
+ /**
43
+ * Lazy initialization of Pino logger to ensure it's created AFTER Jest spies
44
+ * are set up during tests. This prevents the pino-pretty transport from
45
+ * bypassing stdout/stderr spies.
46
+ */
47
+ ensurePinoLogger() {
48
+ if (!this._pinoLogger) {
49
+ this._pinoLogger = pino({
50
+ name: "Brizz",
51
+ level: this.logLevelToPino(this._level),
52
+ // Disable transport in test environment to allow proper spy capture
53
+ transport: this.isProduction() || this.isTest() ? void 0 : {
54
+ target: "pino-pretty",
55
+ options: {
56
+ singleLine: true,
57
+ colorize: true,
58
+ translateTime: "HH:MM:ss",
59
+ ignore: "pid,hostname",
60
+ messageFormat: "[{name}] {msg}"
61
+ }
62
+ }
63
+ });
64
+ }
65
+ return this._pinoLogger;
66
+ }
67
+ isProduction() {
68
+ return process.env["NODE_ENV"] === "production";
69
+ }
70
+ isTest() {
71
+ return process.env["NODE_ENV"] === "test";
72
+ }
73
+ getLogLevelFromEnv() {
74
+ const envLevel = process.env["BRIZZ_LOG_LEVEL"];
75
+ return envLevel ? parseLogLevel(envLevel) : DEFAULT_LOG_LEVEL;
76
+ }
77
+ logLevelToPino(level) {
78
+ switch (level) {
79
+ case 4 /* DEBUG */:
80
+ return "debug";
81
+ case 3 /* INFO */:
82
+ return "info";
83
+ case 2 /* WARN */:
84
+ return "warn";
85
+ case 1 /* ERROR */:
86
+ return "error";
87
+ default:
88
+ return "silent";
89
+ }
90
+ }
91
+ formatMeta(meta) {
92
+ if (meta.length === 0) {
93
+ return {};
94
+ }
95
+ if (meta.length === 1 && typeof meta[0] === "object" && meta[0] !== null) {
96
+ return meta[0];
97
+ }
98
+ return { metadata: meta };
99
+ }
100
+ setLevel(level) {
101
+ this._level = level;
102
+ if (this._pinoLogger) {
103
+ this._pinoLogger.level = this.logLevelToPino(level);
104
+ }
105
+ }
106
+ getLevel() {
107
+ return this._level;
108
+ }
109
+ debug = (msg, ...meta) => {
110
+ if (this._level >= 4 /* DEBUG */) {
111
+ this.ensurePinoLogger().debug(this.formatMeta(meta), msg);
112
+ }
113
+ };
114
+ info = (msg, ...meta) => {
115
+ if (this._level >= 3 /* INFO */) {
116
+ this.ensurePinoLogger().info(this.formatMeta(meta), msg);
117
+ }
118
+ };
119
+ warn = (msg, ...meta) => {
120
+ if (this._level >= 2 /* WARN */) {
121
+ this.ensurePinoLogger().warn(this.formatMeta(meta), msg);
122
+ }
123
+ };
124
+ error = (msg, ...meta) => {
125
+ if (this._level >= 1 /* ERROR */) {
126
+ this.ensurePinoLogger().error(this.formatMeta(meta), msg);
127
+ }
128
+ };
129
+ };
130
+ function parseLogLevel(level) {
131
+ if (!level) {
132
+ return DEFAULT_LOG_LEVEL;
133
+ }
134
+ const normalizedLevel = level.toLowerCase().trim();
135
+ switch (normalizedLevel) {
136
+ case "debug":
137
+ return 4 /* DEBUG */;
138
+ case "info":
139
+ return 3 /* INFO */;
140
+ case "warn":
141
+ case "warning":
142
+ return 2 /* WARN */;
143
+ case "error":
144
+ return 1 /* ERROR */;
145
+ case "none":
146
+ case "off":
147
+ case "silent":
148
+ return 0 /* NONE */;
149
+ default: {
150
+ const numLevel = Number.parseInt(normalizedLevel, 10);
151
+ if (!Number.isNaN(numLevel) && numLevel >= 0 && numLevel <= 4) {
152
+ return numLevel;
153
+ }
154
+ return DEFAULT_LOG_LEVEL;
155
+ }
156
+ }
157
+ }
158
+ var logger = new PinoLogger();
159
+ function setLogLevel(level) {
160
+ const resolvedLevel = typeof level === "string" ? parseLogLevel(level) : level;
161
+ logger.setLevel(resolvedLevel);
162
+ }
163
+ function getLogLevel() {
164
+ return logger.getLevel();
165
+ }
166
+
167
+ // src/internal/instrumentation/vercel-ai/instrumentation.ts
168
+ import {
169
+ InstrumentationBase,
170
+ InstrumentationNodeModuleDefinition
171
+ } from "@opentelemetry/instrumentation";
172
+
173
+ // src/internal/instrumentation/vercel-ai/patchers/base-patcher.ts
174
+ import { SpanKind, SpanStatusCode } from "@opentelemetry/api";
175
+
176
+ // src/internal/instrumentation/vercel-ai/semconv.ts
177
+ var ATTR_GEN_AI_SYSTEM = "gen_ai.system";
178
+ var ATTR_GEN_AI_OPERATION_NAME = "gen_ai.operation.name";
179
+ var ATTR_GEN_AI_REQUEST_MODEL = "gen_ai.request.model";
180
+ var ATTR_GEN_AI_REQUEST_MAX_TOKENS = "gen_ai.request.max_tokens";
181
+ var ATTR_GEN_AI_REQUEST_TEMPERATURE = "gen_ai.request.temperature";
182
+ var ATTR_GEN_AI_REQUEST_TOP_P = "gen_ai.request.top_p";
183
+ var ATTR_GEN_AI_REQUEST_TOP_K = "gen_ai.request.top_k";
184
+ var ATTR_GEN_AI_REQUEST_STOP_SEQUENCES = "gen_ai.request.stop_sequences";
185
+ var ATTR_GEN_AI_REQUEST_FREQUENCY_PENALTY = "gen_ai.request.frequency_penalty";
186
+ var ATTR_GEN_AI_REQUEST_PRESENCE_PENALTY = "gen_ai.request.presence_penalty";
187
+ var ATTR_GEN_AI_RESPONSE_ID = "gen_ai.response.id";
188
+ var ATTR_GEN_AI_RESPONSE_MODEL = "gen_ai.response.model";
189
+ var ATTR_GEN_AI_RESPONSE_FINISH_REASONS = "gen_ai.response.finish_reasons";
190
+ var ATTR_GEN_AI_TOKEN_TYPE = "gen_ai.token.type";
191
+ var ATTR_GEN_AI_PROMPT = "gen_ai.prompt";
192
+ var ATTR_GEN_AI_COMPLETION = "gen_ai.completion";
193
+ var ATTR_GEN_AI_OPENAI_API_BASE = "gen_ai.openai.api_base";
194
+ var ATTR_EVENT_NAME = "event.name";
195
+ var EVENT_GEN_AI_USER_MESSAGE = "gen_ai.user.message";
196
+ var EVENT_GEN_AI_ASSISTANT_MESSAGE = "gen_ai.assistant.message";
197
+ var EVENT_GEN_AI_SYSTEM_MESSAGE = "gen_ai.system.message";
198
+ var EVENT_GEN_AI_TOOL_MESSAGE = "gen_ai.tool.message";
199
+ var METRIC_GEN_AI_CLIENT_OPERATION_DURATION = "gen_ai.client.operation.duration";
200
+ var METRIC_GEN_AI_CLIENT_TOKEN_USAGE = "gen_ai.client.token.usage";
201
+ var OPERATION_NAME_CHAT = "chat";
202
+ var OPERATION_NAME_EMBEDDINGS = "embeddings";
203
+ var TOKEN_TYPE_INPUT = "input";
204
+ var TOKEN_TYPE_OUTPUT = "output";
205
+ var PROVIDER_OPENAI = "openai";
206
+ var PROVIDER_ANTHROPIC = "anthropic";
207
+ var PROVIDER_GOOGLE = "google";
208
+ var PROVIDER_AMAZON = "amazon";
209
+ var PROVIDER_AZURE = "azure";
210
+ var PROVIDER_VERCEL = "vercel";
211
+ var PROVIDER_UNKNOWN = "unknown";
212
+ var SPAN_NAME_GEN_AI_CHAT = "gen_ai.chat";
213
+ var SPAN_NAME_GEN_AI_EMBEDDINGS = "gen_ai.embeddings";
214
+
215
+ // src/internal/instrumentation/vercel-ai/utils.ts
216
+ function detectProvider(model) {
217
+ if (typeof model === "object" && model !== null) {
218
+ const modelObj = model;
219
+ if (modelObj.provider) {
220
+ return {
221
+ system: normalizeProviderName(modelObj.provider),
222
+ apiBase: extractApiBase(modelObj)
223
+ };
224
+ }
225
+ if (modelObj.modelId) {
226
+ return detectProviderFromModelId(modelObj.modelId);
227
+ }
228
+ }
229
+ if (typeof model === "string") {
230
+ return detectProviderFromModelId(model);
231
+ }
232
+ return { system: PROVIDER_UNKNOWN };
233
+ }
234
+ function detectProviderFromModelId(modelId) {
235
+ const lowerModel = modelId.toLowerCase();
236
+ if (lowerModel.startsWith("gpt-") || lowerModel.startsWith("text-davinci-") || lowerModel.startsWith("text-embedding-") || lowerModel.startsWith("dall-e") || lowerModel.startsWith("whisper-") || lowerModel.startsWith("tts-")) {
237
+ return { system: PROVIDER_OPENAI };
238
+ }
239
+ if (lowerModel.startsWith("claude-")) {
240
+ return { system: PROVIDER_ANTHROPIC };
241
+ }
242
+ if (lowerModel.startsWith("gemini-") || lowerModel.startsWith("palm-") || lowerModel.includes("bison") || lowerModel.includes("gecko")) {
243
+ return { system: PROVIDER_GOOGLE };
244
+ }
245
+ if (lowerModel.startsWith("amazon.") || lowerModel.startsWith("anthropic.claude-") || lowerModel.startsWith("ai21.") || lowerModel.startsWith("cohere.") || lowerModel.startsWith("meta.llama")) {
246
+ return { system: PROVIDER_AMAZON };
247
+ }
248
+ if (lowerModel.includes("azure") || lowerModel.includes(".openai.azure.com")) {
249
+ return { system: PROVIDER_AZURE };
250
+ }
251
+ const parts = modelId.split(/[-._/]/);
252
+ if (parts.length > 0 && parts[0]) {
253
+ return { system: normalizeProviderName(parts[0]) };
254
+ }
255
+ return { system: PROVIDER_UNKNOWN };
256
+ }
257
+ function normalizeProviderName(provider) {
258
+ const normalized = provider.toLowerCase().trim();
259
+ switch (normalized) {
260
+ case "openai":
261
+ case "open-ai":
262
+ case "open_ai": {
263
+ return PROVIDER_OPENAI;
264
+ }
265
+ case "anthropic":
266
+ case "claude": {
267
+ return PROVIDER_ANTHROPIC;
268
+ }
269
+ case "google":
270
+ case "vertex":
271
+ case "vertexai":
272
+ case "vertex-ai":
273
+ case "gemini": {
274
+ return PROVIDER_GOOGLE;
275
+ }
276
+ case "amazon":
277
+ case "aws":
278
+ case "bedrock":
279
+ case "amazon-bedrock": {
280
+ return PROVIDER_AMAZON;
281
+ }
282
+ case "azure":
283
+ case "azure-openai":
284
+ case "microsoft": {
285
+ return PROVIDER_AZURE;
286
+ }
287
+ case "vercel":
288
+ case "vercel-ai": {
289
+ return PROVIDER_VERCEL;
290
+ }
291
+ default: {
292
+ return normalized;
293
+ }
294
+ }
295
+ }
296
+ function extractApiBase(model) {
297
+ if (typeof model === "object" && model !== null) {
298
+ const anyModel = model;
299
+ return anyModel.apiBase || anyModel.baseURL || anyModel.endpoint || void 0;
300
+ }
301
+ return void 0;
302
+ }
303
+ function extractModelId(model) {
304
+ if (typeof model === "string") {
305
+ return model;
306
+ }
307
+ if (typeof model === "object" && model !== null) {
308
+ return model.modelId || "unknown";
309
+ }
310
+ return "unknown";
311
+ }
312
+ function messagesToAttributes(messages, prefix, captureContent) {
313
+ const attributes = {};
314
+ for (const [index, msg] of messages.entries()) {
315
+ const baseKey = `${prefix}.${index}`;
316
+ attributes[`${baseKey}.role`] = msg.role;
317
+ if (captureContent && msg.content) {
318
+ if (typeof msg.content === "string") {
319
+ attributes[`${baseKey}.content`] = msg.content;
320
+ } else if (Array.isArray(msg.content)) {
321
+ const textParts = msg.content.filter((part) => part.type === "text" && part.text).map((part) => part.text).join(" ");
322
+ if (textParts) {
323
+ attributes[`${baseKey}.content`] = textParts;
324
+ }
325
+ }
326
+ }
327
+ if (msg.toolInvocations && msg.toolInvocations.length > 0) {
328
+ attributes[`${baseKey}.tool_calls`] = msg.toolInvocations.length;
329
+ }
330
+ }
331
+ return attributes;
332
+ }
333
+ function promptToAttributes(prompt, captureContent) {
334
+ const attributes = {};
335
+ attributes[`${ATTR_GEN_AI_PROMPT}.0.role`] = "user";
336
+ if (captureContent) {
337
+ attributes[`${ATTR_GEN_AI_PROMPT}.0.content`] = prompt;
338
+ }
339
+ return attributes;
340
+ }
341
+ function completionToAttributes(text, finishReason, captureContent) {
342
+ const attributes = {};
343
+ attributes[`${ATTR_GEN_AI_COMPLETION}.0.role`] = "assistant";
344
+ if (captureContent) {
345
+ attributes[`${ATTR_GEN_AI_COMPLETION}.0.content`] = text;
346
+ }
347
+ if (finishReason) {
348
+ attributes[`${ATTR_GEN_AI_COMPLETION}.0.finish_reason`] = finishReason;
349
+ }
350
+ return attributes;
351
+ }
352
+ function tokenUsageToAttributes(usage) {
353
+ if (!usage) {
354
+ return {};
355
+ }
356
+ const attributes = {};
357
+ if (usage.inputTokens !== void 0) {
358
+ attributes["gen_ai.usage.prompt_tokens"] = usage.inputTokens;
359
+ attributes["gen_ai.usage.input_tokens"] = usage.inputTokens;
360
+ attributes["llm.usage.prompt_tokens"] = usage.inputTokens;
361
+ } else if (usage.promptTokens !== void 0) {
362
+ attributes["gen_ai.usage.prompt_tokens"] = usage.promptTokens;
363
+ attributes["gen_ai.usage.input_tokens"] = usage.promptTokens;
364
+ attributes["llm.usage.prompt_tokens"] = usage.promptTokens;
365
+ }
366
+ if (usage.outputTokens !== void 0) {
367
+ attributes["gen_ai.usage.completion_tokens"] = usage.outputTokens;
368
+ attributes["gen_ai.usage.output_tokens"] = usage.outputTokens;
369
+ attributes["llm.usage.completion_tokens"] = usage.outputTokens;
370
+ } else if (usage.completionTokens !== void 0) {
371
+ attributes["gen_ai.usage.completion_tokens"] = usage.completionTokens;
372
+ attributes["gen_ai.usage.output_tokens"] = usage.completionTokens;
373
+ attributes["llm.usage.completion_tokens"] = usage.completionTokens;
374
+ }
375
+ if (usage.totalTokens === void 0) {
376
+ const inputTokens = usage.inputTokens || usage.promptTokens;
377
+ const outputTokens = usage.outputTokens || usage.completionTokens;
378
+ if (inputTokens !== void 0 && outputTokens !== void 0) {
379
+ const totalTokens = inputTokens + outputTokens;
380
+ attributes["gen_ai.usage.total_tokens"] = totalTokens;
381
+ attributes["llm.usage.total_tokens"] = totalTokens;
382
+ }
383
+ } else {
384
+ attributes["gen_ai.usage.total_tokens"] = usage.totalTokens;
385
+ attributes["llm.usage.total_tokens"] = usage.totalTokens;
386
+ }
387
+ return attributes;
388
+ }
389
+ function shouldRecordError(error) {
390
+ if (error instanceof Error) {
391
+ const message = error.message.toLowerCase();
392
+ if (message.includes("abort") || message.includes("cancel")) {
393
+ return false;
394
+ }
395
+ }
396
+ return true;
397
+ }
398
+ function getEnvBool(name) {
399
+ const value = process.env[name];
400
+ if (value === void 0) {
401
+ return void 0;
402
+ }
403
+ return value.toLowerCase() === "true" || value === "1";
404
+ }
405
+
406
+ // src/internal/instrumentation/vercel-ai/patchers/base-patcher.ts
407
+ var BasePatcher = class {
408
+ constructor(context8) {
409
+ this.context = context8;
410
+ }
411
+ createSpan(spanName, params, operationName, additionalAttributes) {
412
+ const provider = detectProvider(params.model);
413
+ const modelId = extractModelId(params.model);
414
+ const span = this.context.tracer.startSpan(spanName, {
415
+ kind: SpanKind.CLIENT,
416
+ attributes: {
417
+ [ATTR_GEN_AI_SYSTEM]: provider.system,
418
+ [ATTR_GEN_AI_OPERATION_NAME]: operationName,
419
+ [ATTR_GEN_AI_REQUEST_MODEL]: modelId,
420
+ ...params.maxTokens && { [ATTR_GEN_AI_REQUEST_MAX_TOKENS]: params.maxTokens },
421
+ ...params.temperature !== void 0 && {
422
+ [ATTR_GEN_AI_REQUEST_TEMPERATURE]: params.temperature
423
+ },
424
+ ...params.topP !== void 0 && { [ATTR_GEN_AI_REQUEST_TOP_P]: params.topP },
425
+ ...params.topK !== void 0 && { [ATTR_GEN_AI_REQUEST_TOP_K]: params.topK },
426
+ ...params.frequencyPenalty !== void 0 && {
427
+ [ATTR_GEN_AI_REQUEST_FREQUENCY_PENALTY]: params.frequencyPenalty
428
+ },
429
+ ...params.presencePenalty !== void 0 && {
430
+ [ATTR_GEN_AI_REQUEST_PRESENCE_PENALTY]: params.presencePenalty
431
+ },
432
+ ...params.stopSequences && {
433
+ [ATTR_GEN_AI_REQUEST_STOP_SEQUENCES]: params.stopSequences
434
+ },
435
+ ...provider.apiBase && { [ATTR_GEN_AI_OPENAI_API_BASE]: provider.apiBase },
436
+ ...additionalAttributes
437
+ }
438
+ });
439
+ return { span, provider, modelId };
440
+ }
441
+ handleError(error, span) {
442
+ if (shouldRecordError(error)) {
443
+ span.recordException(error);
444
+ span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
445
+ }
446
+ }
447
+ finalizeDuration(span, startTime, config, provider, modelId, operationName) {
448
+ if (config.enableMetrics) {
449
+ const duration = (globalThis.performance.now() - startTime) / 1e3;
450
+ this.context.recordDurationMetric(duration, provider.system, modelId, operationName);
451
+ }
452
+ span.end();
453
+ }
454
+ };
455
+
456
+ // src/internal/instrumentation/vercel-ai/patchers/generate-text-patcher.ts
457
+ import { context, SpanStatusCode as SpanStatusCode2, trace } from "@opentelemetry/api";
458
+ var GenerateTextPatcher = class extends BasePatcher {
459
+ patch(original) {
460
+ return async (params) => {
461
+ const config = this.context.getConfig();
462
+ const startTime = globalThis.performance.now();
463
+ const { span, provider, modelId } = this.createSpan(
464
+ SPAN_NAME_GEN_AI_CHAT,
465
+ params,
466
+ OPERATION_NAME_CHAT
467
+ );
468
+ if (params.prompt) {
469
+ span.setAttributes(
470
+ promptToAttributes(params.prompt, config.captureMessageContent || false)
471
+ );
472
+ } else if (params.messages) {
473
+ span.setAttributes(
474
+ messagesToAttributes(
475
+ params.messages,
476
+ "gen_ai.prompt",
477
+ config.captureMessageContent || false
478
+ )
479
+ );
480
+ if (config.emitEvents) {
481
+ this.context.emitMessageEvents(params.messages, provider.system, span);
482
+ }
483
+ }
484
+ try {
485
+ const result = await context.with(
486
+ trace.setSpan(context.active(), span),
487
+ () => original(params)
488
+ );
489
+ if (result.response) {
490
+ span.setAttributes({
491
+ ...result.response.id && { [ATTR_GEN_AI_RESPONSE_ID]: result.response.id },
492
+ ...result.response.model && { [ATTR_GEN_AI_RESPONSE_MODEL]: result.response.model }
493
+ });
494
+ }
495
+ if (result.finishReason) {
496
+ span.setAttribute(ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [result.finishReason]);
497
+ }
498
+ span.setAttributes(
499
+ completionToAttributes(
500
+ result.text,
501
+ result.finishReason,
502
+ config.captureMessageContent || false
503
+ )
504
+ );
505
+ const usage = result.usage || result.totalUsage || result.steps?.[0]?.usage;
506
+ if (usage) {
507
+ span.setAttributes(tokenUsageToAttributes(usage));
508
+ if (config.enableMetrics) {
509
+ this.context.recordTokenMetrics(usage, provider.system, modelId);
510
+ }
511
+ }
512
+ if (config.emitEvents) {
513
+ this.context.emitAssistantMessageEvent(result.text, provider.system, span);
514
+ }
515
+ span.setStatus({ code: SpanStatusCode2.OK });
516
+ return result;
517
+ } catch (error) {
518
+ this.handleError(error, span);
519
+ throw error;
520
+ } finally {
521
+ this.finalizeDuration(span, startTime, config, provider, modelId, OPERATION_NAME_CHAT);
522
+ }
523
+ };
524
+ }
525
+ };
526
+
527
+ // src/internal/instrumentation/vercel-ai/patchers/stream-text-patcher.ts
528
+ import { context as context2, trace as trace2 } from "@opentelemetry/api";
529
+ var StreamTextPatcher = class extends BasePatcher {
530
+ constructor(context8, streamHandler) {
531
+ super(context8);
532
+ this.streamHandler = streamHandler;
533
+ }
534
+ patch(original) {
535
+ return async (params) => {
536
+ const config = this.context.getConfig();
537
+ const startTime = globalThis.performance.now();
538
+ const { span, provider, modelId } = this.createSpan(
539
+ SPAN_NAME_GEN_AI_CHAT,
540
+ params,
541
+ OPERATION_NAME_CHAT,
542
+ { "gen_ai.streaming": true }
543
+ );
544
+ if (params.prompt) {
545
+ span.setAttributes(
546
+ promptToAttributes(params.prompt, config.captureMessageContent || false)
547
+ );
548
+ } else if (params.messages) {
549
+ span.setAttributes(
550
+ messagesToAttributes(
551
+ params.messages,
552
+ "gen_ai.prompt",
553
+ config.captureMessageContent || false
554
+ )
555
+ );
556
+ if (config.emitEvents) {
557
+ this.context.emitMessageEvents(params.messages, provider.system, span);
558
+ }
559
+ }
560
+ try {
561
+ const stream = await context2.with(
562
+ trace2.setSpan(context2.active(), span),
563
+ () => original(params)
564
+ );
565
+ return this.streamHandler.wrapStream(stream, span, config, provider, modelId, startTime);
566
+ } catch (error) {
567
+ this.handleError(error, span);
568
+ span.end();
569
+ throw error;
570
+ }
571
+ };
572
+ }
573
+ };
574
+
575
+ // src/internal/instrumentation/vercel-ai/patchers/embeddings-patcher.ts
576
+ import { context as context3, SpanStatusCode as SpanStatusCode3, trace as trace3 } from "@opentelemetry/api";
577
+ var EmbeddingsPatcher = class extends BasePatcher {
578
+ patch(original, isMany = false) {
579
+ return async (params) => {
580
+ const config = this.context.getConfig();
581
+ const startTime = globalThis.performance.now();
582
+ const additionalAttributes = isMany ? { "gen_ai.embeddings.count": params.values ? params.values.length : 0 } : {};
583
+ const { span, provider, modelId } = this.createSpan(
584
+ SPAN_NAME_GEN_AI_EMBEDDINGS,
585
+ params,
586
+ OPERATION_NAME_EMBEDDINGS,
587
+ additionalAttributes
588
+ );
589
+ if (!isMany && config.captureMessageContent && params.value) {
590
+ span.setAttribute("gen_ai.prompt.0.content", params.value);
591
+ }
592
+ try {
593
+ const result = await context3.with(
594
+ trace3.setSpan(context3.active(), span),
595
+ () => original(params)
596
+ );
597
+ if (result.response) {
598
+ span.setAttributes({
599
+ ...result.response.id && { [ATTR_GEN_AI_RESPONSE_ID]: result.response.id },
600
+ ...result.response.model && { [ATTR_GEN_AI_RESPONSE_MODEL]: result.response.model }
601
+ });
602
+ }
603
+ if (isMany) {
604
+ if (result.embeddings && result.embeddings.length > 0 && result.embeddings[0]) {
605
+ span.setAttribute("gen_ai.response.embedding_dimensions", result.embeddings[0].length);
606
+ }
607
+ } else {
608
+ if (result.embedding) {
609
+ span.setAttribute("gen_ai.response.embedding_dimensions", result.embedding.length);
610
+ }
611
+ }
612
+ if (result.usage) {
613
+ span.setAttributes(tokenUsageToAttributes(result.usage));
614
+ if (config.enableMetrics) {
615
+ this.context.recordTokenMetrics(result.usage, provider.system, modelId);
616
+ }
617
+ }
618
+ span.setStatus({ code: SpanStatusCode3.OK });
619
+ return result;
620
+ } catch (error) {
621
+ this.handleError(error, span);
622
+ throw error;
623
+ } finally {
624
+ this.finalizeDuration(span, startTime, config, provider, modelId, OPERATION_NAME_EMBEDDINGS);
625
+ }
626
+ };
627
+ }
628
+ };
629
+
630
+ // src/internal/instrumentation/vercel-ai/stream-handler.ts
631
+ import { SpanStatusCode as SpanStatusCode4 } from "@opentelemetry/api";
632
+ var StreamHandler = class {
633
+ constructor(context8) {
634
+ this.context = context8;
635
+ }
636
+ wrapStream(stream, span, config, provider, modelId, startTime) {
637
+ const self = this;
638
+ let fullText = "";
639
+ let finishReason;
640
+ let usage;
641
+ let response;
642
+ const wrappedStream = new Proxy(stream, {
643
+ get(target, prop) {
644
+ if (prop === Symbol.asyncIterator) {
645
+ return async function* () {
646
+ try {
647
+ for await (const chunk of target) {
648
+ if (chunk.type === "text-delta" && chunk.textDelta) {
649
+ fullText += chunk.textDelta;
650
+ } else if (chunk.type === "finish") {
651
+ finishReason = chunk.finishReason;
652
+ usage = chunk.usage;
653
+ } else if (chunk.type === "response-metadata") {
654
+ response = chunk.response;
655
+ }
656
+ yield chunk;
657
+ }
658
+ } finally {
659
+ self.finalizeStream(
660
+ span,
661
+ config,
662
+ provider,
663
+ modelId,
664
+ startTime,
665
+ fullText,
666
+ finishReason,
667
+ usage,
668
+ response
669
+ );
670
+ }
671
+ };
672
+ }
673
+ if (prop === "textStream" || prop === "fullStream") {
674
+ const originalStream = target[prop];
675
+ return {
676
+ [Symbol.asyncIterator]: async function* () {
677
+ try {
678
+ for await (const chunk of originalStream) {
679
+ if (prop === "textStream") {
680
+ fullText += chunk;
681
+ }
682
+ yield chunk;
683
+ }
684
+ } finally {
685
+ const streamUsage = await target.usage.catch(() => null);
686
+ if (streamUsage) {
687
+ usage = streamUsage;
688
+ }
689
+ self.finalizeStream(
690
+ span,
691
+ config,
692
+ provider,
693
+ modelId,
694
+ startTime,
695
+ fullText,
696
+ finishReason,
697
+ usage,
698
+ response
699
+ );
700
+ }
701
+ }
702
+ };
703
+ }
704
+ const value = target[prop];
705
+ if (typeof value === "function") {
706
+ return value.bind(target);
707
+ }
708
+ return value;
709
+ }
710
+ });
711
+ return wrappedStream;
712
+ }
713
+ finalizeStream(span, config, provider, modelId, startTime, fullText, finishReason, usage, response) {
714
+ if (response) {
715
+ span.setAttributes({
716
+ ...response.id && { [ATTR_GEN_AI_RESPONSE_ID]: response.id },
717
+ ...response.model && { [ATTR_GEN_AI_RESPONSE_MODEL]: response.model }
718
+ });
719
+ }
720
+ if (finishReason) {
721
+ span.setAttribute(ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [finishReason]);
722
+ }
723
+ if (fullText) {
724
+ span.setAttributes(
725
+ completionToAttributes(
726
+ fullText,
727
+ finishReason,
728
+ config.captureMessageContent || false
729
+ )
730
+ );
731
+ }
732
+ if (usage) {
733
+ span.setAttributes(tokenUsageToAttributes(usage));
734
+ if (config.enableMetrics) {
735
+ this.context.recordTokenMetrics(usage, provider.system, modelId);
736
+ }
737
+ }
738
+ if (config.enableMetrics) {
739
+ const duration = (performance.now() - startTime) / 1e3;
740
+ this.context.recordDurationMetric(duration, provider.system, modelId, OPERATION_NAME_CHAT);
741
+ }
742
+ span.setStatus({ code: SpanStatusCode4.OK });
743
+ span.end();
744
+ }
745
+ };
746
+
747
+ // src/internal/instrumentation/vercel-ai/telemetry-recorder.ts
748
+ import { context as context4, trace as trace4 } from "@opentelemetry/api";
749
+ import { SeverityNumber } from "@opentelemetry/api-logs";
750
+ var TelemetryRecorder = class {
751
+ constructor(genaiClientOperationDuration, genaiClientTokenUsage, logger2) {
752
+ this.genaiClientOperationDuration = genaiClientOperationDuration;
753
+ this.genaiClientTokenUsage = genaiClientTokenUsage;
754
+ this.logger = logger2;
755
+ }
756
+ /**
757
+ * Record token usage metrics
758
+ */
759
+ recordTokenMetrics(usage, system, model) {
760
+ if (!this.genaiClientTokenUsage) {
761
+ return;
762
+ }
763
+ const commonAttrs = {
764
+ [ATTR_GEN_AI_SYSTEM]: system,
765
+ [ATTR_GEN_AI_REQUEST_MODEL]: model
766
+ };
767
+ const inputTokens = usage.inputTokens || usage.promptTokens;
768
+ const outputTokens = usage.outputTokens || usage.completionTokens;
769
+ if (inputTokens !== void 0) {
770
+ this.genaiClientTokenUsage.record(inputTokens, {
771
+ ...commonAttrs,
772
+ [ATTR_GEN_AI_TOKEN_TYPE]: TOKEN_TYPE_INPUT
773
+ });
774
+ }
775
+ if (outputTokens !== void 0) {
776
+ this.genaiClientTokenUsage.record(outputTokens, {
777
+ ...commonAttrs,
778
+ [ATTR_GEN_AI_TOKEN_TYPE]: TOKEN_TYPE_OUTPUT
779
+ });
780
+ }
781
+ }
782
+ /**
783
+ * Record operation duration metric
784
+ */
785
+ recordDurationMetric(duration, system, model, operation) {
786
+ if (!this.genaiClientOperationDuration) {
787
+ return;
788
+ }
789
+ this.genaiClientOperationDuration.record(duration, {
790
+ [ATTR_GEN_AI_SYSTEM]: system,
791
+ [ATTR_GEN_AI_REQUEST_MODEL]: model,
792
+ [ATTR_GEN_AI_OPERATION_NAME]: operation
793
+ });
794
+ }
795
+ /**
796
+ * Emit message events
797
+ */
798
+ emitMessageEvents(messages, system, span) {
799
+ if (!this.logger) {
800
+ return;
801
+ }
802
+ const ctx = trace4.setSpan(context4.active(), span);
803
+ for (const msg of messages) {
804
+ let eventName;
805
+ switch (msg.role) {
806
+ case "system": {
807
+ eventName = EVENT_GEN_AI_SYSTEM_MESSAGE;
808
+ break;
809
+ }
810
+ case "user": {
811
+ eventName = EVENT_GEN_AI_USER_MESSAGE;
812
+ break;
813
+ }
814
+ case "assistant": {
815
+ eventName = EVENT_GEN_AI_ASSISTANT_MESSAGE;
816
+ break;
817
+ }
818
+ case "tool":
819
+ case "function": {
820
+ eventName = EVENT_GEN_AI_TOOL_MESSAGE;
821
+ break;
822
+ }
823
+ default: {
824
+ continue;
825
+ }
826
+ }
827
+ this.logger.emit({
828
+ timestamp: Date.now(),
829
+ context: ctx,
830
+ severityNumber: SeverityNumber.INFO,
831
+ attributes: {
832
+ [ATTR_EVENT_NAME]: eventName,
833
+ [ATTR_GEN_AI_SYSTEM]: system
834
+ },
835
+ body: {
836
+ role: msg.role,
837
+ content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
838
+ name: msg.name
839
+ }
840
+ });
841
+ }
842
+ }
843
+ /**
844
+ * Emit assistant message event
845
+ */
846
+ emitAssistantMessageEvent(text, system, span) {
847
+ if (!this.logger) {
848
+ return;
849
+ }
850
+ const ctx = trace4.setSpan(context4.active(), span);
851
+ this.logger.emit({
852
+ timestamp: Date.now(),
853
+ context: ctx,
854
+ severityNumber: SeverityNumber.INFO,
855
+ attributes: {
856
+ [ATTR_EVENT_NAME]: EVENT_GEN_AI_ASSISTANT_MESSAGE,
857
+ [ATTR_GEN_AI_SYSTEM]: system
858
+ },
859
+ body: {
860
+ role: "assistant",
861
+ content: text
862
+ }
863
+ });
864
+ }
865
+ };
866
+
867
+ // src/internal/instrumentation/vercel-ai/instrumentation.ts
868
+ var PACKAGE_NAME = "@brizz/vercel-ai-instrumentation";
869
+ var PACKAGE_VERSION = "0.1.0";
870
+ var VercelAIInstrumentation = class _VercelAIInstrumentation extends InstrumentationBase {
871
+ _genaiClientOperationDuration;
872
+ _genaiClientTokenUsage;
873
+ _telemetryRecorder;
874
+ _streamHandler;
875
+ _patchers = /* @__PURE__ */ new Map();
876
+ // Holds last patched namespace when available (reserved for future factory wrapping)
877
+ _vercelAiNamespace = null;
878
+ static _WRAPPED_SYMBOL = Symbol.for("brizz.vercel-ai.patched");
879
+ constructor(config = {}) {
880
+ super(PACKAGE_NAME, PACKAGE_VERSION, config);
881
+ const cfg = this.getConfig();
882
+ const envCC = getEnvBool("OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT");
883
+ if (envCC !== void 0) {
884
+ cfg.captureMessageContent = envCC;
885
+ }
886
+ this._initializeComponents();
887
+ }
888
+ setConfig(config = {}) {
889
+ const {
890
+ captureMessageContent = true,
891
+ enableMetrics = true,
892
+ emitEvents = true,
893
+ ...validConfig
894
+ } = config;
895
+ const fullConfig = {
896
+ ...validConfig,
897
+ captureMessageContent,
898
+ enableMetrics,
899
+ emitEvents
900
+ };
901
+ super.setConfig(fullConfig);
902
+ }
903
+ _initializeComponents() {
904
+ this._telemetryRecorder = new TelemetryRecorder(
905
+ this._genaiClientOperationDuration,
906
+ this._genaiClientTokenUsage,
907
+ this.logger
908
+ );
909
+ this._streamHandler = new StreamHandler({
910
+ recordTokenMetrics: this._telemetryRecorder.recordTokenMetrics.bind(this._telemetryRecorder),
911
+ recordDurationMetric: this._telemetryRecorder.recordDurationMetric.bind(
912
+ this._telemetryRecorder
913
+ )
914
+ });
915
+ const patcherContext = {
916
+ tracer: this.tracer,
917
+ getConfig: this.getConfig.bind(this),
918
+ recordTokenMetrics: this._telemetryRecorder.recordTokenMetrics.bind(this._telemetryRecorder),
919
+ recordDurationMetric: this._telemetryRecorder.recordDurationMetric.bind(
920
+ this._telemetryRecorder
921
+ ),
922
+ emitMessageEvents: this._telemetryRecorder.emitMessageEvents.bind(this._telemetryRecorder),
923
+ emitAssistantMessageEvent: this._telemetryRecorder.emitAssistantMessageEvent.bind(
924
+ this._telemetryRecorder
925
+ )
926
+ };
927
+ this._patchers.set("generateText", new GenerateTextPatcher(patcherContext));
928
+ this._patchers.set("streamText", new StreamTextPatcher(patcherContext, this._streamHandler));
929
+ this._patchers.set("embed", new EmbeddingsPatcher(patcherContext));
930
+ this._patchers.set("embedMany", new EmbeddingsPatcher(patcherContext));
931
+ }
932
+ init() {
933
+ return [
934
+ new InstrumentationNodeModuleDefinition(
935
+ "ai",
936
+ [">=4.0.0 <6"],
937
+ (moduleExports) => {
938
+ logger.info("Starting instrumentation of Vercel AI SDK module");
939
+ this._vercelAiNamespace = moduleExports;
940
+ const patched = this._patchModuleExports(moduleExports);
941
+ return patched ?? moduleExports;
942
+ },
943
+ (moduleExports) => {
944
+ logger.debug("Uninstrumenting @vercel/ai module");
945
+ return moduleExports;
946
+ }
947
+ )
948
+ ];
949
+ }
950
+ _updateMetricInstruments() {
951
+ const config = this.getConfig();
952
+ if (!config.enableMetrics) {
953
+ return;
954
+ }
955
+ this._genaiClientOperationDuration = this.meter.createHistogram(
956
+ METRIC_GEN_AI_CLIENT_OPERATION_DURATION,
957
+ {
958
+ description: "GenAI operation duration",
959
+ unit: "s",
960
+ advice: {
961
+ explicitBucketBoundaries: [
962
+ 0.01,
963
+ 0.02,
964
+ 0.04,
965
+ 0.08,
966
+ 0.16,
967
+ 0.32,
968
+ 0.64,
969
+ 1.28,
970
+ 2.56,
971
+ 5.12,
972
+ 10.24,
973
+ 20.48,
974
+ 40.96,
975
+ 81.92
976
+ ]
977
+ }
978
+ }
979
+ );
980
+ this._genaiClientTokenUsage = this.meter.createHistogram(METRIC_GEN_AI_CLIENT_TOKEN_USAGE, {
981
+ description: "Measures number of input and output tokens used",
982
+ unit: "{token}",
983
+ advice: {
984
+ explicitBucketBoundaries: [
985
+ 1,
986
+ 4,
987
+ 16,
988
+ 64,
989
+ 256,
990
+ 1024,
991
+ 4096,
992
+ 16384,
993
+ 65536,
994
+ 262144,
995
+ 1048576,
996
+ 4194304,
997
+ 16777216,
998
+ 67108864
999
+ ]
1000
+ }
1001
+ });
1002
+ this._telemetryRecorder = new TelemetryRecorder(
1003
+ this._genaiClientOperationDuration,
1004
+ this._genaiClientTokenUsage,
1005
+ this.logger
1006
+ );
1007
+ }
1008
+ /**
1009
+ * Patch known AI SDK functions in-place on the provided module exports object.
1010
+ * This approach is compatible with both CJS and ESM module loaders.
1011
+ */
1012
+ _patchModuleExports(moduleExports) {
1013
+ if (!moduleExports || typeof moduleExports !== "object") {
1014
+ return null;
1015
+ }
1016
+ let inPlacePatched = true;
1017
+ const wrapFunction = (name, isEmbedMany = false) => {
1018
+ const current = moduleExports[name];
1019
+ if (typeof current !== "function") {
1020
+ return;
1021
+ }
1022
+ const currentFn = current;
1023
+ if (currentFn[_VercelAIInstrumentation._WRAPPED_SYMBOL]) {
1024
+ return;
1025
+ }
1026
+ const descriptor = Object.getOwnPropertyDescriptor(moduleExports, name);
1027
+ if (descriptor && (!descriptor.writable || !descriptor.configurable) && !descriptor.set) {
1028
+ inPlacePatched = false;
1029
+ return;
1030
+ }
1031
+ const patcher = this._patchers.get(name);
1032
+ if (!patcher) {
1033
+ return;
1034
+ }
1035
+ const patched = isEmbedMany ? patcher.patch(currentFn, true) : patcher.patch(currentFn);
1036
+ try {
1037
+ Object.defineProperty(patched, _VercelAIInstrumentation._WRAPPED_SYMBOL, {
1038
+ value: true,
1039
+ enumerable: false,
1040
+ configurable: false
1041
+ });
1042
+ } catch {
1043
+ }
1044
+ try {
1045
+ moduleExports[name] = patched;
1046
+ } catch {
1047
+ inPlacePatched = false;
1048
+ }
1049
+ };
1050
+ wrapFunction("generateText");
1051
+ wrapFunction("streamText");
1052
+ wrapFunction("embed");
1053
+ wrapFunction("embedMany", true);
1054
+ if (!inPlacePatched) {
1055
+ const proxiedModule = new Proxy(moduleExports, {
1056
+ get: (target, prop, receiver) => {
1057
+ const originalValue = Reflect.get(target, prop, receiver);
1058
+ if (typeof originalValue === "function" && typeof prop === "string" && this._patchers.has(prop)) {
1059
+ const patcher = this._patchers.get(prop);
1060
+ const isEmbedMany = prop === "embedMany";
1061
+ const wrapped = isEmbedMany ? patcher.patch(originalValue, true) : patcher.patch(originalValue);
1062
+ return wrapped;
1063
+ }
1064
+ return originalValue;
1065
+ }
1066
+ });
1067
+ return proxiedModule;
1068
+ }
1069
+ return moduleExports;
1070
+ }
1071
+ /**
1072
+ * Manual instrumentation hook for bundlers/Next.js. Applies in-place wrapping
1073
+ * on the provided module namespace.
1074
+ */
1075
+ manuallyInstrument(module3) {
1076
+ try {
1077
+ const result = this._patchModuleExports(module3);
1078
+ if (result !== null) {
1079
+ logger.debug("Applied manual Vercel AI instrumentation");
1080
+ this._vercelAiNamespace = result;
1081
+ return result;
1082
+ }
1083
+ logger.warn("Manual Vercel AI instrumentation received invalid module");
1084
+ return module3;
1085
+ } catch (error) {
1086
+ logger.error(`Failed manual Vercel AI instrumentation: ${String(error)}`);
1087
+ return this._vercelAiNamespace || module3;
1088
+ }
1089
+ }
1090
+ /**
1091
+ * Wrap a created provider/client instance (factory return) when possible.
1092
+ * Call this from wrappers that construct provider clients (e.g., OpenAI SDK).
1093
+ */
1094
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1095
+ wrapFactoryReturn(instance) {
1096
+ return instance;
1097
+ }
1098
+ };
1099
+
1100
+ // src/internal/instrumentation/auto-init.ts
1101
+ var autoInstrumentationsLoaded = false;
1102
+ var exceptionLogger = (error) => {
1103
+ logger.error(`Exception in instrumentation: ${String(error)}`);
1104
+ };
1105
+ function loadNodeAutoInstrumentations() {
1106
+ try {
1107
+ const nodeInstrumentations = getNodeAutoInstrumentations();
1108
+ registerInstrumentations({ instrumentations: nodeInstrumentations });
1109
+ return nodeInstrumentations;
1110
+ } catch (error) {
1111
+ logger.error(`Failed to load Node.js auto-instrumentations: ${String(error)}`);
1112
+ return [];
1113
+ }
1114
+ }
1115
+ function loadGenAIInstrumentations() {
1116
+ const instrumentations = [];
1117
+ const genAIInstrumentationClasses = [
1118
+ { class: VercelAIInstrumentation, name: "Vercel AI" },
1119
+ // Load first to avoid conflicts
1120
+ { class: OpenAIInstrumentation, name: "OpenAI" },
1121
+ { class: AnthropicInstrumentation, name: "Anthropic" },
1122
+ { class: CohereInstrumentation, name: "Cohere" },
1123
+ { class: VertexAIInstrumentation, name: "Vertex AI" },
1124
+ { class: BedrockInstrumentation, name: "Bedrock" },
1125
+ { class: PineconeInstrumentation, name: "Pinecone" },
1126
+ { class: LangChainInstrumentation, name: "LangChain" },
1127
+ { class: LlamaIndexInstrumentation, name: "LlamaIndex" },
1128
+ { class: ChromaDBInstrumentation, name: "ChromaDB" },
1129
+ { class: QdrantInstrumentation, name: "Qdrant" },
1130
+ { class: TogetherInstrumentation, name: "Together" }
1131
+ ];
1132
+ for (const config of genAIInstrumentationClasses) {
1133
+ try {
1134
+ const instrumentation = new config.class({ exceptionLogger });
1135
+ instrumentations.push(instrumentation);
1136
+ logger.debug(`Auto-loaded ${config.name} instrumentation`);
1137
+ } catch (error) {
1138
+ logger.error(`Failed to auto-load ${config.name} instrumentation: ${String(error)}`);
1139
+ }
1140
+ }
1141
+ try {
1142
+ registerInstrumentations({ instrumentations });
1143
+ logger.info(`Auto-registered ${instrumentations.length} GenAI instrumentations`);
1144
+ } catch (error) {
1145
+ logger.error(`Failed to register GenAI instrumentations: ${String(error)}`);
1146
+ }
1147
+ return instrumentations;
1148
+ }
1149
+ function autoInitializeInstrumentations() {
1150
+ if (autoInstrumentationsLoaded) {
1151
+ return;
1152
+ }
1153
+ try {
1154
+ const nodeInstrumentations = loadNodeAutoInstrumentations();
1155
+ const genAIInstrumentations = loadGenAIInstrumentations();
1156
+ autoInstrumentationsLoaded = true;
1157
+ logger.info(
1158
+ `Auto-initialization complete: ${nodeInstrumentations.length} node + ${genAIInstrumentations.length} GenAI instrumentations`
1159
+ );
1160
+ } catch (error) {
1161
+ logger.error(`Auto-initialization failed: ${String(error)}`);
1162
+ autoInstrumentationsLoaded = false;
1163
+ }
1164
+ }
1165
+ autoInitializeInstrumentations();
1166
+
1167
+ // src/internal/sdk.ts
1168
+ import { resourceFromAttributes as resourceFromAttributes2 } from "@opentelemetry/resources";
1169
+ import { NodeSDK } from "@opentelemetry/sdk-node";
1170
+
1171
+ // src/internal/config.ts
1172
+ function resolveConfig(options) {
1173
+ const envLogLevel = process.env["BRIZZ_LOG_LEVEL"] || options.logLevel?.toString() || DEFAULT_LOG_LEVEL.toString();
1174
+ let resolvedLogLevel;
1175
+ if (envLogLevel) {
1176
+ resolvedLogLevel = parseLogLevel(envLogLevel);
1177
+ } else if (typeof options.logLevel === "string") {
1178
+ resolvedLogLevel = parseLogLevel(options.logLevel);
1179
+ } else {
1180
+ resolvedLogLevel = options.logLevel || DEFAULT_LOG_LEVEL;
1181
+ }
1182
+ setLogLevel(resolvedLogLevel);
1183
+ let maskingStatus;
1184
+ if (options.masking === true) {
1185
+ maskingStatus = "enabled";
1186
+ } else if (options.masking === false) {
1187
+ maskingStatus = "disabled";
1188
+ } else if (typeof options.masking === "object") {
1189
+ maskingStatus = "custom";
1190
+ } else {
1191
+ maskingStatus = "default-disabled";
1192
+ }
1193
+ logger.debug("Starting configuration resolution", {
1194
+ appName: options.appName,
1195
+ baseUrl: options.baseUrl,
1196
+ hasApiKey: !!options.apiKey,
1197
+ disableBatch: options.disableBatch,
1198
+ logLevel: resolvedLogLevel,
1199
+ headersCount: Object.keys(options.headers || {}).length,
1200
+ masking: maskingStatus
1201
+ });
1202
+ let resolvedMasking;
1203
+ if (options.masking === true) {
1204
+ resolvedMasking = {
1205
+ spanMasking: {},
1206
+ eventMasking: {}
1207
+ };
1208
+ } else if (options.masking && typeof options.masking === "object") {
1209
+ resolvedMasking = options.masking;
1210
+ }
1211
+ const resolvedConfig = {
1212
+ ...options,
1213
+ appName: process.env["BRIZZ_APP_NAME"] || options.appName || "unknown-app",
1214
+ baseUrl: process.env["BRIZZ_BASE_URL"] || options.baseUrl || "https://telemetry.brizz.dev",
1215
+ headers: { ...options.headers },
1216
+ apiKey: process.env["BRIZZ_API_KEY"] || options.apiKey,
1217
+ disableBatch: process.env["BRIZZ_DISABLE_BATCH"] === "true" || !!options.disableBatch,
1218
+ logLevel: resolvedLogLevel,
1219
+ masking: resolvedMasking
1220
+ };
1221
+ if (resolvedConfig.apiKey) {
1222
+ resolvedConfig.headers["Authorization"] = `Bearer ${resolvedConfig.apiKey}`;
1223
+ }
1224
+ if (process.env["BRIZZ_HEADERS"]) {
1225
+ try {
1226
+ const envHeaders = JSON.parse(process.env["BRIZZ_HEADERS"]);
1227
+ Object.assign(resolvedConfig.headers, envHeaders);
1228
+ logger.debug("Added headers from environment variable", {
1229
+ headers: Object.keys(envHeaders)
1230
+ });
1231
+ } catch (error) {
1232
+ logger.error("Failed to parse BRIZZ_HEADERS environment variable", { error });
1233
+ throw new Error("Invalid JSON in BRIZZ_HEADERS environment variable");
1234
+ }
1235
+ }
1236
+ logger.debug("Configuration resolved with environment variables", {
1237
+ appName: resolvedConfig.appName,
1238
+ baseUrl: resolvedConfig.baseUrl,
1239
+ hasApiKey: !!resolvedConfig.apiKey,
1240
+ disableBatch: resolvedConfig.disableBatch,
1241
+ envOverrides: {
1242
+ hasEnvApiKey: !!process.env["BRIZZ_API_KEY"],
1243
+ hasEnvBaseUrl: !!process.env["BRIZZ_BASE_URL"],
1244
+ hasEnvBatch: !!process.env["BRIZZ_DISABLE_BATCH"],
1245
+ hasEnvHeaders: !!process.env["BRIZZ_HEADERS"]
1246
+ }
1247
+ });
1248
+ return resolvedConfig;
1249
+ }
1250
+
1251
+ // src/internal/instrumentation/registry.ts
1252
+ import { AnthropicInstrumentation as AnthropicInstrumentation2 } from "@traceloop/instrumentation-anthropic";
1253
+ import { BedrockInstrumentation as BedrockInstrumentation2 } from "@traceloop/instrumentation-bedrock";
1254
+ import { ChromaDBInstrumentation as ChromaDBInstrumentation2 } from "@traceloop/instrumentation-chromadb";
1255
+ import { CohereInstrumentation as CohereInstrumentation2 } from "@traceloop/instrumentation-cohere";
1256
+ import { LangChainInstrumentation as LangChainInstrumentation2 } from "@traceloop/instrumentation-langchain";
1257
+ import { LlamaIndexInstrumentation as LlamaIndexInstrumentation2 } from "@traceloop/instrumentation-llamaindex";
1258
+ import { OpenAIInstrumentation as OpenAIInstrumentation2 } from "@traceloop/instrumentation-openai";
1259
+ import { PineconeInstrumentation as PineconeInstrumentation2 } from "@traceloop/instrumentation-pinecone";
1260
+ import { QdrantInstrumentation as QdrantInstrumentation2 } from "@traceloop/instrumentation-qdrant";
1261
+ import { TogetherInstrumentation as TogetherInstrumentation2 } from "@traceloop/instrumentation-together";
1262
+ import { VertexAIInstrumentation as VertexAIInstrumentation2 } from "@traceloop/instrumentation-vertexai";
1263
+ var InstrumentationRegistry = class _InstrumentationRegistry {
1264
+ static instance;
1265
+ manualModules = null;
1266
+ static getInstance() {
1267
+ if (!_InstrumentationRegistry.instance) {
1268
+ _InstrumentationRegistry.instance = new _InstrumentationRegistry();
1269
+ }
1270
+ return _InstrumentationRegistry.instance;
1271
+ }
1272
+ /**
1273
+ * Set manual instrumentation modules for Next.js/Webpack environments
1274
+ */
1275
+ setManualModules(modules) {
1276
+ this.manualModules = modules;
1277
+ logger.info("Manual instrumentation modules configured for Next.js/Webpack compatibility");
1278
+ }
1279
+ /**
1280
+ * Helper to load instrumentation with optional manual module
1281
+ */
1282
+ loadInstrumentation(InstrumentationClass, name, manualModule, exceptionLogger2) {
1283
+ try {
1284
+ const inst = new InstrumentationClass({
1285
+ exceptionLogger: exceptionLogger2 || ((error) => logger.error(`Exception in instrumentation: ${String(error)}`))
1286
+ });
1287
+ if (manualModule) {
1288
+ inst.manuallyInstrument(manualModule);
1289
+ logger.debug(`Manual instrumentation enabled for ${name}`);
1290
+ }
1291
+ return inst;
1292
+ } catch (error) {
1293
+ logger.error(`Failed to load ${name} instrumentation: ${String(error)}`);
1294
+ return null;
1295
+ }
1296
+ }
1297
+ /**
1298
+ * Get manual instrumentations only.
1299
+ * Auto-instrumentations are handled at import time.
1300
+ */
1301
+ getManualInstrumentations() {
1302
+ if (!this.manualModules || Object.keys(this.manualModules).length === 0) {
1303
+ logger.debug("No manual instrumentation modules configured");
1304
+ return [];
1305
+ }
1306
+ const instrumentations = [];
1307
+ const exceptionLogger2 = (error) => {
1308
+ logger.error(`Exception in manual instrumentation: ${String(error)}`);
1309
+ };
1310
+ this.loadManualInstrumentations(instrumentations, exceptionLogger2);
1311
+ logger.info(`Loaded ${instrumentations.length} manual instrumentations`);
1312
+ return instrumentations;
1313
+ }
1314
+ /**
1315
+ * Load manual instrumentations only (with modules provided by user).
1316
+ * @private
1317
+ */
1318
+ loadManualInstrumentations(instrumentations, exceptionLogger2) {
1319
+ const instrumentationConfigs = [
1320
+ { class: OpenAIInstrumentation2, name: "OpenAI", module: this.manualModules?.openAI },
1321
+ { class: AnthropicInstrumentation2, name: "Anthropic", module: this.manualModules?.anthropic },
1322
+ { class: CohereInstrumentation2, name: "Cohere", module: this.manualModules?.cohere },
1323
+ {
1324
+ class: VertexAIInstrumentation2,
1325
+ name: "Vertex AI",
1326
+ module: this.manualModules?.google_vertexai
1327
+ },
1328
+ { class: BedrockInstrumentation2, name: "Bedrock", module: this.manualModules?.bedrock },
1329
+ { class: PineconeInstrumentation2, name: "Pinecone", module: this.manualModules?.pinecone },
1330
+ { class: LangChainInstrumentation2, name: "LangChain", module: this.manualModules?.langchain },
1331
+ {
1332
+ class: LlamaIndexInstrumentation2,
1333
+ name: "LlamaIndex",
1334
+ module: this.manualModules?.llamaindex
1335
+ },
1336
+ { class: ChromaDBInstrumentation2, name: "ChromaDB", module: this.manualModules?.chromadb },
1337
+ { class: QdrantInstrumentation2, name: "Qdrant", module: this.manualModules?.qdrant },
1338
+ { class: TogetherInstrumentation2, name: "Together", module: this.manualModules?.together },
1339
+ { class: VercelAIInstrumentation, name: "Vercel AI", module: this.manualModules?.vercelAI }
1340
+ ];
1341
+ for (const config of instrumentationConfigs) {
1342
+ if (config.module) {
1343
+ const instrumentation = this.loadInstrumentation(
1344
+ config.class,
1345
+ config.name,
1346
+ config.module,
1347
+ exceptionLogger2
1348
+ );
1349
+ if (instrumentation) {
1350
+ instrumentations.push(instrumentation);
1351
+ }
1352
+ }
1353
+ }
1354
+ }
1355
+ };
1356
+
1357
+ // src/internal/log/logging.ts
1358
+ import { SeverityNumber as SeverityNumber2 } from "@opentelemetry/api-logs";
1359
+ import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
1360
+ import { resourceFromAttributes } from "@opentelemetry/resources";
1361
+ import {
1362
+ LoggerProvider
1363
+ } from "@opentelemetry/sdk-logs";
1364
+
1365
+ // src/internal/log/processors/log-processor.ts
1366
+ import { context as context5 } from "@opentelemetry/api";
1367
+ import { BatchLogRecordProcessor, SimpleLogRecordProcessor } from "@opentelemetry/sdk-logs";
1368
+
1369
+ // src/internal/masking/patterns.ts
1370
+ var DEFAULT_PII_PATTERNS = [
1371
+ // Email addresses
1372
+ {
1373
+ name: "email_addresses",
1374
+ pattern: String.raw`\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b`
1375
+ },
1376
+ // Phone numbers (US format)
1377
+ {
1378
+ name: "us_phone_numbers",
1379
+ pattern: String.raw`(?:^|[\s])(?:\+?1[-.\s]*)?(?:\([0-9]{3}\)\s?[0-9]{3}[-.\s]?[0-9]{4}|[0-9]{3}[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}|[0-9]{10})(?=[\s]|$)`
1380
+ },
1381
+ // Social Security Numbers
1382
+ {
1383
+ name: "ssn",
1384
+ pattern: String.raw`\b(?!000|666|9\d{2})\d{3}[-\s]?(?!00)\d{2}[-\s]?(?!0000)\d{4}\b`
1385
+ },
1386
+ // Credit card numbers
1387
+ {
1388
+ name: "credit_cards",
1389
+ pattern: String.raw`\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\\d{3})\\d{11})\b`
1390
+ },
1391
+ {
1392
+ name: "credit_cards_with_separators",
1393
+ pattern: String.raw`\b(?:4\\d{3}|5[1-5]\\d{2}|3[47]\\d{2})[-\s]?\\d{4}[-\s]?\\d{4}[-\s]?\\d{4}\b`
1394
+ },
1395
+ // IP addresses (IPv4)
1396
+ {
1397
+ name: "ipv4_addresses",
1398
+ pattern: String.raw`\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?!\.[0-9])\b`
1399
+ },
1400
+ // API keys/tokens
1401
+ {
1402
+ name: "generic_api_keys",
1403
+ pattern: String.raw`\b(?:[Aa][Pp][Ii][_-]?[Kk][Ee][Yy]|[Tt][Oo][Kk][Ee][Nn]|[Ss][Ee][Cc][Rr][Ee][Tt])[_-]?[=:]?\s*["']?(?:[a-zA-Z0-9\-_.]{20,})["']?\b`
1404
+ },
1405
+ {
1406
+ name: "openai_keys",
1407
+ pattern: String.raw`\bsk[-_][a-zA-Z0-9]{20,}\b`
1408
+ },
1409
+ {
1410
+ name: "base64_secrets",
1411
+ pattern: String.raw`\b[A-Za-z0-9+/]{64,}={0,2}\b`
1412
+ },
1413
+ // AWS Keys
1414
+ {
1415
+ name: "aws_access_keys",
1416
+ pattern: String.raw`\b(?:AKIA|ABIA|ACCA|ASIA)[0-9A-Z]{16}\b`
1417
+ },
1418
+ {
1419
+ name: "aws_secret_keys",
1420
+ pattern: String.raw`\b[A-Za-z0-9/+=]*[A-Z][A-Za-z0-9/+=]*[a-z][A-Za-z0-9/+=]*[/+=][A-Za-z0-9/+=]{30,}\b`
1421
+ },
1422
+ // GitHub tokens
1423
+ {
1424
+ name: "github_tokens",
1425
+ pattern: String.raw`\bghp_[a-zA-Z0-9]{36}\b`
1426
+ },
1427
+ // Slack tokens
1428
+ {
1429
+ name: "slack_tokens",
1430
+ pattern: String.raw`\bxox[baprs]-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24,34}\b`
1431
+ },
1432
+ // Stripe keys
1433
+ {
1434
+ name: "stripe_keys",
1435
+ pattern: String.raw`\b(?:sk|pk)_(?:test|live)_[a-zA-Z0-9]{24,}\b`
1436
+ },
1437
+ // JWT tokens
1438
+ {
1439
+ name: "jwt_tokens",
1440
+ pattern: String.raw`\beyJ[A-Za-z0-9_-]{2,}\\.[A-Za-z0-9_-]{2,}\\.[A-Za-z0-9_-]{2,}\b`
1441
+ },
1442
+ // MAC addresses
1443
+ {
1444
+ name: "mac_addresses",
1445
+ pattern: String.raw`\b(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\b`
1446
+ },
1447
+ // IPv6 addresses
1448
+ {
1449
+ name: "ipv6_addresses",
1450
+ pattern: String.raw`\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b`
1451
+ },
1452
+ // Medical records
1453
+ {
1454
+ name: "medical_record_numbers",
1455
+ pattern: String.raw`\b(?:[Mm][Rr][Nn])[-\s]?\d{6,10}\b`
1456
+ },
1457
+ // Bitcoin addresses
1458
+ {
1459
+ name: "bitcoin_addresses",
1460
+ pattern: String.raw`\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\b`
1461
+ },
1462
+ // Ethereum addresses
1463
+ {
1464
+ name: "ethereum_addresses",
1465
+ pattern: String.raw`\b0x[a-fA-F0-9]{40}(?![a-fA-F0-9])\b`
1466
+ },
1467
+ // UUIDs
1468
+ {
1469
+ name: "uuids",
1470
+ pattern: String.raw`\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}(?![0-9a-fA-F-])\b`
1471
+ },
1472
+ // Database connection strings
1473
+ {
1474
+ name: "database_connections",
1475
+ pattern: String.raw`\b(?:[Mm][Oo][Nn][Gg][Oo][Dd][Bb]|[Pp][Oo][Ss][Tt][Gg][Rr][Ee][Ss]|[Mm][Yy][Ss][Qq][Ll]|[Rr][Ee][Dd][Ii][Ss]|[Mm][Ss][Ss][Qq][Ll]|[Oo][Rr][Aa][Cc][Ll][Ee]):\\/\\/[^\\s]+\b`
1476
+ },
1477
+ // Private keys
1478
+ {
1479
+ name: "rsa_private_keys",
1480
+ pattern: "-----BEGIN (?:RSA )?PRIVATE KEY-----"
1481
+ },
1482
+ {
1483
+ name: "pgp_private_keys",
1484
+ pattern: "-----BEGIN PGP PRIVATE KEY BLOCK-----"
1485
+ },
1486
+ {
1487
+ name: "certificates",
1488
+ pattern: "-----BEGIN CERTIFICATE-----"
1489
+ },
1490
+ // Date of birth patterns
1491
+ {
1492
+ name: "date_of_birth_us",
1493
+ pattern: String.raw`\b(?:0[1-9]|1[0-2])[-/](?:0[1-9]|[12]\\d|3[01])[-/](?:19|20)\\d{2}\b`
1494
+ },
1495
+ {
1496
+ name: "date_of_birth_iso",
1497
+ pattern: String.raw`\b(?:19|20)\\d{2}[-/](?:0[1-9]|1[0-2])[-/](?:0[1-9]|[12]\\d|3[01])\b`
1498
+ },
1499
+ // US Identification Numbers
1500
+ {
1501
+ name: "us_passport_numbers",
1502
+ pattern: String.raw`\b[A-Z]?\\d{6,9}\b`
1503
+ },
1504
+ {
1505
+ name: "drivers_license",
1506
+ pattern: String.raw`\b[A-Z]{1,2}\\d{3,8}[-\s]?\\d{2,5}[-\s]?\\d{2,5}[-\s]?\\d{1,5}[-\s]?\\d?\b`
1507
+ },
1508
+ {
1509
+ name: "bank_account_numbers",
1510
+ pattern: String.raw`\b\\d{10,17}\b`
1511
+ },
1512
+ {
1513
+ name: "aba_routing_numbers",
1514
+ pattern: String.raw`\b((0[0-9])|(1[0-2])|(2[1-9])|(3[0-2])|(6[1-9])|(7[0-2])|80)([0-9]{7})\b`
1515
+ },
1516
+ {
1517
+ name: "health_insurance_numbers",
1518
+ pattern: String.raw`\b\\d{10}[A-Z]\b`
1519
+ },
1520
+ {
1521
+ name: "employee_ids",
1522
+ pattern: String.raw`\b(?:[Ee][Mm][Pp]|[Ee][Mm][Pp][Ll][Oo][Yy][Ee][Ee]|[Ee])[-\s]?\\d{5,8}\b`
1523
+ },
1524
+ {
1525
+ name: "tax_ein",
1526
+ pattern: String.raw`\b\\d{2}-\\d{7}\b`
1527
+ },
1528
+ {
1529
+ name: "medicare_beneficiary_id",
1530
+ pattern: String.raw`\b[1-9][A-Z][A-Z0-9]\\d-[A-Z][A-Z0-9]\\d-[A-Z][A-Z0-9]\\d{2}\b`
1531
+ },
1532
+ {
1533
+ name: "national_provider_id",
1534
+ pattern: String.raw`\b1\\d{9}\b`
1535
+ },
1536
+ {
1537
+ name: "dea_numbers",
1538
+ pattern: String.raw`\b[A-Z]{2}\\d{7}\b`
1539
+ },
1540
+ {
1541
+ name: "itin",
1542
+ pattern: String.raw`\b9\\d{2}(?:[ \\-]?)[7,8]\\d(?:[ \\-]?)\\d{4}\b`
1543
+ },
1544
+ // Vehicle and Location
1545
+ {
1546
+ name: "vin_numbers",
1547
+ pattern: String.raw`\b[A-HJ-NPR-Z0-9]{17}\b`
1548
+ },
1549
+ {
1550
+ name: "coordinates",
1551
+ pattern: String.raw`\b[-+]?(?:[0-8]?\\d(?:\\.\\d+)?|90(?:\\.0+)?),\\s*[-+]?(?:1[0-7]\\d(?:\\.\\d+)?|180(?:\\.0+)?|[0-9]?\\d(?:\\.\\d+)?)\b`
1552
+ },
1553
+ {
1554
+ name: "us_license_plates",
1555
+ pattern: String.raw`\b[A-Z]{1,3}[-\s]\\d{1,4}[A-Z]?\b|\b\\d{1,2}[A-Z]{1,3}\\d{1,4}\b`
1556
+ },
1557
+ {
1558
+ name: "us_zip_codes",
1559
+ pattern: String.raw`\b(\\d{5}-\\d{4}|\\d{5})\b`
1560
+ },
1561
+ {
1562
+ name: "us_street_addresses",
1563
+ pattern: String.raw`\b\\d{1,8}\b[\\s\\S]{10,100}?\b(AK|AL|AR|AZ|CA|CO|CT|DC|DE|FL|GA|HI|IA|ID|IL|IN|KS|KY|LA|MA|MD|ME|MI|MN|MO|MS|MT|NC|ND|NE|NH|NJ|NM|NV|NY|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VA|VT|WA|WI|WV|WY)\b\\s\\d{5}\b`
1564
+ },
1565
+ // International Banking
1566
+ {
1567
+ name: "iban",
1568
+ pattern: String.raw`\b[A-Z]{2}\d{2}[A-Z0-9]{4}\d{7}([A-Z0-9]?){0,16}\b`
1569
+ },
1570
+ {
1571
+ name: "swift_bic",
1572
+ pattern: String.raw`\b[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?\b`
1573
+ },
1574
+ // Additional API Keys and Tokens
1575
+ {
1576
+ name: "google_oauth",
1577
+ pattern: String.raw`\bya29\\.[a-zA-Z0-9_-]{60,}\b`
1578
+ },
1579
+ {
1580
+ name: "firebase_tokens",
1581
+ pattern: String.raw`\bAAAA[A-Za-z0-9_-]{100,}\b`
1582
+ },
1583
+ {
1584
+ name: "google_app_ids",
1585
+ pattern: String.raw`\b[0-9]+-\w+\.apps\.googleusercontent\.com\b`
1586
+ },
1587
+ {
1588
+ name: "facebook_secrets",
1589
+ pattern: String.raw`\b(facebook_secret|FACEBOOK_SECRET|facebook_app_secret|FACEBOOK_APP_SECRET)[a-z_ =\\s"'\\:]{0,5}[^a-zA-Z0-9][a-f0-9]{32}[^a-zA-Z0-9]`
1590
+ },
1591
+ {
1592
+ name: "github_keys",
1593
+ pattern: String.raw`\b(GITHUB_SECRET|GITHUB_KEY|github_secret|github_key|github_token|GITHUB_TOKEN|github_api_key|GITHUB_API_KEY)[a-z_ =\\s\"'\\:]{0,10}[^a-zA-Z0-9][a-zA-Z0-9]{40}[^a-zA-Z0-9]`
1594
+ },
1595
+ {
1596
+ name: "heroku_keys",
1597
+ pattern: String.raw`\b(heroku_api_key|HEROKU_API_KEY|heroku_secret|HEROKU_SECRET)[a-z_ =\\s\"'\\:]{0,10}[^a-zA-Z0-9-]\\w{8}(?:-\\w{4}){3}-\\w{12}[^a-zA-Z0-9\\-]`
1598
+ },
1599
+ {
1600
+ name: "slack_api_keys",
1601
+ pattern: String.raw`\b(slack_api_key|SLACK_API_KEY|slack_key|SLACK_KEY)[a-z_ =\\s\"'\\:]{0,10}[^a-f0-9][a-f0-9]{32}[^a-f0-9]`
1602
+ },
1603
+ {
1604
+ name: "slack_api_tokens",
1605
+ pattern: String.raw`\b(xox[pb](?:-[a-zA-Z0-9]+){4,})\b`
1606
+ },
1607
+ // Extended Private Keys and Certificates
1608
+ {
1609
+ name: "dsa_private_keys",
1610
+ pattern: String.raw`-----BEGIN DSA PRIVATE KEY-----(?:[a-zA-Z0-9\+\=\/"']|\s)+?-----END DSA PRIVATE KEY-----`
1611
+ },
1612
+ {
1613
+ name: "ec_private_keys",
1614
+ pattern: String.raw`-----BEGIN (?:EC|ECDSA) PRIVATE KEY-----(?:[a-zA-Z0-9\+\=\/"']|\s)+?-----END (?:EC|ECDSA) PRIVATE KEY-----`
1615
+ },
1616
+ {
1617
+ name: "encrypted_private_keys",
1618
+ pattern: String.raw`-----BEGIN ENCRYPTED PRIVATE KEY-----(?:.|\s)+?-----END ENCRYPTED PRIVATE KEY-----`
1619
+ },
1620
+ {
1621
+ name: "ssl_certificates",
1622
+ pattern: String.raw`-----BEGIN CERTIFICATE-----(?:.|\n)+?\s-----END CERTIFICATE-----`
1623
+ },
1624
+ {
1625
+ name: "ssh_dss_public",
1626
+ pattern: String.raw`\bssh-dss [0-9A-Za-z+/]+[=]{2}\b`
1627
+ },
1628
+ {
1629
+ name: "ssh_rsa_public",
1630
+ pattern: String.raw`\bssh-rsa AAAA[0-9A-Za-z+/]+[=]{0,3} [^@]+@[^@]+\b`
1631
+ },
1632
+ {
1633
+ name: "putty_ssh_keys",
1634
+ pattern: String.raw`PuTTY-User-Key-File-2: ssh-(?:rsa|dss)\s*Encryption: none(?:.|\s?)*?Private-MAC:`
1635
+ },
1636
+ // International Phone Numbers
1637
+ {
1638
+ name: "france_phone_numbers",
1639
+ pattern: String.raw`\b([0O]?[1lI][1lI])?[3E][3E][0O]?[\\dOIlZEASB]{9}\b`
1640
+ },
1641
+ {
1642
+ name: "german_phone_numbers",
1643
+ pattern: String.raw`\b[\d\w]\d{2}[\d\w]{6}\d[\d\w]\b`
1644
+ },
1645
+ {
1646
+ name: "uk_phone_numbers",
1647
+ pattern: String.raw`\b([0O]?[1lI][1lI])?[4A][4A][\\dOIlZEASB]{10,11}\b`
1648
+ },
1649
+ // International IDs
1650
+ {
1651
+ name: "uk_drivers_license",
1652
+ pattern: String.raw`\b[A-Z]{5}\d{6}[A-Z]{2}\d{1}[A-Z]{2}\b`
1653
+ },
1654
+ {
1655
+ name: "uk_passport",
1656
+ pattern: String.raw`\b\\d{10}GB[RP]\\d{7}[UMF]{1}\\d{9}\b`
1657
+ },
1658
+ {
1659
+ name: "argentina_dni",
1660
+ pattern: String.raw`\b\\d{2}\\.\\d{3}\\.\\d{3}\b`
1661
+ },
1662
+ {
1663
+ name: "australia_tfn",
1664
+ pattern: String.raw`\b[Tt][Ff][Nn](:|:\\s|\\s|)(\\d{8,9})\b`
1665
+ },
1666
+ {
1667
+ name: "canada_passport",
1668
+ pattern: String.raw`\b[\\w]{2}[\\d]{6}\b`
1669
+ },
1670
+ {
1671
+ name: "croatia_vat",
1672
+ pattern: String.raw`\bHR\\d{11}\b`
1673
+ },
1674
+ {
1675
+ name: "czech_vat",
1676
+ pattern: String.raw`\bCZ\\d{8,10}\b`
1677
+ },
1678
+ {
1679
+ name: "denmark_personal_id",
1680
+ pattern: String.raw`\b(?:\\d{10}|\\d{6}[-\\s]\\d{4})\b`
1681
+ },
1682
+ {
1683
+ name: "france_national_id",
1684
+ pattern: String.raw`\b\\d{12}\b`
1685
+ },
1686
+ {
1687
+ name: "france_ssn",
1688
+ pattern: String.raw`\b(?:\\d{13}|\\d{13}\\s\\d{2})\b`
1689
+ },
1690
+ {
1691
+ name: "france_passport",
1692
+ pattern: String.raw`\b\\d{2}11\\d{5}\b`
1693
+ },
1694
+ {
1695
+ name: "california_drivers_license",
1696
+ pattern: String.raw`\b[A-Z]{1}\\d{7}\b`
1697
+ },
1698
+ // Medical and Healthcare
1699
+ {
1700
+ name: "hipaa_ndc",
1701
+ pattern: String.raw`\b\\d{4,5}-\\d{3,4}-\\d{1,2}\b`
1702
+ },
1703
+ // Security and Network
1704
+ {
1705
+ name: "cve_numbers",
1706
+ pattern: String.raw`\b[Cc][Vv][Ee]-\\d{4}-\\d{4,7}\b`
1707
+ },
1708
+ {
1709
+ name: "microsoft_oauth",
1710
+ pattern: String.raw`https://login\.microsoftonline\.com/common/oauth2/v2\.0/token|https://login\.windows\.net/common/oauth2/token`
1711
+ },
1712
+ {
1713
+ name: "postgres_connections",
1714
+ pattern: String.raw`\b(?:[Pp][Oo][Ss][Tt][Gg][Rr][Ee][Ss]|[Pp][Gg][Ss][Qq][Ll])\\:\\/\\/`
1715
+ },
1716
+ {
1717
+ name: "box_links",
1718
+ pattern: String.raw`https://app\.box\.com/[s|l]/\S+`
1719
+ },
1720
+ {
1721
+ name: "dropbox_links",
1722
+ pattern: String.raw`https://www\.dropbox\.com/(?:s|l)/\S+`
1723
+ },
1724
+ // Credit Card Variants
1725
+ {
1726
+ name: "amex_cards",
1727
+ pattern: String.raw`\b3[47][0-9]{13}\b`
1728
+ },
1729
+ {
1730
+ name: "visa_cards",
1731
+ pattern: String.raw`\b4[0-9]{12}(?:[0-9]{3})?\b`
1732
+ },
1733
+ {
1734
+ name: "discover_cards",
1735
+ pattern: String.raw`\b65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}\b`
1736
+ },
1737
+ {
1738
+ name: "enhanced_credit_cards",
1739
+ pattern: String.raw`\b((4\\d{3}|5[1-5]\\d{2}|2\\d{3}|3[47]\\d{1,2})[\\s\\-]?\\d{4,6}[\\s\\-]?\\d{4,6}?([\\s\\-]\\d{3,4})?(\\d{3})?)\b`
1740
+ },
1741
+ // Bank Routing Numbers (US specific)
1742
+ {
1743
+ name: "bbva_routing_ca",
1744
+ pattern: String.raw`\\b321170538\\b`
1745
+ },
1746
+ {
1747
+ name: "boa_routing_ca",
1748
+ pattern: String.raw`\\b(?:121|026)00(?:0|9)(?:358|593)\\b`
1749
+ },
1750
+ {
1751
+ name: "chase_routing_ca",
1752
+ pattern: String.raw`\\b322271627\\b`
1753
+ },
1754
+ {
1755
+ name: "citibank_routing_ca",
1756
+ pattern: String.raw`\\b32(?:11|22)71(?:18|72)4\\b`
1757
+ },
1758
+ {
1759
+ name: "usbank_routing_ca",
1760
+ pattern: String.raw`\\b12(?:1122676|2235821)\\b`
1761
+ },
1762
+ {
1763
+ name: "united_bank_routing_ca",
1764
+ pattern: String.raw`\\b122243350\\b`
1765
+ },
1766
+ {
1767
+ name: "wells_fargo_routing_ca",
1768
+ pattern: String.raw`\\b121042882\\b`
1769
+ },
1770
+ // Unrealistic alphanumeric identifiers
1771
+ {
1772
+ name: "generic_non_usual",
1773
+ pattern: String.raw`(?:^|\s)(?=[A-Za-z0-9_\)\*\=@]*[A-Za-z])(?=[A-Za-z0-9_\)\*\=@]*[0-9])([A-Za-z0-9_\)\*\=@]{5,})(?=\s|$)`
1774
+ }
1775
+ ];
1776
+
1777
+ // src/internal/masking/utils.ts
1778
+ function isValidPatternName(name) {
1779
+ return /^[a-zA-Z0-9_]+$/.test(name);
1780
+ }
1781
+ function isLikelyReDoSPattern(pattern) {
1782
+ const dangerousPatterns = [
1783
+ // Nested quantifiers like (a+)+, (a*)+, (a+)*
1784
+ /\([^)]*[+*]\)[+*]/,
1785
+ // Alternation with overlapping groups like (a|a)*
1786
+ /\([^)]*\|[^)]*\)[+*]/,
1787
+ // Complex backtracking patterns - but more specific
1788
+ /\([^)]*[+*][^)]*[+*][^)]*\)[+*]/
1789
+ ];
1790
+ return dangerousPatterns.some((dangerous) => dangerous.test(pattern));
1791
+ }
1792
+ function getGroupedPattern(patternEntry) {
1793
+ let name = patternEntry.name;
1794
+ if (!name || name === "") {
1795
+ name = `pattern_${Math.random().toString(16).slice(2)}`;
1796
+ }
1797
+ if (!isValidPatternName(name)) {
1798
+ throw new Error(
1799
+ `Pattern name '${name}' must only contain alphanumeric characters and underscores`
1800
+ );
1801
+ }
1802
+ if (isLikelyReDoSPattern(patternEntry.pattern)) {
1803
+ throw new Error(`Potentially dangerous ReDoS pattern detected: '${patternEntry.pattern}'`);
1804
+ }
1805
+ try {
1806
+ new RegExp(patternEntry.pattern);
1807
+ } catch (error) {
1808
+ throw new Error(`Invalid regex pattern '${patternEntry.pattern}': ${String(error)}`);
1809
+ }
1810
+ return `(?<${name}>${patternEntry.pattern})`;
1811
+ }
1812
+ function isIPatternEntry(obj) {
1813
+ return typeof obj === "object" && obj !== null && typeof obj.pattern === "string" && (obj.name === void 0 || typeof obj.name === "string");
1814
+ }
1815
+ function isIEventMaskingRule(obj) {
1816
+ return typeof obj === "object" && obj !== null && typeof obj.mode === "string" && Array.isArray(obj.patterns) && obj.patterns.every(
1817
+ (p) => isIPatternEntry(p) || typeof p === "string"
1818
+ ) && (obj.attributePattern === void 0 || typeof obj.attributePattern === "string");
1819
+ }
1820
+ function convertPatternsToPatternEntries(patterns) {
1821
+ const patternEntries = [];
1822
+ for (const pattern of patterns) {
1823
+ if (typeof pattern === "string") {
1824
+ patternEntries.push({ pattern, name: "" });
1825
+ } else if (isIPatternEntry(pattern)) {
1826
+ patternEntries.push(pattern);
1827
+ } else {
1828
+ throw new Error("Patterns must be either strings or PatternEntry instances");
1829
+ }
1830
+ }
1831
+ return patternEntries;
1832
+ }
1833
+ function compilePatternEntries(patternEntries) {
1834
+ const patternGroups = [];
1835
+ for (const patternEntry of patternEntries) {
1836
+ try {
1837
+ patternGroups.push(getGroupedPattern(patternEntry));
1838
+ } catch (error) {
1839
+ logger.warn(`Invalid pattern '${patternEntry.name}': ${patternEntry.pattern}`, error);
1840
+ continue;
1841
+ }
1842
+ }
1843
+ if (patternGroups.length === 0) {
1844
+ return null;
1845
+ }
1846
+ try {
1847
+ return new RegExp(patternGroups.join("|"));
1848
+ } catch (error) {
1849
+ logger.warn("Failed to compile pattern entries into regex", error);
1850
+ return null;
1851
+ }
1852
+ }
1853
+ function getCompiledAttributeNamePattern(rule) {
1854
+ if (!rule.attributePattern) {
1855
+ logger.debug("No attribute pattern provided, using default .*");
1856
+ return /.*/;
1857
+ }
1858
+ let compiledPatternString = rule.attributePattern;
1859
+ if (isIEventMaskingRule(rule) && rule.eventNamePattern) {
1860
+ compiledPatternString = `(${compiledPatternString})|(${rule.eventNamePattern})`;
1861
+ }
1862
+ return new RegExp(compiledPatternString);
1863
+ }
1864
+ function shouldContinueExecution(startTime, iterations, timeoutMs) {
1865
+ if (Date.now() - startTime > timeoutMs) {
1866
+ logger.warn("Regex execution timed out - potential ReDoS pattern detected");
1867
+ return false;
1868
+ }
1869
+ const maxIterations = 1e3;
1870
+ if (iterations > maxIterations) {
1871
+ logger.warn("Regex execution exceeded maximum iterations - potential ReDoS pattern detected");
1872
+ return false;
1873
+ }
1874
+ return true;
1875
+ }
1876
+ function createGlobalPattern(pattern) {
1877
+ return new RegExp(
1878
+ pattern.source,
1879
+ pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g"
1880
+ );
1881
+ }
1882
+ function executeRegexWithTimeout(pattern, value, timeoutMs = 100) {
1883
+ const matches = [];
1884
+ const globalPattern = createGlobalPattern(pattern);
1885
+ const startTime = Date.now();
1886
+ let match;
1887
+ let iterations = 0;
1888
+ while ((match = globalPattern.exec(value)) !== null) {
1889
+ if (!shouldContinueExecution(startTime, ++iterations, timeoutMs)) {
1890
+ break;
1891
+ }
1892
+ matches.push(match);
1893
+ if (match[0].length === 0) {
1894
+ globalPattern.lastIndex = match.index + 1;
1895
+ }
1896
+ }
1897
+ return matches;
1898
+ }
1899
+ function maskStringByPattern(value, pattern, mode = "full") {
1900
+ const matches = [];
1901
+ try {
1902
+ const regexMatches = executeRegexWithTimeout(pattern, value);
1903
+ for (const match of regexMatches) {
1904
+ matches.push({
1905
+ start: match.index,
1906
+ end: match.index + match[0].length,
1907
+ text: match[0],
1908
+ groups: match.groups
1909
+ });
1910
+ }
1911
+ } catch (error) {
1912
+ logger.warn("Regex execution failed, skipping masking", error);
1913
+ return value;
1914
+ }
1915
+ for (const matchInfo of matches.reverse()) {
1916
+ let patternName = "unknown";
1917
+ if (matchInfo.groups) {
1918
+ for (const [groupName, groupValue] of Object.entries(matchInfo.groups)) {
1919
+ if (groupValue !== void 0) {
1920
+ if (groupName.includes("_") && /\d$/.test(groupName)) {
1921
+ const parts = groupName.split("_");
1922
+ patternName = parts[0] || groupName;
1923
+ } else {
1924
+ patternName = groupName;
1925
+ }
1926
+ break;
1927
+ }
1928
+ }
1929
+ }
1930
+ logger.info(`Masking detected: pattern '${patternName}' found match in value`);
1931
+ const masked = mode === "partial" ? matchInfo.text[0] + "*****" : "*****";
1932
+ value = value.slice(0, matchInfo.start) + masked + value.slice(matchInfo.end);
1933
+ }
1934
+ return value;
1935
+ }
1936
+ function maskStringByPatternBasedRule(value, rule) {
1937
+ const patternEntries = convertPatternsToPatternEntries(rule.patterns);
1938
+ if (patternEntries.length === 0) {
1939
+ logger.warn("No patterns provided for masking rule, returning original value");
1940
+ return value;
1941
+ }
1942
+ const mode = rule.mode;
1943
+ if (!patternEntries || patternEntries.length === 0) {
1944
+ return mode === "partial" && value ? value[0] + "*****" : "*****";
1945
+ }
1946
+ const compiledPatterns = compilePatternEntries(patternEntries);
1947
+ if (!compiledPatterns) {
1948
+ return value;
1949
+ }
1950
+ return maskStringByPattern(value, compiledPatterns, mode);
1951
+ }
1952
+ function maskValue(value, rule) {
1953
+ if (typeof value === "string") {
1954
+ return maskStringByPatternBasedRule(value, rule);
1955
+ } else if (typeof value === "boolean" || typeof value === "number") {
1956
+ return maskStringByPatternBasedRule(String(value), rule);
1957
+ } else if (Array.isArray(value)) {
1958
+ return value.map((v) => maskStringByPatternBasedRule(String(v), rule));
1959
+ } else if (value !== null && typeof value === "object") {
1960
+ const result = {};
1961
+ for (const [k, v] of Object.entries(value)) {
1962
+ result[k] = maskValue(v, rule);
1963
+ }
1964
+ return result;
1965
+ } else {
1966
+ throw new Error(`Unsupported value type for masking: ${typeof value}`);
1967
+ }
1968
+ }
1969
+ function maskAttributes(attributes, rules, outputOriginalValue = false) {
1970
+ if (!attributes || Object.keys(attributes).length === 0) {
1971
+ return {};
1972
+ }
1973
+ const maskedAttributes = { ...attributes };
1974
+ for (const rule of rules) {
1975
+ const compiledAttributeNamePattern = getCompiledAttributeNamePattern(rule);
1976
+ const attributesToMask = compiledAttributeNamePattern ? Object.keys(maskedAttributes).filter((attr) => compiledAttributeNamePattern.test(attr)) : Object.keys(maskedAttributes);
1977
+ for (const attribute of attributesToMask) {
1978
+ const value = maskedAttributes[attribute];
1979
+ if (value === null || value === void 0) {
1980
+ continue;
1981
+ }
1982
+ if (outputOriginalValue) {
1983
+ logger.debug(`Masking attribute '${attribute}' with original value`, { value });
1984
+ }
1985
+ maskedAttributes[attribute] = maskValue(value, rule);
1986
+ }
1987
+ }
1988
+ return maskedAttributes;
1989
+ }
1990
+
1991
+ // src/internal/semantic-conventions.ts
1992
+ import { createContextKey } from "@opentelemetry/api";
1993
+ var BRIZZ = "brizz";
1994
+ var PROPERTIES = "properties";
1995
+ var SESSION_ID = "session.id";
1996
+ var PROPERTIES_CONTEXT_KEY = createContextKey(PROPERTIES);
1997
+
1998
+ // src/internal/log/processors/log-processor.ts
1999
+ var DEFAULT_LOG_MASKING_RULES = [
2000
+ {
2001
+ mode: "partial",
2002
+ attributePattern: "event.name",
2003
+ patterns: DEFAULT_PII_PATTERNS
2004
+ }
2005
+ ];
2006
+ var BrizzSimpleLogRecordProcessor = class extends SimpleLogRecordProcessor {
2007
+ config;
2008
+ constructor(exporter, config) {
2009
+ super(exporter);
2010
+ this.config = config;
2011
+ }
2012
+ onEmit(logRecord) {
2013
+ const maskingConfig = this.config.masking?.eventMasking;
2014
+ if (maskingConfig) {
2015
+ maskLog(logRecord, maskingConfig);
2016
+ }
2017
+ const associationProperties = context5.active().getValue(PROPERTIES_CONTEXT_KEY);
2018
+ if (associationProperties) {
2019
+ for (const [key, value] of Object.entries(associationProperties)) {
2020
+ logRecord.setAttribute(`${BRIZZ}.${key}`, value);
2021
+ }
2022
+ }
2023
+ super.onEmit(logRecord);
2024
+ }
2025
+ };
2026
+ var BrizzBatchLogRecordProcessor = class extends BatchLogRecordProcessor {
2027
+ config;
2028
+ constructor(exporter, config) {
2029
+ super(exporter);
2030
+ this.config = config;
2031
+ }
2032
+ onEmit(logRecord) {
2033
+ const maskingConfig = this.config.masking?.eventMasking;
2034
+ if (maskingConfig) {
2035
+ maskLog(logRecord, maskingConfig);
2036
+ }
2037
+ const associationProperties = context5.active().getValue(PROPERTIES_CONTEXT_KEY);
2038
+ if (associationProperties) {
2039
+ for (const [key, value] of Object.entries(associationProperties)) {
2040
+ logRecord.setAttribute(`${BRIZZ}.${key}`, value);
2041
+ }
2042
+ }
2043
+ super.onEmit(logRecord);
2044
+ }
2045
+ };
2046
+ function maskLog(logRecord, config) {
2047
+ if (!logRecord.attributes) {
2048
+ return logRecord;
2049
+ }
2050
+ let rules = config.rules || [];
2051
+ if (!config.disableDefaultRules) {
2052
+ rules = [...DEFAULT_LOG_MASKING_RULES, ...rules];
2053
+ }
2054
+ try {
2055
+ if (logRecord.attributes && Object.keys(logRecord.attributes).length > 0) {
2056
+ const attributesRecord = {};
2057
+ for (const [key, value] of Object.entries(logRecord.attributes)) {
2058
+ attributesRecord[key] = value;
2059
+ }
2060
+ const maskedAttributes = maskAttributes(attributesRecord, rules);
2061
+ if (maskedAttributes) {
2062
+ const newAttributes = {};
2063
+ for (const [key, value] of Object.entries(maskedAttributes)) {
2064
+ newAttributes[key] = value;
2065
+ }
2066
+ logRecord.setAttributes(newAttributes);
2067
+ }
2068
+ }
2069
+ if (config.maskBody && logRecord.body !== void 0 && logRecord.body !== null) {
2070
+ let maskedBody = logRecord.body;
2071
+ for (const rule of rules) {
2072
+ maskedBody = maskValue(maskedBody, rule);
2073
+ }
2074
+ logRecord.setBody(maskedBody);
2075
+ }
2076
+ return logRecord;
2077
+ } catch (error) {
2078
+ logger.error("Error masking log record:", error);
2079
+ return logRecord;
2080
+ }
2081
+ }
2082
+
2083
+ // src/internal/log/logging.ts
2084
+ var LoggingModule = class _LoggingModule {
2085
+ static instance = null;
2086
+ logExporter = null;
2087
+ logProcessor = null;
2088
+ loggerProvider = null;
2089
+ static getInstance() {
2090
+ if (!_LoggingModule.instance) {
2091
+ throw new Error("Brizz must be initialized before accessing LoggingModule");
2092
+ }
2093
+ return _LoggingModule.instance;
2094
+ }
2095
+ /**
2096
+ * Initialize the logging module with the provided configuration
2097
+ */
2098
+ setup(config) {
2099
+ logger.info("Setting up logging module");
2100
+ this.initLogExporter(config);
2101
+ this.initLogProcessor(config);
2102
+ this.initLoggerProvider(config);
2103
+ _LoggingModule.instance = this;
2104
+ logger.info("Logging module setup completed");
2105
+ }
2106
+ /**
2107
+ * Initialize the log exporter
2108
+ */
2109
+ initLogExporter(config) {
2110
+ if (this.logExporter) {
2111
+ logger.debug("Log exporter already initialized, skipping re-initialization");
2112
+ return;
2113
+ }
2114
+ if (config.customLogExporter) {
2115
+ logger.debug("Using custom log exporter");
2116
+ this.logExporter = config.customLogExporter;
2117
+ logger.debug("Custom log exporter initialized successfully");
2118
+ return;
2119
+ }
2120
+ const logsUrl = config.baseUrl.replace(/\/$/, "") + "/v1/logs";
2121
+ logger.debug("Initializing default OTLP log exporter", { url: logsUrl });
2122
+ const headers = { ...config.headers };
2123
+ this.logExporter = new OTLPLogExporter({
2124
+ url: logsUrl,
2125
+ headers
2126
+ });
2127
+ logger.debug("OTLP log exporter initialized successfully");
2128
+ }
2129
+ /**
2130
+ * Initialize the log processor with masking support
2131
+ */
2132
+ initLogProcessor(config) {
2133
+ if (this.logProcessor) {
2134
+ logger.debug("Log processor already initialized, skipping re-initialization");
2135
+ return;
2136
+ }
2137
+ if (!this.logExporter) {
2138
+ throw new Error("Log exporter must be initialized before processor");
2139
+ }
2140
+ logger.debug("Initializing log processor", {
2141
+ disableBatch: config.disableBatch,
2142
+ hasMasking: !!config.masking?.eventMasking
2143
+ });
2144
+ this.logProcessor = config.disableBatch ? new BrizzSimpleLogRecordProcessor(this.logExporter, config) : new BrizzBatchLogRecordProcessor(this.logExporter, config);
2145
+ logger.debug("Log processor initialized successfully");
2146
+ }
2147
+ /**
2148
+ * Initialize the logger provider
2149
+ */
2150
+ initLoggerProvider(config) {
2151
+ if (this.loggerProvider) {
2152
+ logger.debug("Logger provider already initialized, skipping re-initialization");
2153
+ return;
2154
+ }
2155
+ if (!this.logProcessor) {
2156
+ throw new Error("Log processor must be initialized before logger provider");
2157
+ }
2158
+ logger.debug("Creating resource with service name", {
2159
+ serviceName: config.appName
2160
+ });
2161
+ const resource = resourceFromAttributes({
2162
+ "service.name": config.appName
2163
+ });
2164
+ logger.debug("Creating logger provider with resource");
2165
+ this.loggerProvider = new LoggerProvider({
2166
+ resource,
2167
+ processors: [this.logProcessor]
2168
+ });
2169
+ logger.debug("Logger provider initialization completed");
2170
+ }
2171
+ /**
2172
+ * Emit a custom event to the telemetry pipeline
2173
+ */
2174
+ emitEvent(name, attributes, body, severityNumber = SeverityNumber2.INFO) {
2175
+ logger.debug("Attempting to emit event", {
2176
+ name,
2177
+ hasAttributes: !!attributes,
2178
+ attributesCount: attributes ? Object.keys(attributes).length : 0,
2179
+ hasBody: !!body,
2180
+ severityNumber
2181
+ });
2182
+ if (!this.loggerProvider) {
2183
+ logger.error("Cannot emit event: Logger provider not initialized");
2184
+ throw new Error("Logging module not initialized");
2185
+ }
2186
+ const logAttributes = { "event.name": name };
2187
+ if (attributes) {
2188
+ Object.assign(logAttributes, attributes);
2189
+ logger.debug("Combined log attributes", { attributes: Object.keys(logAttributes) });
2190
+ }
2191
+ logger.debug("Getting logger instance for brizz_events");
2192
+ const eventLogger = this.loggerProvider.getLogger("brizz.events");
2193
+ logger.debug("Emitting log record with eventName", { eventName: name });
2194
+ try {
2195
+ eventLogger.emit({
2196
+ eventName: name,
2197
+ attributes: logAttributes,
2198
+ severityNumber,
2199
+ body
2200
+ });
2201
+ logger.debug("Event successfully emitted", { eventName: name });
2202
+ } catch (error) {
2203
+ logger.error(`Failed to emit event '${name}'`, { error, eventName: name });
2204
+ logger.error("Log record that failed", {
2205
+ eventName: name,
2206
+ hasAttributes: logAttributes,
2207
+ severityNumber,
2208
+ hasBody: body
2209
+ });
2210
+ throw error instanceof Error ? error : new Error(String(error));
2211
+ }
2212
+ }
2213
+ /**
2214
+ * Check if the module is initialized
2215
+ */
2216
+ isInitialized() {
2217
+ return this.loggerProvider !== null;
2218
+ }
2219
+ /**
2220
+ * Get the logger provider
2221
+ */
2222
+ getLoggerProvider() {
2223
+ return this.loggerProvider;
2224
+ }
2225
+ /**
2226
+ * Shutdown the logging module
2227
+ */
2228
+ async shutdown() {
2229
+ logger.debug("Shutting down logging module");
2230
+ if (this.loggerProvider) {
2231
+ await this.loggerProvider.shutdown();
2232
+ this.loggerProvider = null;
2233
+ }
2234
+ this.logProcessor = null;
2235
+ this.logExporter = null;
2236
+ if (_LoggingModule.instance === this) {
2237
+ _LoggingModule.instance = null;
2238
+ }
2239
+ logger.debug("Logging module shutdown completed");
2240
+ }
2241
+ };
2242
+ function emitEvent(name, attributes, body, severityNumber = SeverityNumber2.INFO) {
2243
+ return LoggingModule.getInstance().emitEvent(name, attributes, body, severityNumber);
2244
+ }
2245
+
2246
+ // src/internal/metric/metrics.ts
2247
+ import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
2248
+ import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
2249
+ var MetricsModule = class _MetricsModule {
2250
+ static instance = null;
2251
+ metricsExporter = null;
2252
+ metricsReader = null;
2253
+ static getInstance() {
2254
+ if (!_MetricsModule.instance) {
2255
+ throw new Error("Brizz must be initialized before accessing MetricsModule");
2256
+ }
2257
+ return _MetricsModule.instance;
2258
+ }
2259
+ /**
2260
+ * Initialize the metrics module with the provided configuration
2261
+ */
2262
+ setup(config) {
2263
+ logger.info("Setting up metrics module");
2264
+ this.initMetricsReader(config);
2265
+ _MetricsModule.instance = this;
2266
+ logger.info("Metrics module setup completed");
2267
+ }
2268
+ /**
2269
+ * Initialize the metrics exporter
2270
+ */
2271
+ initMetricsExporter(config) {
2272
+ if (this.metricsExporter) {
2273
+ logger.debug("Metrics exporter already initialized, skipping re-initialization");
2274
+ return;
2275
+ }
2276
+ const metricsUrl = config.baseUrl.replace(/\/$/, "") + "/v1/metrics";
2277
+ logger.debug("Initializing metrics exporter", { url: metricsUrl });
2278
+ this.metricsExporter = new OTLPMetricExporter({
2279
+ url: metricsUrl,
2280
+ headers: config.headers
2281
+ });
2282
+ logger.debug("Metrics exporter initialized successfully");
2283
+ }
2284
+ /**
2285
+ * Initialize the metrics reader
2286
+ */
2287
+ initMetricsReader(config) {
2288
+ if (this.metricsReader) {
2289
+ logger.debug("Metrics reader already initialized, skipping re-initialization");
2290
+ return;
2291
+ }
2292
+ if (config.customMetricReader) {
2293
+ logger.debug("Using custom metric reader");
2294
+ this.metricsReader = config.customMetricReader;
2295
+ logger.debug("Custom metric reader initialized successfully");
2296
+ return;
2297
+ }
2298
+ logger.debug(
2299
+ "Using default metrics flow - creating OTLP exporter and PeriodicExportingMetricReader"
2300
+ );
2301
+ this.initMetricsExporter(config);
2302
+ if (!this.metricsExporter) {
2303
+ throw new Error("Failed to initialize metrics exporter");
2304
+ }
2305
+ this.metricsReader = new PeriodicExportingMetricReader({
2306
+ exporter: this.metricsExporter
2307
+ });
2308
+ logger.debug("Default metrics reader initialized successfully");
2309
+ }
2310
+ /**
2311
+ * Get the metrics exporter
2312
+ */
2313
+ getMetricsExporter() {
2314
+ if (!this.metricsExporter) {
2315
+ throw new Error("Metrics module not initialized");
2316
+ }
2317
+ return this.metricsExporter;
2318
+ }
2319
+ /**
2320
+ * Get the metrics reader
2321
+ */
2322
+ getMetricsReader() {
2323
+ if (!this.metricsReader) {
2324
+ throw new Error("Metrics module not initialized");
2325
+ }
2326
+ return this.metricsReader;
2327
+ }
2328
+ /**
2329
+ * Shutdown the metrics module
2330
+ */
2331
+ shutdown() {
2332
+ logger.debug("Shutting down metrics module");
2333
+ this.metricsReader = null;
2334
+ this.metricsExporter = null;
2335
+ if (_MetricsModule.instance === this) {
2336
+ _MetricsModule.instance = null;
2337
+ }
2338
+ logger.debug("Metrics module shutdown completed");
2339
+ }
2340
+ };
2341
+ function getMetricsExporter() {
2342
+ return MetricsModule.getInstance().getMetricsExporter();
2343
+ }
2344
+ function getMetricsReader() {
2345
+ return MetricsModule.getInstance().getMetricsReader();
2346
+ }
2347
+
2348
+ // src/internal/trace/tracing.ts
2349
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
2350
+
2351
+ // src/internal/trace/processors/span-processor.ts
2352
+ import { context as context6 } from "@opentelemetry/api";
2353
+ import {
2354
+ BatchSpanProcessor,
2355
+ SimpleSpanProcessor
2356
+ } from "@opentelemetry/sdk-trace-base";
2357
+ var DEFAULT_MASKING_RULES = [
2358
+ {
2359
+ mode: "partial",
2360
+ attributePattern: "gen_ai.prompt",
2361
+ patterns: DEFAULT_PII_PATTERNS
2362
+ },
2363
+ {
2364
+ mode: "partial",
2365
+ attributePattern: "gen_ai.completion",
2366
+ patterns: DEFAULT_PII_PATTERNS
2367
+ },
2368
+ {
2369
+ mode: "partial",
2370
+ attributePattern: "traceloop.entity.input",
2371
+ patterns: DEFAULT_PII_PATTERNS
2372
+ },
2373
+ {
2374
+ mode: "partial",
2375
+ attributePattern: "traceloop.entity.output",
2376
+ patterns: DEFAULT_PII_PATTERNS
2377
+ }
2378
+ ];
2379
+ var BrizzSimpleSpanProcessor = class extends SimpleSpanProcessor {
2380
+ config;
2381
+ constructor(spanExporter, config) {
2382
+ super(spanExporter);
2383
+ this.config = config;
2384
+ }
2385
+ // Will work with the following code:
2386
+ // const span = tracer.startSpan('sensitive-operation',{attributes:{
2387
+ // 'user.password': 'secret123',
2388
+ // 'user.email': 'user@example.com',
2389
+ // }});
2390
+ //
2391
+ // Won't work because onStart is called before attributes are set:
2392
+ // span.setAttributes({
2393
+ // 'user.password': 'secret123',
2394
+ // 'user.email': 'user@example.com'
2395
+ // });
2396
+ onStart(span, parentContext) {
2397
+ const maskingConfig = this.config.masking?.spanMasking;
2398
+ if (maskingConfig) {
2399
+ maskSpan(span, maskingConfig);
2400
+ }
2401
+ const associationProperties = context6.active().getValue(PROPERTIES_CONTEXT_KEY);
2402
+ if (associationProperties) {
2403
+ for (const [key, value] of Object.entries(associationProperties)) {
2404
+ span.setAttribute(`${BRIZZ}.${key}`, value);
2405
+ }
2406
+ }
2407
+ super.onStart(span, parentContext);
2408
+ }
2409
+ };
2410
+ var BrizzBatchSpanProcessor = class extends BatchSpanProcessor {
2411
+ config;
2412
+ constructor(spanExporter, config) {
2413
+ super(spanExporter);
2414
+ this.config = config;
2415
+ }
2416
+ onStart(span, parentContext) {
2417
+ const maskingConfig = this.config.masking?.spanMasking;
2418
+ if (maskingConfig) {
2419
+ maskSpan(span, maskingConfig);
2420
+ }
2421
+ const associationProperties = context6.active().getValue(PROPERTIES_CONTEXT_KEY);
2422
+ if (associationProperties) {
2423
+ for (const [key, value] of Object.entries(associationProperties)) {
2424
+ span.setAttribute(`${BRIZZ}.${key}`, value);
2425
+ }
2426
+ }
2427
+ super.onStart(span, parentContext);
2428
+ }
2429
+ };
2430
+ function maskSpan(span, config) {
2431
+ if (!span.attributes || Object.keys(span.attributes).length === 0) {
2432
+ return span;
2433
+ }
2434
+ let rules = config.rules || [];
2435
+ if (!config.disableDefaultRules) {
2436
+ rules = [...DEFAULT_MASKING_RULES, ...rules];
2437
+ }
2438
+ try {
2439
+ const attributesRecord = {};
2440
+ for (const [key, value] of Object.entries(span.attributes)) {
2441
+ attributesRecord[key] = value;
2442
+ }
2443
+ const maskedAttributes = maskAttributes(attributesRecord, rules);
2444
+ if (maskedAttributes && Object.keys(maskedAttributes).length > 0) {
2445
+ const merged = { ...span.attributes };
2446
+ for (const [key, value] of Object.entries(maskedAttributes)) {
2447
+ merged[key] = value;
2448
+ }
2449
+ span.setAttributes(merged);
2450
+ }
2451
+ return span;
2452
+ } catch (error) {
2453
+ logger.error("Error masking span:", error);
2454
+ return span;
2455
+ }
2456
+ }
2457
+
2458
+ // src/internal/trace/tracing.ts
2459
+ var TracingModule = class _TracingModule {
2460
+ static instance = null;
2461
+ spanExporter = null;
2462
+ spanProcessor = null;
2463
+ static getInstance() {
2464
+ if (!_TracingModule.instance) {
2465
+ throw new Error("Brizz must be initialized before accessing TracingModule");
2466
+ }
2467
+ return _TracingModule.instance;
2468
+ }
2469
+ /**
2470
+ * Initialize the tracing module with the provided configuration
2471
+ */
2472
+ setup(config) {
2473
+ logger.info("Setting up tracing module");
2474
+ this.initSpanExporter(config);
2475
+ this.initSpanProcessor(config);
2476
+ _TracingModule.instance = this;
2477
+ logger.info("Tracing module setup completed");
2478
+ }
2479
+ /**
2480
+ * Initialize the span exporter
2481
+ */
2482
+ initSpanExporter(config) {
2483
+ if (this.spanExporter) {
2484
+ logger.debug("Span exporter already initialized, skipping re-initialization");
2485
+ return;
2486
+ }
2487
+ if (config.customSpanExporter) {
2488
+ logger.debug("Using custom span exporter");
2489
+ this.spanExporter = config.customSpanExporter;
2490
+ logger.debug("Custom span exporter initialized successfully");
2491
+ return;
2492
+ }
2493
+ const tracesUrl = config.baseUrl.replace(/\/$/, "") + "/v1/traces";
2494
+ logger.debug("Initializing default OTLP span exporter", { url: tracesUrl });
2495
+ this.spanExporter = new OTLPTraceExporter({
2496
+ url: tracesUrl,
2497
+ headers: config.headers
2498
+ });
2499
+ logger.debug("OTLP span exporter initialized successfully");
2500
+ }
2501
+ /**
2502
+ * Initialize the span processor with masking support
2503
+ */
2504
+ initSpanProcessor(config) {
2505
+ if (this.spanProcessor) {
2506
+ logger.debug("Span processor already initialized, skipping re-initialization");
2507
+ return;
2508
+ }
2509
+ if (!this.spanExporter) {
2510
+ throw new Error("Span exporter must be initialized before processor");
2511
+ }
2512
+ logger.debug("Initializing span processor", {
2513
+ disableBatch: config.disableBatch,
2514
+ hasMasking: !!config.masking?.spanMasking
2515
+ });
2516
+ this.spanProcessor = config.disableBatch ? new BrizzSimpleSpanProcessor(this.spanExporter, config) : new BrizzBatchSpanProcessor(this.spanExporter, config);
2517
+ logger.debug("Span processor initialized successfully");
2518
+ }
2519
+ /**
2520
+ * Get the span exporter
2521
+ */
2522
+ getSpanExporter() {
2523
+ if (!this.spanExporter) {
2524
+ throw new Error("Tracing module not initialized");
2525
+ }
2526
+ return this.spanExporter;
2527
+ }
2528
+ /**
2529
+ * Get the span processor
2530
+ */
2531
+ getSpanProcessor() {
2532
+ if (!this.spanProcessor) {
2533
+ throw new Error("Tracing module not initialized");
2534
+ }
2535
+ return this.spanProcessor;
2536
+ }
2537
+ async shutdown() {
2538
+ logger.debug("Shutting down tracing module");
2539
+ if (this.spanProcessor) {
2540
+ await this.spanProcessor.shutdown();
2541
+ this.spanProcessor = null;
2542
+ }
2543
+ if (this.spanExporter) {
2544
+ await this.spanExporter.shutdown();
2545
+ this.spanExporter = null;
2546
+ }
2547
+ _TracingModule.instance = null;
2548
+ logger.debug("Tracing module shutdown completed");
2549
+ }
2550
+ };
2551
+ function getSpanExporter() {
2552
+ return TracingModule.getInstance().getSpanExporter();
2553
+ }
2554
+ function getSpanProcessor() {
2555
+ return TracingModule.getInstance().getSpanProcessor();
2556
+ }
2557
+
2558
+ // src/internal/trace/session.ts
2559
+ import { context as context7 } from "@opentelemetry/api";
2560
+ function withProperties(properties, fn, thisArg, ...args) {
2561
+ if (Object.keys(properties).length === 0) {
2562
+ return fn.apply(thisArg, args);
2563
+ }
2564
+ const newContext = context7.active().setValue(PROPERTIES_CONTEXT_KEY, properties);
2565
+ return context7.with(newContext, fn, thisArg, ...args);
2566
+ }
2567
+ function WithSessionId(sessionId, fn, thisArg, ...args) {
2568
+ return withProperties({ [SESSION_ID]: sessionId }, fn, thisArg, ...args);
2569
+ }
2570
+
2571
+ // src/internal/sdk.ts
2572
+ var _Brizz = class __Brizz {
2573
+ static instance = null;
2574
+ /** Flag indicating if SDK initialization has completed successfully */
2575
+ _initialized = false;
2576
+ /** OpenTelemetry sdk instance */
2577
+ _sdk = null;
2578
+ static getInstance() {
2579
+ if (!__Brizz.instance) {
2580
+ throw new Error("Brizz must be initialized before accessing TracingModule");
2581
+ }
2582
+ return __Brizz.instance;
2583
+ }
2584
+ /**
2585
+ * Initialize the Brizz SDK with the provided configuration.
2586
+ *
2587
+ * @param {IBrizzInitializeOptions} options - Configuration options for the SDK
2588
+ * @throws {Error} - If initialization fails
2589
+ *
2590
+ * @example
2591
+ * ```typescript
2592
+ * Brizz.initialize({
2593
+ * appName: 'my-app',
2594
+ * baseUrl: 'http://localhost:4318',
2595
+ * apiKey: 'your-api-key'
2596
+ * });
2597
+ * ```
2598
+ */
2599
+ initialize(options) {
2600
+ if (this._initialized) {
2601
+ logger.warn("Brizz SDK already initialized");
2602
+ return;
2603
+ }
2604
+ logger.info("Starting Brizz SDK initialization");
2605
+ try {
2606
+ const resolvedConfig = resolveConfig(options);
2607
+ this.initializeModules(resolvedConfig);
2608
+ this.setupInstrumentation(options);
2609
+ this.createAndStartNodeSDK(options, resolvedConfig);
2610
+ this._initialized = true;
2611
+ logger.info("Brizz SDK initialization completed successfully", {
2612
+ moduleSystem: this.detectModuleSystem()
2613
+ });
2614
+ } catch (error) {
2615
+ logger.error("Failed to initialize Brizz SDK", { error });
2616
+ throw new Error(`Failed to initialize SDK: ${String(error)}`);
2617
+ }
2618
+ }
2619
+ /**
2620
+ * Set up instrumentation registry and configure manual modules.
2621
+ * @private
2622
+ */
2623
+ setupInstrumentation(options) {
2624
+ const registry = InstrumentationRegistry.getInstance();
2625
+ if (options.instrumentModules && Object.keys(options.instrumentModules).length > 0) {
2626
+ registry.setManualModules(options.instrumentModules);
2627
+ }
2628
+ }
2629
+ /**
2630
+ * Create and start NodeSDK if not disabled.
2631
+ * Only handles manual instrumentations now - auto instrumentations are loaded at import time.
2632
+ * @private
2633
+ */
2634
+ createAndStartNodeSDK(options, resolvedConfig) {
2635
+ if (options.disableNodeSdk) {
2636
+ logger.info("NodeSDK disabled - only telemetry modules initialized");
2637
+ return;
2638
+ }
2639
+ const registry = InstrumentationRegistry.getInstance();
2640
+ const manualInstrumentations = registry.getManualInstrumentations();
2641
+ this._sdk = new NodeSDK({
2642
+ spanProcessors: [getSpanProcessor()],
2643
+ metricReader: getMetricsReader(),
2644
+ resource: resourceFromAttributes2({
2645
+ "service.name": resolvedConfig.appName
2646
+ }),
2647
+ instrumentations: manualInstrumentations
2648
+ });
2649
+ this._sdk.start();
2650
+ if (manualInstrumentations.length > 0) {
2651
+ logger.info(`NodeSDK started with ${manualInstrumentations.length} manual instrumentations`);
2652
+ } else {
2653
+ logger.info("NodeSDK started - using auto-instrumentations loaded at import time");
2654
+ }
2655
+ }
2656
+ /**
2657
+ * Initialize telemetry modules.
2658
+ *
2659
+ * Sets up the tracing, metrics, and logging modules with their
2660
+ * respective exporters and processors.
2661
+ *
2662
+ * @param {IResolvedBrizzConfig} config - Resolved configuration
2663
+ * @private
2664
+ */
2665
+ initializeModules(config) {
2666
+ logger.info("Initializing telemetry modules");
2667
+ logger.debug("Initializing tracing module");
2668
+ const tracingModule = new TracingModule();
2669
+ tracingModule.setup(config);
2670
+ logger.debug("Initializing metrics module");
2671
+ const metricsModule = new MetricsModule();
2672
+ metricsModule.setup(config);
2673
+ logger.debug("Initializing logging module");
2674
+ const loggingModule = new LoggingModule();
2675
+ loggingModule.setup(config);
2676
+ logger.info("All telemetry modules initialized successfully");
2677
+ }
2678
+ /**
2679
+ * Detect the current module system (ESM or CJS) using reliable indicators
2680
+ *
2681
+ * @returns {string} - 'ESM' or 'CJS'
2682
+ * @private
2683
+ */
2684
+ detectModuleSystem() {
2685
+ const inCJS = typeof module !== "undefined" && typeof exports !== "undefined" && typeof __require === "function" && typeof __filename === "string" && typeof __dirname === "string" && this === (typeof exports !== "undefined" ? exports : void 0);
2686
+ return inCJS ? "CJS" : "ESM";
2687
+ }
2688
+ /**
2689
+ * Gracefully shutdown the Brizz SDK.
2690
+ *
2691
+ * This method stops all telemetry collection, flushes any pending data,
2692
+ * and releases resources. Should be called before application termination.
2693
+ *
2694
+ * @returns {Promise<void>} - Resolves when shutdown is complete
2695
+ * @throws {Error} - If shutdown fails
2696
+ *
2697
+ * @example
2698
+ * ```typescript
2699
+ * // Shutdown before app exit
2700
+ * await Brizz.shutdown();
2701
+ * ```
2702
+ */
2703
+ async shutdown() {
2704
+ if (!this._initialized) {
2705
+ logger.warn("Brizz SDK not initialized");
2706
+ return;
2707
+ }
2708
+ try {
2709
+ await this.shutdownModules();
2710
+ await this._sdk?.shutdown();
2711
+ this._initialized = false;
2712
+ this._sdk = null;
2713
+ __Brizz.instance = null;
2714
+ logger.info("Brizz SDK shut down successfully");
2715
+ } catch (error) {
2716
+ if (error instanceof Error && error.message.includes("ENOTFOUND")) {
2717
+ logger.debug(`Network error during shutdown (expected in tests): ${error.message}`);
2718
+ } else {
2719
+ logger.error(`Failed to shutdown Brizz SDK: ${String(error)}`);
2720
+ throw error;
2721
+ }
2722
+ }
2723
+ }
2724
+ /**
2725
+ * Shutdown all telemetry modules.
2726
+ * @private
2727
+ */
2728
+ async shutdownModules() {
2729
+ logger.info("Shutting down telemetry modules");
2730
+ try {
2731
+ try {
2732
+ const tracingModule = TracingModule.getInstance();
2733
+ await tracingModule.shutdown();
2734
+ } catch {
2735
+ logger.debug("Tracing module already shut down or not initialized");
2736
+ }
2737
+ try {
2738
+ const metricsModule = MetricsModule.getInstance();
2739
+ metricsModule.shutdown();
2740
+ } catch {
2741
+ logger.debug("Metrics module already shut down or not initialized");
2742
+ }
2743
+ try {
2744
+ const loggingModule = LoggingModule.getInstance();
2745
+ await loggingModule.shutdown();
2746
+ } catch {
2747
+ logger.debug("Logging module already shut down or not initialized");
2748
+ }
2749
+ logger.info("All telemetry modules shut down successfully");
2750
+ } catch (error) {
2751
+ logger.error("Error shutting down modules", { error });
2752
+ throw error;
2753
+ }
2754
+ }
2755
+ };
2756
+ var Brizz = new _Brizz();
2757
+
2758
+ // src/index.ts
2759
+ import { SeverityNumber as SeverityNumber3 } from "@opentelemetry/api-logs";
2760
+
2761
+ // src/node/runtime.ts
2762
+ function detectRuntime() {
2763
+ const [major, minor] = process.versions.node.split(".").map(Number);
2764
+ const noNodeJSGlobals = typeof __filename === "undefined" && typeof __dirname === "undefined";
2765
+ const noModuleSystem = typeof module === "undefined" && typeof exports === "undefined";
2766
+ const hasRequire = typeof __require === "function";
2767
+ const isESM = noNodeJSGlobals && noModuleSystem;
2768
+ const isCJS = hasRequire && typeof module !== "undefined" && typeof exports !== "undefined" && typeof __filename === "string" && typeof __dirname === "string";
2769
+ const supportsLoaderAPI = (major ?? 0) >= 21 || (major ?? 0) === 20 && (minor ?? 0) >= 6 || (major ?? 0) === 18 && (minor ?? 0) >= 19;
2770
+ const supportsRegister = !!process.features?.typescript || !!globalThis.module?.register;
2771
+ logger.debug("Runtime detection results:", {
2772
+ nodeVersion: `${major ?? 0}.${minor ?? 0}`,
2773
+ isESM,
2774
+ isCJS,
2775
+ supportsLoaderAPI,
2776
+ supportsRegister,
2777
+ detectionLogic: {
2778
+ noNodeJSGlobals,
2779
+ noModuleSystem,
2780
+ hasRequire,
2781
+ esmCondition: `${noNodeJSGlobals} && ${noModuleSystem} = ${isESM}`,
2782
+ cjsCondition: `require && module && exports && __filename && __dirname = ${isCJS}`
2783
+ },
2784
+ checks: {
2785
+ __filename: typeof __filename,
2786
+ __dirname: typeof __dirname,
2787
+ require: typeof __require,
2788
+ module: typeof module,
2789
+ exports: typeof exports,
2790
+ "process.features": process.features,
2791
+ "globalThis.module": globalThis.module
2792
+ }
2793
+ });
2794
+ return {
2795
+ isESM,
2796
+ isCJS,
2797
+ nodeVersion: process.versions.node,
2798
+ supportsLoaderAPI,
2799
+ supportsRegister
2800
+ };
2801
+ }
2802
+
2803
+ // src/node/loader.ts
2804
+ import module2 from "module";
2805
+ import { createAddHookMessageChannel } from "import-in-the-middle";
2806
+ var loaderDebug = (() => {
2807
+ const isDebug = process.env["BRIZZ_ESM_DEBUG"] === "true" || process.env["BRIZZ_LOG_LEVEL"] === "debug";
2808
+ return {
2809
+ log: (msg, data) => {
2810
+ if (!isDebug) {
2811
+ return;
2812
+ }
2813
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2814
+ const dataStr = data ? ` ${JSON.stringify(data)}` : "";
2815
+ console.log(`[${timestamp}] [ESM-LOADER] ${msg}${dataStr}`);
2816
+ },
2817
+ error: (msg, error) => {
2818
+ if (!isDebug) {
2819
+ return;
2820
+ }
2821
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2822
+ const errorStr = error instanceof Error ? ` ${error.message}` : error ? ` ${JSON.stringify(error)}` : "";
2823
+ console.error(`[${timestamp}] [ESM-LOADER] ERROR: ${msg}${errorStr}`);
2824
+ }
2825
+ };
2826
+ })();
2827
+ var LOADER_REGISTERED_KEY = Symbol.for("__brizz_esm_loader_registered__");
2828
+ function checkLoaderAPISupport() {
2829
+ const [major, minor] = process.versions.node.split(".").map(Number);
2830
+ if (major === void 0 || minor === void 0) {
2831
+ loaderDebug.log("Failed to detect Node version, assuming loader API is supported");
2832
+ return true;
2833
+ }
2834
+ const supported = major >= 21 || major === 20 && minor >= 6 || major === 18 && minor >= 19;
2835
+ loaderDebug.log("Loader API support check:", {
2836
+ nodeVersion: `${major}.${minor}`,
2837
+ supportsLoaderAPI: supported
2838
+ });
2839
+ return supported;
2840
+ }
2841
+ function maybeRegisterESMLoader() {
2842
+ if (globalThis[LOADER_REGISTERED_KEY] === true) {
2843
+ loaderDebug.log("ESM loader already registered, skipping");
2844
+ return false;
2845
+ }
2846
+ globalThis[LOADER_REGISTERED_KEY] = true;
2847
+ loaderDebug.log("Starting ESM loader registration...");
2848
+ if (!checkLoaderAPISupport()) {
2849
+ loaderDebug.log("Node.js version does not support loader API, skipping");
2850
+ return false;
2851
+ }
2852
+ try {
2853
+ loaderDebug.log("Creating MessageChannel for import-in-the-middle...");
2854
+ const { addHookMessagePort } = createAddHookMessageChannel();
2855
+ loaderDebug.log("Registering import-in-the-middle/hook.mjs...");
2856
+ module2.register("import-in-the-middle/hook.mjs", {
2857
+ data: { addHookMessagePort },
2858
+ transferList: [addHookMessagePort]
2859
+ });
2860
+ loaderDebug.log("ESM loader successfully registered!");
2861
+ return true;
2862
+ } catch (error) {
2863
+ loaderDebug.error("Failed to register ESM loader:", error);
2864
+ globalThis[LOADER_REGISTERED_KEY] = false;
2865
+ return false;
2866
+ }
2867
+ }
2868
+ if (globalThis[LOADER_REGISTERED_KEY] !== true) {
2869
+ loaderDebug.log("Loader module imported, attempting to register...");
2870
+ maybeRegisterESMLoader();
2871
+ }
2872
+
2873
+ // src/init.ts
2874
+ var init_exports = {};
2875
+ export {
2876
+ Brizz,
2877
+ DEFAULT_PII_PATTERNS,
2878
+ LogLevel,
2879
+ SeverityNumber3 as SeverityNumber,
2880
+ VercelAIInstrumentation,
2881
+ WithSessionId,
2882
+ detectRuntime,
2883
+ emitEvent,
2884
+ getLogLevel,
2885
+ getMetricsExporter,
2886
+ getMetricsReader,
2887
+ getSpanExporter,
2888
+ getSpanProcessor,
2889
+ init_exports as init,
2890
+ logger,
2891
+ maskAttributes,
2892
+ maskValue,
2893
+ maybeRegisterESMLoader,
2894
+ setLogLevel
2895
+ };
10
2896
  //# sourceMappingURL=index.js.map