@outputai/core 0.3.3-next.e0cece4.0 → 0.3.3-next.e8eff63.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@outputai/core",
3
- "version": "0.3.3-next.e0cece4.0",
3
+ "version": "0.3.3-next.e8eff63.0",
4
4
  "description": "The core module of the output framework",
5
5
  "type": "module",
6
6
  "exports": {
package/src/consts.js CHANGED
@@ -32,3 +32,7 @@ export const BusEventType = {
32
32
 
33
33
  RUNTIME_ERROR: 'runtime_error'
34
34
  };
35
+
36
+ export const WorkflowSpecialOutput = {
37
+ CONTINUED_AS_NEW: '<<continued_as_new>>'
38
+ };
@@ -1,8 +1,8 @@
1
1
  // THIS RUNS IN THE TEMPORAL'S SANDBOX ENVIRONMENT
2
- import { workflowInfo, proxySinks, ApplicationFailure, ContinueAsNew } from '@temporalio/workflow';
2
+ import { workflowInfo, proxySinks, ApplicationFailure, ContinueAsNew, isCancellation } from '@temporalio/workflow';
3
3
  import { memoToHeaders } from '../sandboxed_utils.js';
4
4
  import { deepMerge } from '#utils';
5
- import { METADATA_ACCESS_SYMBOL } from '#consts';
5
+ import { METADATA_ACCESS_SYMBOL, WorkflowSpecialOutput } from '#consts';
6
6
  // this is a dynamic generated file with activity configs overwrites
7
7
  import stepOptions from '../temp/__activity_options.js';
8
8
 
@@ -44,7 +44,12 @@ class WorkflowExecutionInterceptor {
44
44
  * a new trace file will be generated
45
45
  */
46
46
  if ( error instanceof ContinueAsNew ) {
47
- sinks.workflow.end( '<continued_as_new>' );
47
+ sinks.workflow.end( WorkflowSpecialOutput.CONTINUED_AS_NEW );
48
+ throw error;
49
+ }
50
+
51
+ if ( isCancellation( error ) ) {
52
+ sinks.workflow.error( error );
48
53
  throw error;
49
54
  }
50
55
 
@@ -6,6 +6,7 @@ const workflowInfoMock = vi.fn();
6
6
  const workflowStartMock = vi.fn();
7
7
  const workflowEndMock = vi.fn();
8
8
  const workflowErrorMock = vi.fn();
9
+ const isCancellationMock = vi.fn();
9
10
  vi.mock( '@temporalio/workflow', () => ( {
10
11
  workflowInfo: ( ...args ) => workflowInfoMock( ...args ),
11
12
  proxySinks: () => ( {
@@ -26,7 +27,8 @@ vi.mock( '@temporalio/workflow', () => ( {
26
27
  super( 'ContinueAsNew' );
27
28
  this.name = 'ContinueAsNew';
28
29
  }
29
- }
30
+ },
31
+ isCancellation: ( ...args ) => isCancellationMock( ...args )
30
32
  } ) );
31
33
 
32
34
  const memoToHeadersMock = vi.fn( memo => ( memo ? { ...memo, __asHeaders: true } : {} ) );
@@ -50,6 +52,7 @@ vi.mock( '../temp/__activity_options.js', () => ( { default: stepOptionsDefault
50
52
  describe( 'workflow interceptors', () => {
51
53
  beforeEach( () => {
52
54
  vi.clearAllMocks();
55
+ isCancellationMock.mockReturnValue( false );
53
56
  workflowInfoMock.mockReturnValue( { workflowType: 'MyWorkflow', memo: { executionContext: { id: 'ctx-1' } } } );
54
57
  } );
55
58
 
@@ -151,8 +154,25 @@ describe( 'workflow interceptors', () => {
151
154
  expect( error.details ).toEqual( [ meta ] );
152
155
  } );
153
156
 
157
+ it( 'calls sinks.workflow.error and rethrows cancellation errors without wrapping', async () => {
158
+ const { interceptors } = await import( './workflow.js' );
159
+ const { ApplicationFailure } = await import( '@temporalio/workflow' );
160
+ const { inbound } = interceptors();
161
+ const interceptor = inbound[0];
162
+ const cancellation = new Error( 'Workflow cancelled' );
163
+ const next = vi.fn().mockRejectedValue( cancellation );
164
+ isCancellationMock.mockReturnValue( true );
165
+
166
+ await expect( interceptor.execute( { args: [ {} ] }, next ) ).rejects.toBe( cancellation );
167
+ expect( isCancellationMock ).toHaveBeenCalledWith( cancellation );
168
+ expect( cancellation ).not.toBeInstanceOf( ApplicationFailure );
169
+ expect( workflowErrorMock ).toHaveBeenCalledWith( cancellation );
170
+ expect( workflowEndMock ).not.toHaveBeenCalled();
171
+ } );
172
+
154
173
  it( 'on ContinueAsNew calls sinks.trace.addWorkflowEventEnd and rethrows', async () => {
155
174
  const { ContinueAsNew } = await import( '@temporalio/workflow' );
175
+ const { WorkflowSpecialOutput } = await import( '#consts' );
156
176
  const { interceptors } = await import( './workflow.js' );
157
177
  const { inbound } = interceptors();
158
178
  const interceptor = inbound[0];
@@ -160,7 +180,7 @@ describe( 'workflow interceptors', () => {
160
180
  const next = vi.fn().mockRejectedValue( continueErr );
161
181
 
162
182
  await expect( interceptor.execute( { args: [ {} ] }, next ) ).rejects.toThrow( ContinueAsNew );
163
- expect( workflowEndMock ).toHaveBeenCalledWith( '<continued_as_new>' );
183
+ expect( workflowEndMock ).toHaveBeenCalledWith( WorkflowSpecialOutput.CONTINUED_AS_NEW );
164
184
  expect( workflowErrorMock ).not.toHaveBeenCalled();
165
185
  } );
166
186
  } );