@outputai/http 0.4.1-dev.6555a2c.0 → 0.4.1-dev.7aa9a5f.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.
@@ -13,7 +13,6 @@ RequestInit };
13
13
  * Behaves the same as any fetch function except:
14
14
  * - Sets a request header called `x-request--trace-id` with a random UUID;
15
15
  * - Sends the request, response, error and/or failure to the Trace system;
16
- * - Emits a `http:request` event on every call (success, http_error, network_error).
17
16
  *
18
17
  * @see {@link https://fetch.spec.whatwg.org/}
19
18
  * @param input - URL string, URL object or Request object (undici's or Node's)
@@ -15,7 +15,6 @@ export * as undici from 'undici';
15
15
  * Behaves the same as any fetch function except:
16
16
  * - Sets a request header called `x-request--trace-id` with a random UUID;
17
17
  * - Sends the request, response, error and/or failure to the Trace system;
18
- * - Emits a `http:request` event on every call (success, http_error, network_error).
19
18
  *
20
19
  * @see {@link https://fetch.spec.whatwg.org/}
21
20
  * @param input - URL string, URL object or Request object (undici's or Node's)
@@ -30,25 +29,20 @@ export const fetch = async (input, init) => {
30
29
  const requestId = randomUUID();
31
30
  headers.set('x-request-trace-id', requestId);
32
31
  const request = new undici.Request(base, { headers });
33
- const method = request.method;
34
- const url = request.url;
35
- const startedAt = performance.now();
36
32
  await logRequest({ requestId, request });
37
33
  try {
38
34
  const response = await undici.fetch(request);
39
- const durationMs = Math.round(performance.now() - startedAt);
40
35
  // This enriches the response of the request id, so it is identifiable later.
41
36
  addRequestIdToResponse(response, requestId);
42
37
  if (response.status > 399) {
43
- await logError({ requestId, response, method, url, durationMs });
38
+ await logError({ requestId, response });
44
39
  return response;
45
40
  }
46
- await logResponse({ requestId, response, method, url, durationMs });
41
+ await logResponse({ requestId, response });
47
42
  return response;
48
43
  }
49
44
  catch (error) {
50
- const durationMs = Math.round(performance.now() - startedAt);
51
- logFailure({ requestId, error: error, method, url, durationMs });
45
+ logFailure({ requestId, error: error });
52
46
  throw error;
53
47
  }
54
48
  };
@@ -62,13 +62,8 @@ describe('fetch/index', () => {
62
62
  expect(loggerMock.logRequest.mock.calls[0][0].request.method).toBe('GET');
63
63
  expect(loggerMock.logRequest.mock.calls[0][0].request.url).toBe(`${MOCK_ORIGIN}/ok`);
64
64
  expect(loggerMock.logResponse).toHaveBeenCalledTimes(1);
65
- const responseCall = loggerMock.logResponse.mock.calls[0][0];
66
- expect(responseCall.requestId).toBe(FIXED_REQUEST_ID);
67
- expect(responseCall.response).toBe(response);
68
- expect(responseCall.method).toBe('GET');
69
- expect(responseCall.url).toBe(`${MOCK_ORIGIN}/ok`);
70
- expect(typeof responseCall.durationMs).toBe('number');
71
- expect(responseCall.durationMs).toBeGreaterThanOrEqual(0);
65
+ expect(loggerMock.logResponse.mock.calls[0][0].requestId).toBe(FIXED_REQUEST_ID);
66
+ expect(loggerMock.logResponse.mock.calls[0][0].response).toBe(response);
72
67
  expect(utilsMock.addRequestIdToResponse).toHaveBeenCalledTimes(1);
73
68
  expect(utilsMock.addRequestIdToResponse).toHaveBeenCalledWith(response, FIXED_REQUEST_ID);
74
69
  expect(loggerMock.logError).not.toHaveBeenCalled();
@@ -12,55 +12,34 @@ export declare const logRequest: ({ requestId, request }: {
12
12
  }) => Promise<void>;
13
13
  /**
14
14
  * Sends the trace error event for an http response with error status
15
- * and emits a `http:request` event with `outcome: 'http_error'`.
16
15
  *
17
16
  * @param options
18
17
  * @param options.requestId - id of the request
19
18
  * @param options.response - The HTTP Response object
20
- * @param options.method - HTTP method of the request
21
- * @param options.url - URL of the request
22
- * @param options.durationMs - elapsed time from request issuance to response, in milliseconds
23
19
  */
24
- export declare const logError: ({ requestId, response, method, url, durationMs }: {
20
+ export declare const logError: ({ requestId, response }: {
25
21
  requestId: string;
26
22
  response: Response;
27
- method: string;
28
- url: string;
29
- durationMs: number;
30
23
  }) => Promise<void>;
31
24
  /**
32
25
  * Sends the trace end event for an http response
33
- * and emits a `http:request` event with `outcome: 'success'`.
34
26
  *
35
27
  * @param {object} options
36
28
  * @param options.requestId - id of the request
37
29
  * @param {Response} options.response - The HTTP Response object
38
- * @param options.method - HTTP method of the request
39
- * @param options.url - URL of the request
40
- * @param options.durationMs - elapsed time from request issuance to response, in milliseconds
41
30
  */
42
- export declare const logResponse: ({ requestId, response, method, url, durationMs }: {
31
+ export declare const logResponse: ({ requestId, response }: {
43
32
  requestId: string;
44
33
  response: Response;
45
- method: string;
46
- url: string;
47
- durationMs: number;
48
34
  }) => Promise<void>;
49
35
  /**
50
36
  * Creates the trace error event for a network/connection failure
51
- * and emits a `http:request` event with `outcome: 'network_error'`.
52
37
  *
53
38
  * @param options
54
39
  * @param options.requestId - id of the request
55
40
  * @param options.error - The error thrown
56
- * @param options.method - HTTP method of the request
57
- * @param options.url - URL of the request
58
- * @param options.durationMs - elapsed time from request issuance to failure, in milliseconds
59
41
  */
60
- export declare const logFailure: ({ requestId, error, method, url, durationMs }: {
42
+ export declare const logFailure: ({ requestId, error }: {
61
43
  requestId: string;
62
44
  error: Error;
63
- method: string;
64
- url: string;
65
- durationMs: number;
66
45
  }) => void;
@@ -1,10 +1,6 @@
1
- import { Tracing, emitEvent } from '@outputai/core/sdk_activity_integration';
1
+ import { Tracing } from '@outputai/core/sdk_activity_integration';
2
2
  import { config } from '../config.js';
3
3
  import { parseBody, redactHeaders, serializeError } from './utils.js';
4
- /** Single source of truth for the `http:request` event shape. */
5
- const emitHttpRequestEvent = (payload) => {
6
- emitEvent('http:request', payload);
7
- };
8
4
  /**
9
5
  * Sends the trace start event for an http request
10
6
  *
@@ -24,65 +20,38 @@ export const logRequest = async ({ requestId, request }) => {
24
20
  };
25
21
  /**
26
22
  * Sends the trace error event for an http response with error status
27
- * and emits a `http:request` event with `outcome: 'http_error'`.
28
23
  *
29
24
  * @param options
30
25
  * @param options.requestId - id of the request
31
26
  * @param options.response - The HTTP Response object
32
- * @param options.method - HTTP method of the request
33
- * @param options.url - URL of the request
34
- * @param options.durationMs - elapsed time from request issuance to response, in milliseconds
35
27
  */
36
- export const logError = async ({ requestId, response, method, url, durationMs }) => {
37
- await Tracing.addEventError({
38
- id: requestId, details: {
39
- status: response.status,
40
- statusText: response.statusText,
41
- headers: redactHeaders(response.headers),
42
- body: await parseBody(response)
43
- }
44
- });
45
- emitHttpRequestEvent({
46
- requestId, method, url, status: response.status, durationMs, outcome: 'http_error'
47
- });
48
- };
28
+ export const logError = async ({ requestId, response }) => Tracing.addEventError({
29
+ id: requestId, details: {
30
+ status: response.status,
31
+ statusText: response.statusText,
32
+ headers: redactHeaders(response.headers),
33
+ body: await parseBody(response)
34
+ }
35
+ });
49
36
  /**
50
37
  * Sends the trace end event for an http response
51
- * and emits a `http:request` event with `outcome: 'success'`.
52
38
  *
53
39
  * @param {object} options
54
40
  * @param options.requestId - id of the request
55
41
  * @param {Response} options.response - The HTTP Response object
56
- * @param options.method - HTTP method of the request
57
- * @param options.url - URL of the request
58
- * @param options.durationMs - elapsed time from request issuance to response, in milliseconds
59
42
  */
60
- export const logResponse = async ({ requestId, response, method, url, durationMs }) => {
61
- await Tracing.addEventEnd({
62
- id: requestId, details: {
63
- status: response.status,
64
- statusText: response.statusText,
65
- ...(config.logVerbose && { headers: redactHeaders(response.headers), body: await parseBody(response) })
66
- }
67
- });
68
- emitHttpRequestEvent({
69
- requestId, method, url, status: response.status, durationMs, outcome: 'success'
70
- });
71
- };
43
+ export const logResponse = async ({ requestId, response }) => Tracing.addEventEnd({
44
+ id: requestId, details: {
45
+ status: response.status,
46
+ statusText: response.statusText,
47
+ ...(config.logVerbose && { headers: redactHeaders(response.headers), body: await parseBody(response) })
48
+ }
49
+ });
72
50
  /**
73
51
  * Creates the trace error event for a network/connection failure
74
- * and emits a `http:request` event with `outcome: 'network_error'`.
75
52
  *
76
53
  * @param options
77
54
  * @param options.requestId - id of the request
78
55
  * @param options.error - The error thrown
79
- * @param options.method - HTTP method of the request
80
- * @param options.url - URL of the request
81
- * @param options.durationMs - elapsed time from request issuance to failure, in milliseconds
82
56
  */
83
- export const logFailure = ({ requestId, error, method, url, durationMs }) => {
84
- Tracing.addEventError({ id: requestId, details: serializeError(error) });
85
- emitHttpRequestEvent({
86
- requestId, method, url, status: undefined, durationMs, outcome: 'network_error'
87
- });
88
- };
57
+ export const logFailure = ({ requestId, error }) => Tracing.addEventError({ id: requestId, details: serializeError(error) });
@@ -20,13 +20,11 @@ vi.mock('@outputai/core/sdk_activity_integration', () => {
20
20
  Attribute: {
21
21
  HTTPRequestCount
22
22
  }
23
- },
24
- emitEvent: vi.fn()
23
+ }
25
24
  };
26
25
  });
27
- import { Tracing, emitEvent } from '@outputai/core/sdk_activity_integration';
26
+ import { Tracing } from '@outputai/core/sdk_activity_integration';
28
27
  const tracing = vi.mocked(Tracing, true);
29
- const emit = vi.mocked(emitEvent, true);
30
28
  /** Loads logger with optional verbose tracing env so `config.js` is evaluated fresh. */
31
29
  async function logLogger(verbose) {
32
30
  vi.resetModules();
@@ -43,7 +41,6 @@ beforeEach(() => {
43
41
  tracing.addEventEnd.mockClear();
44
42
  tracing.addEventError.mockClear();
45
43
  tracing.addEventAttribute.mockClear();
46
- emit.mockClear();
47
44
  });
48
45
  describe('fetch/logger', () => {
49
46
  describe('logRequest', () => {
@@ -118,9 +115,7 @@ describe('fetch/logger', () => {
118
115
  'content-type': 'application/json'
119
116
  }
120
117
  });
121
- await logError({
122
- requestId: 'e1', response, method: 'GET', url: 'https://upstream.test/x', durationMs: 1
123
- });
118
+ await logError({ requestId: 'e1', response });
124
119
  expect(tracing.addEventError).toHaveBeenCalledWith({
125
120
  id: 'e1',
126
121
  details: {
@@ -143,9 +138,7 @@ describe('fetch/logger', () => {
143
138
  statusText: 'Bad Gateway',
144
139
  headers: { 'content-type': 'text/plain' }
145
140
  });
146
- await logError({
147
- requestId: 'e2', response, method: 'GET', url: 'https://upstream.test/y', durationMs: 1
148
- });
141
+ await logError({ requestId: 'e2', response });
149
142
  expect(tracing.addEventError).toHaveBeenCalledWith({
150
143
  id: 'e2',
151
144
  details: {
@@ -165,9 +158,7 @@ describe('fetch/logger', () => {
165
158
  statusText: 'OK',
166
159
  headers: { 'content-type': 'application/json', Authorization: 'x' }
167
160
  });
168
- await logResponse({
169
- requestId: 'lr1', response, method: 'GET', url: 'https://x.test/a', durationMs: 1
170
- });
161
+ await logResponse({ requestId: 'lr1', response });
171
162
  expect(tracing.addEventEnd).toHaveBeenCalledWith({
172
163
  id: 'lr1',
173
164
  details: {
@@ -186,9 +177,7 @@ describe('fetch/logger', () => {
186
177
  'Set-Cookie': 'a=b'
187
178
  }
188
179
  });
189
- await logResponse({
190
- requestId: 'lr-v', response, method: 'POST', url: 'https://x.test/b', durationMs: 1
191
- });
180
+ await logResponse({ requestId: 'lr-v', response });
192
181
  expect(tracing.addEventEnd).toHaveBeenCalledWith({
193
182
  id: 'lr-v',
194
183
  details: {
@@ -207,7 +196,7 @@ describe('fetch/logger', () => {
207
196
  it('forwards serialized error details (including stack) to Tracing.addEventError', async () => {
208
197
  const { logFailure } = await logLogger(false);
209
198
  const err = new TypeError('network');
210
- logFailure({ requestId: 'f1', error: err, method: 'GET', url: 'https://example.test/x', durationMs: 12 });
199
+ logFailure({ requestId: 'f1', error: err });
211
200
  expect(tracing.addEventError).toHaveBeenCalledWith({
212
201
  id: 'f1',
213
202
  details: {
@@ -220,63 +209,4 @@ describe('fetch/logger', () => {
220
209
  });
221
210
  });
222
211
  });
223
- describe('http:request event emission', () => {
224
- it('emits http:request with outcome=success on logResponse', async () => {
225
- const { logResponse } = await logLogger(false);
226
- const response = new Response('', { status: 200 });
227
- await logResponse({
228
- requestId: 'r-ok',
229
- response,
230
- method: 'GET',
231
- url: 'https://api.example.com/ok',
232
- durationMs: 42
233
- });
234
- expect(emit).toHaveBeenCalledWith('http:request', {
235
- requestId: 'r-ok',
236
- method: 'GET',
237
- url: 'https://api.example.com/ok',
238
- status: 200,
239
- durationMs: 42,
240
- outcome: 'success'
241
- });
242
- });
243
- it('emits http:request with outcome=http_error on logError', async () => {
244
- const { logError } = await logLogger(false);
245
- const response = new Response('boom', { status: 500 });
246
- await logError({
247
- requestId: 'r-err',
248
- response,
249
- method: 'POST',
250
- url: 'https://api.example.com/err',
251
- durationMs: 15
252
- });
253
- expect(emit).toHaveBeenCalledWith('http:request', {
254
- requestId: 'r-err',
255
- method: 'POST',
256
- url: 'https://api.example.com/err',
257
- status: 500,
258
- durationMs: 15,
259
- outcome: 'http_error'
260
- });
261
- });
262
- it('emits http:request with outcome=network_error on logFailure (status undefined)', async () => {
263
- const { logFailure } = await logLogger(false);
264
- const err = new TypeError('network');
265
- logFailure({
266
- requestId: 'r-net',
267
- error: err,
268
- method: 'GET',
269
- url: 'https://api.example.com/net',
270
- durationMs: 9
271
- });
272
- expect(emit).toHaveBeenCalledWith('http:request', {
273
- requestId: 'r-net',
274
- method: 'GET',
275
- url: 'https://api.example.com/net',
276
- status: undefined,
277
- durationMs: 9,
278
- outcome: 'network_error'
279
- });
280
- });
281
- });
282
212
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@outputai/http",
3
- "version": "0.4.1-dev.6555a2c.0",
3
+ "version": "0.4.1-dev.7aa9a5f.0",
4
4
  "description": "Framework abstraction to make HTTP calls with tracing",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -11,7 +11,7 @@
11
11
  "dependencies": {
12
12
  "ky": "1.14.3",
13
13
  "undici": "8.1.0",
14
- "@outputai/core": "0.4.1-dev.6555a2c.0"
14
+ "@outputai/core": "0.4.1-dev.7aa9a5f.0"
15
15
  },
16
16
  "license": "Apache-2.0",
17
17
  "publishConfig": {