@outputai/core 0.10.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.
Files changed (45) hide show
  1. package/package.json +1 -1
  2. package/src/bus.js +58 -20
  3. package/src/bus.spec.js +135 -77
  4. package/src/consts.js +2 -1
  5. package/src/helpers/object.js +48 -35
  6. package/src/helpers/object.spec.js +123 -75
  7. package/src/hooks/index.d.ts +48 -45
  8. package/src/hooks/index.js +49 -44
  9. package/src/hooks/index.spec.js +74 -102
  10. package/src/interface/workflow.js +92 -85
  11. package/src/interface/workflow.spec.js +135 -142
  12. package/src/sdk/helpers/objects.d.ts +24 -19
  13. package/src/sdk/runtime/events.d.ts +4 -6
  14. package/src/sdk/runtime/events.js +2 -15
  15. package/src/sdk/runtime/events.spec.js +14 -92
  16. package/src/worker/global_functions.js +2 -2
  17. package/src/worker/global_functions.spec.js +3 -3
  18. package/src/worker/index.js +3 -3
  19. package/src/worker/index.spec.js +6 -6
  20. package/src/worker/interceptors/activity.js +4 -4
  21. package/src/worker/interceptors/activity.spec.js +9 -9
  22. package/src/worker/interceptors/workflow.js +5 -5
  23. package/src/worker/interceptors/workflow.spec.js +7 -7
  24. package/src/worker/loader/activities.js +56 -40
  25. package/src/worker/loader/activities.spec.js +21 -22
  26. package/src/worker/loader/workflows.spec.js +1 -2
  27. package/src/worker/log_hooks.js +9 -9
  28. package/src/worker/log_hooks.spec.js +2 -2
  29. package/src/worker/sinks.js +8 -8
  30. package/src/worker/sinks.spec.js +9 -9
  31. package/src/worker/webpack_loaders/consts.js +6 -0
  32. package/src/worker/webpack_loaders/tools.js +1 -146
  33. package/src/worker/webpack_loaders/tools.spec.js +0 -23
  34. package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.js +24 -32
  35. package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.spec.js +82 -279
  36. package/src/worker/webpack_loaders/workflow_rewriter/index.mjs +6 -7
  37. package/src/worker/webpack_loaders/workflow_rewriter/index.spec.js +57 -119
  38. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_activity_calls.js +88 -0
  39. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_activity_calls.spec.js +165 -0
  40. package/src/worker/webpack_loaders/workflow_validator/index.mjs +96 -29
  41. package/src/worker/webpack_loaders/workflow_validator/index.spec.js +110 -583
  42. package/src/worker/webpack_loaders/{npm_workflow_export_resolve.js → workflow_validator/npm_workflow_export_resolve.js} +1 -1
  43. package/src/worker/webpack_loaders/{npm_workflow_export_resolve.spec.js → workflow_validator/npm_workflow_export_resolve.spec.js} +1 -1
  44. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.js +0 -193
  45. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.spec.js +0 -123
@@ -5,8 +5,7 @@ vi.mock( '#consts', () => ( {
5
5
  ACTIVITY_GET_TRACE_DESTINATIONS: '__internal#getTraceDestinations',
6
6
  WORKFLOWS_INDEX_FILENAME: '__workflows_entrypoint.js',
7
7
  WORKFLOW_CATALOG: 'catalog',
8
- ACTIVITY_OPTIONS_FILENAME: '__activity_options.js',
9
- SHARED_STEP_PREFIX: '$shared'
8
+ ACTIVITY_OPTIONS_FILENAME: '__activity_options.js'
10
9
  } ) );
11
10
 
12
11
  const sendHttpRequestMock = vi.fn();
