@outputai/http 0.2.0 → 0.2.1-next.fd72d95.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 (49) hide show
  1. package/dist/fetch/index.d.ts +22 -0
  2. package/dist/fetch/index.js +45 -0
  3. package/dist/fetch/index.spec.js +206 -0
  4. package/dist/fetch/logger.d.ts +45 -0
  5. package/dist/fetch/logger.js +54 -0
  6. package/dist/fetch/logger.spec.js +182 -0
  7. package/dist/fetch/utils.d.ts +36 -0
  8. package/dist/fetch/utils.js +91 -0
  9. package/dist/fetch/utils.spec.js +253 -0
  10. package/dist/index.d.ts +2 -1
  11. package/dist/index.js +4 -26
  12. package/dist/index.spec.js +11 -389
  13. package/package.json +3 -2
  14. package/dist/hooks/assign_request_id.d.ts +0 -9
  15. package/dist/hooks/assign_request_id.js +0 -15
  16. package/dist/hooks/index.d.ts +0 -4
  17. package/dist/hooks/index.js +0 -4
  18. package/dist/hooks/trace_error.d.ts +0 -14
  19. package/dist/hooks/trace_error.js +0 -61
  20. package/dist/hooks/trace_error.spec.js +0 -35
  21. package/dist/hooks/trace_request.d.ts +0 -6
  22. package/dist/hooks/trace_request.js +0 -25
  23. package/dist/hooks/trace_request.spec.js +0 -60
  24. package/dist/hooks/trace_response.d.ts +0 -6
  25. package/dist/hooks/trace_response.js +0 -26
  26. package/dist/hooks/trace_response.spec.js +0 -68
  27. package/dist/index.integration.test.d.ts +0 -1
  28. package/dist/index.integration.test.js +0 -389
  29. package/dist/utils/create_trace_id.d.ts +0 -13
  30. package/dist/utils/create_trace_id.js +0 -20
  31. package/dist/utils/create_trace_id.spec.d.ts +0 -1
  32. package/dist/utils/create_trace_id.spec.js +0 -20
  33. package/dist/utils/index.d.ts +0 -4
  34. package/dist/utils/index.js +0 -4
  35. package/dist/utils/parse_request_body.d.ts +0 -7
  36. package/dist/utils/parse_request_body.js +0 -19
  37. package/dist/utils/parse_request_body.spec.d.ts +0 -1
  38. package/dist/utils/parse_request_body.spec.js +0 -19
  39. package/dist/utils/parse_response_body.d.ts +0 -10
  40. package/dist/utils/parse_response_body.js +0 -14
  41. package/dist/utils/parse_response_body.spec.d.ts +0 -1
  42. package/dist/utils/parse_response_body.spec.js +0 -19
  43. package/dist/utils/redact_headers.d.ts +0 -6
  44. package/dist/utils/redact_headers.js +0 -27
  45. package/dist/utils/redact_headers.spec.d.ts +0 -1
  46. package/dist/utils/redact_headers.spec.js +0 -245
  47. /package/dist/{hooks/trace_error.spec.d.ts → fetch/index.spec.d.ts} +0 -0
  48. /package/dist/{hooks/trace_request.spec.d.ts → fetch/logger.spec.d.ts} +0 -0
  49. /package/dist/{hooks/trace_response.spec.d.ts → fetch/utils.spec.d.ts} +0 -0
