autotel-cloudflare 3.1.0 → 4.0.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 (76) hide show
  1. package/dist/agents.d.ts.map +1 -1
  2. package/dist/agents.js +7 -0
  3. package/dist/agents.js.map +1 -1
  4. package/package.json +8 -4
  5. package/src/actors/alarms.ts +0 -225
  6. package/src/actors/index.ts +0 -36
  7. package/src/actors/instrument-actor.test.ts +0 -179
  8. package/src/actors/instrument-actor.ts +0 -574
  9. package/src/actors/sockets.ts +0 -217
  10. package/src/actors/storage.ts +0 -263
  11. package/src/actors/traced-handler.ts +0 -300
  12. package/src/actors/types.ts +0 -98
  13. package/src/actors.ts +0 -50
  14. package/src/agents/agent.ts +0 -327
  15. package/src/agents/base.ts +0 -26
  16. package/src/agents/index.ts +0 -46
  17. package/src/agents/mcp.ts +0 -38
  18. package/src/agents/observability.ts +0 -145
  19. package/src/agents/otel-observability.test.ts +0 -269
  20. package/src/agents/otel-observability.ts +0 -557
  21. package/src/agents/types.ts +0 -61
  22. package/src/agents.ts +0 -87
  23. package/src/bindings/ai.test.ts +0 -170
  24. package/src/bindings/ai.ts +0 -73
  25. package/src/bindings/analytics-engine.test.ts +0 -175
  26. package/src/bindings/analytics-engine.ts +0 -78
  27. package/src/bindings/bindings-cache.test.ts +0 -80
  28. package/src/bindings/bindings-detection.test.ts +0 -235
  29. package/src/bindings/bindings-this-binding.test.ts +0 -294
  30. package/src/bindings/bindings.ts +0 -720
  31. package/src/bindings/browser-rendering.test.ts +0 -160
  32. package/src/bindings/browser-rendering.ts +0 -70
  33. package/src/bindings/common.ts +0 -84
  34. package/src/bindings/hyperdrive.test.ts +0 -176
  35. package/src/bindings/hyperdrive.ts +0 -74
  36. package/src/bindings/images.test.ts +0 -262
  37. package/src/bindings/images.ts +0 -182
  38. package/src/bindings/index.ts +0 -20
  39. package/src/bindings/queue-producer.test.ts +0 -224
  40. package/src/bindings/queue-producer.ts +0 -105
  41. package/src/bindings/rate-limiter.test.ts +0 -140
  42. package/src/bindings/rate-limiter.ts +0 -69
  43. package/src/bindings/vectorize.test.ts +0 -362
  44. package/src/bindings/vectorize.ts +0 -86
  45. package/src/bindings.ts +0 -6
  46. package/src/events.ts +0 -6
  47. package/src/execution-logger.test.ts +0 -127
  48. package/src/execution-logger.ts +0 -112
  49. package/src/global/cache.test.ts +0 -292
  50. package/src/global/cache.ts +0 -164
  51. package/src/global/fetch.test.ts +0 -399
  52. package/src/global/fetch.ts +0 -136
  53. package/src/global/index.ts +0 -7
  54. package/src/handlers/durable-objects.test.ts +0 -524
  55. package/src/handlers/durable-objects.ts +0 -250
  56. package/src/handlers/index.ts +0 -6
  57. package/src/handlers/workflows.test.ts +0 -411
  58. package/src/handlers/workflows.ts +0 -345
  59. package/src/handlers.ts +0 -6
  60. package/src/index.ts +0 -91
  61. package/src/logger.ts +0 -15
  62. package/src/native/native-tracing.test.ts +0 -54
  63. package/src/native/native-tracing.ts +0 -83
  64. package/src/native.ts +0 -12
  65. package/src/parse-error.ts +0 -1
  66. package/src/sampling.ts +0 -6
  67. package/src/testing.ts +0 -6
  68. package/src/wrappers/cf-attributes.test.ts +0 -334
  69. package/src/wrappers/define-worker-fetch.test.ts +0 -102
  70. package/src/wrappers/define-worker-fetch.ts +0 -71
  71. package/src/wrappers/index.ts +0 -13
  72. package/src/wrappers/instrument.integration.test.ts +0 -578
  73. package/src/wrappers/instrument.ts +0 -806
  74. package/src/wrappers/native-instrument.test.ts +0 -153
  75. package/src/wrappers/wrap-do.ts +0 -34
  76. package/src/wrappers/wrap-module.ts +0 -37
