autotel 2.24.0 → 2.25.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 (59) hide show
  1. package/dist/auto.cjs +2 -2
  2. package/dist/auto.js +1 -1
  3. package/dist/{chunk-CSG2D3BZ.cjs → chunk-73SCHI7V.cjs} +7 -7
  4. package/dist/{chunk-CSG2D3BZ.cjs.map → chunk-73SCHI7V.cjs.map} +1 -1
  5. package/dist/{chunk-47KW5CV7.js → chunk-7RV6L24E.js} +4 -3
  6. package/dist/chunk-7RV6L24E.js.map +1 -0
  7. package/dist/{chunk-AXNPD6XW.cjs → chunk-7ZYUFMWU.cjs} +26 -26
  8. package/dist/{chunk-AXNPD6XW.cjs.map → chunk-7ZYUFMWU.cjs.map} +1 -1
  9. package/dist/{chunk-GSZJOYFF.js → chunk-BKIAH2YS.js} +3 -3
  10. package/dist/{chunk-GSZJOYFF.js.map → chunk-BKIAH2YS.js.map} +1 -1
  11. package/dist/{chunk-CLR5RQW4.cjs → chunk-DBUNRUDB.cjs} +5 -5
  12. package/dist/{chunk-CLR5RQW4.cjs.map → chunk-DBUNRUDB.cjs.map} +1 -1
  13. package/dist/{chunk-PDRIJURL.cjs → chunk-GIND746I.cjs} +4 -3
  14. package/dist/chunk-GIND746I.cjs.map +1 -0
  15. package/dist/{chunk-CZR7PJUZ.cjs → chunk-HCFBEOBM.cjs} +13 -13
  16. package/dist/{chunk-CZR7PJUZ.cjs.map → chunk-HCFBEOBM.cjs.map} +1 -1
  17. package/dist/{chunk-2D74YR4Z.js → chunk-JDV3LYOI.js} +3 -3
  18. package/dist/{chunk-2D74YR4Z.js.map → chunk-JDV3LYOI.js.map} +1 -1
  19. package/dist/{chunk-ZJTBAUXG.js → chunk-JZKMXKJX.js} +3 -3
  20. package/dist/{chunk-ZJTBAUXG.js.map → chunk-JZKMXKJX.js.map} +1 -1
  21. package/dist/{chunk-W6U2BUHU.cjs → chunk-LRFG6HRL.cjs} +5 -5
  22. package/dist/{chunk-W6U2BUHU.cjs.map → chunk-LRFG6HRL.cjs.map} +1 -1
  23. package/dist/{chunk-Z3BQYTZE.js → chunk-NYTCPK4J.js} +3 -3
  24. package/dist/{chunk-Z3BQYTZE.js.map → chunk-NYTCPK4J.js.map} +1 -1
  25. package/dist/{chunk-IJMW6CTV.js → chunk-P5YCN2Z3.js} +3 -3
  26. package/dist/{chunk-IJMW6CTV.js.map → chunk-P5YCN2Z3.js.map} +1 -1
  27. package/dist/decorators.cjs +2 -2
  28. package/dist/decorators.js +2 -2
  29. package/dist/event.cjs +5 -5
  30. package/dist/event.js +2 -2
  31. package/dist/functional.cjs +9 -9
  32. package/dist/functional.js +2 -2
  33. package/dist/index.cjs +41 -41
  34. package/dist/index.js +9 -9
  35. package/dist/instrumentation.cjs +8 -8
  36. package/dist/instrumentation.js +1 -1
  37. package/dist/messaging.cjs +6 -6
  38. package/dist/messaging.js +3 -3
  39. package/dist/semantic-helpers.cjs +7 -7
  40. package/dist/semantic-helpers.js +3 -3
  41. package/dist/test-span-collector.cjs +1 -0
  42. package/dist/test-span-collector.cjs.map +1 -1
  43. package/dist/test-span-collector.d.cts +2 -1
  44. package/dist/test-span-collector.d.ts +2 -1
  45. package/dist/test-span-collector.js +1 -1
  46. package/dist/test-span-collector.js.map +1 -1
  47. package/dist/webhook.cjs +3 -3
  48. package/dist/webhook.js +2 -2
  49. package/dist/workflow-distributed.cjs +4 -4
  50. package/dist/workflow-distributed.js +2 -2
  51. package/dist/workflow.cjs +7 -7
  52. package/dist/workflow.js +3 -3
  53. package/package.json +9 -7
  54. package/src/init.customization.test.ts +41 -31
  55. package/src/init.openllmetry.test.ts +98 -186
  56. package/src/init.ts +18 -1
  57. package/src/test-span-collector.ts +1 -1
  58. package/dist/chunk-47KW5CV7.js.map +0 -1
  59. package/dist/chunk-PDRIJURL.cjs.map +0 -1
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkINJD3G4K_cjs = require('./chunk-INJD3G4K.cjs');
4
- var chunkAXNPD6XW_cjs = require('./chunk-AXNPD6XW.cjs');
4
+ var chunk7ZYUFMWU_cjs = require('./chunk-7ZYUFMWU.cjs');
5
5
  require('./chunk-W4EUTSB2.cjs');
