@brizz/sdk 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -50,6 +50,7 @@ pnpm add @brizz/sdk
50
50
  ## Quick Start
51
51
 
52
52
  First, set up your environment variables:
53
+
53
54
  ```bash
54
55
  BRIZZ_API_KEY=your-api-key
55
56
  BRIZZ_BASE_URL=https://telemetry.brizz.dev # Optional
@@ -60,6 +61,7 @@ BRIZZ_LOG_LEVEL=info # Optional: debug, info, warn, error
60
61
  ### CommonJS Projects
61
62
 
62
63
  **Option 1: Preload Only (Zero Config)**
64
+
63
65
  ```bash
64
66
  node --require @brizz/sdk/preload your-app.js
65
67
  ```
@@ -74,10 +76,11 @@ generateText({
74
76
  model: openai('gpt-3.5-turbo'),
75
77
  prompt: 'Hello, world!',
76
78
  experimental_telemetry: { isEnabled: true },
77
- }).then(result => console.log(result.text));
79
+ }).then((result) => console.log(result.text));
78
80
  ```
79
81
 
80
82
  **Option 2: Preload + Initialize (Custom Config)**
83
+
81
84
  ```bash
82
85
  node --require @brizz/sdk/preload your-app.js
83
86
  ```
@@ -97,6 +100,7 @@ const { generateText } = require('ai');
97
100
  ```
98
101
 
99
102
  **Option 3: Manual Import + Initialize**
103
+
100
104
  ```javascript
101
105
  // Must be first import
102
106
  const { Brizz } = require('@brizz/sdk');
@@ -113,9 +117,11 @@ const { openai } = require('@ai-sdk/openai');
113
117
 
114
118
  ### ESM Projects
115
119
 
116
- > ⚠️ **ESM Requirement**: ESM projects **must** use the `--import @brizz/sdk/loader` flag for instrumentation to work. Manual import without the loader will not instrument AI libraries.
120
+ > ⚠️ **ESM Requirement**: ESM projects **must** use the `--import @brizz/sdk/loader` flag for
121
+ > instrumentation to work. Manual import without the loader will not instrument AI libraries.
117
122
 
118
123
  **Loader + Initialize (Required for ESM)**
124
+
119
125
  ```bash
120
126
  node --import @brizz/sdk/loader your-app.mjs
121
127
  ```
