@forgehive/hive-sdk 0.0.3 → 0.1.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.
@@ -77,8 +77,15 @@ describe('HiveLogClient Metadata', () => {
77
77
  it('should send log without metadata parameter', async () => {
78
78
  mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
79
79
 
80
- const logItem = { input: 'test-input', output: 'test-output' }
81
- const result = await client.sendLog('test-task', logItem)
80
+ const executionRecord = {
81
+ input: 'test-input',
82
+ output: 'test-output',
83
+ taskName: 'test-task',
84
+ type: 'success' as const,
85
+ boundaries: {},
86
+ metadata: {}
87
+ }
88
+ const result = await client.sendLog(executionRecord)
82
89
 
83
90
  expect(result).toBe('success')
84
91
  expect(mockedAxios.post).toHaveBeenCalledWith(
@@ -89,6 +96,9 @@ describe('HiveLogClient Metadata', () => {
89
96
  logItem: JSON.stringify({
90
97
  input: 'test-input',
91
98
  output: 'test-output',
99
+ taskName: 'test-task',
100
+ type: 'success',
101
+ boundaries: {},
92
102
  metadata: {}
93
103
  })
94
104
  },
@@ -104,13 +114,20 @@ describe('HiveLogClient Metadata', () => {
104
114
  it('should send log with metadata parameter', async () => {
105
115
  mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
106
116
 
107
- const logItem = { input: 'test-input', output: 'test-output' }
117
+ const executionRecord = {
118
+ input: 'test-input',
119
+ output: 'test-output',
120
+ taskName: 'test-task',
121
+ type: 'success' as const,
122
+ boundaries: {},
123
+ metadata: {}
124
+ }
108
125
  const metadata: Metadata = {
109
126
  requestId: 'req-123',
110
127
  userId: 'user-456'
111
128
  }
112
129
 
113
- const result = await client.sendLog('test-task', logItem, metadata)
130
+ const result = await client.sendLog(executionRecord, metadata)
114
131
 
115
132
  expect(result).toBe('success')
116
133
  expect(mockedAxios.post).toHaveBeenCalledWith(
@@ -121,6 +138,9 @@ describe('HiveLogClient Metadata', () => {
121
138
  logItem: JSON.stringify({
122
139
  input: 'test-input',
123
140
  output: 'test-output',
141
+ taskName: 'test-task',
142
+ type: 'success',
143
+ boundaries: {},
124
144
  metadata: {
125
145
  requestId: 'req-123',
126
146
  userId: 'user-456'
@@ -140,7 +160,7 @@ describe('HiveLogClient Metadata', () => {
140
160
  mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
141
161
 
142
162
  const metadata: Metadata = { type: 'minimal' }
143
- const result = await client.sendLog('test-task', { input: 'simple input' }, metadata)
163
+ const result = await client.sendLog({ input: 'simple input', taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: {} }, metadata)
144
164
 
145
165
  expect(result).toBe('success')
146
166
  expect(mockedAxios.post).toHaveBeenCalledWith(
@@ -150,6 +170,9 @@ describe('HiveLogClient Metadata', () => {
150
170
  taskName: 'test-task',
151
171
  logItem: JSON.stringify({
152
172
  input: 'simple input',
173
+ taskName: 'test-task',
174
+ type: 'success',
175
+ boundaries: {},
153
176
  metadata: { type: 'minimal' }
154
177
  })
155
178
  },
@@ -161,7 +184,7 @@ describe('HiveLogClient Metadata', () => {
161
184
  mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
162
185
 
163
186
  const metadata: Metadata = { type: 'null-test' }
164
- const result = await client.sendLog('test-task', { input: null }, metadata)
187
+ const result = await client.sendLog({ input: null, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: {} }, metadata)
165
188
 
166
189
  expect(result).toBe('success')
167
190
  expect(mockedAxios.post).toHaveBeenCalledWith(
@@ -171,6 +194,9 @@ describe('HiveLogClient Metadata', () => {
171
194
  taskName: 'test-task',
172
195
  logItem: JSON.stringify({
173
196
  input: null,
197
+ taskName: 'test-task',
198
+ type: 'success',
199
+ boundaries: {},
174
200
  metadata: { type: 'null-test' }
175
201
  })
176
202
  },
@@ -191,10 +217,13 @@ describe('HiveLogClient Metadata', () => {
191
217
  const client = new HiveLogClient({ ...testConfig, metadata: baseMetadata })
192
218
  const logItem = { input: 'test' }
193
219
 
194
- await client.sendLog('test-task', logItem)
220
+ await client.sendLog({ ...logItem, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: {} })
195
221
 
196
222
  const expectedLogItem = {
197
223
  input: 'test',
224
+ taskName: 'test-task',
225
+ type: 'success',
226
+ boundaries: {},
198
227
  metadata: {
199
228
  environment: 'production',
200
229
  version: '1.0.0'
@@ -229,7 +258,7 @@ describe('HiveLogClient Metadata', () => {
229
258
  }
230
259
  }
231
260
 
232
- await client.sendLog('test-task', logItem)
261
+ await client.sendLog({ ...logItem, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: logItem.metadata || {} })
233
262
 
234
263
  const expectedLogItem = {
235
264
  input: 'test',
@@ -237,7 +266,10 @@ describe('HiveLogClient Metadata', () => {
237
266
  environment: 'production', // from base
238
267
  version: '1.1.0', // from logItem (overrides base)
239
268
  sessionId: 'session-123' // from logItem
240
- }
269
+ },
270
+ taskName: 'test-task',
271
+ type: 'success',
272
+ boundaries: {}
241
273
  }
242
274
 
243
275
  expect(mockedAxios.post).toHaveBeenCalledWith(
@@ -276,7 +308,7 @@ describe('HiveLogClient Metadata', () => {
276
308
  priority: 'sendLog'
277
309
  }
278
310
 
279
- await client.sendLog('test-task', logItem, sendLogMetadata)
311
+ await client.sendLog({ ...logItem, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: logItem.metadata || {} }, sendLogMetadata)
280
312
 
281
313
  const expectedLogItem = {
282
314
  input: 'test',
@@ -286,7 +318,10 @@ describe('HiveLogClient Metadata', () => {
286
318
  priority: 'sendLog', // from sendLog (highest priority)
287
319
  sessionId: 'session-123', // from logItem
288
320
  requestId: 'req-456' // from sendLog
289
- }
321
+ },
322
+ taskName: 'test-task',
323
+ type: 'success',
324
+ boundaries: {}
290
325
  }
291
326
 
292
327
  expect(mockedAxios.post).toHaveBeenCalledWith(
@@ -327,7 +362,7 @@ describe('HiveLogClient Metadata', () => {
327
362
  version: '1.2.0' // overrides both base and logItem
328
363
  }
329
364
 
330
- await client.sendLog('search-task', logItem, sendLogMetadata)
365
+ await client.sendLog({ ...logItem, taskName: 'search-task', type: 'success' as const, boundaries: {}, metadata: logItem.metadata || {} }, sendLogMetadata)
331
366
 
332
367
  const expectedLogItem = {
333
368
  input: { query: 'search' },
@@ -341,7 +376,10 @@ describe('HiveLogClient Metadata', () => {
341
376
  processingTime: '250', // from logItem
342
377
  requestId: 'req-789', // from sendLog
343
378
  userId: 'user-123' // from sendLog
344
- }
379
+ },
380
+ taskName: 'search-task',
381
+ type: 'success',
382
+ boundaries: {}
345
383
  }
346
384
 
347
385
  expect(mockedAxios.post).toHaveBeenCalledWith(
@@ -368,10 +406,13 @@ describe('HiveLogClient Metadata', () => {
368
406
  // No metadata property
369
407
  }
370
408
 
371
- await client.sendLog('test-task', logItem)
409
+ await client.sendLog({ ...logItem, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: {} })
372
410
 
373
411
  const expectedLogItem = {
374
412
  input: 'test',
413
+ taskName: 'test-task',
414
+ type: 'success',
415
+ boundaries: {},
375
416
  metadata: {
376
417
  environment: 'test' // Only base metadata should be used
377
418
  }
@@ -399,13 +440,16 @@ describe('HiveLogClient Metadata', () => {
399
440
  metadata: undefined
400
441
  }
401
442
 
402
- await client.sendLog('test-task', logItem)
443
+ await client.sendLog({ ...logItem, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: logItem.metadata || {} })
403
444
 
404
445
  const expectedLogItem = {
405
446
  input: 'test',
406
447
  metadata: {
407
448
  environment: 'test' // Only base metadata should be used
408
- }
449
+ },
450
+ taskName: 'test-task',
451
+ type: 'success',
452
+ boundaries: {}
409
453
  }
410
454
 
411
455
  expect(mockedAxios.post).toHaveBeenCalledWith(
@@ -425,11 +469,14 @@ describe('HiveLogClient Metadata', () => {
425
469
  const client = new HiveLogClient({ ...testConfig, metadata: {} })
426
470
  const logItem = { input: 'test', metadata: {} }
427
471
 
428
- await client.sendLog('test-task', logItem, {})
472
+ await client.sendLog({ ...logItem, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: logItem.metadata || {} }, {})
429
473
 
430
474
  const expectedLogItem = {
431
475
  input: 'test',
432
- metadata: {} // All empty metadata objects result in empty final metadata
476
+ metadata: {}, // All empty metadata objects result in empty final metadata
477
+ taskName: 'test-task',
478
+ type: 'success',
479
+ boundaries: {}
433
480
  }
434
481
 
435
482
  expect(mockedAxios.post).toHaveBeenCalledWith(
@@ -447,7 +494,7 @@ describe('HiveLogClient Metadata', () => {
447
494
  const baseMetadata: Metadata = { environment: 'test' }
448
495
  const silentClient = new HiveLogClient({ projectName: 'silent-project', metadata: baseMetadata })
449
496
 
450
- const result = await silentClient.sendLog('test-task', { input: 'test' }, { requestId: 'req-123' })
497
+ const result = await silentClient.sendLog({ input: 'test', taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: {} }, { requestId: 'req-123' })
451
498
 
452
499
  expect(result).toBe('silent')
453
500
  expect(mockedAxios.post).not.toHaveBeenCalled()
@@ -459,7 +506,7 @@ describe('HiveLogClient Metadata', () => {
459
506
  const baseMetadata: Metadata = { environment: 'test' }
460
507
  const client = new HiveLogClient({ ...testConfig, metadata: baseMetadata })
461
508
 
462
- const result = await client.sendLog('test-task', { input: 'test' }, { requestId: 'req-123' })
509
+ const result = await client.sendLog({ input: 'test', taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: {} }, { requestId: 'req-123' })
463
510
 
464
511
  expect(result).toBe('error')
465
512
  })
@@ -5,7 +5,7 @@ import { HiveLogClient } from '../index'
5
5
  jest.mock('axios')
6
6
  const mockedAxios = axios as jest.Mocked<typeof axios>
7
7
 
8
- describe('HiveLogClient sendLog', () => {
8
+ describe('HiveLogClient sendLog with ExecutionRecord', () => {
9
9
  let client: HiveLogClient
10
10
 
11
11
  const testConfig = {
@@ -23,13 +23,21 @@ describe('HiveLogClient sendLog', () => {
23
23
  jest.clearAllMocks()
24
24
  })
25
25
 
26
- describe('successful sendLog', () => {
27
- it('should send log successfully and return true', async () => {
26
+ describe('successful sendLog with ExecutionRecord', () => {
27
+ it('should send log successfully with ExecutionRecord and return success', async () => {
28
28
  // Mock successful axios response
29
29
  mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
30
30
 
31
- const logItem = { input: 'test-input', output: 'test-output' }
32
- const result = await client.sendLog('test-task', logItem)
31
+ const executionRecord = {
32
+ input: { value: 'test-input' },
33
+ output: { result: 'test-output' },
34
+ taskName: 'test-task',
35
+ type: 'success' as const,
36
+ boundaries: {},
37
+ metadata: {}
38
+ }
39
+
40
+ const result = await client.sendLog(executionRecord)
33
41
 
34
42
  expect(result).toBe('success')
35
43
  expect(mockedAxios.post).toHaveBeenCalledTimes(1)
@@ -38,7 +46,14 @@ describe('HiveLogClient sendLog', () => {
38
46
  {
39
47
  projectName: 'test-project',
40
48
  taskName: 'test-task',
41
- logItem: JSON.stringify({ ...logItem, metadata: {} })
49
+ logItem: JSON.stringify({
50
+ input: { value: 'test-input' },
51
+ output: { result: 'test-output' },
52
+ taskName: 'test-task',
53
+ type: 'success',
54
+ boundaries: {},
55
+ metadata: {}
56
+ })
42
57
  },
43
58
  {
44
59
  headers: {
@@ -49,19 +64,22 @@ describe('HiveLogClient sendLog', () => {
49
64
  )
50
65
  })
51
66
 
52
- it('should handle complex log items', async () => {
67
+ it('should handle ExecutionRecord with complex boundaries', async () => {
53
68
  mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
54
69
 
55
- const complexLogItem = {
70
+ const executionRecord = {
56
71
  input: { userId: 123, action: 'login' },
57
72
  output: { success: true, sessionId: 'abc123' },
58
- error: null,
73
+ taskName: 'complex-task',
74
+ type: 'success' as const,
59
75
  boundaries: {
60
- database: [{ input: 'SELECT * FROM users', output: [{ id: 123 }], error: null }]
61
- }
76
+ database: [{ input: 'SELECT * FROM users', output: [{ id: 123 }], error: null }],
77
+ api: [{ input: { endpoint: '/auth' }, output: { token: 'jwt123' }, error: null }]
78
+ },
79
+ metadata: { environment: 'test' }
62
80
  }
63
81
 
64
- const result = await client.sendLog('complex-task', complexLogItem)
82
+ const result = await client.sendLog(executionRecord)
65
83
 
66
84
  expect(result).toBe('success')
67
85
  expect(mockedAxios.post).toHaveBeenCalledWith(
@@ -69,7 +87,17 @@ describe('HiveLogClient sendLog', () => {
69
87
  {
70
88
  projectName: 'test-project',
71
89
  taskName: 'complex-task',
72
- logItem: JSON.stringify({ ...complexLogItem, metadata: {} })
90
+ logItem: JSON.stringify({
91
+ input: { userId: 123, action: 'login' },
92
+ output: { success: true, sessionId: 'abc123' },
93
+ taskName: 'complex-task',
94
+ type: 'success',
95
+ boundaries: {
96
+ database: [{ input: 'SELECT * FROM users', output: [{ id: 123 }], error: null }],
97
+ api: [{ input: { endpoint: '/auth' }, output: { token: 'jwt123' }, error: null }]
98
+ },
99
+ metadata: { environment: 'test' }
100
+ })
73
101
  },
74
102
  {
75
103
  headers: {
@@ -79,64 +107,288 @@ describe('HiveLogClient sendLog', () => {
79
107
  }
80
108
  )
81
109
  })
110
+
111
+ it('should handle ExecutionRecord with error', async () => {
112
+ mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
113
+
114
+ const executionRecord = {
115
+ input: { value: 'test-input' },
116
+ output: undefined,
117
+ error: 'Task execution failed',
118
+ taskName: 'error-task',
119
+ type: 'error' as const,
120
+ boundaries: {},
121
+ metadata: {}
122
+ }
123
+
124
+ const result = await client.sendLog(executionRecord)
125
+
126
+ expect(result).toBe('success')
127
+ expect(mockedAxios.post).toHaveBeenCalledWith(
128
+ 'https://test-host.com/api/tasks/log-ingest',
129
+ {
130
+ projectName: 'test-project',
131
+ taskName: 'error-task',
132
+ logItem: JSON.stringify({
133
+ input: { value: 'test-input' },
134
+ output: undefined,
135
+ error: 'Task execution failed',
136
+ taskName: 'error-task',
137
+ type: 'error',
138
+ boundaries: {},
139
+ metadata: {}
140
+ })
141
+ },
142
+ expect.any(Object)
143
+ )
144
+ })
145
+
146
+ it('should use "unknown-task" when taskName is missing', async () => {
147
+ mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
148
+
149
+ const executionRecord = {
150
+ input: { value: 'test-input' },
151
+ output: { result: 'test-output' },
152
+ // taskName is missing
153
+ type: 'success' as const,
154
+ boundaries: {},
155
+ metadata: {}
156
+ }
157
+
158
+ const result = await client.sendLog(executionRecord)
159
+
160
+ expect(result).toBe('success')
161
+ expect(mockedAxios.post).toHaveBeenCalledWith(
162
+ 'https://test-host.com/api/tasks/log-ingest',
163
+ {
164
+ projectName: 'test-project',
165
+ taskName: 'unknown-task',
166
+ logItem: JSON.stringify({
167
+ input: { value: 'test-input' },
168
+ output: { result: 'test-output' },
169
+ type: 'success',
170
+ boundaries: {},
171
+ metadata: {},
172
+ taskName: 'unknown-task'
173
+ })
174
+ },
175
+ expect.any(Object)
176
+ )
177
+ })
178
+ })
179
+
180
+ describe('sendLog with additional metadata', () => {
181
+ it('should merge metadata from ExecutionRecord and sendLog parameter', async () => {
182
+ mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
183
+
184
+ const executionRecord = {
185
+ input: { value: 'test-input' },
186
+ output: { result: 'test-output' },
187
+ taskName: 'metadata-task',
188
+ type: 'success' as const,
189
+ boundaries: {},
190
+ metadata: {
191
+ recordMeta: 'from-record',
192
+ sharedKey: 'record-value'
193
+ }
194
+ }
195
+
196
+ const sendLogMetadata = {
197
+ sendLogMeta: 'from-sendlog',
198
+ sharedKey: 'sendlog-value' // This should override record value
199
+ }
200
+
201
+ const result = await client.sendLog(executionRecord, sendLogMetadata)
202
+
203
+ expect(result).toBe('success')
204
+ expect(mockedAxios.post).toHaveBeenCalledWith(
205
+ 'https://test-host.com/api/tasks/log-ingest',
206
+ {
207
+ projectName: 'test-project',
208
+ taskName: 'metadata-task',
209
+ logItem: JSON.stringify({
210
+ input: { value: 'test-input' },
211
+ output: { result: 'test-output' },
212
+ taskName: 'metadata-task',
213
+ type: 'success',
214
+ boundaries: {},
215
+ metadata: {
216
+ recordMeta: 'from-record',
217
+ sharedKey: 'sendlog-value', // sendLog metadata takes priority
218
+ sendLogMeta: 'from-sendlog'
219
+ }
220
+ })
221
+ },
222
+ expect.any(Object)
223
+ )
224
+ })
82
225
  })
83
226
 
84
227
  describe('failed sendLog', () => {
85
- it('should return false when axios throws an error', async () => {
228
+ it('should return error when axios throws an error', async () => {
86
229
  // Mock axios to throw an error
87
230
  mockedAxios.post.mockRejectedValueOnce(new Error('Network error'))
88
231
 
89
- const logItem = { input: 'test-input' }
90
- const result = await client.sendLog('test-task', logItem)
232
+ const executionRecord = {
233
+ input: { value: 'test-input' },
234
+ taskName: 'test-task',
235
+ type: 'success' as const,
236
+ boundaries: {},
237
+ metadata: {}
238
+ }
239
+
240
+ const result = await client.sendLog(executionRecord)
91
241
 
92
242
  expect(result).toBe('error')
93
243
  })
94
244
 
95
- it('should return false when server returns 500', async () => {
245
+ it('should return error when server returns 500', async () => {
96
246
  // Mock axios to throw a server error
97
247
  const serverError = new Error('Server Error')
98
248
  mockedAxios.post.mockRejectedValueOnce(serverError)
99
249
 
100
- const result = await client.sendLog('test-task', { input: 'test' })
250
+ const executionRecord = {
251
+ input: { value: 'test' },
252
+ taskName: 'test-task',
253
+ type: 'success' as const,
254
+ boundaries: {},
255
+ metadata: {}
256
+ }
257
+
258
+ const result = await client.sendLog(executionRecord)
101
259
 
102
260
  expect(result).toBe('error')
103
261
  })
104
262
  })
105
263
 
106
- describe('sendLog parameters', () => {
107
- it('should handle log items with minimal input', async () => {
264
+ describe('sendLog in silent mode', () => {
265
+ it('should return silent when client is not initialized', async () => {
266
+ const uninitializedClient = new HiveLogClient({
267
+ projectName: 'test-project'
268
+ // No API credentials
269
+ })
270
+
271
+ const executionRecord = {
272
+ input: { value: 'test-input' },
273
+ taskName: 'test-task',
274
+ type: 'success' as const,
275
+ boundaries: {},
276
+ metadata: {}
277
+ }
278
+
279
+ const result = await uninitializedClient.sendLog(executionRecord)
280
+
281
+ expect(result).toBe('silent')
282
+ expect(mockedAxios.post).not.toHaveBeenCalled()
283
+ })
284
+ })
285
+ })
286
+
287
+
288
+ describe('HiveLogClient getListener', () => {
289
+ let client: HiveLogClient
290
+
291
+ const testConfig = {
292
+ projectName: 'test-project',
293
+ apiKey: 'test-api-key',
294
+ apiSecret: 'test-api-secret',
295
+ host: 'https://test-host.com'
296
+ }
297
+
298
+ beforeEach(() => {
299
+ client = new HiveLogClient(testConfig)
300
+ jest.clearAllMocks()
301
+ })
302
+
303
+ describe('getListener method', () => {
304
+ it('should return a function that calls sendLog', async () => {
108
305
  mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
109
306
 
110
- const result = await client.sendLog('minimal-task', { input: 'minimal input' })
307
+ const listener = client.getListener()
111
308
 
112
- expect(result).toBe('success')
309
+ expect(typeof listener).toBe('function')
310
+
311
+ const executionRecord = {
312
+ input: { value: 'test-input' },
313
+ output: { result: 'test-output' },
314
+ taskName: 'test-task',
315
+ type: 'success' as const,
316
+ boundaries: {},
317
+ metadata: {}
318
+ }
319
+
320
+ await listener(executionRecord)
321
+
322
+ expect(mockedAxios.post).toHaveBeenCalledTimes(1)
113
323
  expect(mockedAxios.post).toHaveBeenCalledWith(
114
324
  'https://test-host.com/api/tasks/log-ingest',
115
325
  {
116
326
  projectName: 'test-project',
117
- taskName: 'minimal-task',
118
- logItem: JSON.stringify({ input: 'minimal input', metadata: {} })
327
+ taskName: 'test-task',
328
+ logItem: JSON.stringify({
329
+ input: { value: 'test-input' },
330
+ output: { result: 'test-output' },
331
+ taskName: 'test-task',
332
+ type: 'success',
333
+ boundaries: {},
334
+ metadata: {}
335
+ })
119
336
  },
120
337
  expect.any(Object)
121
338
  )
122
339
  })
123
340
 
124
- it('should handle null/undefined values in log items', async () => {
341
+ it('should return a function that calls sendLog with provided metadata', async () => {
125
342
  mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
126
343
 
127
- const logItem = { input: null, output: undefined, error: 'some error' }
128
- const result = await client.sendLog('null-task', logItem)
344
+ const listener = client.getListener()
345
+
346
+ const executionRecord = {
347
+ input: { value: 'test-input' },
348
+ output: { result: 'test-output' },
349
+ taskName: 'test-task',
350
+ type: 'success' as const,
351
+ boundaries: {},
352
+ metadata: { recordMeta: 'from-record' }
353
+ }
354
+
355
+ await listener(executionRecord)
129
356
 
130
- expect(result).toBe('success')
131
357
  expect(mockedAxios.post).toHaveBeenCalledWith(
132
358
  'https://test-host.com/api/tasks/log-ingest',
133
359
  {
134
360
  projectName: 'test-project',
135
- taskName: 'null-task',
136
- logItem: JSON.stringify({ ...logItem, metadata: {} })
361
+ taskName: 'test-task',
362
+ logItem: JSON.stringify({
363
+ input: { value: 'test-input' },
364
+ output: { result: 'test-output' },
365
+ taskName: 'test-task',
366
+ type: 'success',
367
+ boundaries: {},
368
+ metadata: {
369
+ recordMeta: 'from-record'
370
+ }
371
+ })
137
372
  },
138
373
  expect.any(Object)
139
374
  )
140
375
  })
376
+
377
+ it('should handle listener errors gracefully', async () => {
378
+ mockedAxios.post.mockRejectedValueOnce(new Error('Network error'))
379
+
380
+ const listener = client.getListener()
381
+
382
+ const executionRecord = {
383
+ input: { value: 'test-input' },
384
+ taskName: 'test-task',
385
+ type: 'success' as const,
386
+ boundaries: {},
387
+ metadata: {}
388
+ }
389
+
390
+ // Should not throw, even if sendLog fails
391
+ await expect(listener(executionRecord)).resolves.toBeUndefined()
392
+ })
141
393
  })
142
394
  })