@@ -63,6 +62,7 @@ describe( 'loadActivities', () => {
63
62
  it( 'loadActivities returns map including system activity and writes options file', async () => {
64
63
  const { loadActivities } = await import( './activities.js' );
65
64
 
65
+ importComponentsMock.mockImplementationOnce( async function *() {} );
66
66
  importComponentsMock.mockImplementationOnce( async function *() {
67
67
  yield {
68
68
  fn: () => {},
@@ -70,7 +70,6 @@ describe( 'loadActivities', () => {
70
70
  path: '/a/steps.js'
71
71
  };
72
72
  } );
73
- importComponentsMock.mockImplementationOnce( async function *() {} );
74
73
 
75
74
  const workflows = [ { name: 'A', path: '/a/workflow.js' } ];
76
75
  const { activities, optionsFile } = await loadActivities( '/root', workflows );
@@ -89,11 +88,11 @@ describe( 'loadActivities', () => {
89
88
 
90
89
  it( 'loadActivities omits activity options when component has no options or no activityOptions', async () => {
91
90
  const { loadActivities } = await import( './activities.js' );
91
+ importComponentsMock.mockImplementationOnce( async function *() {} );
92
92
  importComponentsMock.mockImplementationOnce( async function *() {
93
93
  yield { fn: () => {}, metadata: { name: 'NoOptions' }, path: '/a/steps.js' };
94
94
  yield { fn: () => {}, metadata: { name: 'EmptyOptions', options: {} }, path: '/a/steps2.js' };
95
95
  } );
96
- importComponentsMock.mockImplementationOnce( async function *() {} );
97
96
 
98
97
  await loadActivities( '/root', [ { name: 'A', path: '/a/workflow.js' } ] );
99
98
  const written = JSON.parse(
@@ -105,6 +104,7 @@ describe( 'loadActivities', () => {
105
104
 
106
105
  it( 'loadActivities throws when two activities in the same workflow share a name', async () => {
107
106
  const { loadActivities } = await import( './activities.js' );
107
+ importComponentsMock.mockImplementationOnce( async function *() {} );
108
108
  importComponentsMock.mockImplementationOnce( async function *() {
109
109
  yield { fn: () => {}, metadata: { name: 'DuplicateActivity' }, path: '/a/steps.js' };
110
110
  yield { fn: () => {}, metadata: { name: 'DuplicateActivity' }, path: '/a/evaluators.js' };
@@ -118,7 +118,6 @@ Activity names must be unique within a workflow.'
118
118
 
119
119
  it( 'loadActivities throws when two shared activities share a name', async () => {
120
120
  const { loadActivities } = await import( './activities.js' );
121
- importComponentsMock.mockImplementationOnce( async function *() {} );
122
121
  importComponentsMock.mockImplementationOnce( async function *() {
123
122
  yield { fn: () => {}, metadata: { name: 'DuplicateShared' }, path: '/root/shared/steps/a.js' };
124
123
  yield { fn: () => {}, metadata: { name: 'DuplicateShared' }, path: '/root/shared/evaluators/a.js' };
@@ -133,8 +132,8 @@ Activity names must be unique within a workflow.'
133
132
  const { loadActivities } = await import( './activities.js' );
134
133
  const workflowFiles = [ { path: '/a/steps/foo.js' } ];
135
134
  const sharedFiles = [ { path: '/root/shared/steps/baz.js' } ];
136
- matchFilesMock.mockReturnValueOnce( workflowFiles );
137
135
  matchFilesMock.mockReturnValueOnce( sharedFiles );
136
+ matchFilesMock.mockReturnValueOnce( workflowFiles );
138
137
  importComponentsMock.mockImplementationOnce( async function *() {} );
139
138
  importComponentsMock.mockImplementationOnce( async function *() {} );
140
139
 
@@ -143,12 +142,12 @@ Activity names must be unique within a workflow.'
143
142
 
144
143
  expect( matchFilesMock ).toHaveBeenCalledTimes( 2 );
145
144
  expect( buildActivityMatcherMock ).toHaveBeenCalledWith( '/a' );
146
- expect( matchFilesMock ).toHaveBeenNthCalledWith( 1, '/a', [ activityMatcherMock ] );
147
- expect( matchFilesMock ).toHaveBeenNthCalledWith( 2, '/root', [ sharedStepsDirMock, sharedEvaluatorsDirMock ] );
145
+ expect( matchFilesMock ).toHaveBeenNthCalledWith( 1, '/root', [ sharedStepsDirMock, sharedEvaluatorsDirMock ] );
146
+ expect( matchFilesMock ).toHaveBeenNthCalledWith( 2, '/a', [ activityMatcherMock ] );
148
147
 
149
148
  expect( importComponentsMock ).toHaveBeenCalledTimes( 2 );
150
- expect( importComponentsMock ).toHaveBeenNthCalledWith( 1, workflowFiles );
151
- expect( importComponentsMock ).toHaveBeenNthCalledWith( 2, sharedFiles );
149
+ expect( importComponentsMock ).toHaveBeenNthCalledWith( 1, sharedFiles );
150
+ expect( importComponentsMock ).toHaveBeenNthCalledWith( 2, workflowFiles );
152
151
  } );
153
152
 
154
153
  it( 'loads shared activities from external workflow packages', async () => {
@@ -157,8 +156,6 @@ Activity names must be unique within a workflow.'
157
156
  const localWorkflow = { name: 'Local', path: '/root/workflows/local/workflow.js' };
158
157
  const externalWorkflow = { name: 'External', path: '/root/node_modules/pkg/workflows/a/workflow.js', external: true };
159
158
  findSharedActivitiesFromWorkflowsMock.mockReturnValue( externalSharedFiles );
160
- importComponentsMock.mockImplementationOnce( async function *() {} );
161
- importComponentsMock.mockImplementationOnce( async function *() {} );
162
159
  importComponentsMock.mockImplementationOnce( async function *() {
163
160
  yield {
164
161
  fn: () => {},
@@ -170,27 +167,29 @@ Activity names must be unique within a workflow.'
170
167
  const { activities } = await loadActivities( '/root', [ localWorkflow, externalWorkflow ] );
171
168
 
172
169
  expect( findSharedActivitiesFromWorkflowsMock ).toHaveBeenCalledWith( [ externalWorkflow ] );
173
- expect( importComponentsMock ).toHaveBeenNthCalledWith( 3, externalSharedFiles );
174
- expect( activities['$shared#ExternalShared'] ).toBeTypeOf( 'function' );
170
+ expect( importComponentsMock ).toHaveBeenNthCalledWith( 1, externalSharedFiles );
171
+ expect( activities['Local#ExternalShared'] ).toBeTypeOf( 'function' );
172
+ expect( activities['External#ExternalShared'] ).toBeTypeOf( 'function' );
175
173
  const written = JSON.parse(
176
174
  writeFileInTempDirMock.mock.calls[0][0].replace( /^export default\s*/, '' ).replace( /;\s*$/, '' )
177
175
  );
178
- expect( written['$shared#ExternalShared'] ).toEqual( { retry: { maximumAttempts: 2 } } );
176
+ expect( written['Local#ExternalShared'] ).toEqual( { retry: { maximumAttempts: 2 } } );
177
+ expect( written['External#ExternalShared'] ).toEqual( { retry: { maximumAttempts: 2 } } );
179
178
  } );
180
179
 
181
180
  it( 'loadActivities includes nested workflow steps and shared evaluators', async () => {
182
181
  const { loadActivities } = await import( './activities.js' );
183
182
  importComponentsMock.mockImplementationOnce( async function *() {
184
- yield { fn: () => {}, metadata: { name: 'ActNested' }, path: '/a/steps/foo.js' };
183
+ yield { fn: () => {}, metadata: { name: 'SharedEval' }, path: '/root/shared/evaluators/bar.js' };
185
184
  } );
186
185
  importComponentsMock.mockImplementationOnce( async function *() {
187
- yield { fn: () => {}, metadata: { name: 'SharedEval' }, path: '/root/shared/evaluators/bar.js' };
186
+ yield { fn: () => {}, metadata: { name: 'ActNested' }, path: '/a/steps/foo.js' };
188
187
  } );
189
188
 
190
189
  const workflows = [ { name: 'A', path: '/a/workflow.js' } ];
191
190
  const { activities } = await loadActivities( '/root', workflows );
192
191
  expect( activities['A#ActNested'] ).toBeTypeOf( 'function' );
193
- expect( activities['$shared#SharedEval'] ).toBeTypeOf( 'function' );
192
+ expect( activities['A#SharedEval'] ).toBeTypeOf( 'function' );
194
193
  } );
195
194
 
196
195
  it( 'collects shared nested steps and evaluators across multiple subfolders', async () => {
@@ -205,9 +204,9 @@ Activity names must be unique within a workflow.'
205
204
 
206
205
  const workflows = [ { name: 'A', path: '/a/workflow.js' } ];
207
206
  const { activities } = await loadActivities( '/root', workflows );
208
- expect( activities['$shared#SharedStepPrimary'] ).toBeTypeOf( 'function' );
209
- expect( activities['$shared#SharedStepSecondary'] ).toBeTypeOf( 'function' );
210
- expect( activities['$shared#SharedEvalPrimary'] ).toBeTypeOf( 'function' );
211
- expect( activities['$shared#SharedEvalSecondary'] ).toBeTypeOf( 'function' );
207
+ expect( activities['A#SharedStepPrimary'] ).toBeTypeOf( 'function' );
208
+ expect( activities['A#SharedStepSecondary'] ).toBeTypeOf( 'function' );
209
+ expect( activities['A#SharedEvalPrimary'] ).toBeTypeOf( 'function' );
210
+ expect( activities['A#SharedEvalSecondary'] ).toBeTypeOf( 'function' );
212
211
  } );
213
212
  } );
@@ -5,8 +5,7 @@ vi.mock( '#consts', () => ( {
5
5
  ACTIVITY_GET_TRACE_DESTINATIONS: '__internal#getTraceDestinations',
6
6
  WORKFLOWS_INDEX_FILENAME: '__workflows_entrypoint.js',
7
7
  WORKFLOW_CATALOG: 'catalog',
8
- ACTIVITY_OPTIONS_FILENAME: '__activity_options.js',
9
- SHARED_STEP_PREFIX: '$shared'
8
+ ACTIVITY_OPTIONS_FILENAME: '__activity_options.js'
10
9
  } ) );
11
10
 
12
11
  const { importComponentsMock, findWorkflowsInNodeModulesMock, matchFilesMock, writeFileInTempDirMock } = vi.hoisted( () => ( {
@@ -1,4 +1,4 @@
1
- import { messageBus } from '#bus';
1
+ import { mainEventBus } from '#bus';
2
2
  import { createChildLogger } from '#logger';
3
3
  import { ACTIVITY_GET_TRACE_DESTINATIONS, BusEventType, LifecycleEvent, WORKFLOW_CATALOG } from '#consts';
4
4
 
@@ -25,21 +25,21 @@ const serializedActivityFields = activityInfo => ( {
25
25
 
26
26
  const shouldLogActivity = activityInfo => activityInfo.activityType !== ACTIVITY_GET_TRACE_DESTINATIONS;
27
27
 
28
- messageBus.on( BusEventType.ACTIVITY_START, ( { activityInfo, outputActivityKind } ) =>
28
+ mainEventBus.on( BusEventType.ACTIVITY_START, ( { activityInfo, outputActivityKind } ) =>
29
29
  shouldLogActivity( activityInfo ) && activityLog.info( `Started ${activityInfo.activityType} ${outputActivityKind}`, {
30
30
  event: LifecycleEvent.START,
31
31
  ...serializedActivityFields( activityInfo )
32
32
  } )
33
33
  );
34
34
 
35
- messageBus.on( BusEventType.ACTIVITY_END, ( { activityInfo, outputActivityKind } ) =>
35
+ mainEventBus.on( BusEventType.ACTIVITY_END, ( { activityInfo, outputActivityKind } ) =>
36
36
  shouldLogActivity( activityInfo ) && activityLog.info( `Ended ${activityInfo.activityType} ${outputActivityKind}`, {
37
37
  event: LifecycleEvent.END,
38
38
  ...serializedActivityFields( activityInfo )
39
39
  } )
40
40
  );
41
41
 
42
- messageBus.on( BusEventType.ACTIVITY_ERROR, ( { activityInfo, outputActivityKind, error } ) =>
42
+ mainEventBus.on( BusEventType.ACTIVITY_ERROR, ( { activityInfo, outputActivityKind, error } ) =>
43
43
  shouldLogActivity( activityInfo ) && activityLog.error( `Error ${activityInfo.activityType} ${outputActivityKind}: ${error.constructor.name}`, {
44
44
  event: LifecycleEvent.ERROR,
45
45
  ...serializedActivityFields( activityInfo ),
@@ -47,7 +47,7 @@ messageBus.on( BusEventType.ACTIVITY_ERROR, ( { activityInfo, outputActivityKind
47
47
  } )
48
48
  );
49
49
 
50
- messageBus.on( BusEventType.ACTIVITY_LOG, ( { level, message, metadata, activityInfo } ) =>
50
+ mainEventBus.on( BusEventType.ACTIVITY_LOG, ( { level, message, metadata, activityInfo } ) =>
51
51
  activityLog[level]( message, {
52
52
  ...metadata ?? {},
53
53
  ...serializedActivityFields( activityInfo )
@@ -68,21 +68,21 @@ const serializeWorkflowFields = workflowDetails => ( {
68
68
 
69
69
  const shouldLogWorkflow = workflowDetails => workflowDetails.workflowType !== WORKFLOW_CATALOG;
70
70
 
71
- messageBus.on( BusEventType.WORKFLOW_START, ( { workflowDetails } ) =>
71
+ mainEventBus.on( BusEventType.WORKFLOW_START, ( { workflowDetails } ) =>
72
72
  shouldLogWorkflow( workflowDetails ) && workflowLog.info( `Started ${workflowDetails.workflowType} workflow`, {
73
73
  event: LifecycleEvent.START,
74
74
  ...serializeWorkflowFields( workflowDetails )
75
75
  } )
76
76
  );
77
77
 
78
- messageBus.on( BusEventType.WORKFLOW_END, ( { workflowDetails } ) =>
78
+ mainEventBus.on( BusEventType.WORKFLOW_END, ( { workflowDetails } ) =>
79
79
  shouldLogWorkflow( workflowDetails ) && workflowLog.info( `Ended ${workflowDetails.workflowType} workflow`, {
80
80
  event: LifecycleEvent.END,
81
81
  ...serializeWorkflowFields( workflowDetails )
82
82
  } )
83
83
  );
84
84
 
85
- messageBus.on( BusEventType.WORKFLOW_ERROR, ( { workflowDetails, error } ) =>
85
+ mainEventBus.on( BusEventType.WORKFLOW_ERROR, ( { workflowDetails, error } ) =>
86
86
  shouldLogWorkflow( workflowDetails ) && workflowLog.error( `Error ${workflowDetails.workflowType} workflow: ${error.constructor.name}`, {
87
87
  event: LifecycleEvent.ERROR,
88
88
  ...serializeWorkflowFields( workflowDetails ),
@@ -90,7 +90,7 @@ messageBus.on( BusEventType.WORKFLOW_ERROR, ( { workflowDetails, error } ) =>
90
90
  } )
91
91
  );
92
92
 
93
- messageBus.on( BusEventType.WORKFLOW_LOG, ( { level, message, metadata, workflowDetails } ) =>
93
+ mainEventBus.on( BusEventType.WORKFLOW_LOG, ( { level, message, metadata, workflowDetails } ) =>
94
94
  workflowLog[level]( message, {
95
95
  ...metadata ?? {},
96
96
  ...serializeWorkflowFields( workflowDetails )
@@ -22,14 +22,14 @@ const createChildLoggerMock = vi.hoisted( () =>
22
22
  );
23
23
 
24
24
  const onHandlers = vi.hoisted( () => ( {} ) );
25
- const messageBusMock = vi.hoisted( () => ( {
25
+ const mainEventBusMock = vi.hoisted( () => ( {
26
26
  on: vi.fn( ( eventType, handler ) => {
27
27
  onHandlers[eventType] = handler;
28
28
  } )
29
29
  } ) );
30
30
 
31
31
  vi.mock( '#logger', () => ( { createChildLogger: createChildLoggerMock } ) );
32
- vi.mock( '#bus', () => ( { messageBus: messageBusMock } ) );
32
+ vi.mock( '#bus', () => ( { mainEventBus: mainEventBusMock } ) );
33
33
 
34
34
  import './log_hooks.js';
35
35
 
@@ -1,6 +1,6 @@
1
1
  import { BusEventType, ComponentType } from '#consts';
2
2
  import * as Tracing from '#tracing';
3
- import { messageBus } from '#bus';
3
+ import { mainEventBus } from '#bus';
4
4
  import { createWorkflowDetails } from '#helpers/temporal_context';
5
5
 
6
6
  // This sink allow for sandbox Temporal environment to send trace logs back to the main thread.
@@ -12,15 +12,15 @@ export const sinks = {
12
12
  workflow: {
13
13
  log: {
14
14
  fn: ( workflowInfo, { level, message, metadata } ) => {
15
- messageBus.emit( BusEventType.WORKFLOW_LOG, { level, message, metadata, workflowDetails: createWorkflowDetails( workflowInfo ) } );
15
+ mainEventBus.emit( BusEventType.WORKFLOW_LOG, { level, message, metadata, workflowDetails: createWorkflowDetails( workflowInfo ) } );
16
16
  },
17
17
  callDuringReplay: false
18
18
  },
19
19
  start: {
20
20
  fn: ( workflowInfo, input ) => {
21
21
  const { runId, workflowType, memo: { traceInfo }, parent } = workflowInfo;
22
- messageBus.emit( BusEventType.WORKFLOW_START, { workflowDetails: createWorkflowDetails( workflowInfo ) } );
23
- if ( traceInfo ) { // internal workflows (catalog) do not have this info
22
+ mainEventBus.emit( BusEventType.WORKFLOW_START, { workflowDetails: createWorkflowDetails( workflowInfo ) } );
23
+ if ( traceInfo ) {
24
24
  Tracing.addEventStart( {
25
25
  id: runId,
26
26
  kind: ComponentType.WORKFLOW,
@@ -37,8 +37,8 @@ export const sinks = {
37
37
  end: {
38
38
  fn: ( workflowInfo, output ) => {
39
39
  const { runId, memo: { traceInfo } } = workflowInfo;
40
- messageBus.emit( BusEventType.WORKFLOW_END, { workflowDetails: createWorkflowDetails( workflowInfo ) } );
41
- if ( traceInfo ) { // internal workflows (catalog) do not have this info
40
+ mainEventBus.emit( BusEventType.WORKFLOW_END, { workflowDetails: createWorkflowDetails( workflowInfo ) } );
41
+ if ( traceInfo ) {
42
42
  Tracing.addEventEnd( { id: runId, details: output, traceInfo } );
43
43
  }
44
44
  },
@@ -48,8 +48,8 @@ export const sinks = {
48
48
  error: {
49
49
  fn: ( workflowInfo, error ) => {
50
50
  const { runId, memo: { traceInfo } } = workflowInfo;
51
- messageBus.emit( BusEventType.WORKFLOW_ERROR, { workflowDetails: createWorkflowDetails( workflowInfo ), error } );
52
- if ( traceInfo ) { // internal workflows (catalog) do not have this info
51
+ mainEventBus.emit( BusEventType.WORKFLOW_ERROR, { workflowDetails: createWorkflowDetails( workflowInfo ), error } );
52
+ if ( traceInfo ) {
53
53
  Tracing.addEventError( { id: runId, details: error, traceInfo } );
54
54
  }
55
55
  },
@@ -1,7 +1,7 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
2
  import { BusEventType, ComponentType } from '#consts';
3
3
 
4
- const messageBusMock = vi.hoisted( () => ( {
4
+ const mainEventBusMock = vi.hoisted( () => ( {
5
5
  emit: vi.fn()
6
6
  } ) );
7
7
 
@@ -15,7 +15,7 @@ const createWorkflowDetailsMock = vi.hoisted( () => vi.fn( workflowInfo => ( {
15
15
  runId: workflowInfo.runId
16
16
  } ) ) );
17
17
 
18
- vi.mock( '#bus', () => ( { messageBus: messageBusMock } ) );
18
+ vi.mock( '#bus', () => ( { mainEventBus: mainEventBusMock } ) );
19
19
  vi.mock( '#tracing', () => ( {
20
20
  addEventStart: addEventStartMock,
21
21
  addEventEnd: addEventEndMock,
@@ -69,7 +69,7 @@ describe( 'worker/sinks', () => {
69
69
  } );
70
70
 
71
71
  expect( createWorkflowDetailsMock ).toHaveBeenCalledWith( workflowInfo );
72
- expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_LOG, {
72
+ expect( mainEventBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_LOG, {
73
73
  level: 'info',
74
74
  message: 'workflow detail',
75
75
  metadata,
@@ -83,7 +83,7 @@ describe( 'worker/sinks', () => {
83
83
 
84
84
  sinks.workflow.start.fn( workflowInfo, input );
85
85
 
86
- expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_START, { workflowDetails } );
86
+ expect( mainEventBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_START, { workflowDetails } );
87
87
  expect( addEventStartMock ).toHaveBeenCalledWith( {
88
88
  id: 'run-1',
89
89
  kind: ComponentType.WORKFLOW,
@@ -99,7 +99,7 @@ describe( 'worker/sinks', () => {
99
99
 
100
100
  sinks.workflow.start.fn( { ...workflowInfo, memo: {} }, { value: 'input' } );
101
101
 
102
- expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_START, { workflowDetails } );
102
+ expect( mainEventBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_START, { workflowDetails } );
103
103
  expect( addEventStartMock ).not.toHaveBeenCalled();
104
104
  } );
105
105
 
@@ -109,7 +109,7 @@ describe( 'worker/sinks', () => {
109
109
 
110
110
  sinks.workflow.end.fn( workflowInfo, output );
111
111
 
112
- expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_END, { workflowDetails } );
112
+ expect( mainEventBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_END, { workflowDetails } );
113
113
  expect( addEventEndMock ).toHaveBeenCalledWith( {
114
114
  id: 'run-1',
115
115
  details: output,
@@ -122,7 +122,7 @@ describe( 'worker/sinks', () => {
122
122
 
123
123
  sinks.workflow.end.fn( { ...workflowInfo, memo: {} }, { value: 'output' } );
124
124
 
125
- expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_END, { workflowDetails } );
125
+ expect( mainEventBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_END, { workflowDetails } );
126
126
  expect( addEventEndMock ).not.toHaveBeenCalled();
127
127
  } );
128
128
 
@@ -132,7 +132,7 @@ describe( 'worker/sinks', () => {
132
132
 
133
133
  sinks.workflow.error.fn( workflowInfo, error );
134
134
 
135
- expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_ERROR, { workflowDetails, error } );
135
+ expect( mainEventBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_ERROR, { workflowDetails, error } );
136
136
  expect( addEventErrorMock ).toHaveBeenCalledWith( {
137
137
  id: 'run-1',
138
138
  details: error,
@@ -146,7 +146,7 @@ describe( 'worker/sinks', () => {
146
146
 
147
147
  sinks.workflow.error.fn( { ...workflowInfo, memo: {} }, error );
148
148
 
149
- expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_ERROR, { workflowDetails, error } );
149
+ expect( mainEventBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_ERROR, { workflowDetails, error } );
150
150
  expect( addEventErrorMock ).not.toHaveBeenCalled();
151
151
  } );
152
152
 
@@ -7,3 +7,9 @@ export const ComponentFile = {
7
7
  STEPS: 'steps',
8
8
  WORKFLOW: 'workflow'
9
9
  };
10
+
11
+ export const ComponentFactory = {
12
+ EVALUATOR: 'evaluator',
13
+ STEP: 'step',
14
+ WORKFLOW: 'workflow'
15
+ };
@@ -2,27 +2,14 @@ import parser from '@babel/parser';
2
2
  import { resolve as resolvePath } from 'node:path';
3
3
  import { readFileSync } from 'node:fs';
4
4
  import {
5
- blockStatement,
6
- callExpression,
7
- functionExpression,
8
- identifier,
9
- isArrowFunctionExpression,
10
5
  isAssignmentPattern,
11
- isBlockStatement,
12
6
  isCallExpression,
13
7
  isExportNamedDeclaration,
14
- isFunctionExpression,
15
8
  isIdentifier,
16
- isVariableDeclarator,
17
9
  isStringLiteral,
18
10
  isVariableDeclaration,
19
11
  isObjectExpression,
20
- memberExpression,
21
- returnStatement,
22
- stringLiteral,
23
- thisExpression,
24
- isExportDefaultDeclaration,
25
- isFunctionDeclaration
12
+ isExportDefaultDeclaration
26
13
  } from '@babel/types';
27
14
  import { ComponentFile, NodeType } from './consts.js';
28
15
 
@@ -100,17 +87,6 @@ export const getLocalNameFromDestructuredProperty = prop => {
100
87
  return null;
101
88
  };
102
89
 
103
- /**
104
- * Convert an ArrowFunctionExpression to a FunctionExpression.
105
- * Wraps expression bodies in a block with a return statement.
106
- * @param {import('@babel/types').ArrowFunctionExpression} arrow - Arrow function.
107
- * @returns {import('@babel/types').FunctionExpression} Function expression.
108
- */
109
- export const toFunctionExpression = arrow => {
110
- const body = isBlockStatement( arrow.body ) ? arrow.body : blockStatement( [ returnStatement( arrow.body ) ] );
111
- return functionExpression( null, arrow.params, body, arrow.generator ?? false, arrow.async ?? false );
112
- };
113
-
114
90
  /**
115
91
  * Check if a module specifier or request string points to steps.js or is in a steps folder.
116
92
  * Matches: steps.js, /steps.js, /steps/*.js
@@ -231,38 +207,6 @@ export const getFileKind = path => {
231
207
  return null;
232
208
  };
233
209
 
234
- /**
235
- * Create a `this.method(literalName, ...args)` CallExpression.
236
- * @param {string} method - Method name on `this`.
237
- * @param {string} literalName - First string literal argument.
238
- * @param {import('@babel/types').Expression[]} args - Remaining call arguments.
239
- * @returns {import('@babel/types').CallExpression} Call expression node.
240
- */
241
- export const createThisMethodCall = ( method, literalName, args ) =>
242
- callExpression( memberExpression( thisExpression(), identifier( method ) ), [ stringLiteral( literalName ), ...args ] );
243
-
244
- /**
245
- * Build a CallExpression that binds `this` at the call site:
246
- * fn(arg1, arg2) -> fn.call(this, arg1, arg2)
247
- *
248
- * When to use:
249
- * - Inside workflow `fn` rewriting, local call-chain functions must receive the dynamic `this`
250
- * so that emitted `this.invokeStep(...)` and similar calls inside them operate correctly.
251
- *
252
- * Example:
253
- * // Input AST intent:
254
- * foo(a, b);
255
- *
256
- * // Rewritten AST:
257
- * foo.call(this, a, b);
258
- *
259
- * @param {string} calleeName - Identifier name of the function being called (e.g., 'foo').
260
- * @param {import('@babel/types').Expression[]} args - Original call arguments.
261
- * @returns {import('@babel/types').CallExpression} CallExpression node representing `callee.call(this, ...args)`.
262
- */
263
- export const bindThisAtCallSite = ( calleeName, args ) =>
264
- callExpression( memberExpression( identifier( calleeName ), identifier( 'call' ) ), [ thisExpression(), ...args ] );
265
-
266
210
  /**
267
211
  * Resolve an options object's name property to a string.
268
212
  * Accepts literal strings or top-level const string identifiers.
@@ -466,92 +410,3 @@ export const buildWorkflowNameMap = ( path, cache ) => {
466
410
  return result;
467
411
  };
468
412
 
469
- /**
470
- * Determine whether a node represents a function body usable as a workflow `fn`.
471
- *
472
- * Why this matters:
473
- * - Workflow `fn` needs a dynamic `this` so the rewriter can emit calls like `this.invokeStep(...)`.
474
- * - Arrow functions do not have their own `this`; they capture `this` lexically, which breaks the runtime contract.
475
- *
476
- * Accepts:
477
- * - FunctionExpression (possibly async/generator), e.g.:
478
- * const obj = {
479
- * fn: async function (input) {
480
- * return input;
481
- * }
482
- * };
483
- *
484
- * Rejects:
485
- * - ArrowFunctionExpression, e.g.:
486
- * const obj = {
487
- * fn: async (input) => input
488
- * };
489
- *
490
- * - Any other non-function expression.
491
- *
492
- * Notes:
493
- * - The rewriter will proactively convert arrow `fn` to a FunctionExpression before further processing.
494
- *
495
- * @param {import('@babel/types').Expression} v - Candidate node for `fn` value.
496
- * @returns {boolean} True if `v` is a FunctionExpression and not an arrow function.
497
- */
498
- export const isFunction = v => isFunctionExpression( v ) && !isArrowFunctionExpression( v );
499
-
500
- /**
501
- * Determine whether a variable declarator represents a function-like value.
502
- *
503
- * Use case:
504
- * - When `fn` calls a locally-declared function (directly or transitively), we need to:
505
- * - propagate `this` to that function call (`callee.call(this, ...)`)
506
- * - traverse into that function's body to rewrite imported step/workflow/evaluator calls.
507
- *
508
- * Matches patterns like:
509
- * - Function expression:
510
- * const foo = function (x) { return x + 1; };
511
- *
512
- * - Async/generator function expression:
513
- * const foo = async function (x) { return await work(x); };
514
- *
515
- * - Arrow function (will be normalized to FunctionExpression by the rewriter):
516
- * const foo = (x) => x + 1;
517
- * const foo = async (x) => await work(x);
518
- *
519
- * Does not match:
520
- * - Non-function initializers:
521
- * const foo = 42;
522
- * const foo = someIdentifier;
523
- *
524
- * @param {import('@babel/types').Node} v - AST node (typically a VariableDeclarator).
525
- * @returns {boolean} True if the declarator's initializer is a function (arrow or function expression).
526
- */
527
- export const isVarFunction = v =>
528
- isVariableDeclarator( v ) && ( isFunctionExpression( v.init ) || isArrowFunctionExpression( v.init ) );
529
-
530
- /**
531
- * Determine whether a binding node corresponds to a function-like declaration usable
532
- * as a call-chain function target during workflow rewriting.
533
- *
534
- * Matches:
535
- * - FunctionDeclaration:
536
- * function foo(x) { return x + 1; }
537
- *
538
- * - VariableDeclarator initialized with a function or arrow (normalized later):
539
- * const foo = function (x) { return x + 1; };
540
- * const foo = (x) => x + 1;
541
- *
542
- * Non-matches:
543
- * - Any binding that is not a function declaration nor a variable declarator with a function initializer.
544
- *
545
- * Why this matters:
546
- * - The rewriter traverses call chains from the workflow `fn`. It must recognize which local
547
- * callees are valid function bodies to rewrite and into which it can propagate `this`.
548
- *
549
- * @param {import('@babel/types').Node} node - Binding path node (FunctionDeclaration or VariableDeclarator).
550
- * @returns {boolean} True if the node represents a function-like binding.
551
- */
552
- export const isFunctionLikeBinding = node =>
553
- isFunctionDeclaration( node ) ||
554
- (
555
- isVariableDeclarator( node ) &&
556
- ( isFunctionExpression( node.init ) || isArrowFunctionExpression( node.init ) )
557
- );
@@ -9,7 +9,6 @@ import {
9
9
  extractTopLevelStringConsts,
10
10
  getObjectKeyName,
11
11
  getLocalNameFromDestructuredProperty,
12
- toFunctionExpression,
13
12
  isStepsPath,
14
13
  isSharedStepsPath,
15
14
  isAnyStepsPath,
@@ -17,7 +16,6 @@ import {
17
16
  isSharedEvaluatorsPath,
18
17
  isWorkflowPath,
19
18
  isAbsoluteWorkflowJsResource,
20
- createThisMethodCall,
21
19
  resolveNameFromArg,
22
20
  resolveNameFromOptions,
23
21
  buildStepsNameMap,
@@ -130,17 +128,6 @@ describe( 'workflow_rewriter tools', () => {
130
128
  rmSync( dir, { recursive: true, force: true } );
131
129
  } );
132
130
 
133
- it( 'toFunctionExpression: converts arrow, wraps expression bodies', () => {
134
- const arrowExprBody = t.arrowFunctionExpression( [ t.identifier( 'x' ) ], t.identifier( 'x' ) );
135
- const arrowBlockBody = t.arrowFunctionExpression( [], t.blockStatement( [ t.returnStatement( t.numericLiteral( 1 ) ) ] ) );
136
- const fn1 = toFunctionExpression( arrowExprBody );
137
- const fn2 = toFunctionExpression( arrowBlockBody );
138
- expect( t.isFunctionExpression( fn1 ) ).toBe( true );
139
- expect( t.isBlockStatement( fn1.body ) ).toBe( true );
140
- expect( t.isReturnStatement( fn1.body.body[0] ) ).toBe( true );
141
- expect( t.isFunctionExpression( fn2 ) ).toBe( true );
142
- } );
143
-
144
131
  it( 'isStepsPath: matches LOCAL steps.js (no path traversal)', () => {
145
132
  // Local steps (without ../ or /shared/)
146
133
  expect( isStepsPath( 'steps.js' ) ).toBe( true );
@@ -226,16 +213,6 @@ describe( 'workflow_rewriter tools', () => {
226
213
  expect( isSharedEvaluatorsPath( 'steps.js' ) ).toBe( false );
227
214
  } );
228
215
 
229
- it( 'createThisMethodCall: builds this.method(\'name\', ...args) call', () => {
230
- const call = createThisMethodCall( 'invoke', 'n', [ t.numericLiteral( 1 ), t.identifier( 'x' ) ] );
231
- expect( t.isCallExpression( call ) ).toBe( true );
232
- expect( t.isMemberExpression( call.callee ) ).toBe( true );
233
- expect( t.isThisExpression( call.callee.object ) ).toBe( true );
234
- expect( t.isIdentifier( call.callee.property, { name: 'invoke' } ) ).toBe( true );
235
- expect( t.isStringLiteral( call.arguments[0], { value: 'n' } ) ).toBe( true );
236
- expect( call.arguments.length ).toBe( 3 );
237
- } );
238
-
239
216
  it( 'buildSharedStepsNameMap: reads names from shared steps module and caches result', () => {
240
217
  const dir = mkdtempSync( join( tmpdir(), 'tools-shared-steps-' ) );
241
218
  mkdirSync( join( dir, 'shared', 'steps' ), { recursive: true } );