@outputai/core 0.10.1-dev.b7b2fbe.0 → 0.10.1-next.09ed166.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.
@@ -1,17 +1,17 @@
1
- import { messageBus } from '#bus';
2
- import { BusEventType, ComponentType, WORKFLOW_CATALOG } from '#consts';
1
+ import { mainEventBus, stepEventBus } from '#bus';
2
+ import { BusEventType } from '#consts';
3
3
  import { createChildLogger } from '#logger';
4
4
 
5
5
  const log = createChildLogger( 'Hooks' );
6
6
 
7
7
  /**
8
- * Invokes an external hook handler function with a try catch around it
8
+ * Invokes a function within a try catch and log the error
9
9
  *
10
10
  * @param {Function} fn
11
11
  * @param {any} args - Args to invoke the function with
12
12
  * @param {string} hookName - hookName to identify this hook function in the logs
13
13
  */
14
- const safeInvoke = async ( fn, args, hookName ) => {
14
+ const callHookCb = async ( fn, args, hookName ) => {
15
15
  try {
16
16
  await fn( args );
17
17
  } catch ( error ) {
@@ -19,50 +19,55 @@ const safeInvoke = async ( fn, args, hookName ) => {
19
19
  }
20
20
  };
21
21
 
22
- /** Triggers on any errors: workflow, activity and runtime */
23
- export const onError = handler => {
24
- messageBus.on( BusEventType.ACTIVITY_ERROR, async payload =>
25
- safeInvoke( handler, { source: 'activity', ...payload }, 'onError' ) );
26
- messageBus.on( BusEventType.WORKFLOW_ERROR, async payload =>
27
- safeInvoke( handler, { source: 'workflow', ...payload }, 'onError' ) );
28
- messageBus.on( BusEventType.RUNTIME_ERROR, async payload =>
29
- safeInvoke( handler, { source: 'runtime', ...payload }, 'onError' ) );
22
+ // General Life-cycle
23
+ // --------------------------------------
24
+ const onError = cb => {
25
+ mainEventBus.on( BusEventType.ACTIVITY_ERROR, async payload =>
26
+ callHookCb( cb, { source: 'activity', ...payload }, 'onError' ) );
27
+ mainEventBus.on( BusEventType.WORKFLOW_ERROR, async payload =>
28
+ callHookCb( cb, { source: 'workflow', ...payload }, 'onError' ) );
29
+ mainEventBus.on( BusEventType.RUNTIME_ERROR, async payload =>
30
+ callHookCb( cb, { source: 'runtime', ...payload }, 'onError' ) );
30
31
  };
31
32
 
32
- /** Listen to worker before start events */
33
- export const onBeforeWorkerStart = handler => messageBus.on( BusEventType.WORKER_BEFORE_START, () =>
34
- safeInvoke( handler, undefined, 'onBeforeWorkerStart' ) );
33
+ const onBeforeWorkerStart = cb => mainEventBus.on( BusEventType.WORKER_BEFORE_START, () => callHookCb( cb, undefined, 'onBeforeWorkerStart' ) );
35
34
 
36
- /** Catalog workflow events should not be emitted */
37
- const shouldEmitWorkflowEvent = workflowDetails => WORKFLOW_CATALOG !== workflowDetails.workflowType;
35
+ // Workflow Life-cycle
36
+ // --------------------------------------
37
+ const onWorkflowStart = cb => mainEventBus.on( BusEventType.WORKFLOW_START, payload => callHookCb( cb, payload, 'onWorkflowStart' ) );
38
+ const onWorkflowEnd = cb => mainEventBus.on( BusEventType.WORKFLOW_END, payload => callHookCb( cb, payload, 'onWorkflowEnd' ) );
39
+ const onWorkflowError = cb => mainEventBus.on( BusEventType.WORKFLOW_ERROR, payload => callHookCb( cb, payload, 'onWorkflowError' ) );
38
40
 
39
- /** Listen to workflow start events, excludes catalog workflow */
40
- export const onWorkflowStart = handler => messageBus.on( BusEventType.WORKFLOW_START, ( { workflowDetails, ...eventFields } ) =>
41
- shouldEmitWorkflowEvent( workflowDetails ) ? safeInvoke( handler, { workflowDetails, ...eventFields }, 'onWorkflowStart' ) : null );
41
+ // Activity Life-cycle
42
+ // --------------------------------------
43
+ const onActivityStart = cb => mainEventBus.on( BusEventType.ACTIVITY_START, fields => callHookCb( cb, fields, 'onActivityStart' ) );
44
+ const onActivityEnd = cb => mainEventBus.on( BusEventType.ACTIVITY_END, fields => callHookCb( cb, fields, 'onActivityEnd' ) );
45
+ const onActivityError = cb => mainEventBus.on( BusEventType.ACTIVITY_ERROR, fields => callHookCb( cb, fields, 'onActivityError' ) );
42
46
 
43
- /** Listen to workflow end events, excludes catalog workflow */
44
- export const onWorkflowEnd = handler => messageBus.on( BusEventType.WORKFLOW_END, ( { workflowDetails, ...eventFields } ) =>
45
- shouldEmitWorkflowEvent( workflowDetails ) ? safeInvoke( handler, { workflowDetails, ...eventFields }, 'onWorkflowEnd' ) : null );
46
-
47
- /** Listen to workflow error events, excludes catalog workflow */
48
- export const onWorkflowError = handler => messageBus.on( BusEventType.WORKFLOW_ERROR, ( { workflowDetails, ...eventFields } ) =>
49
- shouldEmitWorkflowEvent( workflowDetails ) ? safeInvoke( handler, { workflowDetails, ...eventFields }, 'onWorkflowError' ) : null );
50
-
51
- /** Internal activities do not trigger hooks */
52
- const shouldEmitActivityEvent = outputActivityKind => outputActivityKind !== ComponentType.INTERNAL_STEP;
53
-
54
- /** Listen to workflow start events, excludes catalog workflow */
55
- export const onActivityStart = handler => messageBus.on( BusEventType.ACTIVITY_START, ( { outputActivityKind, ...eventFields } ) =>
56
- shouldEmitActivityEvent( outputActivityKind ) ? safeInvoke( handler, { outputActivityKind, ...eventFields }, 'onActivityStart' ) : null );
57
-
58
- /** Listen to workflow end events, excludes catalog workflow */
59
- export const onActivityEnd = handler => messageBus.on( BusEventType.ACTIVITY_END, ( { outputActivityKind, ...eventFields } ) =>
60
- shouldEmitActivityEvent( outputActivityKind ) ? safeInvoke( handler, { outputActivityKind, ...eventFields }, 'onActivityEnd' ) : null );
47
+ // Generic Events
48
+ // --------------------------------------
49
+ /** Listen to both sdk and custom events */
50
+ const on = ( eventName, cb ) => {
51
+ stepEventBus.on( `sdk:${eventName}`, payload => callHookCb( cb, payload, eventName ) );
52
+ stepEventBus.on( `usr:${eventName}`, payload => callHookCb( cb, payload, eventName ) );
53
+ };
61
54
 
62
- /** Listen to workflow error events, excludes catalog workflow */
63
- export const onActivityError = handler => messageBus.on( BusEventType.ACTIVITY_ERROR, ( { outputActivityKind, ...eventFields } ) =>
64
- shouldEmitActivityEvent( outputActivityKind ) ? safeInvoke( handler, { outputActivityKind, ...eventFields }, 'onActivityError' ) : null );
55
+ /**
56
+ * Emits a custom event
57
+ * @param {string} eventName
58
+ * @param {any} payload
59
+ */
60
+ const emit = ( eventName, payload ) => stepEventBus.emit( `usr:${eventName}`, payload );
65
61
 
66
- /** Generic listener for events emitted elsewhere (outside core) */
67
- export const on = ( eventName, handler ) => messageBus.on( `external:${eventName}`, payload =>
68
- safeInvoke( handler, payload, eventName ) );
62
+ export {
63
+ emit,
64
+ on,
65
+ onActivityEnd,
66
+ onActivityError,
67
+ onActivityStart,
68
+ onBeforeWorkerStart,
69
+ onError,
70
+ onWorkflowEnd,
71
+ onWorkflowError,
72
+ onWorkflowStart
73
+ };
@@ -1,22 +1,33 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { BusEventType, ComponentType, WORKFLOW_CATALOG } from '#consts';
2
+ import { BusEventType } from '#consts';
3
3
 
4
4
  const logErrorMock = vi.hoisted( () => vi.fn() );
5
5
  const createChildLoggerMock = vi.hoisted( () =>
6
6
  vi.fn( () => ( { error: logErrorMock } ) )
7
7
  );
8
8
 
9
- const onHandlers = vi.hoisted( () => ( {} ) );
10
- const messageBusMock = vi.hoisted( () => ( {
9
+ const mainOnHandlers = vi.hoisted( () => ( {} ) );
10
+ const stepOnHandlers = vi.hoisted( () => ( {} ) );
11
+ const mainEventBusMock = vi.hoisted( () => ( {
11
12
  on: vi.fn( ( eventType, handler ) => {
12
- onHandlers[eventType] = handler;
13
+ mainOnHandlers[eventType] = handler;
14
+ } )
15
+ } ) );
16
+ const stepEventBusMock = vi.hoisted( () => ( {
17
+ emit: vi.fn( () => true ),
18
+ on: vi.fn( ( eventType, handler ) => {
19
+ stepOnHandlers[eventType] = handler;
13
20
  } )
14
21
  } ) );
15
22
 
16
23
  vi.mock( '#logger', () => ( { createChildLogger: createChildLoggerMock } ) );
17
- vi.mock( '#bus', () => ( { messageBus: messageBusMock } ) );
24
+ vi.mock( '#bus', () => ( {
25
+ mainEventBus: mainEventBusMock,
26
+ stepEventBus: stepEventBusMock
27
+ } ) );
18
28
 
19
29
  import {
30
+ emit,
20
31
  on,
21
32
  onActivityEnd,
22
33
  onActivityError,
@@ -38,11 +49,6 @@ const workflowDetails = {
38
49
  attempt: 1
39
50
  };
40
51
 
41
- const catalogWorkflowDetails = {
42
- ...workflowDetails,
43
- workflowType: WORKFLOW_CATALOG
44
- };
45
-
46
52
  const activityInfo = {
47
53
  activityId: 'act-1',
48
54
  activityType: 'wf#step',
@@ -61,8 +67,11 @@ const aggregations = {
61
67
  describe( 'hooks/index', () => {
62
68
  beforeEach( () => {
63
69
  vi.clearAllMocks();
64
- Object.keys( onHandlers ).forEach( k => {
65
- delete onHandlers[k];
70
+ Object.keys( mainOnHandlers ).forEach( k => {
71
+ delete mainOnHandlers[k];
72
+ } );
73
+ Object.keys( stepOnHandlers ).forEach( k => {
74
+ delete stepOnHandlers[k];
66
75
  } );
67
76
  } );
68
77
 
@@ -71,9 +80,9 @@ describe( 'hooks/index', () => {
71
80
  const handler = vi.fn().mockResolvedValue( undefined );
72
81
  onError( handler );
73
82
 
74
- expect( messageBusMock.on ).toHaveBeenCalledWith( BusEventType.ACTIVITY_ERROR, expect.any( Function ) );
75
- expect( messageBusMock.on ).toHaveBeenCalledWith( BusEventType.WORKFLOW_ERROR, expect.any( Function ) );
76
- expect( messageBusMock.on ).toHaveBeenCalledWith( BusEventType.RUNTIME_ERROR, expect.any( Function ) );
83
+ expect( mainEventBusMock.on ).toHaveBeenCalledWith( BusEventType.ACTIVITY_ERROR, expect.any( Function ) );
84
+ expect( mainEventBusMock.on ).toHaveBeenCalledWith( BusEventType.WORKFLOW_ERROR, expect.any( Function ) );
85
+ expect( mainEventBusMock.on ).toHaveBeenCalledWith( BusEventType.RUNTIME_ERROR, expect.any( Function ) );
77
86
  } );
78
87
 
79
88
  it( 'invokes handler with activity-shaped payload, forwarding bus fields', async () => {
@@ -81,7 +90,7 @@ describe( 'hooks/index', () => {
81
90
  onError( handler );
82
91
 
83
92
  const err = new Error( 'act-fail' );
84
- await onHandlers[BusEventType.ACTIVITY_ERROR]( {
93
+ await mainOnHandlers[BusEventType.ACTIVITY_ERROR]( {
85
94
  eventId: 'evt-act-1',
86
95
  eventDate,
87
96
  activityInfo,
@@ -108,7 +117,7 @@ describe( 'hooks/index', () => {
108
117
  onError( handler );
109
118
 
110
119
  const err = new Error( 'wf-fail' );
111
- await onHandlers[BusEventType.WORKFLOW_ERROR]( {
120
+ await mainOnHandlers[BusEventType.WORKFLOW_ERROR]( {
112
121
  eventId: 'evt-wf-1',
113
122
  eventDate,
114
123
  workflowDetails,
@@ -131,7 +140,7 @@ describe( 'hooks/index', () => {
131
140
  onError( handler );
132
141
 
133
142
  const error = new Error( 'rt' );
134
- await onHandlers[BusEventType.RUNTIME_ERROR]( { eventId: 'evt-rt-1', eventDate, error } );
143
+ await mainOnHandlers[BusEventType.RUNTIME_ERROR]( { eventId: 'evt-rt-1', eventDate, error } );
135
144
 
136
145
  expect( handler ).toHaveBeenCalledWith( { eventId: 'evt-rt-1', eventDate, source: 'runtime', error } );
137
146
  } );
@@ -142,68 +151,35 @@ describe( 'hooks/index', () => {
142
151
  const handler = vi.fn().mockResolvedValue( undefined );
143
152
  onBeforeWorkerStart( handler );
144
153
 
145
- expect( messageBusMock.on ).toHaveBeenCalledWith( BusEventType.WORKER_BEFORE_START, expect.any( Function ) );
146
- await onHandlers[BusEventType.WORKER_BEFORE_START]();
154
+ expect( mainEventBusMock.on ).toHaveBeenCalledWith( BusEventType.WORKER_BEFORE_START, expect.any( Function ) );
155
+ await mainOnHandlers[BusEventType.WORKER_BEFORE_START]();
147
156
 
148
157
  expect( handler ).toHaveBeenCalledWith( undefined );
149
158
  } );
150
159
  } );
151
160
 
152
- describe( 'onWorkflowStart', () => {
153
- it( 'skips catalog workflow and forwards bus fields for real workflows', async () => {
154
- const handler = vi.fn().mockResolvedValue( undefined );
155
- onWorkflowStart( handler );
156
-
157
- await Promise.resolve( onHandlers[BusEventType.WORKFLOW_START]( {
158
- eventId: 'evt-ignored', eventDate, workflowDetails: catalogWorkflowDetails
159
- } ) );
160
- expect( handler ).not.toHaveBeenCalled();
161
-
162
- await Promise.resolve( onHandlers[BusEventType.WORKFLOW_START]( {
163
- eventId: 'evt-start-1', eventDate, workflowDetails, extra: 'passthrough'
164
- } ) );
165
- expect( handler ).toHaveBeenCalledWith( {
166
- eventId: 'evt-start-1', eventDate, workflowDetails, extra: 'passthrough'
167
- } );
168
- } );
169
- } );
170
-
171
- describe( 'onWorkflowEnd', () => {
172
- it( 'skips catalog workflow and forwards bus fields for real workflows', async () => {
173
- const handler = vi.fn().mockResolvedValue( undefined );
174
- onWorkflowEnd( handler );
175
-
176
- await Promise.resolve( onHandlers[BusEventType.WORKFLOW_END]( {
177
- eventId: 'evt-ignored', eventDate, workflowDetails: catalogWorkflowDetails
178
- } ) );
179
- expect( handler ).not.toHaveBeenCalled();
180
-
181
- await Promise.resolve( onHandlers[BusEventType.WORKFLOW_END]( {
182
- eventId: 'evt-end-1', eventDate, workflowDetails, extra: 'passthrough'
183
- } ) );
184
- expect( handler ).toHaveBeenCalledWith( {
185
- eventId: 'evt-end-1', eventDate, workflowDetails, extra: 'passthrough'
186
- } );
187
- } );
188
- } );
161
+ describe( 'workflow lifecycle hooks', () => {
162
+ const cases = [
163
+ [ 'onWorkflowStart', onWorkflowStart, BusEventType.WORKFLOW_START, {} ],
164
+ [ 'onWorkflowEnd', onWorkflowEnd, BusEventType.WORKFLOW_END, {} ],
165
+ [ 'onWorkflowError', onWorkflowError, BusEventType.WORKFLOW_ERROR, { error: new Error( 'workflow failed' ) } ]
166
+ ];
189
167
 
190
- describe( 'onWorkflowError', () => {
191
- it( 'skips catalog workflow and forwards bus fields for real workflows', async () => {
168
+ it.each( cases )( '%s forwards bus fields', async ( _name, registerHook, eventType, extraFields ) => {
192
169
  const handler = vi.fn().mockResolvedValue( undefined );
193
- const err = new Error( 'wf' );
194
- onWorkflowError( handler );
170
+ const payload = {
171
+ eventId: 'evt-workflow-1',
172
+ eventDate,
173
+ workflowDetails,
174
+ extra: 'passthrough',
175
+ ...extraFields
176
+ };
177
+ registerHook( handler );
195
178
 
196
- await Promise.resolve( onHandlers[BusEventType.WORKFLOW_ERROR]( {
197
- eventId: 'evt-ignored', eventDate, workflowDetails: catalogWorkflowDetails, error: err
198
- } ) );
199
- expect( handler ).not.toHaveBeenCalled();
179
+ expect( mainEventBusMock.on ).toHaveBeenCalledWith( eventType, expect.any( Function ) );
180
+ await mainOnHandlers[eventType]( payload );
200
181
 
201
- await Promise.resolve( onHandlers[BusEventType.WORKFLOW_ERROR]( {
202
- eventId: 'evt-err-1', eventDate, workflowDetails, error: err, extra: 'passthrough'
203
- } ) );
204
- expect( handler ).toHaveBeenCalledWith( {
205
- eventId: 'evt-err-1', eventDate, workflowDetails, error: err, extra: 'passthrough'
206
- } );
182
+ expect( handler ).toHaveBeenCalledWith( payload );
207
183
  } );
208
184
  } );
209
185
 
@@ -214,53 +190,49 @@ describe( 'hooks/index', () => {
214
190
  [ 'onActivityError', onActivityError, BusEventType.ACTIVITY_ERROR, { error: new Error( 'activity failed' ) } ]
215
191
  ];
216
192
 
217
- it.each( cases )( '%s skips internal activities and forwards bus fields', async ( _name, registerHook, eventType, extraFields = {} ) => {
193
+ it.each( cases )( '%s forwards internal activity bus fields', async ( _name, registerHook, eventType, extraFields = {} ) => {
218
194
  const handler = vi.fn().mockResolvedValue( undefined );
219
- registerHook( handler );
220
-
221
- expect( messageBusMock.on ).toHaveBeenCalledWith( eventType, expect.any( Function ) );
222
-
223
- await Promise.resolve( onHandlers[eventType]( {
224
- eventId: 'evt-ignored',
225
- eventDate,
226
- activityInfo,
227
- workflowDetails,
228
- outputActivityKind: ComponentType.INTERNAL_STEP,
229
- ...extraFields
230
- } ) );
231
- expect( handler ).not.toHaveBeenCalled();
232
-
233
- await Promise.resolve( onHandlers[eventType]( {
195
+ const payload = {
234
196
  eventId: 'evt-activity-1',
235
197
  eventDate,
236
198
  activityInfo,
237
199
  workflowDetails,
238
- outputActivityKind: ComponentType.STEP,
200
+ outputActivityKind: 'internal_step',
239
201
  extra: 'passthrough',
240
202
  ...extraFields
241
- } ) );
203
+ };
204
+ registerHook( handler );
242
205
 
243
- expect( handler ).toHaveBeenCalledWith( {
244
- eventId: 'evt-activity-1',
245
- eventDate,
246
- activityInfo,
247
- workflowDetails,
248
- outputActivityKind: ComponentType.STEP,
249
- extra: 'passthrough',
250
- ...extraFields
251
- } );
206
+ expect( mainEventBusMock.on ).toHaveBeenCalledWith( eventType, expect.any( Function ) );
207
+ await mainOnHandlers[eventType]( payload );
208
+
209
+ expect( handler ).toHaveBeenCalledWith( payload );
252
210
  } );
253
211
  } );
254
212
 
255
213
  describe( 'on', () => {
256
- it( 'subscribes to external event channel and forwards payload', async () => {
214
+ it( 'subscribes to SDK and user event channels and forwards payloads', async () => {
257
215
  const handler = vi.fn().mockResolvedValue( undefined );
258
216
  on( 'myEvent', handler );
259
217
 
260
- expect( messageBusMock.on ).toHaveBeenCalledWith( 'external:myEvent', expect.any( Function ) );
261
- await onHandlers['external:myEvent']( { foo: 1 } );
218
+ expect( stepEventBusMock.on ).toHaveBeenCalledWith( 'sdk:myEvent', expect.any( Function ) );
219
+ expect( stepEventBusMock.on ).toHaveBeenCalledWith( 'usr:myEvent', expect.any( Function ) );
220
+ await stepOnHandlers['sdk:myEvent']( { payload: { source: 'sdk' } } );
221
+ await stepOnHandlers['usr:myEvent']( { payload: { source: 'user' } } );
222
+
223
+ expect( handler ).toHaveBeenNthCalledWith( 1, { payload: { source: 'sdk' } } );
224
+ expect( handler ).toHaveBeenNthCalledWith( 2, { payload: { source: 'user' } } );
225
+ } );
226
+ } );
227
+
228
+ describe( 'emit', () => {
229
+ it( 'emits payloads on the user event channel', () => {
230
+ const payload = { foo: 1 };
231
+
232
+ const emitted = emit( 'myEvent', payload );
262
233
 
263
- expect( handler ).toHaveBeenCalledWith( { foo: 1 } );
234
+ expect( stepEventBusMock.emit ).toHaveBeenCalledWith( 'usr:myEvent', payload );
235
+ expect( emitted ).toBe( true );
264
236
  } );
265
237
  } );
266
238
  } );
@@ -2,14 +2,12 @@
2
2
  * Tools to interact with Events
3
3
  */
4
4
  export declare const Event: {
5
+
5
6
  /**
6
- * Emits a custom event on the in-process message bus.
7
- *
8
- * When called inside an Output activity context, the framework automatically
9
- * attaches `activityInfo`, `workflowDetails`, and `outputActivityKind` onto the emitted payload.
7
+ * Emits an event on step message bus.
10
8
  *
11
9
  * @param eventName - The name of the event to emit
12
- * @param payload - An optional payload to send to the event
10
+ * @param payload - An optional payload to send to the event.
13
11
  */
14
- emit( eventName: string, payload?: object ): void;
12
+ emit( eventName: string, payload?: object ): boolean;
15
13
  };
@@ -1,18 +1,5 @@
1
- import { messageBus } from '#bus';
2
- import { Storage } from '#async_storage';
1
+ import { stepEventBus } from '#bus';
3
2
 
4
3
  export const Event = {
5
- emit: ( eventName, payload ) => {
6
- const ctx = Storage.load();
7
-
8
- messageBus.emit( `external:${eventName}`, {
9
- ...payload ?? {},
10
- ...( ctx && {
11
- activityInfo: ctx.activityInfo,
12
- workflowDetails: ctx.workflowDetails,
13
- outputActivityKind: ctx.outputActivityKind
14
- } )
15
- } );
16
- }
4
+ emit: ( eventName, payload ) => stepEventBus.emit( `sdk:${eventName}`, payload )
17
5
  };
18
-
@@ -1,118 +1,40 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
2
 
3
- const loadMock = vi.hoisted( () => vi.fn() );
4
3
  const emitMock = vi.hoisted( () => vi.fn() );
5
4
 
6
- vi.mock( '#async_storage', () => ( {
7
- Storage: { load: loadMock }
8
- } ) );
9
-
10
5
  vi.mock( '#bus', () => ( {
11
- messageBus: { emit: emitMock }
6
+ stepEventBus: { emit: emitMock }
12
7
  } ) );
13
8
 
14
9
  import { Event } from './events.js';
15
10
 
16
- // `eventId` stamping is the bus layer's responsibility (see bus.spec.js).
17
- // Assertions here use `objectContaining` so they don't have to know about that enrichment.
18
11
  describe( 'Event.emit', () => {
19
12
  beforeEach( () => {
20
13
  vi.clearAllMocks();
21
14
  } );
22
15
 
23
- it( 'forwards activityInfo, workflowDetails, and outputActivityKind from storage', () => {
24
- const activityInfo = {
25
- activityId: 'act-1',
26
- activityType: 'step',
27
- workflowExecution: { workflowId: 'wf-1', runId: 'run-1' },
28
- workflowType: 'workflow'
29
- };
30
- const workflowDetails = {
31
- workflowId: 'wf-1',
32
- runId: 'run-1',
33
- workflowType: 'workflow'
34
- };
35
- loadMock.mockReturnValue( {
36
- activityInfo,
37
- workflowDetails,
38
- outputActivityKind: 'step'
39
- } );
16
+ it( 'forwards class instance payloads unchanged', () => {
17
+ class Payload {
18
+ value = 'test';
19
+ }
20
+ const payload = new Payload();
40
21
 
41
- Event.emit( 'cost:llm:request', { modelId: 'gpt-4o' } );
22
+ Event.emit( 'test:event', payload );
42
23
 
43
- expect( emitMock ).toHaveBeenCalledWith( 'external:cost:llm:request', expect.objectContaining( {
44
- activityInfo,
45
- workflowDetails,
46
- outputActivityKind: 'step',
47
- modelId: 'gpt-4o'
48
- } ) );
24
+ expect( emitMock ).toHaveBeenCalledWith( 'sdk:test:event', payload );
49
25
  } );
50
26
 
51
- it( 'emits payload without context when storage is missing', () => {
52
- loadMock.mockReturnValue( undefined );
27
+ it( 'emits plain object payloads on the SDK event channel', () => {
28
+ const payload = { modelId: 'gpt-4o' };
53
29
 
54
- Event.emit( 'foo:bar', { x: 1 } );
30
+ Event.emit( 'cost:llm:request', payload );
55
31
 
56
- expect( emitMock ).toHaveBeenCalledWith( 'external:foo:bar', { x: 1 } );
32
+ expect( emitMock ).toHaveBeenCalledWith( 'sdk:cost:llm:request', payload );
57
33
  } );
58
34
 
59
- it( 'handles missing payload', () => {
60
- const activityInfo = {
61
- activityId: 'act-2',
62
- activityType: 'step',
63
- workflowExecution: { workflowId: 'wf-2', runId: 'run-2' },
64
- workflowType: 'workflow'
65
- };
66
- const workflowDetails = {
67
- workflowId: 'wf-2',
68
- runId: 'run-2',
69
- workflowType: 'workflow'
70
- };
71
- loadMock.mockReturnValue( {
72
- activityInfo,
73
- workflowDetails,
74
- outputActivityKind: 'step'
75
- } );
76
-
35
+ it( 'forwards a missing payload as undefined', () => {
77
36
  Event.emit( 'lifecycle:start' );
78
37
 
79
- expect( emitMock ).toHaveBeenCalledWith( 'external:lifecycle:start', expect.objectContaining( {
80
- activityInfo,
81
- workflowDetails,
82
- outputActivityKind: 'step'
83
- } ) );
84
- } );
85
-
86
- it( 'does not let payload override activityInfo, workflowDetails, or outputActivityKind', () => {
87
- const activityInfo = {
88
- activityId: 'act-3',
89
- activityType: 'step',
90
- workflowExecution: { workflowId: 'wf-3', runId: 'run-3' },
91
- workflowType: 'workflow'
92
- };
93
- const workflowDetails = {
94
- workflowId: 'wf-3',
95
- runId: 'run-3',
96
- workflowType: 'workflow'
97
- };
98
- loadMock.mockReturnValue( {
99
- activityInfo,
100
- workflowDetails,
101
- outputActivityKind: 'step'
102
- } );
103
-
104
- Event.emit( 'cost:http:request', {
105
- activityInfo: { activityId: 'should-be-overridden' },
106
- workflowDetails: { workflowId: 'should-be-overridden' },
107
- outputActivityKind: 'should-be-overridden',
108
- url: 'https://example.com'
109
- } );
110
-
111
- expect( emitMock ).toHaveBeenCalledWith( 'external:cost:http:request', expect.objectContaining( {
112
- activityInfo,
113
- workflowDetails,
114
- outputActivityKind: 'step',
115
- url: 'https://example.com'
116
- } ) );
38
+ expect( emitMock ).toHaveBeenCalledWith( 'sdk:lifecycle:start', undefined );
117
39
  } );
118
40
  } );
@@ -1,4 +1,4 @@
1
- import { messageBus } from '#bus';
1
+ import { mainEventBus } from '#bus';
2
2
  import { ACTIVITY_LOGGER_SYMBOL, BusEventType } from '#consts';
3
3
  import { activityInfo as activityInfoFn } from '@temporalio/activity';
4
4
  import { assignImmutableProperty } from '#helpers/object';
@@ -9,6 +9,6 @@ import { assignImmutableProperty } from '#helpers/object';
9
9
  export const bindGlobalFunctions = () => {
10
10
  /** Defines the activity logger function, accessible in activity context via logger interface */
11
11
  assignImmutableProperty( globalThis, ACTIVITY_LOGGER_SYMBOL, ( { level, message, metadata } ) =>
12
- messageBus.emit( BusEventType.ACTIVITY_LOG, { level, message, metadata, activityInfo: activityInfoFn() } )
12
+ mainEventBus.emit( BusEventType.ACTIVITY_LOG, { level, message, metadata, activityInfo: activityInfoFn() } )
13
13
  );
14
14
  };
@@ -10,7 +10,7 @@ const {
10
10
  }
11
11
  } ) );
12
12
 
13
- const messageBusMock = vi.hoisted( () => ( {
13
+ const mainEventBusMock = vi.hoisted( () => ( {
14
14
  emit: vi.fn()
15
15
  } ) );
16
16
  const activityInfoMock = vi.hoisted( () => vi.fn( () => ( {
@@ -19,7 +19,7 @@ const activityInfoMock = vi.hoisted( () => vi.fn( () => ( {
19
19
  } ) ) );
20
20
 
21
21
  vi.mock( '#consts', () => ( { ACTIVITY_LOGGER_SYMBOL, BusEventType } ) );
22
- vi.mock( '#bus', () => ( { messageBus: messageBusMock } ) );
22
+ vi.mock( '#bus', () => ( { mainEventBus: mainEventBusMock } ) );
23
23
  vi.mock( '@temporalio/activity', () => ( {
24
24
  activityInfo: activityInfoMock
25
25
  } ) );
@@ -42,7 +42,7 @@ describe( 'worker/global_functions', () => {
42
42
  } );
43
43
 
44
44
  expect( activityInfoMock ).toHaveBeenCalledTimes( 1 );
45
- expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.ACTIVITY_LOG, {
45
+ expect( mainEventBusMock.emit ).toHaveBeenCalledWith( BusEventType.ACTIVITY_LOG, {
46
46
  level: 'debug',
47
47
  message: 'activity detail',
48
48
  metadata,
@@ -13,7 +13,7 @@ import { createChildLogger } from '#logger';
13
13
  import { setupInterruptionHandler } from './interruption.js';
14
14
  import { CatalogJob } from './catalog_workflow/catalog_job.js';
15
15
  import { bootstrapFetchProxy } from './proxy.js';
16
- import { messageBus } from '#bus';
16
+ import { mainEventBus } from '#bus';
17
17
  import { BusEventType } from '#consts';
18
18
  import { setupTelemetry } from './telemetry.js';
19
19
  import { TemporalConnectionMonitor } from './connection_monitor.js';
@@ -60,7 +60,7 @@ const execute = async () => {
60
60
  log.info( 'Loading activities...', { callerDir } );
61
61
  const { activities } = await loadActivities( callerDir, workflows );
62
62
 
63
- messageBus.emit( BusEventType.WORKER_BEFORE_START );
63
+ mainEventBus.emit( BusEventType.WORKER_BEFORE_START );
64
64
  bootstrapFetchProxy();
65
65
 
66
66
  log.info( 'Initializing tracing...' );
@@ -218,7 +218,7 @@ execute()
218
218
  .catch( error => {
219
219
  log.error( 'Fatal error', { error: error.message, stack: error.stack } );
220
220
 
221
- messageBus.emit( BusEventType.RUNTIME_ERROR, { error } );
221
+ mainEventBus.emit( BusEventType.RUNTIME_ERROR, { error } );
222
222
 
223
223
  const timeToFlushEvent = configs.processFailureShutdownDelay;
224
224
  log.info( `Exiting in ${timeToFlushEvent}ms` );