@@ -1,19 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import parseResponseBody from './parse_response_body.js';
3
- describe('utils/parse_response_body', () => {
4
- it('parses JSON when content-type is application/json', async () => {
5
- const res = new Response(JSON.stringify({ ok: true }), { headers: { 'content-type': 'application/json' } });
6
- const result = await parseResponseBody(res);
7
- expect(result).toEqual({ ok: true });
8
- });
9
- it('returns text when content-type is not JSON', async () => {
10
- const res = new Response('hello', { headers: { 'content-type': 'text/plain' } });
11
- const result = await parseResponseBody(res);
12
- expect(result).toBe('hello');
13
- });
14
- it('returns null for empty body', async () => {
15
- const res = new Response('', { headers: { 'content-type': 'text/plain' } });
16
- const result = await parseResponseBody(res);
17
- expect(result).toBeNull();
18
- });
19
- });
@@ -1,6 +0,0 @@
1
- /**
2
- * Redacts sensitive headers for safe logging
3
- * @param headers - Headers object to redact
4
- * @returns Object with sensitive headers redacted
5
- */
6
- export default function redactHeaders(headers: Record<string, string> | Headers): Record<string, string>;
@@ -1,27 +0,0 @@
1
- /**
2
- * Sensitive header patterns for redaction (case-insensitive)
3
- */
4
- const SENSITIVE_HEADER_PATTERNS = [
5
- /authorization/i,
6
- /token/i,
7
- /api-?key/i,
8
- /secret/i,
9
- /password/i,
10
- /pwd/i,
11
- /key/i,
12
- /cookie/i
13
- ];
14
- /**
15
- * Redacts sensitive headers for safe logging
16
- * @param headers - Headers object to redact
17
- * @returns Object with sensitive headers redacted
18
- */
19
- export default function redactHeaders(headers) {
20
- const result = {};
21
- const entries = headers instanceof Headers ? headers.entries() : Object.entries(headers);
22
- for (const [key, value] of entries) {
23
- const isSensitive = SENSITIVE_HEADER_PATTERNS.some(pattern => pattern.test(key));
24
- result[key] = isSensitive ? '[REDACTED]' : value;
25
- }
26
- return result;
27
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,245 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import redactHeaders from './redact_headers.js';
3
- describe('redactHeaders', () => {
4
- describe('with Record<string, string> input', () => {
5
- it('should redact sensitive headers (case insensitive)', () => {
6
- const headers = {
7
- Authorization: 'Bearer token123',
8
- 'X-API-Key': 'secret-key',
9
- apikey: 'another-secret',
10
- 'X-Auth-Token': 'auth-token',
11
- 'Secret-Header': 'top-secret',
12
- Password: 'password123',
13
- 'Private-Key': 'private-key-data',
14
- Cookie: 'session=abc123',
15
- 'Content-Type': 'application/json',
16
- 'User-Agent': 'test-agent'
17
- };
18
- const result = redactHeaders(headers);
19
- expect(result).toEqual({
20
- Authorization: '[REDACTED]',
21
- 'X-API-Key': '[REDACTED]',
22
- apikey: '[REDACTED]',
23
- 'X-Auth-Token': '[REDACTED]',
24
- 'Secret-Header': '[REDACTED]',
25
- Password: '[REDACTED]',
26
- 'Private-Key': '[REDACTED]',
27
- Cookie: '[REDACTED]',
28
- 'Content-Type': 'application/json',
29
- 'User-Agent': 'test-agent'
30
- });
31
- });
32
- it('should handle mixed case header names', () => {
33
- const headers = {
34
- AUTHORIZATION: 'Bearer token',
35
- 'x-api-key': 'secret',
36
- 'Api-Key': 'another-secret',
37
- 'TOKEN-HEADER': 'token-value',
38
- 'content-type': 'application/json'
39
- };
40
- const result = redactHeaders(headers);
41
- expect(result).toEqual({
42
- AUTHORIZATION: '[REDACTED]',
43
- 'x-api-key': '[REDACTED]',
44
- 'Api-Key': '[REDACTED]',
45
- 'TOKEN-HEADER': '[REDACTED]',
46
- 'content-type': 'application/json'
47
- });
48
- });
49
- it('should not redact non-sensitive headers', () => {
50
- const headers = {
51
- 'Content-Type': 'application/json',
52
- Accept: 'application/json',
53
- 'User-Agent': 'test-agent',
54
- 'X-Custom-Header': 'custom-value',
55
- 'Cache-Control': 'no-cache'
56
- };
57
- const result = redactHeaders(headers);
58
- expect(result).toEqual(headers);
59
- });
60
- it('should handle empty headers object', () => {
61
- const headers = {};
62
- const result = redactHeaders(headers);
63
- expect(result).toEqual({});
64
- });
65
- it('should handle headers with empty values', () => {
66
- const headers = {
67
- Authorization: '',
68
- 'Content-Type': 'application/json',
69
- 'X-API-Key': ''
70
- };
71
- const result = redactHeaders(headers);
72
- expect(result).toEqual({
73
- Authorization: '[REDACTED]',
74
- 'Content-Type': 'application/json',
75
- 'X-API-Key': '[REDACTED]'
76
- });
77
- });
78
- });
79
- describe('with Headers object input', () => {
80
- it('should redact sensitive headers from Headers object', () => {
81
- const headers = new Headers();
82
- headers.set('Authorization', 'Bearer token123');
83
- headers.set('X-API-Key', 'secret-key');
84
- headers.set('Content-Type', 'application/json');
85
- headers.set('User-Agent', 'test-agent');
86
- const result = redactHeaders(headers);
87
- expect(result).toEqual({
88
- authorization: '[REDACTED]',
89
- 'x-api-key': '[REDACTED]',
90
- 'content-type': 'application/json',
91
- 'user-agent': 'test-agent'
92
- });
93
- });
94
- it('should handle empty Headers object', () => {
95
- const headers = new Headers();
96
- const result = redactHeaders(headers);
97
- expect(result).toEqual({});
98
- });
99
- it('should preserve header name casing from Headers object', () => {
100
- const headers = new Headers();
101
- headers.set('authorization', 'Bearer token');
102
- headers.set('X-Custom-Header', 'value');
103
- const result = redactHeaders(headers);
104
- expect(result).toEqual({
105
- authorization: '[REDACTED]',
106
- 'x-custom-header': 'value'
107
- });
108
- });
109
- });
110
- describe('sensitive header patterns', () => {
111
- it('should redact headers containing "authorization"', () => {
112
- const headers = {
113
- Authorization: 'Bearer token',
114
- 'X-Authorization': 'token',
115
- 'Custom-Authorization-Header': 'value'
116
- };
117
- const result = redactHeaders(headers);
118
- Object.keys(result).forEach(key => {
119
- if (key.toLowerCase().includes('authorization')) {
120
- expect(result[key]).toBe('[REDACTED]');
121
- }
122
- });
123
- });
124
- it('should redact headers containing "token"', () => {
125
- const headers = {
126
- 'X-Auth-Token': 'token123',
127
- 'Access-Token': 'access123',
128
- 'Refresh-Token': 'refresh123',
129
- 'Token-Header': 'token-value'
130
- };
131
- const result = redactHeaders(headers);
132
- Object.keys(result).forEach(key => {
133
- expect(result[key]).toBe('[REDACTED]');
134
- });
135
- });
136
- it('should redact headers containing "api-key" or "apikey"', () => {
137
- const headers = {
138
- 'X-API-Key': 'key123',
139
- 'X-Api-Key': 'key456',
140
- apikey: 'key789',
141
- 'Custom-ApiKey': 'custom-key'
142
- };
143
- const result = redactHeaders(headers);
144
- Object.keys(result).forEach(key => {
145
- expect(result[key]).toBe('[REDACTED]');
146
- });
147
- });
148
- it('should redact headers containing "secret"', () => {
149
- const headers = {
150
- 'X-Secret': 'secret123',
151
- 'Client-Secret': 'client-secret',
152
- 'Secret-Key': 'secret-key'
153
- };
154
- const result = redactHeaders(headers);
155
- Object.keys(result).forEach(key => {
156
- expect(result[key]).toBe('[REDACTED]');
157
- });
158
- });
159
- it('should redact headers containing "password"', () => {
160
- const headers = {
161
- Password: 'pass123',
162
- 'X-Password': 'secret-pass',
163
- 'User-Password': 'user-pass'
164
- };
165
- const result = redactHeaders(headers);
166
- Object.keys(result).forEach(key => {
167
- expect(result[key]).toBe('[REDACTED]');
168
- });
169
- });
170
- it('should redact headers containing "key"', () => {
171
- const headers = {
172
- 'Private-Key': 'private123',
173
- 'Public-Key': 'public123',
174
- 'Encryption-Key': 'encrypt123',
175
- 'Symmetric-Key': 'sym123'
176
- };
177
- const result = redactHeaders(headers);
178
- Object.keys(result).forEach(key => {
179
- expect(result[key]).toBe('[REDACTED]');
180
- });
181
- });
182
- it('should redact headers containing "cookie"', () => {
183
- const headers = {
184
- Cookie: 'session=abc123',
185
- 'Set-Cookie': 'token=xyz789',
186
- 'X-Cookie-Data': 'cookie-info'
187
- };
188
- const result = redactHeaders(headers);
189
- Object.keys(result).forEach(key => {
190
- expect(result[key]).toBe('[REDACTED]');
191
- });
192
- });
193
- });
194
- describe('edge cases', () => {
195
- it('should handle headers with special characters in values', () => {
196
- const headers = {
197
- Authorization: 'Bearer !@#$%^&*()_+-=[]{}|;:,.<>?',
198
- 'Content-Type': 'application/json; charset=utf-8'
199
- };
200
- const result = redactHeaders(headers);
201
- expect(result).toEqual({
202
- Authorization: '[REDACTED]',
203
- 'Content-Type': 'application/json; charset=utf-8'
204
- });
205
- });
206
- it('should handle headers with unicode characters', () => {
207
- const headers = {
208
- 'X-API-Key': '🔑secret-key🔐',
209
- 'X-Custom': 'héllo wörld'
210
- };
211
- const result = redactHeaders(headers);
212
- expect(result).toEqual({
213
- 'X-API-Key': '[REDACTED]',
214
- 'X-Custom': 'héllo wörld'
215
- });
216
- });
217
- it('should handle very long header values', () => {
218
- const longValue = 'a'.repeat(10000);
219
- const headers = {
220
- Authorization: `Bearer ${longValue}`,
221
- 'X-Long-Header': longValue
222
- };
223
- const result = redactHeaders(headers);
224
- expect(result).toEqual({
225
- Authorization: '[REDACTED]',
226
- 'X-Long-Header': longValue
227
- });
228
- });
229
- it('should match partial words in header names (current behavior)', () => {
230
- const headers = {
231
- Keyboard: 'qwerty', // contains "key" - will be redacted
232
- Secretary: 'admin', // contains "secret" - will be redacted
233
- Tokens: 'abc123', // contains "token" - will be redacted
234
- 'Content-Length': '123' // doesn't contain sensitive patterns - will not be redacted
235
- };
236
- const result = redactHeaders(headers);
237
- expect(result).toEqual({
238
- Keyboard: '[REDACTED]',
239
- Secretary: '[REDACTED]',
240
- Tokens: '[REDACTED]',
241
- 'Content-Length': '123'
242
- });
243
- });
244
- });
245
- });