@@ -147,10 +153,12 @@ const result = await generateText({
147
153
  ## Module System Support
148
154
 
149
155
  ### CommonJS
156
+
150
157
  - **Preload**: `node --require @brizz/sdk/preload app.js` ⭐ (with optional `Brizz.initialize()`)
151
158
  - **Manual**: Require `@brizz/sdk` first, then `Brizz.initialize()`, then AI libraries
152
159
 
153
160
  ### ESM (ES Modules)
161
+
154
162
  - **Loader**: `node --import @brizz/sdk/loader app.mjs` + `Brizz.initialize()` ⭐
155
163
  - **Manual**: Import `@brizz/sdk` first, then `Brizz.initialize()`, then AI libraries
156
164
 
@@ -208,6 +216,7 @@ const stream = streamText({
208
216
  ```
209
217
 
210
218
  This enables automatic tracing of:
219
+
211
220
  - Model calls and responses
212
221
  - Token usage and costs
213
222
  - Tool calls and executions
@@ -250,23 +259,91 @@ API keys, crypto addresses, IPs, and more.
250
259
 
251
260
  Group related operations under a session context:
252
261
 
262
+ ### Function Wrapper Pattern
263
+
253
264
  ```typescript
254
- import { WithSessionId, emitEvent } from '@brizz/sdk';
265
+ import { withSessionId, emitEvent } from '@brizz/sdk';
255
266
 
256
267
  async function processUserWorkflow(userId: string) {
257
- // All traces within this function will include session-123
268
+ // All traces within this function will include the session ID
258
269
  const result = await generateText({
259
270
  model: openai('gpt-4'),
260
271
  messages: [{ role: 'user', content: 'Hello' }],
261
272
  experimental_telemetry: { isEnabled: true },
262
273
  });
263
274
 
264
- emitEvent('workflow.completed', { userId, result: result.text });
265
275
  return result;
266
276
  }
267
277
 
268
- // Wrap function with session context
269
- await WithSessionId('session-123', processUserWorkflow, null, 'user-456');
278
+ // Create a wrapped function that always executes with session context
279
+ const sessionedWorkflow = withSessionId('session-123', processUserWorkflow);
280
+
281
+ // Call multiple times, each with the same session context
282
+ await sessionedWorkflow('user-456');
283
+ await sessionedWorkflow('user-789');
284
+ ```
285
+
286
+ ### Immediate Execution Pattern
287
+
288
+ ```typescript
289
+ import { callWithSessionId } from '@brizz/sdk';
290
+
291
+ // Execute function immediately with session context
292
+ await callWithSessionId('session-123', processUserWorkflow, null, 'user-456');
293
+ ```
294
+
295
+ ### Handling Method Context
296
+
297
+ When wrapping methods that use `this`, you have several options:
298
+
299
+ #### Option 1: Arrow Function (Recommended)
300
+
301
+ ```typescript
302
+ class ChatService {
303
+ async processMessage(userId: string, message: string) {
304
+ // This method uses 'this' context
305
+ return `Processed by ${this.serviceName}: ${message}`;
306
+ }
307
+ }
308
+
309
+ const service = new ChatService();
310
+ // Wrap with arrow function to preserve 'this' context
311
+ const sessionedProcess = withSessionId('session-123', (userId: string, message: string) =>
312
+ service.processMessage(userId, message),
313
+ );
314
+ ```
315
+
316
+ #### Option 2: Using bind()
317
+
318
+ ```typescript
319
+ // Pre-bind the method to preserve 'this' context
320
+ const sessionedProcess = withSessionId('session-123', service.processMessage.bind(service));
321
+ ```
322
+
323
+ #### Option 3: Explicit thisArg Parameter
324
+
325
+ ```typescript
326
+ // Pass 'this' context explicitly as third parameter
327
+ const sessionedProcess = withSessionId(
328
+ 'session-123',
329
+ service.processMessage,
330
+ service, // explicit 'this' context
331
+ );
332
+ ```
333
+
334
+ **Note:** The arrow function approach (Option 1) is recommended as it's more explicit, avoids lint
335
+ warnings, and is less prone to `this` binding issues.
336
+
337
+ ## Deployment Environment
338
+
339
+ Optionally specify the deployment environment for better filtering and organization:
340
+
341
+ ```typescript
342
+ Brizz.initialize({
343
+ apiKey: 'your-api-key',
344
+ appName: 'my-app',
345
+ environment: 'production', // Optional: 'dev', 'staging', 'production', etc.
346
+ });
270
347
  ```
271
348
 
272
349
  ## Custom Events & Logging
package/dist/index.cjs CHANGED
@@ -34,7 +34,7 @@ __export(src_exports, {
34
34
  DEFAULT_PII_PATTERNS: () => DEFAULT_PII_PATTERNS,
35
35
  LogLevel: () => LogLevel,
36
36
  SeverityNumber: () => import_api_logs2.SeverityNumber,
37
- WithSessionId: () => WithSessionId,
37
+ callWithSessionId: () => callWithSessionId,
38
38
  detectRuntime: () => detectRuntime,
39
39
  emitEvent: () => emitEvent,
40
40
  getLogLevel: () => getLogLevel,
@@ -46,7 +46,8 @@ __export(src_exports, {
46
46
  logger: () => logger,
47
47
  maskAttributes: () => maskAttributes,
48
48
  maskValue: () => maskValue,
49
- setLogLevel: () => setLogLevel
49
+ setLogLevel: () => setLogLevel,
50
+ withSessionId: () => withSessionId
50
51
  });
51
52
  module.exports = __toCommonJS(src_exports);
52
53
 
@@ -325,6 +326,7 @@ function resolveConfig(options) {
325
326
  headers: { ...options.headers },
326
327
  apiKey: process.env["BRIZZ_API_KEY"] || options.apiKey,
327
328
  disableBatch: process.env["BRIZZ_DISABLE_BATCH"] === "true" || !!options.disableBatch,
329
+ environment: process.env["BRIZZ_ENVIRONMENT"] || options.environment,
328
330
  logLevel: resolvedLogLevel,
329
331
  masking: resolvedMasking
330
332
  };
@@ -1019,7 +1021,7 @@ function maskStringByPattern(value, pattern, mode = "full") {
1019
1021
  logger.warn("Regex execution failed, skipping masking", error);
1020
1022
  return value;
1021
1023
  }
1022
- for (const matchInfo of matches.reverse()) {
1024
+ for (const matchInfo of matches.toReversed()) {
1023
1025
  let patternName = "unknown";
1024
1026
  if (matchInfo.groups) {
1025
1027
  for (const [groupName, groupValue] of Object.entries(matchInfo.groups)) {
@@ -1265,9 +1267,13 @@ var LoggingModule = class _LoggingModule {
1265
1267
  logger.debug("Creating resource with service name", {
1266
1268
  serviceName: config.appName
1267
1269
  });
1268
- const resource = (0, import_resources.resourceFromAttributes)({
1270
+ const resourceAttributes = {
1269
1271
  "service.name": config.appName
1270
- });
1272
+ };
1273
+ if (config.environment) {
1274
+ resourceAttributes["deployment.environment"] = config.environment;
1275
+ }
1276
+ const resource = (0, import_resources.resourceFromAttributes)(resourceAttributes);
1271
1277
  logger.debug("Creating logger provider with resource");
1272
1278
  this.loggerProvider = new import_sdk_logs2.LoggerProvider({
1273
1279
  resource,
@@ -1458,130 +1464,6 @@ var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otl
1458
1464
  // src/internal/trace/processors/span-processor.ts
1459
1465
  var import_api4 = require("@opentelemetry/api");
1460
1466
  var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
1461
-
1462
- // src/internal/trace/transformations/vercel-ai.ts
1463
- var import_ai_semantic_conventions = require("@traceloop/ai-semantic-conventions");
1464
- var AI_GENERATE_TEXT_DO_GENERATE = "ai.generateText.doGenerate";
1465
- var AI_STREAM_TEXT_DO_STREAM = "ai.streamText.doStream";
1466
- var HANDLED_SPAN_NAMES = {
1467
- [AI_GENERATE_TEXT_DO_GENERATE]: "gen_ai.chat",
1468
- [AI_STREAM_TEXT_DO_STREAM]: "gen_ai.chat",
1469
- "ai.streamText": "ai.streamText",
1470
- "ai.toolCall": (span) => {
1471
- const toolName = span.attributes["ai.toolCall.name"];
1472
- return `${String(toolName ?? "unknown")}.tool`;
1473
- }
1474
- };
1475
- var AI_RESPONSE_TEXT = "ai.response.text";
1476
- var AI_PROMPT_MESSAGES = "ai.prompt.messages";
1477
- var AI_USAGE_PROMPT_TOKENS = "ai.usage.promptTokens";
1478
- var AI_USAGE_COMPLETION_TOKENS = "ai.usage.completionTokens";
1479
- var AI_MODEL_PROVIDER = "ai.model.provider";
1480
- var transformAiSdkSpanName = (span) => {
1481
- if (span.name in HANDLED_SPAN_NAMES) {
1482
- const handler = HANDLED_SPAN_NAMES[span.name];
1483
- if (typeof handler === "function") {
1484
- span.name = handler(span);
1485
- } else if (handler) {
1486
- span.name = handler;
1487
- }
1488
- }
1489
- };
1490
- var transformResponseText = (attributes) => {
1491
- if (AI_RESPONSE_TEXT in attributes) {
1492
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_COMPLETIONS}.0.content`] = attributes[AI_RESPONSE_TEXT];
1493
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_COMPLETIONS}.0.role`] = "assistant";
1494
- delete attributes[AI_RESPONSE_TEXT];
1495
- }
1496
- };
1497
- var transformPromptMessages = (attributes) => {
1498
- if (AI_PROMPT_MESSAGES in attributes) {
1499
- try {
1500
- const messages = JSON.parse(attributes[AI_PROMPT_MESSAGES]);
1501
- for (const [index, msg] of messages.entries()) {
1502
- const message = msg;
1503
- logger.debug("Transforming prompt message", { msg: message, type: typeof message.content });
1504
- if (typeof message.content === "string") {
1505
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_PROMPTS}.${index}.content`] = message.content;
1506
- } else {
1507
- if (Array.isArray(message.content) && message.content.length > 0) {
1508
- const lastContent = message.content.at(-1);
1509
- if (lastContent?.text) {
1510
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_PROMPTS}.${index}.content`] = lastContent.text;
1511
- }
1512
- } else {
1513
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_PROMPTS}.${index}.content`] = JSON.stringify(
1514
- message.content
1515
- );
1516
- }
1517
- }
1518
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_PROMPTS}.${index}.role`] = message.role;
1519
- }
1520
- delete attributes[AI_PROMPT_MESSAGES];
1521
- } catch (error) {
1522
- logger.debug("Skipping prompt messages transformation because of JSON parsing error", {
1523
- e: error
1524
- });
1525
- }
1526
- }
1527
- };
1528
- var transformPromptTokens = (attributes) => {
1529
- if (AI_USAGE_PROMPT_TOKENS in attributes) {
1530
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_PROMPT_TOKENS}`] = attributes[AI_USAGE_PROMPT_TOKENS];
1531
- delete attributes[AI_USAGE_PROMPT_TOKENS];
1532
- }
1533
- };
1534
- var transformCompletionTokens = (attributes) => {
1535
- if (AI_USAGE_COMPLETION_TOKENS in attributes) {
1536
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_COMPLETION_TOKENS}`] = attributes[AI_USAGE_COMPLETION_TOKENS];
1537
- delete attributes[AI_USAGE_COMPLETION_TOKENS];
1538
- }
1539
- };
1540
- var calculateTotalTokens = (attributes) => {
1541
- const promptTokens = attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_PROMPT_TOKENS}`];
1542
- const completionTokens = attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_COMPLETION_TOKENS}`];
1543
- if (promptTokens && completionTokens) {
1544
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_TOTAL_TOKENS}`] = Number(promptTokens) + Number(completionTokens);
1545
- }
1546
- };
1547
- var transformVendor = (attributes) => {
1548
- if (AI_MODEL_PROVIDER in attributes) {
1549
- const vendor = attributes[AI_MODEL_PROVIDER];
1550
- attributes[import_ai_semantic_conventions.SpanAttributes.LLM_SYSTEM] = vendor && vendor.startsWith("openai") ? "OpenAI" : vendor;
1551
- delete attributes[AI_MODEL_PROVIDER];
1552
- }
1553
- };
1554
- var transformAiSdkAttributes = (attributes) => {
1555
- transformResponseText(attributes);
1556
- transformPromptMessages(attributes);
1557
- transformPromptTokens(attributes);
1558
- transformCompletionTokens(attributes);
1559
- calculateTotalTokens(attributes);
1560
- transformVendor(attributes);
1561
- };
1562
- var shouldHandleSpan = (span) => {
1563
- return span.name in HANDLED_SPAN_NAMES;
1564
- };
1565
- var transformAiSdkSpan = (span) => {
1566
- if (!shouldHandleSpan(span)) {
1567
- logger.debug("Skipping span transformation", { spanName: span.name });
1568
- return;
1569
- }
1570
- for (const key in span.attributes) {
1571
- if (Number.isNaN(span.attributes[key])) {
1572
- span.attributes[key] = 0;
1573
- }
1574
- }
1575
- logger.debug("Transforming AI SDK span", {
1576
- spanName: span.name,
1577
- spanContext: span.spanContext(),
1578
- attributes: span.attributes
1579
- });
1580
- transformAiSdkSpanName(span);
1581
- transformAiSdkAttributes(span.attributes);
1582
- };
1583
-
1584
- // src/internal/trace/processors/span-processor.ts
1585
1467
  var DEFAULT_MASKING_RULES = [
1586
1468
  {
1587
1469
  mode: "partial",
@@ -1624,10 +1506,6 @@ var BrizzSimpleSpanProcessor = class extends import_sdk_trace_base.SimpleSpanPro
1624
1506
  }
1625
1507
  super.onStart(span, parentContext);
1626
1508
  }
