@outputai/core 0.6.1-next.d3c9b1f.0 → 0.6.1-next.f8d698e.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 +2 -2
- package/src/interface/webhook.js +1 -1
- package/src/interface/webhook.spec.js +9 -3
- package/src/internal_utils/errors.spec.js +43 -0
- package/src/tracing/tools/utils.js +28 -7
- package/src/tracing/tools/utils.spec.js +78 -9
- package/src/worker/index.js +1 -1
- package/src/worker/index.spec.js +1 -1
- package/src/worker/interceptors/activity.js +18 -25
- package/src/worker/interceptors/activity.spec.js +1 -1
- package/src/worker/interceptors/headers.spec.js +73 -0
- package/src/worker/{interceptors.js → interceptors/index.js} +2 -2
- package/src/worker/interceptors/workflow.js +3 -7
- package/src/worker/interceptors/workflow.spec.js +1 -1
- /package/src/worker/{sandboxed_utils.js → interceptors/headers.js} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@outputai/core",
|
|
3
|
-
"version": "0.6.1-next.
|
|
3
|
+
"version": "0.6.1-next.f8d698e.0",
|
|
4
4
|
"description": "The core module of the output framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"winston": "3.19.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
|
-
"zod": "
|
|
55
|
+
"zod": ">=4.3 <5"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"zod": "4.3.6"
|
package/src/interface/webhook.js
CHANGED
|
@@ -10,6 +10,12 @@ vi.mock( './validations/static.js', () => ( {
|
|
|
10
10
|
validateRequestPayload: validateRequestPayloadMock
|
|
11
11
|
} ) );
|
|
12
12
|
|
|
13
|
+
const activityEnvelope = output => ( {
|
|
14
|
+
__output_activity_wrapper_version: 1,
|
|
15
|
+
output,
|
|
16
|
+
aggregations: null
|
|
17
|
+
} );
|
|
18
|
+
|
|
13
19
|
// Minimal, legible mock of @temporalio/workflow APIs used by webhook.js
|
|
14
20
|
const activityFnMock = vi.fn();
|
|
15
21
|
const proxyActivitiesMock = vi.fn( () => ( { ['__internal#sendHttpRequest']: activityFnMock } ) );
|
|
@@ -70,7 +76,7 @@ describe( 'interface/webhook', () => {
|
|
|
70
76
|
headers: { 'content-type': 'application/json' },
|
|
71
77
|
body: { ok: true }
|
|
72
78
|
};
|
|
73
|
-
activityFnMock.mockResolvedValueOnce( fakeSerializedResponse );
|
|
79
|
+
activityFnMock.mockResolvedValueOnce( activityEnvelope( fakeSerializedResponse ) );
|
|
74
80
|
|
|
75
81
|
const args = { url: 'https://example.com/api', method: 'GET' };
|
|
76
82
|
const res = await sendHttpRequest( args );
|
|
@@ -97,14 +103,14 @@ describe( 'interface/webhook', () => {
|
|
|
97
103
|
const { sendPostRequestAndAwaitWebhook } = await import( './webhook.js' );
|
|
98
104
|
|
|
99
105
|
// Make the inner activity resolve (through sendHttpRequest)
|
|
100
|
-
activityFnMock.mockResolvedValueOnce( {
|
|
106
|
+
activityFnMock.mockResolvedValueOnce( activityEnvelope( {
|
|
101
107
|
url: 'https://webhook.site',
|
|
102
108
|
status: 200,
|
|
103
109
|
statusText: 'OK',
|
|
104
110
|
ok: true,
|
|
105
111
|
headers: {},
|
|
106
112
|
body: null
|
|
107
|
-
} );
|
|
113
|
+
} ) );
|
|
108
114
|
|
|
109
115
|
const url = 'https://webhook.site/ingest';
|
|
110
116
|
const promise = sendPostRequestAndAwaitWebhook( { url, payload: { x: 1 }, headers: { a: 'b' } } );
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { extractErrorDetail } from './errors.js';
|
|
3
|
+
|
|
4
|
+
describe( 'extractErrorDetail', () => {
|
|
5
|
+
it( 'returns a matching value from error details', () => {
|
|
6
|
+
const error = new Error( 'failed' );
|
|
7
|
+
error.details = [
|
|
8
|
+
{ requestId: 'req-1' },
|
|
9
|
+
{ workflowId: 'workflow-1' }
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
expect( extractErrorDetail( error, 'workflowId' ) ).toBe( 'workflow-1' );
|
|
13
|
+
} );
|
|
14
|
+
|
|
15
|
+
it( 'walks the cause chain until it finds matching details', () => {
|
|
16
|
+
const root = new Error( 'root' );
|
|
17
|
+
root.details = [ { traceId: 'trace-1' } ];
|
|
18
|
+
const wrapped = new Error( 'wrapped', { cause: root } );
|
|
19
|
+
|
|
20
|
+
expect( extractErrorDetail( wrapped, 'traceId' ) ).toBe( 'trace-1' );
|
|
21
|
+
} );
|
|
22
|
+
|
|
23
|
+
it( 'prefers details from the current error over causes', () => {
|
|
24
|
+
const root = new Error( 'root' );
|
|
25
|
+
root.details = [ { traceId: 'root-trace' } ];
|
|
26
|
+
const wrapped = new Error( 'wrapped', { cause: root } );
|
|
27
|
+
wrapped.details = [ { traceId: 'wrapped-trace' } ];
|
|
28
|
+
|
|
29
|
+
expect( extractErrorDetail( wrapped, 'traceId' ) ).toBe( 'wrapped-trace' );
|
|
30
|
+
} );
|
|
31
|
+
|
|
32
|
+
it( 'returns null when the key is not found', () => {
|
|
33
|
+
const root = new Error( 'root' );
|
|
34
|
+
root.details = [ { traceId: 'trace-1' } ];
|
|
35
|
+
const wrapped = new Error( 'wrapped', { cause: root } );
|
|
36
|
+
|
|
37
|
+
expect( extractErrorDetail( wrapped, 'missing' ) ).toBeNull();
|
|
38
|
+
} );
|
|
39
|
+
|
|
40
|
+
it( 'returns null for empty errors', () => {
|
|
41
|
+
expect( extractErrorDetail( null, 'traceId' ) ).toBeNull();
|
|
42
|
+
} );
|
|
43
|
+
} );
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { inspect } from 'node:util';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @typedef {object} SerializedError
|
|
3
5
|
* @property {string} name - The error constructor name
|
|
@@ -6,16 +8,35 @@
|
|
|
6
8
|
*/
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
|
-
* Serialize an error object.
|
|
11
|
+
* Recursively Serialize an error object. Navigate using "cause" property.
|
|
10
12
|
*
|
|
11
|
-
*
|
|
13
|
+
* Goes up 10 levels deep.
|
|
12
14
|
*
|
|
13
15
|
* @param {Error} error
|
|
14
16
|
* @returns {SerializedError}
|
|
15
17
|
*/
|
|
16
|
-
export const serializeError =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
export const serializeError = ( () => {
|
|
19
|
+
|
|
20
|
+
const serializeValue = v => {
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse( JSON.stringify( v ) );
|
|
23
|
+
} catch {
|
|
24
|
+
return inspect( v, { depth: 5, breakLength: Infinity, colors: false } );
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return ( error, depth = 0 ) => {
|
|
29
|
+
if ( depth > 10 ) {
|
|
30
|
+
return { name: 'Error', message: 'Cause chain too deep' };
|
|
31
|
+
}
|
|
32
|
+
if ( error instanceof Error ) {
|
|
33
|
+
return {
|
|
34
|
+
name: error.constructor.name,
|
|
35
|
+
message: error.message,
|
|
36
|
+
stack: error.stack,
|
|
37
|
+
...( error.cause !== undefined ? { cause: serializeError( error.cause, depth + 1 ) } : {} )
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return serializeValue( error );
|
|
21
41
|
};
|
|
42
|
+
} )();
|
|
@@ -1,14 +1,83 @@
|
|
|
1
|
-
import { describe,
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import { serializeError } from './utils.js';
|
|
3
3
|
|
|
4
|
-
describe( '
|
|
5
|
-
it( '
|
|
6
|
-
const
|
|
7
|
-
const outer = new Error( 'outer', { cause: inner } );
|
|
4
|
+
describe( 'serializeError', () => {
|
|
5
|
+
it( 'serializes basic Error fields', () => {
|
|
6
|
+
const error = new Error( 'boom' );
|
|
8
7
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
expect(
|
|
12
|
-
|
|
8
|
+
const result = serializeError( error );
|
|
9
|
+
|
|
10
|
+
expect( result ).toMatchObject( {
|
|
11
|
+
name: 'Error',
|
|
12
|
+
message: 'boom'
|
|
13
|
+
} );
|
|
14
|
+
expect( typeof result.stack ).toBe( 'string' );
|
|
15
|
+
expect( result ).not.toHaveProperty( 'cause' );
|
|
16
|
+
} );
|
|
17
|
+
|
|
18
|
+
it( 'preserves custom error constructor names', () => {
|
|
19
|
+
class CustomError extends Error {}
|
|
20
|
+
const error = new CustomError( 'custom boom' );
|
|
21
|
+
|
|
22
|
+
expect( serializeError( error ) ).toMatchObject( {
|
|
23
|
+
name: 'CustomError',
|
|
24
|
+
message: 'custom boom'
|
|
25
|
+
} );
|
|
26
|
+
} );
|
|
27
|
+
|
|
28
|
+
it( 'recursively serializes Error causes', () => {
|
|
29
|
+
const root = new TypeError( 'root failure' );
|
|
30
|
+
const wrapped = new Error( 'wrapped failure', { cause: root } );
|
|
31
|
+
|
|
32
|
+
expect( serializeError( wrapped ) ).toMatchObject( {
|
|
33
|
+
name: 'Error',
|
|
34
|
+
message: 'wrapped failure',
|
|
35
|
+
cause: {
|
|
36
|
+
name: 'TypeError',
|
|
37
|
+
message: 'root failure'
|
|
38
|
+
}
|
|
39
|
+
} );
|
|
40
|
+
} );
|
|
41
|
+
|
|
42
|
+
it( 'preserves JSON-serializable non-Error causes', () => {
|
|
43
|
+
const cause = {
|
|
44
|
+
code: 'bad_input',
|
|
45
|
+
path: [ 'items', 0, 'title' ],
|
|
46
|
+
message: 'Expected title'
|
|
47
|
+
};
|
|
48
|
+
const error = new Error( 'validation failed', { cause } );
|
|
49
|
+
|
|
50
|
+
expect( serializeError( error ) ).toMatchObject( {
|
|
51
|
+
name: 'Error',
|
|
52
|
+
message: 'validation failed',
|
|
53
|
+
cause
|
|
54
|
+
} );
|
|
55
|
+
} );
|
|
56
|
+
|
|
57
|
+
it( 'falls back to inspect for non-JSON-serializable causes', () => {
|
|
58
|
+
const cause = { name: 'circular' };
|
|
59
|
+
cause.self = cause;
|
|
60
|
+
const error = new Error( 'failed', { cause } );
|
|
61
|
+
|
|
62
|
+
const result = serializeError( error );
|
|
63
|
+
|
|
64
|
+
expect( result.cause ).toContain( 'circular' );
|
|
65
|
+
expect( result.cause ).toContain( 'Circular' );
|
|
66
|
+
} );
|
|
67
|
+
|
|
68
|
+
it( 'falls back to inspect for primitive values JSON cannot serialize', () => {
|
|
69
|
+
expect( serializeError( 1n ) ).toBe( '1n' );
|
|
70
|
+
} );
|
|
71
|
+
|
|
72
|
+
it( 'stops serializing cause chains after the depth limit', () => {
|
|
73
|
+
const makeErrorChain = depth => depth === 0 ?
|
|
74
|
+
new Error( 'leaf' ) :
|
|
75
|
+
new Error( `level ${depth}`, { cause: makeErrorChain( depth - 1 ) } );
|
|
76
|
+
const getCauseAtDepth = ( error, depth ) => depth === 0 ?
|
|
77
|
+
error :
|
|
78
|
+
getCauseAtDepth( error.cause, depth - 1 );
|
|
79
|
+
|
|
80
|
+
expect( getCauseAtDepth( serializeError( makeErrorChain( 11 ) ), 11 ) )
|
|
81
|
+
.toEqual( { name: 'Error', message: 'Cause chain too deep' } );
|
|
13
82
|
} );
|
|
14
83
|
} );
|
package/src/worker/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { sinks } from './sinks.js';
|
|
|
5
5
|
import { createCatalog } from './catalog_workflow/index.js';
|
|
6
6
|
import { init as initTracing } from '#tracing';
|
|
7
7
|
import { webpackConfigHook } from './bundler_options.js';
|
|
8
|
-
import { initInterceptors } from './interceptors.js';
|
|
8
|
+
import { initInterceptors } from './interceptors/index.js';
|
|
9
9
|
import { createChildLogger } from '#logger';
|
|
10
10
|
import { registerShutdown } from './shutdown.js';
|
|
11
11
|
import { startCatalog } from './start_catalog.js';
|
package/src/worker/index.spec.js
CHANGED
|
@@ -51,7 +51,7 @@ vi.mock( './catalog_workflow/index.js', () => ( { createCatalog: createCatalogMo
|
|
|
51
51
|
vi.mock( './bundler_options.js', () => ( { webpackConfigHook: vi.fn() } ) );
|
|
52
52
|
|
|
53
53
|
const initInterceptorsMock = vi.fn().mockReturnValue( [] );
|
|
54
|
-
vi.mock( './interceptors.js', () => ( { initInterceptors: initInterceptorsMock } ) );
|
|
54
|
+
vi.mock( './interceptors/index.js', () => ( { initInterceptors: initInterceptorsMock } ) );
|
|
55
55
|
|
|
56
56
|
const startCatalogMock = vi.fn().mockResolvedValue( undefined );
|
|
57
57
|
vi.mock( './start_catalog.js', () => ( { startCatalog: startCatalogMock } ) );
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Context, activityInfo as activityInfoFn } from '@temporalio/activity';
|
|
2
2
|
import { Storage } from '#async_storage';
|
|
3
3
|
import * as Tracing from '#tracing';
|
|
4
|
-
import { headersToObject } from '
|
|
4
|
+
import { headersToObject } from './headers.js';
|
|
5
5
|
import { ACTIVITY_WRAPPER_VERSION_FIELD, BusEventType, METADATA_ACCESS_SYMBOL, Signal } from '#consts';
|
|
6
6
|
import { activityHeartbeatEnabled, activityHeartbeatIntervalMs, namespace } from '../configs.js';
|
|
7
7
|
import { messageBus } from '#bus';
|
|
@@ -29,37 +29,30 @@ const log = createChildLogger( 'ActivityInterceptor' );
|
|
|
29
29
|
*/
|
|
30
30
|
export class ActivityExecutionInterceptor {
|
|
31
31
|
constructor( { activities, workflows, connection } ) {
|
|
32
|
-
|
|
33
|
-
this.
|
|
34
|
-
map
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
// convert activities{} object to a map: activityType:kind
|
|
33
|
+
this.activityKindMap = new Map( Object.entries( activities )
|
|
34
|
+
.map( ( [ type, fn ] ) => ( [ type, fn[METADATA_ACCESS_SYMBOL].type ] ) ) );
|
|
35
|
+
|
|
36
|
+
// convert workflows[] array to a map: workflowType/alias.n:path
|
|
37
|
+
this.workflowsPathMap = new Map( workflows.flatMap( ( { name, aliases, path } ) =>
|
|
38
|
+
[ name, ...aliases ?? [] ].map( a => ( [ a, path ] ) )
|
|
39
|
+
) );
|
|
40
40
|
this.connection = connection;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
/**
|
|
44
|
-
* Returns a workflow entry by its name or throws error
|
|
45
|
-
* @param {string} workflowType
|
|
46
|
-
* @returns {object} Workflow entry
|
|
47
|
-
* @throws {Error}
|
|
48
|
-
*/
|
|
49
|
-
getWorkflowEntry( workflowType ) {
|
|
50
|
-
const workflowEntry = this.workflowsMap.get( workflowType );
|
|
51
|
-
if ( !workflowEntry ) {
|
|
52
|
-
throw new Error( `Activity interceptor: workflow "${workflowType}" not found in workflowsMap.` );
|
|
53
|
-
}
|
|
54
|
-
return workflowEntry;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
43
|
async execute( input, next ) {
|
|
58
44
|
const activityInfo = activityInfoFn();
|
|
59
45
|
const { workflowExecution: { workflowId, runId }, activityId, activityType, workflowType } = activityInfo;
|
|
60
46
|
const { traceInfo, workflowDetails } = headersToObject( input.headers );
|
|
61
|
-
const
|
|
62
|
-
const
|
|
47
|
+
const outputActivityKind = this.activityKindMap.get( activityType );
|
|
48
|
+
const workflowFilename = this.workflowsPathMap.get( workflowType );
|
|
49
|
+
|
|
50
|
+
if ( !outputActivityKind ) {
|
|
51
|
+
throw new Error( `Activity interceptor: activity "${activityType}" was not registered.` );
|
|
52
|
+
}
|
|
53
|
+
if ( !workflowFilename ) {
|
|
54
|
+
throw new Error( `Activity interceptor: workflow "${workflowType}" was not registered.` );
|
|
55
|
+
}
|
|
63
56
|
|
|
64
57
|
const state = {
|
|
65
58
|
heartbeat: null,
|
|
@@ -73,7 +73,7 @@ vi.mock( '#tracing', () => ( {
|
|
|
73
73
|
addEventError: addEventErrorMock
|
|
74
74
|
} ) );
|
|
75
75
|
|
|
76
|
-
vi.mock( '
|
|
76
|
+
vi.mock( './headers.js', () => ( {
|
|
77
77
|
headersToObject: () => ( { traceInfo: traceInfoMock, workflowDetails: workflowDetailsMock } )
|
|
78
78
|
} ) );
|
|
79
79
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
const toPayloadMock = vi.hoisted( () => vi.fn( value => ( { encoded: value } ) ) );
|
|
4
|
+
const fromPayloadMock = vi.hoisted( () => vi.fn( payload => payload.encoded ) );
|
|
5
|
+
|
|
6
|
+
vi.mock( '@temporalio/common', () => ( {
|
|
7
|
+
defaultPayloadConverter: {
|
|
8
|
+
toPayload: toPayloadMock,
|
|
9
|
+
fromPayload: fromPayloadMock
|
|
10
|
+
}
|
|
11
|
+
} ) );
|
|
12
|
+
|
|
13
|
+
describe( 'headers utils', () => {
|
|
14
|
+
beforeEach( () => {
|
|
15
|
+
vi.clearAllMocks();
|
|
16
|
+
} );
|
|
17
|
+
|
|
18
|
+
describe( 'memoToHeaders', () => {
|
|
19
|
+
it( 'converts memo entries into Temporal payload headers', async () => {
|
|
20
|
+
const { memoToHeaders } = await import( './headers.js' );
|
|
21
|
+
const memo = {
|
|
22
|
+
traceInfo: { runId: 'run-1' },
|
|
23
|
+
workflowDetails: { workflowId: 'workflow-1' }
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const headers = memoToHeaders( memo );
|
|
27
|
+
|
|
28
|
+
expect( headers ).toEqual( {
|
|
29
|
+
traceInfo: { encoded: memo.traceInfo },
|
|
30
|
+
workflowDetails: { encoded: memo.workflowDetails }
|
|
31
|
+
} );
|
|
32
|
+
expect( toPayloadMock ).toHaveBeenCalledTimes( 2 );
|
|
33
|
+
expect( toPayloadMock ).toHaveBeenCalledWith( memo.traceInfo );
|
|
34
|
+
expect( toPayloadMock ).toHaveBeenCalledWith( memo.workflowDetails );
|
|
35
|
+
} );
|
|
36
|
+
|
|
37
|
+
it( 'returns an empty object for nullish memo', async () => {
|
|
38
|
+
const { memoToHeaders } = await import( './headers.js' );
|
|
39
|
+
|
|
40
|
+
expect( memoToHeaders() ).toEqual( {} );
|
|
41
|
+
expect( memoToHeaders( null ) ).toEqual( {} );
|
|
42
|
+
expect( toPayloadMock ).not.toHaveBeenCalled();
|
|
43
|
+
} );
|
|
44
|
+
} );
|
|
45
|
+
|
|
46
|
+
describe( 'headersToObject', () => {
|
|
47
|
+
it( 'converts Temporal payload headers into plain object values', async () => {
|
|
48
|
+
const { headersToObject } = await import( './headers.js' );
|
|
49
|
+
const headers = {
|
|
50
|
+
traceInfo: { encoded: { runId: 'run-1' } },
|
|
51
|
+
workflowDetails: { encoded: { workflowId: 'workflow-1' } }
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const object = headersToObject( headers );
|
|
55
|
+
|
|
56
|
+
expect( object ).toEqual( {
|
|
57
|
+
traceInfo: headers.traceInfo.encoded,
|
|
58
|
+
workflowDetails: headers.workflowDetails.encoded
|
|
59
|
+
} );
|
|
60
|
+
expect( fromPayloadMock ).toHaveBeenCalledTimes( 2 );
|
|
61
|
+
expect( fromPayloadMock ).toHaveBeenCalledWith( headers.traceInfo );
|
|
62
|
+
expect( fromPayloadMock ).toHaveBeenCalledWith( headers.workflowDetails );
|
|
63
|
+
} );
|
|
64
|
+
|
|
65
|
+
it( 'returns an empty object for nullish headers', async () => {
|
|
66
|
+
const { headersToObject } = await import( './headers.js' );
|
|
67
|
+
|
|
68
|
+
expect( headersToObject() ).toEqual( {} );
|
|
69
|
+
expect( headersToObject( null ) ).toEqual( {} );
|
|
70
|
+
expect( fromPayloadMock ).not.toHaveBeenCalled();
|
|
71
|
+
} );
|
|
72
|
+
} );
|
|
73
|
+
} );
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { dirname, join } from 'path';
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
|
-
import { ActivityExecutionInterceptor } from './
|
|
3
|
+
import { ActivityExecutionInterceptor } from './activity.js';
|
|
4
4
|
|
|
5
5
|
const __dirname = dirname( fileURLToPath( import.meta.url ) );
|
|
6
6
|
|
|
7
7
|
export const initInterceptors = ( { activities, workflows, connection } ) => ( {
|
|
8
|
-
workflowModules: [ join( __dirname, './
|
|
8
|
+
workflowModules: [ join( __dirname, './workflow.js' ) ],
|
|
9
9
|
activity: [
|
|
10
10
|
() => ( {
|
|
11
11
|
inbound: new ActivityExecutionInterceptor( { activities, workflows, connection } )
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// THIS RUNS IN THE TEMPORAL'S SANDBOX ENVIRONMENT
|
|
2
2
|
import { workflowInfo, proxySinks, ApplicationFailure, ContinueAsNew, isCancellation } from '@temporalio/workflow';
|
|
3
|
-
import { memoToHeaders } from '
|
|
3
|
+
import { memoToHeaders } from './headers.js';
|
|
4
4
|
import { deepMerge } from '#utils';
|
|
5
5
|
import { METADATA_ACCESS_SYMBOL, WorkflowSpecialOutput } from '#consts';
|
|
6
6
|
// this is a dynamic generated file with activity configs overwrites
|
|
@@ -8,13 +8,9 @@ import stepOptions from '../temp/__activity_options.js';
|
|
|
8
8
|
import { createWorkflowDetails } from '#internal_utils/temporal_context';
|
|
9
9
|
|
|
10
10
|
/*
|
|
11
|
-
This
|
|
12
|
-
|
|
13
|
-
This interceptor adds information value from workflowInfo().memo as Activity invocation headers.
|
|
14
|
-
|
|
11
|
+
This interceptor adds Memo and serialized workflowInfo() to the Activity invocation headers.
|
|
15
12
|
This is a strategy to share values between the workflow context and activity context.
|
|
16
|
-
|
|
17
|
-
We also want to preserve existing headers that might have been inject somewhere else and
|
|
13
|
+
We also want to preserve existing headers that might have been inject somewhere else.
|
|
18
14
|
*/
|
|
19
15
|
class HeadersInjectionInterceptor {
|
|
20
16
|
async scheduleActivity( input, next ) {
|
|
@@ -61,7 +61,7 @@ vi.mock( '@temporalio/workflow', () => ( {
|
|
|
61
61
|
} ) );
|
|
62
62
|
|
|
63
63
|
const memoToHeadersMock = vi.fn( memo => ( memo ? { ...memo, __asHeaders: true } : {} ) );
|
|
64
|
-
vi.mock( '
|
|
64
|
+
vi.mock( './headers.js', () => ( { memoToHeaders: ( ...args ) => memoToHeadersMock( ...args ) } ) );
|
|
65
65
|
|
|
66
66
|
const deepMergeMock = vi.fn( ( a, b ) => ( { ...( a || {} ), ...( b || {} ) } ) );
|
|
67
67
|
vi.mock( '#utils', () => ( { deepMerge: ( ...args ) => deepMergeMock( ...args ) } ) );
|
|
File without changes
|