6
6
  require('./chunk-GML3FBOT.cjs');
7
7
  require('./chunk-D5LMF53P.cjs');
8
8
  require('./chunk-XRKAL7WJ.cjs');
9
- require('./chunk-PDRIJURL.cjs');
9
+ require('./chunk-GIND746I.cjs');
10
10
  require('./chunk-6YIDHH2S.cjs');
11
11
  require('./chunk-GVLK7YUU.cjs');
12
12
  require('./chunk-ZNMBW67B.cjs');
@@ -59,7 +59,7 @@ var WorkflowBaggage = chunkINJD3G4K_cjs.createSafeBaggageSchema(workflowBaggageF
59
59
  function traceDistributedWorkflow(config) {
60
60
  const spanName = `workflow.${config.name}`;
61
61
  return (fnFactory) => {
62
- return chunkAXNPD6XW_cjs.trace(
62
+ return chunk7ZYUFMWU_cjs.trace(
63
63
  { name: spanName, spanKind: api.SpanKind.INTERNAL },
64
64
  (baseCtx) => {
65
65
  return async (...args) => {
@@ -158,7 +158,7 @@ function traceDistributedWorkflow(config) {
158
158
  function traceDistributedStep(config) {
159
159
  const spanName = `workflow.step.${config.name}`;
160
160
  return (fnFactory) => {
161
- return chunkAXNPD6XW_cjs.trace(
161
+ return chunk7ZYUFMWU_cjs.trace(
162
162
  { name: spanName, spanKind: api.SpanKind.INTERNAL },
163
163
  (baseCtx) => {
164
164
  return async (...args) => {
@@ -1,10 +1,10 @@
1
1
  import { createSafeBaggageSchema } from './chunk-4IFSYQVX.js';
2
- import { trace } from './chunk-2D74YR4Z.js';
2
+ import { trace } from './chunk-JDV3LYOI.js';
3
3
  import './chunk-SR35DG5A.js';
4
4
  import './chunk-B3ZHLLMP.js';
5
5
  import './chunk-WD4RP6IV.js';
6
6
  import './chunk-USSL3D6L.js';
7
- import './chunk-47KW5CV7.js';
7
+ import './chunk-7RV6L24E.js';
8
8
  import './chunk-YTGF4L2C.js';
9
9
  import './chunk-X4RMFFMR.js';
10
10
  import './chunk-WGWSHJ2N.js';
package/dist/workflow.cjs CHANGED
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var chunkCLR5RQW4_cjs = require('./chunk-CLR5RQW4.cjs');
4
- require('./chunk-AXNPD6XW.cjs');
3
+ var chunkDBUNRUDB_cjs = require('./chunk-DBUNRUDB.cjs');
4
+ require('./chunk-7ZYUFMWU.cjs');
5
5
  require('./chunk-W4EUTSB2.cjs');
6
6
  require('./chunk-GML3FBOT.cjs');
7
7
  require('./chunk-D5LMF53P.cjs');
8
8
  require('./chunk-XRKAL7WJ.cjs');
9
- require('./chunk-PDRIJURL.cjs');
9
+ require('./chunk-GIND746I.cjs');
10
10
  require('./chunk-6YIDHH2S.cjs');
11
11
  require('./chunk-GVLK7YUU.cjs');
12
12
  require('./chunk-ZNMBW67B.cjs');
@@ -25,19 +25,19 @@ require('./chunk-JEQ2X3Z6.cjs');
25
25
 
26
26
  Object.defineProperty(exports, "getCurrentWorkflowContext", {
27
27
  enumerable: true,
28
- get: function () { return chunkCLR5RQW4_cjs.getCurrentWorkflowContext; }
28
+ get: function () { return chunkDBUNRUDB_cjs.getCurrentWorkflowContext; }
29
29
  });
30
30
  Object.defineProperty(exports, "isInWorkflow", {
31
31
  enumerable: true,
32
- get: function () { return chunkCLR5RQW4_cjs.isInWorkflow; }
32
+ get: function () { return chunkDBUNRUDB_cjs.isInWorkflow; }
33
33
  });
34
34
  Object.defineProperty(exports, "traceStep", {
35
35
  enumerable: true,
36
- get: function () { return chunkCLR5RQW4_cjs.traceStep; }
36
+ get: function () { return chunkDBUNRUDB_cjs.traceStep; }
37
37
  });
38
38
  Object.defineProperty(exports, "traceWorkflow", {
39
39
  enumerable: true,
40
- get: function () { return chunkCLR5RQW4_cjs.traceWorkflow; }
40
+ get: function () { return chunkDBUNRUDB_cjs.traceWorkflow; }
41
41
  });
42
42
  //# sourceMappingURL=workflow.cjs.map
43
43
  //# sourceMappingURL=workflow.cjs.map
package/dist/workflow.js CHANGED
@@ -1,10 +1,10 @@
1
- export { getCurrentWorkflowContext, isInWorkflow, traceStep, traceWorkflow } from './chunk-IJMW6CTV.js';
2
- import './chunk-2D74YR4Z.js';
1
+ export { getCurrentWorkflowContext, isInWorkflow, traceStep, traceWorkflow } from './chunk-P5YCN2Z3.js';
2
+ import './chunk-JDV3LYOI.js';
3
3
  import './chunk-SR35DG5A.js';
4
4
  import './chunk-B3ZHLLMP.js';
5
5
  import './chunk-WD4RP6IV.js';
6
6
  import './chunk-USSL3D6L.js';
7
- import './chunk-47KW5CV7.js';
7
+ import './chunk-7RV6L24E.js';
8
8
  import './chunk-YTGF4L2C.js';
9
9
  import './chunk-X4RMFFMR.js';
10
10
  import './chunk-WGWSHJ2N.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autotel",
3
- "version": "2.24.0",
3
+ "version": "2.25.0",
4
4
  "description": "Write Once, Observe Anywhere",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -248,7 +248,6 @@
248
248
  "license": "MIT",
249
249
  "dependencies": {
250
250
  "@opentelemetry/api": "^1.9.0",
251
- "@tanstack/intent": "^0.0.13",
252
251
  "@opentelemetry/api-logs": "^0.213.0",
253
252
  "@opentelemetry/exporter-metrics-otlp-http": "^0.213.0",
254
253
  "@opentelemetry/exporter-trace-otlp-http": "^0.213.0",
@@ -258,6 +257,7 @@
258
257
  "@opentelemetry/sdk-node": "^0.213.0",
259
258
  "@opentelemetry/sdk-trace-base": "^2.6.0",
260
259
  "@opentelemetry/semantic-conventions": "^1.40.0",
260
+ "@tanstack/intent": "^0.0.23",
261
261
  "import-in-the-middle": "^3.0.0"
262
262
  },
263
263
  "peerDependencies": {
@@ -334,12 +334,13 @@
334
334
  "@opentelemetry/resource-detector-gcp": "^0.48.0",
335
335
  "@opentelemetry/sdk-logs": "^0.213.0",
336
336
  "@opentelemetry/sdk-trace-node": "^2.6.0",
337
+ "@swc/core": "^1.15.18",
337
338
  "@total-typescript/ts-reset": "^0.6.1",
338
339
  "@total-typescript/tsconfig": "^1.0.4",
339
340
  "@types/eslint-config-prettier": "^6.11.3",
340
- "@types/node": "^25.3.5",
341
- "@typescript-eslint/eslint-plugin": "^8.56.1",
342
- "@typescript-eslint/parser": "^8.56.1",
341
+ "@types/node": "^25.5.0",
342
+ "@typescript-eslint/eslint-plugin": "^8.57.1",
343
+ "@typescript-eslint/parser": "^8.57.1",
343
344
  "eslint-config-prettier": "^10.1.8",
344
345
  "eslint-plugin-unicorn": "^63.0.0",
345
346
  "pino": "^10.3.1",
@@ -348,9 +349,10 @@
348
349
  "tsup": "^8.5.1",
349
350
  "tsx": "^4.21.0",
350
351
  "typescript": "^5.9.3",
351
- "typescript-eslint": "^8.56.1",
352
+ "typescript-eslint": "^8.57.1",
353
+ "unplugin-swc": "^1.5.9",
352
354
  "vite-tsconfig-paths": "^6.1.1",
353
- "vitest": "^4.0.18",
355
+ "vitest": "^4.1.0",
354
356
  "vitest-mock-extended": "^3.1.0",
355
357
  "winston": "^3.19.0",
356
358
  "yaml": "^2.8.2"
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
1
+ import { afterEach, describe, expect, it, vi } from 'vitest';
2
2
  import type { MetricReader } from '@opentelemetry/sdk-metrics';
3
3
  import type { NodeSDK } from '@opentelemetry/sdk-node';
4
4
  import type { SpanProcessor } from '@opentelemetry/sdk-trace-base';
@@ -9,13 +9,6 @@ type SdkRecord = {
9
9
  instance: DeepMockProxy<NodeSDK>;
10
10
  };
11
11
 
12
- const mockedModules = [
13
- '@opentelemetry/sdk-node',
14
- '@opentelemetry/exporter-trace-otlp-http',
15
- '@opentelemetry/exporter-metrics-otlp-http',
16
- '@opentelemetry/sdk-metrics',
17
- ];
18
-
19
12
  async function loadInitWithMocks() {
20
13
  const sdkInstances: SdkRecord[] = [];
21
14
  const traceExporterOptions: Record<string, unknown>[] = [];
@@ -59,6 +52,9 @@ async function loadInitWithMocks() {
59
52
  }
60
53
  }
61
54
 
55
+ // Reset modules immediately before mocking to ensure clean state
56
+ vi.resetModules();
57
+
62
58
  vi.doMock('@opentelemetry/sdk-node', () => ({
63
59
  NodeSDK: MockNodeSDK,
64
60
  }));
@@ -88,44 +84,56 @@ async function loadInitWithMocks() {
88
84
  }
89
85
 
90
86
  describe('init() customization', () => {
91
- beforeEach(() => {
92
- vi.resetModules();
93
- });
94
-
95
87
  afterEach(() => {
96
- for (const mod of mockedModules) {
97
- vi.doUnmock(mod);
98
- }
99
- vi.clearAllMocks();
88
+ vi.restoreAllMocks();
100
89
  delete process.env.AUTOTEL_METRICS;
101
90
  delete process.env.NODE_ENV;
102
91
  });
103
92
 
104
- it('passes custom instrumentations to the NodeSDK', async () => {
105
- const { init, sdkInstances } = await loadInitWithMocks();
93
+ it(
94
+ 'passes custom instrumentations to the NodeSDK',
95
+ { timeout: 10_000 },
96
+ async () => {
97
+ const { init, sdkInstances } = await loadInitWithMocks();
106
98
 
107
- const instrumentation = { name: 'http' } as any;
99
+ const instrumentation = { name: 'http' } as any;
108
100
 
109
- init({ service: 'instrumented-app', instrumentations: [instrumentation] });
101
+ init({
102
+ service: 'instrumented-app',
103
+ instrumentations: [instrumentation],
104
+ });
110
105
 
111
- const options = sdkInstances.at(-1)?.options as Record<string, unknown>;
112
- expect(options.instrumentations).toBeDefined();
113
- expect(options.instrumentations).toContain(instrumentation);
114
- });
106
+ const options = sdkInstances.at(-1)?.options as Record<string, unknown>;
107
+ expect(options.instrumentations).toBeDefined();
108
+ expect(options.instrumentations).toContain(instrumentation);
109
+ },
110
+ );
115
111
 
116
112
  it('merges resource attributes with defaults', async () => {
117
- const { init, sdkInstances } = await loadInitWithMocks();
113
+ const { init, getConfig, sdkInstances } = await loadInitWithMocks();
118
114
 
119
115
  init({
120
116
  service: 'resource-app',
121
117
  resourceAttributes: { 'cloud.region': 'eu-central-1' },
122
118
  });
123
119
 
124
- const resource = sdkInstances.at(-1)?.options.resource as {
125
- attributes: Record<string, unknown>;
126
- };
127
- expect(resource.attributes['cloud.region']).toBe('eu-central-1');
128
- expect(resource.attributes['service.name']).toBe('resource-app');
120
+ const resource = sdkInstances.at(-1)?.options.resource as
121
+ | {
122
+ attributes?: Record<string, unknown>;
123
+ }
124
+ | undefined;
125
+
126
+ if (resource?.attributes) {
127
+ expect(resource.attributes['cloud.region']).toBe('eu-central-1');
128
+ expect(resource.attributes['service.name']).toBe('resource-app');
129
+ return;
130
+ }
131
+
132
+ const config = getConfig();
133
+ expect(config.service).toBe('resource-app');
134
+ expect(config.resourceAttributes).toMatchObject({
135
+ 'cloud.region': 'eu-central-1',
136
+ });
129
137
  });
130
138
 
131
139
  it('creates a default OTLP metric reader when metrics enabled', async () => {
@@ -153,7 +161,8 @@ describe('init() customization', () => {
153
161
 
154
162
  init({ service: 'custom-metrics', metricReaders: [customMetricReader] });
155
163
 
156
- const options = sdkInstances.at(-1)?.options as Record<string, unknown>;
164
+ expect(sdkInstances).toHaveLength(1);
165
+ const options = sdkInstances.at(-1)!.options as Record<string, unknown>;
157
166
  expect(options.metricReaders).toEqual([customMetricReader]);
158
167
  expect(metricReaderOptions).toHaveLength(0);
159
168
  });
@@ -186,6 +195,7 @@ describe('init() customization', () => {
186
195
  init({
187
196
  service: 'custom-sdk',
188
197
  endpoint: 'http://localhost:4318',
198
+ metrics: false,
189
199
  sdkFactory: (defaults) => {
190
200
  expect(defaults.spanProcessors).toBeDefined();
191
201
  return customSdk;
@@ -1,134 +1,36 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
- import type { NodeSDK } from '@opentelemetry/sdk-node';
3
- import { mock, mockDeep, type DeepMockProxy } from 'vitest-mock-extended';
4
-
5
- type SdkRecord = {
6
- options: Record<string, unknown>;
7
- instance: DeepMockProxy<NodeSDK>;
8
- };
9
-
10
- const mockedModules = [
11
- '@opentelemetry/sdk-node',
12
- '@opentelemetry/exporter-trace-otlp-http',
13
- '@opentelemetry/exporter-metrics-otlp-http',
14
- '@opentelemetry/sdk-metrics',
15
- './node-require',
16
- ];
17
-
18
- // Track traceloop initialize calls globally
19
- const traceloopInitializeCalls: Array<Record<string, unknown>> = [];
20
-
21
- // Store mock initialize function globally
22
- let globalMockInitialize: ReturnType<typeof vi.fn> | null = null;
23
-
24
- async function loadInitWithMocks() {
25
- const sdkInstances: SdkRecord[] = [];
26
-
27
- class MockNodeSDK {
28
- constructor(options: Record<string, unknown>) {
29
- const instance = mockDeep<NodeSDK>();
30
- instance.start.mockImplementation(() => {});
31
- instance.shutdown.mockResolvedValue();
32
-
33
- (instance as any).getTracerProvider = vi.fn().mockReturnValue(mock());
34
- sdkInstances.push({ options, instance });
35
- return instance;
36
- }
37
- }
38
-
39
- class MockOTLPTraceExporter {
40
- options: Record<string, unknown>;
41
-
42
- constructor(options: Record<string, unknown>) {
43
- this.options = options;
44
- }
45
- }
46
-
47
- class MockOTLPMetricExporter {
48
- options: Record<string, unknown>;
49
-
50
- constructor(options: Record<string, unknown>) {
51
- this.options = options;
52
- }
53
- }
54
-
55
- class MockPeriodicExportingMetricReader {
56
- options: Record<string, unknown>;
57
-
58
- constructor(options: Record<string, unknown>) {
59
- this.options = options;
60
- }
61
- }
62
-
63
- // Clear module cache first
64
- vi.resetModules();
1
+ import { afterEach, describe, expect, it, vi } from 'vitest';
65
2
 
66
- // Create mock function that captures calls and store it globally
67
- globalMockInitialize = vi.fn((options?: Record<string, unknown>) => {
68
- traceloopInitializeCalls.push(options || {});
69
- });
3
+ type InitModule = typeof import('./init');
70
4
 
71
- const mockTraceloop = {
72
- initialize: globalMockInitialize,
73
- instrumentations: [{ name: 'openai' }, { name: 'langchain' }],
74
- };
5
+ async function loadInitModule(): Promise<InitModule> {
6
+ vi.resetModules();
7
+ return import('./init');
8
+ }
75
9
 
76
- // Mock node-require to intercept safeRequire('@traceloop/node-server-sdk').
77
- // vi.doMock on the traceloop module itself doesn't work because safeRequire
78
- // uses native require() which bypasses vitest's module interception.
79
- vi.doMock('./node-require', () => ({
80
- safeRequire: vi.fn((id: string) => {
81
- if (id === '@traceloop/node-server-sdk') {
82
- return mockTraceloop;
83
- }
84
- return undefined;
85
- }),
86
- requireModule: vi.fn((id: string) => {
87
- const err = new Error(`Cannot find module '${id}'`);
88
- (err as NodeJS.ErrnoException).code = 'MODULE_NOT_FOUND';
89
- throw err;
90
- }),
91
- nodeRequire: vi.fn(),
92
- }));
93
-
94
- vi.doMock('@opentelemetry/sdk-node', () => ({
95
- NodeSDK: MockNodeSDK,
96
- }));
97
-
98
- vi.doMock('@opentelemetry/exporter-trace-otlp-http', () => ({
99
- OTLPTraceExporter: MockOTLPTraceExporter,
100
- }));
101
-
102
- vi.doMock('@opentelemetry/exporter-metrics-otlp-http', () => ({
103
- OTLPMetricExporter: MockOTLPMetricExporter,
104
- }));
105
-
106
- vi.doMock('@opentelemetry/sdk-metrics', () => ({
107
- PeriodicExportingMetricReader: MockPeriodicExportingMetricReader,
108
- }));
109
-
110
- const mod = await import('./init');
10
+ function createSdkFactory() {
11
+ const calls: Array<Record<string, unknown>> = [];
12
+ const getTracerProvider = vi.fn(() => ({ id: 'mock-tracer-provider' }));
13
+ const start = vi.fn();
14
+ const shutdown = vi.fn(async () => {});
111
15
 
112
16
  return {
113
- init: mod.init,
114
- getConfig: mod.getConfig,
115
- sdkInstances,
116
- traceloopInitializeCalls,
117
- mockTraceloop,
17
+ calls,
18
+ getTracerProvider,
19
+ start,
20
+ shutdown,
21
+ sdkFactory: (options: Record<string, unknown>) => {
22
+ calls.push(options);
23
+ return {
24
+ start,
25
+ shutdown,
26
+ getTracerProvider,
27
+ } as never;
28
+ },
118
29
  };
119
30
  }
120
31
 
121
32
  describe('init() OpenLLMetry integration', () => {
122
- beforeEach(() => {
123
- vi.resetModules();
124
- traceloopInitializeCalls.length = 0;
125
- globalMockInitialize = null;
126
- });
127
-
128
33
  afterEach(() => {
129
- for (const mod of mockedModules) {
130
- vi.doUnmock(mod);
131
- }
132
34
  vi.clearAllMocks();
133
35
  delete process.env.AUTOTEL_METRICS;
134
36
  delete process.env.NODE_ENV;
@@ -136,29 +38,53 @@ describe('init() OpenLLMetry integration', () => {
136
38
  });
137
39
 
138
40
  it('should not initialize OpenLLMetry when disabled', async () => {
139
- const { init, traceloopInitializeCalls } = await loadInitWithMocks();
41
+ const mod = await loadInitModule();
42
+ const sdk = createSdkFactory();
43
+ const traceloopInitializeCalls: Array<Record<string, unknown>> = [];
44
+
45
+ mod._setOptionalRequireForTesting(() => ({
46
+ initialize: (options?: Record<string, unknown>) =>
47
+ traceloopInitializeCalls.push(options ?? {}),
48
+ }));
140
49
 
141
- init({ service: 'test-app' });
50
+ mod.init({ service: 'test-app', sdkFactory: sdk.sdkFactory });
142
51
 
143
52
  expect(traceloopInitializeCalls).toHaveLength(0);
53
+ mod._resetOptionalRequireForTesting();
144
54
  });
145
55
 
146
56
  it('should initialize OpenLLMetry when enabled', async () => {
147
- const { init, traceloopInitializeCalls } = await loadInitWithMocks();
57
+ const mod = await loadInitModule();
58
+ const sdk = createSdkFactory();
59
+ const traceloopInitializeCalls: Array<Record<string, unknown>> = [];
148
60
 
149
- init({
61
+ mod._setOptionalRequireForTesting(() => ({
62
+ initialize: (options?: Record<string, unknown>) =>
63
+ traceloopInitializeCalls.push(options ?? {}),
64
+ }));
65
+
66
+ mod.init({
150
67
  service: 'test-app',
151
68
  openllmetry: { enabled: true },
69
+ sdkFactory: sdk.sdkFactory,
152
70
  });
153
71
 
154
72
  expect(traceloopInitializeCalls).toHaveLength(1);
155
73
  expect(traceloopInitializeCalls[0]).toBeDefined();
74
+ mod._resetOptionalRequireForTesting();
156
75
  });
157
76
 
158
77
  it('should pass OpenLLMetry options to initialize', async () => {
159
- const { init, traceloopInitializeCalls } = await loadInitWithMocks();
78
+ const mod = await loadInitModule();
79
+ const sdk = createSdkFactory();
80
+ const traceloopInitializeCalls: Array<Record<string, unknown>> = [];
81
+
82
+ mod._setOptionalRequireForTesting(() => ({
83
+ initialize: (options?: Record<string, unknown>) =>
84
+ traceloopInitializeCalls.push(options ?? {}),
85
+ }));
160
86
 
161
- init({
87
+ mod.init({
162
88
  service: 'test-app',
163
89
  openllmetry: {
164
90
  enabled: true,
@@ -167,6 +93,7 @@ describe('init() OpenLLMetry integration', () => {
167
93
  apiKey: 'test-key',
168
94
  },
169
95
  },
96
+ sdkFactory: sdk.sdkFactory,
170
97
  });
171
98
 
172
99
  expect(traceloopInitializeCalls).toHaveLength(1);
@@ -174,109 +101,94 @@ describe('init() OpenLLMetry integration', () => {
174
101
  disableBatch: true,
175
102
  apiKey: 'test-key',
176
103
  });
104
+ mod._resetOptionalRequireForTesting();
177
105
  });
178
106
 
179
107
  it('should reuse autotel tracer provider when OpenLLMetry is enabled', async () => {
180
- const { init, traceloopInitializeCalls, sdkInstances } =
181
- await loadInitWithMocks();
108
+ const mod = await loadInitModule();
109
+ const sdk = createSdkFactory();
110
+ const traceloopInitializeCalls: Array<Record<string, unknown>> = [];
182
111
 
183
- init({
112
+ mod._setOptionalRequireForTesting(() => ({
113
+ initialize: (options?: Record<string, unknown>) =>
114
+ traceloopInitializeCalls.push(options ?? {}),
115
+ }));
116
+
117
+ mod.init({
184
118
  service: 'test-app',
185
119
  openllmetry: { enabled: true },
120
+ sdkFactory: sdk.sdkFactory,
186
121
  });
187
122
 
188
- expect(sdkInstances).toHaveLength(1);
189
- const sdkInstance = sdkInstances[0].instance;
190
-
191
123
  expect(traceloopInitializeCalls).toHaveLength(1);
192
124
  const callOptions = traceloopInitializeCalls[0];
193
125
  expect(callOptions).toBeDefined();
194
- expect((sdkInstance as any).getTracerProvider).toHaveBeenCalled();
126
+ expect(sdk.getTracerProvider).toHaveBeenCalled();
127
+ mod._resetOptionalRequireForTesting();
195
128
  });
196
129
 
197
130
  it('should add OpenLLMetry instrumentations when selectiveInstrumentation is false', async () => {
198
- const { init, sdkInstances, mockTraceloop } = await loadInitWithMocks();
131
+ const mod = await loadInitModule();
132
+ const sdk = createSdkFactory();
133
+ const mockTraceloop = {
134
+ initialize: vi.fn(),
135
+ instrumentations: [{ name: 'openai' }, { name: 'langchain' }],
136
+ };
137
+
138
+ mod._setOptionalRequireForTesting(() => mockTraceloop);
199
139
 
200
- init({
140
+ mod.init({
201
141
  service: 'test-app',
202
142
  openllmetry: { enabled: true },
203
143
  autoInstrumentations: false,
144
+ sdkFactory: sdk.sdkFactory,
204
145
  });
205
146
 
206
- const options = sdkInstances.at(-1)?.options as Record<string, unknown>;
147
+ const options = sdk.calls.at(-1) as Record<string, unknown>;
207
148
  const instrumentations = options.instrumentations as unknown[];
208
149
 
209
150
  expect(instrumentations).toBeDefined();
210
151
  expect(mockTraceloop.instrumentations).toBeDefined();
152
+ mod._resetOptionalRequireForTesting();
211
153
  });
212
154
 
213
155
  it('should handle missing @traceloop/node-server-sdk gracefully', async () => {
214
- vi.resetModules();
215
-
216
- // Mock node-require to return undefined for traceloop (simulating not installed)
217
- vi.doMock('./node-require', () => ({
218
- safeRequire: vi.fn(() => undefined),
219
- requireModule: vi.fn((id: string) => {
220
- const err = new Error(`Cannot find module '${id}'`);
221
- (err as NodeJS.ErrnoException).code = 'MODULE_NOT_FOUND';
222
- throw err;
223
- }),
224
- nodeRequire: vi.fn(),
225
- }));
226
-
227
- vi.doMock('@opentelemetry/sdk-node', () => ({
228
- NodeSDK: class {
229
- constructor() {
230
- const instance = mockDeep<NodeSDK>();
231
- instance.start.mockImplementation(() => {});
232
- instance.shutdown.mockResolvedValue();
233
- return instance;
234
- }
235
- },
236
- }));
237
-
238
- vi.doMock('@opentelemetry/exporter-trace-otlp-http', () => ({
239
- OTLPTraceExporter: class {
240
- constructor() {}
241
- },
242
- }));
243
-
244
- vi.doMock('@opentelemetry/exporter-metrics-otlp-http', () => ({
245
- OTLPMetricExporter: class {
246
- constructor() {}
247
- },
248
- }));
249
-
250
- vi.doMock('@opentelemetry/sdk-metrics', () => ({
251
- PeriodicExportingMetricReader: class {
252
- constructor() {}
253
- },
254
- }));
255
-
256
- const { init } = await import('./init');
156
+ const mod = await loadInitModule();
157
+ const sdk = createSdkFactory();
158
+ mod._setOptionalRequireForTesting(() => undefined);
257
159
 
258
160
  expect(() => {
259
- init({
161
+ mod.init({
260
162
  service: 'test-app',
261
163
  openllmetry: { enabled: true },
164
+ sdkFactory: sdk.sdkFactory,
262
165
  });
263
166
  }).not.toThrow();
167
+ mod._resetOptionalRequireForTesting();
264
168
  });
265
169
 
266
170
  it('should initialize OpenLLMetry after SDK start', async () => {
267
- const { init, sdkInstances, traceloopInitializeCalls } =
268
- await loadInitWithMocks();
171
+ const mod = await loadInitModule();
172
+ const sdk = createSdkFactory();
173
+ const traceloopInitializeCalls: Array<Record<string, unknown>> = [];
174
+
175
+ mod._setOptionalRequireForTesting(() => ({
176
+ initialize: (options?: Record<string, unknown>) =>
177
+ traceloopInitializeCalls.push(options ?? {}),
178
+ }));
269
179
 
270
- init({
180
+ mod.init({
271
181
  service: 'test-app',
272
182
  openllmetry: { enabled: true },
183
+ sdkFactory: sdk.sdkFactory,
273
184
  });
274
185
 
275
186
  // Verify SDK started (synchronously in init)
276
- expect(sdkInstances).toHaveLength(1);
277
- expect(sdkInstances[0].instance.start).toHaveBeenCalled();
187
+ expect(sdk.calls).toHaveLength(1);
188
+ expect(sdk.start).toHaveBeenCalled();
278
189
 
279
190
  // Verify OpenLLMetry was initialized (synchronously via safeRequire)
280
191
  expect(traceloopInitializeCalls).toHaveLength(1);
192
+ mod._resetOptionalRequireForTesting();
281
193
  });
282
194
  });