1627
- onEnd(span) {
1628
- transformAiSdkSpan(span);
1629
- super.onEnd(span);
1630
- }
1631
1509
  };
1632
1510
  var BrizzBatchSpanProcessor = class extends import_sdk_trace_base.BatchSpanProcessor {
1633
1511
  config;
@@ -1648,10 +1526,6 @@ var BrizzBatchSpanProcessor = class extends import_sdk_trace_base.BatchSpanProce
1648
1526
  }
1649
1527
  super.onStart(span, parentContext);
1650
1528
  }
1651
- onEnd(span) {
1652
- transformAiSdkSpan(span);
1653
- super.onEnd(span);
1654
- }
1655
1529
  };
1656
1530
  function maskSpan(span, config) {
1657
1531
  if (!span.attributes || Object.keys(span.attributes).length === 0) {
@@ -1791,7 +1665,18 @@ function withProperties(properties, fn, thisArg, ...args) {
1791
1665
  const newContext = import_api5.context.active().setValue(PROPERTIES_CONTEXT_KEY, properties);
1792
1666
  return import_api5.context.with(newContext, fn, thisArg, ...args);
1793
1667
  }
1794
- function WithSessionId(sessionId, fn, thisArg, ...args) {
1668
+ function withSessionId(sessionId, fn, thisArg) {
1669
+ return function wrapped(...args) {
1670
+ const base = import_api5.context.active();
1671
+ const prev = base.getValue(PROPERTIES_CONTEXT_KEY);
1672
+ const next = base.setValue(
1673
+ PROPERTIES_CONTEXT_KEY,
1674
+ prev ? { ...prev, [SESSION_ID]: sessionId } : { [SESSION_ID]: sessionId }
1675
+ );
1676
+ return import_api5.context.with(next, fn, thisArg ?? this, ...args);
1677
+ };
1678
+ }
1679
+ function callWithSessionId(sessionId, fn, thisArg, ...args) {
1795
1680
  return withProperties({ [SESSION_ID]: sessionId }, fn, thisArg, ...args);
1796
1681
  }
1797
1682
 
@@ -1865,12 +1750,16 @@ var _Brizz = class __Brizz {
1865
1750
  }
1866
1751
  const registry = InstrumentationRegistry.getInstance();
1867
1752
  const manualInstrumentations = registry.getManualInstrumentations();
1753
+ const resourceAttributes = {
1754
+ "service.name": resolvedConfig.appName
1755
+ };
1756
+ if (resolvedConfig.environment) {
1757
+ resourceAttributes["deployment.environment"] = resolvedConfig.environment;
1758
+ }
1868
1759
  this._sdk = new import_sdk_node.NodeSDK({
1869
1760
  spanProcessors: [getSpanProcessor()],
1870
1761
  metricReader: getMetricsReader(),
1871
- resource: (0, import_resources2.resourceFromAttributes)({
1872
- "service.name": resolvedConfig.appName
1873
- }),
1762
+ resource: (0, import_resources2.resourceFromAttributes)(resourceAttributes),
1874
1763
  instrumentations: manualInstrumentations
1875
1764
  });
1876
1765
  this._sdk.start();
@@ -1994,7 +1883,10 @@ function detectRuntime() {
1994
1883
  const isESM = noNodeJSGlobals && noModuleSystem;
1995
1884
  const isCJS = hasRequire && typeof module !== "undefined" && typeof exports !== "undefined" && typeof __filename === "string" && typeof __dirname === "string";
1996
1885
  const supportsLoaderAPI = (major ?? 0) >= 21 || (major ?? 0) === 20 && (minor ?? 0) >= 6 || (major ?? 0) === 18 && (minor ?? 0) >= 19;
1997
- const supportsRegister = !!process.features?.typescript || !!globalThis.module?.register;
1886
+ const supportsRegister = (
1887
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1888
+ !!process.features?.typescript || !!globalThis.module?.register
1889
+ );
1998
1890
  logger.debug("Runtime detection results:", {
1999
1891
  nodeVersion: `${major ?? 0}.${minor ?? 0}`,
2000
1892
  isESM,
@@ -2015,6 +1907,7 @@ function detectRuntime() {
2015
1907
  module: typeof module,
2016
1908
  exports: typeof exports,
2017
1909
  "process.features": process.features,
1910
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2018
1911
  "globalThis.module": globalThis.module
2019
1912
  }
2020
1913
  });
@@ -2035,7 +1928,7 @@ var init_exports = {};
2035
1928
  DEFAULT_PII_PATTERNS,
2036
1929
  LogLevel,
2037
1930
  SeverityNumber,
2038
- WithSessionId,
1931
+ callWithSessionId,
2039
1932
  detectRuntime,
2040
1933
  emitEvent,
2041
1934
  getLogLevel,
@@ -2047,6 +1940,7 @@ var init_exports = {};
2047
1940
  logger,
2048
1941
  maskAttributes,
2049
1942
  maskValue,
2050
- setLogLevel
1943
+ setLogLevel,
1944
+ withSessionId
2051
1945
  });
2052
1946
  //# sourceMappingURL=index.cjs.map