@@ -1,160 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { instrumentBrowserRendering } from './browser-rendering';
3
- import { trace, SpanStatusCode, SpanKind } from '@opentelemetry/api';
4
-
5
- describe('Browser Rendering Instrumentation', () => {
6
- let mockTracer: any;
7
- let mockSpan: any;
8
- let getTracerSpy: any;
9
- let mockBrowser: any;
10
-
11
- beforeEach(() => {
12
- mockSpan = {
13
- spanContext: () => ({
14
- traceId: 'test-trace-id',
15
- spanId: 'test-span-id',
16
- traceFlags: 1,
17
- }),
18
- setAttribute: vi.fn(),
19
- setAttributes: vi.fn(),
20
- setStatus: vi.fn(),
21
- recordException: vi.fn(),
22
- end: vi.fn(),
23
- isRecording: () => true,
24
- updateName: vi.fn(),
25
- addEvent: vi.fn(),
26
- };
27
-
28
- mockTracer = {
29
- startActiveSpan: vi.fn((name, options, fn) => {
30
- return fn(mockSpan);
31
- }),
32
- };
33
-
34
- getTracerSpy = vi.spyOn(trace, 'getTracer').mockReturnValue(mockTracer as any);
35
-
36
- mockBrowser = {
37
- fetch: vi.fn(async () => new Response('<html></html>', { status: 200 })),
38
- someOtherMethod: vi.fn(() => 'passthrough-value'),
39
- };
40
- });
41
-
42
- afterEach(() => {
43
- getTracerSpy.mockRestore();
44
- });
45
-
46
- describe('fetch()', () => {
47
- it('should create span with correct attributes', async () => {
48
- const instrumented = instrumentBrowserRendering(mockBrowser, 'my-browser');
49
-
50
- await instrumented.fetch('https://example.com/page');
51
-
52
- expect(mockTracer.startActiveSpan).toHaveBeenCalledTimes(1);
53
-
54
- const [spanName, spanOptions] = mockTracer.startActiveSpan.mock.calls[0];
55
- expect(spanName).toBe('BrowserRendering my-browser: fetch');
56
- expect(spanOptions.kind).toBe(SpanKind.CLIENT);
57
- expect(spanOptions.attributes['browser.system']).toBe('cloudflare-browser-rendering');
58
- expect(spanOptions.attributes['url.full']).toBe('https://example.com/page');
59
- });
60
-
61
- it('should record http.response.status_code', async () => {
62
- mockBrowser.fetch = vi.fn(async () => new Response('Not Found', { status: 404 }));
63
-
64
- const instrumented = instrumentBrowserRendering(mockBrowser, 'my-browser');
65
-
66
- await instrumented.fetch('https://example.com/missing');
67
-
68
- expect(mockSpan.setAttribute).toHaveBeenCalledWith('http.response.status_code', 404);
69
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
70
- expect(mockSpan.end).toHaveBeenCalled();
71
- });
72
-
73
- it('should handle errors by recording exception and rethrowing', async () => {
74
- const error = new Error('Browser rendering failed');
75
- mockBrowser.fetch = vi.fn(async () => {
76
- throw error;
77
- });
78
-
79
- const instrumented = instrumentBrowserRendering(mockBrowser, 'my-browser');
80
-
81
- await expect(instrumented.fetch('https://example.com/broken')).rejects.toThrow('Browser rendering failed');
82
-
83
- expect(mockSpan.recordException).toHaveBeenCalledWith(error);
84
- expect(mockSpan.setStatus).toHaveBeenCalledWith({
85
- code: SpanStatusCode.ERROR,
86
- message: 'Browser rendering failed',
87
- });
88
- expect(mockSpan.end).toHaveBeenCalled();
89
- });
90
-
91
- it('should use default binding name when none provided', async () => {
92
- const instrumented = instrumentBrowserRendering(mockBrowser);
93
-
94
- await instrumented.fetch('https://example.com/page');
95
-
96
- const spanName = mockTracer.startActiveSpan.mock.calls[0][0];
97
- expect(spanName).toBe('BrowserRendering browser: fetch');
98
- });
99
-
100
- it('should handle URL objects as input', async () => {
101
- const instrumented = instrumentBrowserRendering(mockBrowser, 'my-browser');
102
-
103
- const url = new URL('https://example.com/rendered-page');
104
- await instrumented.fetch(url);
105
-
106
- const spanOptions = mockTracer.startActiveSpan.mock.calls[0][1];
107
- expect(spanOptions.attributes['url.full']).toBe('https://example.com/rendered-page');
108
- });
109
-
110
- it('should handle Request objects as input', async () => {
111
- const instrumented = instrumentBrowserRendering(mockBrowser, 'my-browser');
112
-
113
- const request = new Request('https://example.com/request-page');
114
- await instrumented.fetch(request);
115
-
116
- const spanOptions = mockTracer.startActiveSpan.mock.calls[0][1];
117
- expect(spanOptions.attributes['url.full']).toBe('https://example.com/request-page');
118
- });
119
-
120
- it('should set OK status and end span on success', async () => {
121
- const instrumented = instrumentBrowserRendering(mockBrowser, 'my-browser');
122
-
123
- const result = await instrumented.fetch('https://example.com/page');
124
-
125
- expect(result).toBeInstanceOf(Response);
126
- expect(mockSpan.setAttribute).toHaveBeenCalledWith('http.response.status_code', 200);
127
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
128
- expect(mockSpan.end).toHaveBeenCalled();
129
- });
130
- });
131
-
132
- describe('this-binding', () => {
133
- it('should invoke fetch() with original object as this, not the proxy', async () => {
134
- let receivedThis: any;
135
- const mockBrowserObj = {
136
- fetch: vi.fn(async function(this: any) {
137
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
138
- receivedThis = this;
139
- return new Response('ok', { status: 200 });
140
- }),
141
- };
142
- const instrumented = instrumentBrowserRendering(mockBrowserObj, 'test');
143
- await instrumented.fetch('https://example.com');
144
- expect(receivedThis).toBe(mockBrowserObj);
145
- });
146
- });
147
-
148
- describe('Non-instrumented methods', () => {
149
- it('should pass through non-instrumented methods unchanged', () => {
150
- const instrumented = instrumentBrowserRendering(mockBrowser, 'my-browser');
151
-
152
- const result = instrumented.someOtherMethod();
153
-
154
- expect(result).toBe('passthrough-value');
155
- expect(mockBrowser.someOtherMethod).toHaveBeenCalled();
156
- // No span should be created for non-instrumented methods
157
- expect(mockTracer.startActiveSpan).not.toHaveBeenCalled();
158
- });
159
- });
160
- });
@@ -1,70 +0,0 @@
1
- /**
2
- * Browser Rendering binding instrumentation
3
- */
4
-
5
- import {
6
- trace,
7
- SpanKind,
8
- SpanStatusCode,
9
- } from '@opentelemetry/api';
10
- import type { WorkerTracer } from 'autotel-edge';
11
- import { wrap, setAttr } from './common';
12
-
13
- interface BrowserRenderingLike {
14
- fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
15
- }
16
-
17
- /**
18
- * Instrument Browser Rendering binding (manual only — not auto-detected)
19
- */
20
- export function instrumentBrowserRendering<T extends BrowserRenderingLike>(browser: T, bindingName?: string): T {
21
- const name = bindingName || 'browser';
22
-
23
- const handler: ProxyHandler<T> = {
24
- get(target, prop) {
25
- const value = Reflect.get(target, prop);
26
-
27
- if (prop === 'fetch' && typeof value === 'function') {
28
- return new Proxy(value, {
29
- apply: (fnTarget, _thisArg, args) => {
30
- const [input] = args as [RequestInfo | URL, RequestInit | undefined];
31
- const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
32
- const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
33
-
34
- return tracer.startActiveSpan(
35
- `BrowserRendering ${name}: fetch`,
36
- {
37
- kind: SpanKind.CLIENT,
38
- attributes: {
39
- 'browser.system': 'cloudflare-browser-rendering',
40
- 'url.full': url,
41
- },
42
- },
43
- async (span) => {
44
- try {
45
- const result = await Reflect.apply(fnTarget, target, args);
46
- setAttr(span, 'http.response.status_code', result?.status);
47
- span.setStatus({ code: SpanStatusCode.OK });
48
- return result;
49
- } catch (error) {
50
- span.recordException(error as Error);
51
- span.setStatus({
52
- code: SpanStatusCode.ERROR,
53
- message: error instanceof Error ? error.message : String(error),
54
- });
55
- throw error;
56
- } finally {
57
- span.end();
58
- }
59
- },
60
- );
61
- },
62
- });
63
- }
64
-
65
- return value;
66
- },
67
- };
68
-
69
- return wrap(browser, handler);
70
- }
@@ -1,84 +0,0 @@
1
- /**
2
- * Common instrumentation utilities
3
- */
4
-
5
- /**
6
- * Promise tracker for waitUntil
7
- */
8
- export class PromiseTracker {
9
- private promises: Promise<unknown>[] = [];
10
-
11
- track(promise: Promise<unknown>): void {
12
- this.promises.push(promise);
13
- }
14
-
15
- async wait(): Promise<void> {
16
- await Promise.allSettled(this.promises);
17
- }
18
- }
19
-
20
- /**
21
- * Proxy ExecutionContext to track waitUntil promises
22
- */
23
- export function proxyExecutionContext(ctx: ExecutionContext): {
24
- ctx: ExecutionContext;
25
- tracker: PromiseTracker;
26
- } {
27
- const tracker = new PromiseTracker();
28
-
29
- const proxied = new Proxy(ctx, {
30
- get(target, prop) {
31
- if (prop === 'waitUntil') {
32
- return (promise: Promise<unknown>) => {
33
- tracker.track(promise);
34
- return target.waitUntil(promise);
35
- };
36
- }
37
- return Reflect.get(target, prop);
38
- },
39
- });
40
-
41
- return { ctx: proxied, tracker };
42
- }
43
-
44
- /**
45
- * Helper to wrap/unwrap proxied objects
46
- */
47
- const unwrapSymbol = Symbol('unwrap');
48
-
49
- type Wrapped<T> = { [unwrapSymbol]: T } & T;
50
-
51
- export function isWrapped<T>(item: T): item is Wrapped<T> {
52
- return item && !!(item as Wrapped<T>)[unwrapSymbol];
53
- }
54
-
55
- export function unwrap<T extends object>(item: T): T {
56
- if (item && isWrapped(item)) {
57
- return item[unwrapSymbol];
58
- } else {
59
- return item;
60
- }
61
- }
62
-
63
- /**
64
- * Set attribute only if value is defined and non-null
65
- */
66
- export function setAttr(span: { setAttribute: (key: string, value: any) => void }, key: string, value: unknown): void {
67
- if (value !== undefined && value !== null) {
68
- span.setAttribute(key, value);
69
- }
70
- }
71
-
72
- export function wrap<T extends object>(
73
- item: T,
74
- handler: ProxyHandler<T>,
75
- ): Wrapped<T> {
76
- const proxy = new Proxy(item, handler) as Wrapped<T>;
77
- Object.defineProperty(proxy, unwrapSymbol, {
78
- value: item,
79
- writable: false,
80
- enumerable: false,
81
- configurable: false,
82
- });
83
- return proxy;
84
- }
@@ -1,176 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { instrumentHyperdrive } from './hyperdrive';
3
- import { trace, SpanStatusCode, SpanKind } from '@opentelemetry/api';
4
-
5
- describe('Hyperdrive Binding Instrumentation', () => {
6
- let mockTracer: any;
7
- let mockSpan: any;
8
- let getTracerSpy: any;
9
-
10
- beforeEach(() => {
11
- mockSpan = {
12
- spanContext: () => ({
13
- traceId: 'test-trace-id',
14
- spanId: 'test-span-id',
15
- traceFlags: 1,
16
- }),
17
- setAttribute: vi.fn(),
18
- setAttributes: vi.fn(),
19
- setStatus: vi.fn(),
20
- recordException: vi.fn(),
21
- end: vi.fn(),
22
- isRecording: () => true,
23
- updateName: vi.fn(),
24
- addEvent: vi.fn(),
25
- };
26
-
27
- mockTracer = {
28
- startActiveSpan: vi.fn((name, options, fn) => {
29
- return fn(mockSpan);
30
- }),
31
- };
32
-
33
- getTracerSpy = vi.spyOn(trace, 'getTracer').mockReturnValue(mockTracer as any);
34
- });
35
-
36
- afterEach(() => {
37
- getTracerSpy.mockRestore();
38
- });
39
-
40
- function createMockHyperdrive(overrides: Partial<Hyperdrive> = {}): Hyperdrive {
41
- return {
42
- connect: vi.fn(async () => ({} as Socket)),
43
- connectionString: 'postgresql://user:secret-password@db.example.com:5432/mydb',
44
- host: 'db.example.com',
45
- port: 5432,
46
- user: 'user',
47
- password: 'secret-password',
48
- database: 'mydb',
49
- ...overrides,
50
- } as unknown as Hyperdrive;
51
- }
52
-
53
- describe('connect()', () => {
54
- it('should create span with correct attributes', async () => {
55
- const mockHyperdrive = createMockHyperdrive();
56
- const instrumented = instrumentHyperdrive(mockHyperdrive, 'my-db');
57
-
58
- await instrumented.connect();
59
-
60
- expect(mockTracer.startActiveSpan).toHaveBeenCalledTimes(1);
61
-
62
- const [spanName, options] = mockTracer.startActiveSpan.mock.calls[0];
63
- expect(spanName).toBe('Hyperdrive my-db: connect');
64
- expect(options.kind).toBe(SpanKind.CLIENT);
65
- expect(options.attributes['db.system']).toBe('cloudflare-hyperdrive');
66
- expect(options.attributes['db.operation']).toBe('connect');
67
- expect(options.attributes['server.address']).toBe('db.example.com');
68
- expect(options.attributes['server.port']).toBe(5432);
69
- expect(options.attributes['db.user']).toBe('user');
70
- });
71
-
72
- it('should handle errors correctly', async () => {
73
- const connectError = new Error('Connection refused');
74
- const mockHyperdrive = createMockHyperdrive({
75
- connect: vi.fn(async () => {
76
- throw connectError;
77
- }) as any,
78
- });
79
- const instrumented = instrumentHyperdrive(mockHyperdrive, 'my-db');
80
-
81
- await expect(instrumented.connect()).rejects.toThrow('Connection refused');
82
-
83
- expect(mockSpan.recordException).toHaveBeenCalledWith(connectError);
84
- expect(mockSpan.setStatus).toHaveBeenCalledWith({
85
- code: SpanStatusCode.ERROR,
86
- message: 'Connection refused',
87
- });
88
- expect(mockSpan.end).toHaveBeenCalled();
89
- });
90
-
91
- it('should set OK status and end span on success', async () => {
92
- const mockSocket = { readable: true } as unknown as Socket;
93
- const mockHyperdrive = createMockHyperdrive({
94
- connect: vi.fn(async () => mockSocket) as any,
95
- });
96
- const instrumented = instrumentHyperdrive(mockHyperdrive, 'my-db');
97
-
98
- const result = await instrumented.connect();
99
-
100
- expect(result).toBe(mockSocket);
101
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
102
- expect(mockSpan.end).toHaveBeenCalled();
103
- });
104
-
105
- it('should use default binding name when none provided', async () => {
106
- const mockHyperdrive = createMockHyperdrive();
107
- const instrumented = instrumentHyperdrive(mockHyperdrive);
108
-
109
- await instrumented.connect();
110
-
111
- const [spanName] = mockTracer.startActiveSpan.mock.calls[0];
112
- expect(spanName).toBe('Hyperdrive hyperdrive: connect');
113
- });
114
- });
115
-
116
- describe('this-binding', () => {
117
- it('should invoke connect() with original object as this, not the proxy', async () => {
118
- let receivedThis: any;
119
- const mockHyperdrive = {
120
- connect: vi.fn(async function(this: any) {
121
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
122
- receivedThis = this;
123
- return {} as Socket;
124
- }),
125
- connectionString: 'postgresql://user:pass@host:5432/db',
126
- host: 'host',
127
- port: 5432,
128
- user: 'user',
129
- password: 'pass',
130
- database: 'db',
131
- } as unknown as Hyperdrive;
132
- const instrumented = instrumentHyperdrive(mockHyperdrive, 'test');
133
- await instrumented.connect();
134
- expect(receivedThis).toBe(mockHyperdrive);
135
- });
136
- });
137
-
138
- describe('non-instrumented properties', () => {
139
- it('should pass through non-instrumented properties', () => {
140
- const mockHyperdrive = createMockHyperdrive();
141
- const instrumented = instrumentHyperdrive(mockHyperdrive, 'my-db');
142
-
143
- expect(instrumented.connectionString).toBe('postgresql://user:secret-password@db.example.com:5432/mydb');
144
- expect(instrumented.host).toBe('db.example.com');
145
- expect(instrumented.port).toBe(5432);
146
- expect(instrumented.user).toBe('user');
147
- expect(instrumented.database).toBe('mydb');
148
- });
149
- });
150
-
151
- describe('security', () => {
152
- it('should never record password as an attribute', async () => {
153
- const mockHyperdrive = createMockHyperdrive({
154
- password: 'super-secret-password',
155
- });
156
- const instrumented = instrumentHyperdrive(mockHyperdrive, 'my-db');
157
-
158
- await instrumented.connect();
159
-
160
- const [, options] = mockTracer.startActiveSpan.mock.calls[0];
161
-
162
- // Verify password is not in the attributes
163
- const attributeKeys = Object.keys(options.attributes);
164
- for (const key of attributeKeys) {
165
- expect(options.attributes[key]).not.toBe('super-secret-password');
166
- }
167
- expect(options.attributes['db.password']).toBeUndefined();
168
- expect(options.attributes['password']).toBeUndefined();
169
-
170
- // Also verify setAttribute was not called with the password
171
- for (const call of mockSpan.setAttribute.mock.calls) {
172
- expect(call[1]).not.toBe('super-secret-password');
173
- }
174
- });
175
- });
176
- });
@@ -1,74 +0,0 @@
1
- /**
2
- * Hyperdrive binding instrumentation
3
- */
4
-
5
- import {
6
- trace,
7
- SpanKind,
8
- SpanStatusCode,
9
- } from '@opentelemetry/api';
10
- import type { WorkerTracer } from 'autotel-edge';
11
- import { wrap, setAttr } from './common';
12
-
13
- /**
14
- * Instrument Hyperdrive binding
15
- */
16
- export function instrumentHyperdrive<T extends Hyperdrive>(hyperdrive: T, bindingName?: string): T {
17
- const name = bindingName || 'hyperdrive';
18
-
19
- const handler: ProxyHandler<T> = {
20
- get(target, prop) {
21
- const value = Reflect.get(target, prop);
22
-
23
- if (prop === 'connect' && typeof value === 'function') {
24
- return new Proxy(value, {
25
- apply: (fnTarget, _thisArg, args) => {
26
- const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
27
-
28
- const attributes: Record<string, string | number> = {
29
- 'db.system': 'cloudflare-hyperdrive',
30
- 'db.operation': 'connect',
31
- };
32
-
33
- // Extract connection info safely (never record password)
34
- try {
35
- setAttr({ setAttribute: (k: string, v: any) => { if (v !== undefined && v !== null) attributes[k] = v; } }, 'server.address', target.host);
36
- setAttr({ setAttribute: (k: string, v: any) => { if (v !== undefined && v !== null) attributes[k] = v; } }, 'server.port', target.port);
37
- setAttr({ setAttribute: (k: string, v: any) => { if (v !== undefined && v !== null) attributes[k] = v; } }, 'db.user', target.user);
38
- } catch {
39
- // Properties may not be accessible in all environments
40
- }
41
-
42
- return tracer.startActiveSpan(
43
- `Hyperdrive ${name}: connect`,
44
- {
45
- kind: SpanKind.CLIENT,
46
- attributes,
47
- },
48
- async (span) => {
49
- try {
50
- const result = await Reflect.apply(fnTarget, target, args);
51
- span.setStatus({ code: SpanStatusCode.OK });
52
- return result;
53
- } catch (error) {
54
- span.recordException(error as Error);
55
- span.setStatus({
56
- code: SpanStatusCode.ERROR,
57
- message: error instanceof Error ? error.message : String(error),
58
- });
59
- throw error;
60
- } finally {
61
- span.end();
62
- }
63
- },
64
- );
65
- },
66
- });
67
- }
68
-
69
- return value;
70
- },
71
- };
72
-
73
- return wrap(hyperdrive, handler);
74
- }