@outputai/core 0.10.1-next.fc0a41f.0 → 0.11.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 +12 -7
- package/src/consts.js +5 -2
- package/src/errors.d.ts +12 -2
- package/src/errors.js +17 -3
- package/src/errors.spec.js +19 -0
- package/src/helpers/activity_options.js +21 -0
- package/src/helpers/activity_options.spec.js +55 -0
- package/src/helpers/error_serializer.js +236 -0
- package/src/helpers/error_serializer.spec.js +413 -0
- package/src/helpers/errors.js +55 -13
- package/src/helpers/errors.spec.js +166 -66
- package/src/helpers/fetch.js +1 -38
- package/src/helpers/fetch.spec.js +1 -39
- package/src/helpers/function.js +13 -0
- package/src/helpers/function.spec.js +23 -1
- package/src/helpers/redact.js +51 -0
- package/src/helpers/redact.spec.js +66 -0
- package/src/helpers/string.js +10 -0
- package/src/helpers/string.spec.js +36 -1
- package/src/hooks/index.d.ts +35 -44
- package/src/hooks/index.js +2 -1
- package/src/hooks/index.spec.js +15 -7
- package/src/interface/evaluator.d.ts +10 -9
- package/src/interface/evaluator.js +1 -6
- package/src/interface/evaluator.spec.js +10 -10
- package/src/interface/step.d.ts +16 -15
- package/src/interface/step.js +1 -6
- package/src/interface/step.spec.js +10 -10
- package/src/interface/validations/index.js +33 -53
- package/src/interface/validations/index.spec.js +25 -17
- package/src/interface/webhook.js +1 -2
- package/src/interface/webhook.spec.js +25 -19
- package/src/interface/workflow.d.ts +25 -18
- package/src/interface/workflow.js +24 -52
- package/src/interface/workflow.spec.js +109 -108
- package/src/interface/workflow_activity_options.js +2 -5
- package/src/temporal/client.js +47 -0
- package/src/temporal/client.spec.js +124 -0
- package/src/temporal/index.d.ts +32 -0
- package/src/temporal/index.js +1 -0
- package/src/tracing/trace_engine.js +9 -11
- package/src/tracing/trace_engine.spec.js +67 -28
- package/src/worker/catalog_workflow/catalog_job.js +3 -3
- package/src/worker/catalog_workflow/catalog_job.spec.js +1 -1
- package/src/worker/index.js +10 -1
- package/src/worker/index.spec.js +23 -8
- package/src/worker/interceptors/activity.js +32 -19
- package/src/worker/interceptors/activity.spec.js +71 -166
- package/src/worker/interceptors/workflow.js +53 -11
- package/src/worker/interceptors/workflow.spec.js +176 -49
- package/src/worker/loader/workflows.js +16 -3
- package/src/worker/loader/workflows.spec.js +37 -5
- package/src/worker/log_hooks.js +13 -10
- package/src/worker/log_hooks.spec.js +12 -4
- package/src/worker/sinks.js +3 -1
- package/src/worker/sinks.spec.js +21 -4
- package/src/worker/telemetry.js +2 -1
- package/src/worker/temporal_logger.js +33 -0
- package/src/worker/temporal_logger.spec.js +90 -0
- package/src/helpers/aggregations.js +0 -44
- package/src/helpers/aggregations.spec.js +0 -92
- package/src/tracing/tools/utils.js +0 -42
- package/src/tracing/tools/utils.spec.js +0 -83
|
@@ -53,10 +53,12 @@ describe( 'interface validators', () => {
|
|
|
53
53
|
it( 'validates workflow definitions, input, output, and invocation options', () => {
|
|
54
54
|
expect( () => WorkflowValidator.validateDefinition( workflowArgs ) ).not.toThrow();
|
|
55
55
|
const validator = new WorkflowValidator( workflowArgs );
|
|
56
|
+
const input = { value: 'ok' };
|
|
57
|
+
const output = { result: 'ok' };
|
|
56
58
|
|
|
57
|
-
expect(
|
|
58
|
-
expect(
|
|
59
|
-
expect( () => validator.
|
|
59
|
+
expect( validator.parseInput( input ) ).toEqual( input );
|
|
60
|
+
expect( validator.parseOutput( output ) ).toEqual( output );
|
|
61
|
+
expect( () => validator.parseInvocationOptions( {
|
|
60
62
|
detached: true,
|
|
61
63
|
activityOptions: { retry: { maximumAttempts: 1 } },
|
|
62
64
|
context: { info: { workflowId: 'test-workflow' } }
|
|
@@ -71,10 +73,10 @@ describe( 'interface validators', () => {
|
|
|
71
73
|
|
|
72
74
|
const validator = new WorkflowValidator( workflowArgs );
|
|
73
75
|
|
|
74
|
-
expect( () => validator.
|
|
75
|
-
expect( () => validator.
|
|
76
|
-
expect( () => validator.
|
|
77
|
-
expect( () => validator.
|
|
76
|
+
expect( () => validator.parseInput( { value: 1 } ) ).toThrow( ValidationError );
|
|
77
|
+
expect( () => validator.parseInput( { value: 1 } ) ).toThrow( /Workflow "valid_workflow" input validation failed/ );
|
|
78
|
+
expect( () => validator.parseOutput( { result: 1 } ) ).toThrow( /Workflow "valid_workflow" output validation failed/ );
|
|
79
|
+
expect( () => validator.parseInvocationOptions( {
|
|
78
80
|
options: { activityOptions: { retry: { maximumAttempts: 1 } } }
|
|
79
81
|
} ) ).toThrow( /Workflow "valid_workflow" invocation options validation failed/ );
|
|
80
82
|
} );
|
|
@@ -84,9 +86,11 @@ describe( 'interface validators', () => {
|
|
|
84
86
|
name: 'schema_less_workflow',
|
|
85
87
|
fn
|
|
86
88
|
} );
|
|
89
|
+
const input = { anything: true };
|
|
90
|
+
const output = { anything: true };
|
|
87
91
|
|
|
88
|
-
expect(
|
|
89
|
-
expect(
|
|
92
|
+
expect( validator.parseInput( input ) ).toBe( input );
|
|
93
|
+
expect( validator.parseOutput( output ) ).toBe( output );
|
|
90
94
|
} );
|
|
91
95
|
} );
|
|
92
96
|
|
|
@@ -94,9 +98,11 @@ describe( 'interface validators', () => {
|
|
|
94
98
|
it( 'validates step definitions, input, and output', () => {
|
|
95
99
|
expect( () => StepValidator.validateDefinition( stepArgs ) ).not.toThrow();
|
|
96
100
|
const validator = new StepValidator( stepArgs );
|
|
101
|
+
const input = { value: 'ok' };
|
|
102
|
+
const output = { result: 'ok' };
|
|
97
103
|
|
|
98
|
-
expect(
|
|
99
|
-
expect(
|
|
104
|
+
expect( validator.parseInput( input ) ).toEqual( input );
|
|
105
|
+
expect( validator.parseOutput( output ) ).toEqual( output );
|
|
100
106
|
} );
|
|
101
107
|
|
|
102
108
|
it( 'throws ValidationError with useful prefixes for invalid step data', () => {
|
|
@@ -106,8 +112,8 @@ describe( 'interface validators', () => {
|
|
|
106
112
|
|
|
107
113
|
const validator = new StepValidator( stepArgs );
|
|
108
114
|
|
|
109
|
-
expect( () => validator.
|
|
110
|
-
expect( () => validator.
|
|
115
|
+
expect( () => validator.parseInput( { value: 1 } ) ).toThrow( /Step "valid_step" input validation failed/ );
|
|
116
|
+
expect( () => validator.parseOutput( { result: 1 } ) ).toThrow( /Step "valid_step" output validation failed/ );
|
|
111
117
|
} );
|
|
112
118
|
} );
|
|
113
119
|
|
|
@@ -115,9 +121,11 @@ describe( 'interface validators', () => {
|
|
|
115
121
|
it( 'validates evaluator definitions, input, and EvaluationResult output', () => {
|
|
116
122
|
expect( () => EvaluatorValidator.validateDefinition( evaluatorArgs ) ).not.toThrow();
|
|
117
123
|
const validator = new EvaluatorValidator( evaluatorArgs );
|
|
124
|
+
const input = { value: 'ok' };
|
|
125
|
+
const output = new EvaluationResult( { value: 'pass', confidence: 1 } );
|
|
118
126
|
|
|
119
|
-
expect(
|
|
120
|
-
expect(
|
|
127
|
+
expect( validator.parseInput( input ) ).toEqual( input );
|
|
128
|
+
expect( validator.parseOutput( output ) ).toEqual( output );
|
|
121
129
|
} );
|
|
122
130
|
|
|
123
131
|
it( 'throws ValidationError for output schemas and invalid evaluator output', () => {
|
|
@@ -128,8 +136,8 @@ describe( 'interface validators', () => {
|
|
|
128
136
|
|
|
129
137
|
const validator = new EvaluatorValidator( evaluatorArgs );
|
|
130
138
|
|
|
131
|
-
expect( () => validator.
|
|
132
|
-
expect( () => validator.
|
|
139
|
+
expect( () => validator.parseInput( { value: 1 } ) ).toThrow( /Evaluator "valid_evaluator" input validation failed/ );
|
|
140
|
+
expect( () => validator.parseOutput( { value: 'pass', confidence: 1 } ) ).toThrow(
|
|
133
141
|
/Evaluator "valid_evaluator" output validation failed/
|
|
134
142
|
);
|
|
135
143
|
} );
|
package/src/interface/webhook.js
CHANGED
|
@@ -19,7 +19,7 @@ import { validateRequestPayload } from './validations/index.js';
|
|
|
19
19
|
*/
|
|
20
20
|
export async function sendHttpRequest( { url, method = 'GET', payload = undefined, headers = undefined, responseOptions = {} } ) {
|
|
21
21
|
validateRequestPayload( { method, url, payload, headers, responseOptions } );
|
|
22
|
-
|
|
22
|
+
return proxyActivities( {
|
|
23
23
|
startToCloseTimeout: '3m',
|
|
24
24
|
retry: {
|
|
25
25
|
initialInterval: '15s',
|
|
@@ -27,7 +27,6 @@ export async function sendHttpRequest( { url, method = 'GET', payload = undefine
|
|
|
27
27
|
nonRetryableErrorTypes: [ FatalError.name ]
|
|
28
28
|
}
|
|
29
29
|
} )[ACTIVITY_SEND_HTTP_REQUEST]( { method, url, payload, headers, responseOptions } );
|
|
30
|
-
return res.output;
|
|
31
30
|
};
|
|
32
31
|
|
|
33
32
|
/**
|
|
@@ -1,24 +1,14 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
|
|
3
|
-
// Mocks for module aliases used by webhook.js
|
|
4
|
-
vi.mock( '#consts', () => ( {
|
|
5
|
-
ACTIVITY_SEND_HTTP_REQUEST: '__internal#sendHttpRequest'
|
|
6
|
-
} ) );
|
|
2
|
+
import { ACTIVITY_SEND_HTTP_REQUEST } from '#consts';
|
|
7
3
|
|
|
8
4
|
const validateRequestPayloadMock = vi.fn();
|
|
9
5
|
vi.mock( './validations/index.js', () => ( {
|
|
10
6
|
validateRequestPayload: validateRequestPayloadMock
|
|
11
7
|
} ) );
|
|
12
8
|
|
|
13
|
-
const activityEnvelope = output => ( {
|
|
14
|
-
__output_activity_wrapper_version: 1,
|
|
15
|
-
output,
|
|
16
|
-
aggregations: null
|
|
17
|
-
} );
|
|
18
|
-
|
|
19
9
|
// Minimal, legible mock of @temporalio/workflow APIs used by webhook.js
|
|
20
10
|
const activityFnMock = vi.fn();
|
|
21
|
-
const proxyActivitiesMock = vi.fn( () => ( { [
|
|
11
|
+
const proxyActivitiesMock = vi.fn( () => ( { [ACTIVITY_SEND_HTTP_REQUEST]: activityFnMock } ) );
|
|
22
12
|
|
|
23
13
|
const storedHandlers = new Map();
|
|
24
14
|
const defineSignalMock = name => name;
|
|
@@ -76,7 +66,7 @@ describe( 'interface/webhook', () => {
|
|
|
76
66
|
headers: { 'content-type': 'application/json' },
|
|
77
67
|
body: { ok: true }
|
|
78
68
|
};
|
|
79
|
-
activityFnMock.mockResolvedValueOnce(
|
|
69
|
+
activityFnMock.mockResolvedValueOnce( fakeSerializedResponse );
|
|
80
70
|
|
|
81
71
|
const args = { url: 'https://example.com/api', method: 'GET' };
|
|
82
72
|
const res = await sendHttpRequest( args );
|
|
@@ -112,7 +102,7 @@ describe( 'interface/webhook', () => {
|
|
|
112
102
|
it( 'sendHttpRequest forwards response options', async () => {
|
|
113
103
|
const { sendHttpRequest } = await import( './webhook.js' );
|
|
114
104
|
|
|
115
|
-
activityFnMock.mockResolvedValueOnce(
|
|
105
|
+
activityFnMock.mockResolvedValueOnce( { ok: true } );
|
|
116
106
|
|
|
117
107
|
const args = {
|
|
118
108
|
url: 'https://example.com/api',
|
|
@@ -137,15 +127,14 @@ describe( 'interface/webhook', () => {
|
|
|
137
127
|
it( 'sendPostRequestAndAwaitWebhook posts wrapped payload and resolves on resume signal', async () => {
|
|
138
128
|
const { sendPostRequestAndAwaitWebhook } = await import( './webhook.js' );
|
|
139
129
|
|
|
140
|
-
|
|
141
|
-
activityFnMock.mockResolvedValueOnce( activityEnvelope( {
|
|
130
|
+
activityFnMock.mockResolvedValueOnce( {
|
|
142
131
|
url: 'https://webhook.site',
|
|
143
132
|
status: 200,
|
|
144
133
|
statusText: 'OK',
|
|
145
134
|
ok: true,
|
|
146
135
|
headers: {},
|
|
147
136
|
body: null
|
|
148
|
-
} )
|
|
137
|
+
} );
|
|
149
138
|
|
|
150
139
|
const url = 'https://webhook.site/ingest';
|
|
151
140
|
const promise = sendPostRequestAndAwaitWebhook( { url, payload: { x: 1 }, headers: { a: 'b' } } );
|
|
@@ -158,7 +147,24 @@ describe( 'interface/webhook', () => {
|
|
|
158
147
|
expect( callArgs.headers ).toEqual( { a: 'b' } );
|
|
159
148
|
expect( callArgs.responseOptions ).toEqual( {} );
|
|
160
149
|
|
|
161
|
-
|
|
162
|
-
|
|
150
|
+
await vi.waitFor( () => expect( storedHandlers.has( 'resume' ) ).toBe( true ) );
|
|
151
|
+
|
|
152
|
+
expect( sinks.trace.start ).toHaveBeenCalledWith( {
|
|
153
|
+
id: 'wf-123-https://webhook.site/ingest-uuid-mock',
|
|
154
|
+
name: 'resume',
|
|
155
|
+
kind: 'webhook'
|
|
156
|
+
} );
|
|
157
|
+
|
|
158
|
+
const webhookPayload = { status: 'completed' };
|
|
159
|
+
storedHandlers.get( 'resume' )( webhookPayload );
|
|
160
|
+
|
|
161
|
+
await expect( promise ).resolves.toEqual( webhookPayload );
|
|
162
|
+
expect( sinks.trace.end ).toHaveBeenCalledWith( {
|
|
163
|
+
id: 'wf-123-https://webhook.site/ingest-uuid-mock',
|
|
164
|
+
details: webhookPayload
|
|
165
|
+
} );
|
|
166
|
+
|
|
167
|
+
storedHandlers.get( 'resume' )( { status: 'duplicate' } );
|
|
168
|
+
expect( sinks.trace.end ).toHaveBeenCalledTimes( 1 );
|
|
163
169
|
} );
|
|
164
170
|
} );
|
|
@@ -21,6 +21,8 @@ export type WorkflowContext<
|
|
|
21
21
|
* It acts as a checkpoint when the workflow gets too long or approaches certain scaling limits.
|
|
22
22
|
*
|
|
23
23
|
* It accepts input with the same schema as the parent workflow function (`inputSchema`).
|
|
24
|
+
* The next run parses that input like any other workflow start; pass wire-format values if
|
|
25
|
+
* `inputSchema` transforms are not safe to apply twice.
|
|
24
26
|
*
|
|
25
27
|
* Calling this function must be the last statement in the workflow, accompanied by a `return`:
|
|
26
28
|
*
|
|
@@ -38,7 +40,7 @@ export type WorkflowContext<
|
|
|
38
40
|
* @returns The workflow output type for type-checking; never returns at runtime.
|
|
39
41
|
*/
|
|
40
42
|
continueAsNew: InputSchema extends AnyZodSchema ?
|
|
41
|
-
( input: z.
|
|
43
|
+
( input: z.input<InputSchema> ) => ( OutputSchema extends AnyZodSchema ? z.infer<OutputSchema> : void ) :
|
|
42
44
|
() => ( OutputSchema extends AnyZodSchema ? z.infer<OutputSchema> : void ),
|
|
43
45
|
|
|
44
46
|
/**
|
|
@@ -122,39 +124,44 @@ export type WorkflowOptions = {
|
|
|
122
124
|
/**
|
|
123
125
|
* The handler function of a workflow.
|
|
124
126
|
*
|
|
125
|
-
* @param input -
|
|
127
|
+
* @param input - Parsed workflow input (`z.infer<inputSchema>`).
|
|
126
128
|
* @param context - A context object with tools and information.
|
|
127
129
|
*
|
|
128
|
-
* @returns A value
|
|
130
|
+
* @returns A value accepted by `outputSchema` before parse (`z.input<outputSchema>`).
|
|
129
131
|
*/
|
|
130
132
|
export type WorkflowFunction<
|
|
131
133
|
InputSchema extends AnyZodSchema | undefined = undefined,
|
|
132
134
|
OutputSchema extends AnyZodSchema | undefined = undefined
|
|
133
135
|
> = InputSchema extends AnyZodSchema ?
|
|
134
136
|
( input: z.infer<InputSchema>, context: WorkflowContext<InputSchema, OutputSchema> ) =>
|
|
135
|
-
Promise<OutputSchema extends AnyZodSchema ? z.
|
|
137
|
+
Promise<OutputSchema extends AnyZodSchema ? z.input<OutputSchema> : void> :
|
|
136
138
|
( input: undefined | null, context: WorkflowContext<InputSchema, OutputSchema> ) =>
|
|
137
|
-
Promise<OutputSchema extends AnyZodSchema ? z.
|
|
139
|
+
Promise<OutputSchema extends AnyZodSchema ? z.input<OutputSchema> : void>;
|
|
138
140
|
|
|
139
141
|
/**
|
|
140
142
|
* A wrapper around the user defined `fn` handler function.
|
|
141
143
|
*
|
|
142
|
-
*
|
|
144
|
+
* Callers pass values accepted by `inputSchema` (`z.input`). The wrapper parses input,
|
|
145
|
+
* invokes `fn`, parses output, and returns `z.infer<outputSchema>`.
|
|
143
146
|
*
|
|
144
147
|
* The second argument is a WorkflowInvocationOptions object, allowing workflows configuration overwrite.
|
|
145
148
|
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* @param input - The workflow input; it matches the schema defined by `inputSchema`.
|
|
149
|
+
* @param input - The workflow input before `inputSchema` parse.
|
|
149
150
|
* @param options - Additional options for the invocation.
|
|
150
|
-
* @returns
|
|
151
|
+
* @returns The workflow output after `outputSchema` parse.
|
|
151
152
|
*/
|
|
152
|
-
export type WorkflowFunctionWrapper<
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
153
|
+
export type WorkflowFunctionWrapper<
|
|
154
|
+
InputSchema extends AnyZodSchema | undefined = undefined,
|
|
155
|
+
OutputSchema extends AnyZodSchema | undefined = undefined
|
|
156
|
+
> = InputSchema extends AnyZodSchema ?
|
|
157
|
+
(
|
|
158
|
+
input: z.input<InputSchema>,
|
|
159
|
+
options?: WorkflowInvocationOptions
|
|
160
|
+
) => Promise<OutputSchema extends AnyZodSchema ? z.infer<OutputSchema> : void> :
|
|
161
|
+
(
|
|
162
|
+
input?: undefined | null,
|
|
163
|
+
options?: WorkflowInvocationOptions
|
|
164
|
+
) => Promise<OutputSchema extends AnyZodSchema ? z.infer<OutputSchema> : void>;
|
|
158
165
|
|
|
159
166
|
/**
|
|
160
167
|
* Creates a workflow.
|
|
@@ -270,7 +277,7 @@ export type WorkflowFunctionWrapper<WorkflowFunction extends ( ...args: any ) =>
|
|
|
270
277
|
* @param params.outputSchema - Zod schema for workflow output
|
|
271
278
|
* @param params.fn - A function containing the workflow code
|
|
272
279
|
* @param params.options - Optional workflow options.
|
|
273
|
-
* @returns
|
|
280
|
+
* @returns A wrapper that parses input/output around `fn`
|
|
274
281
|
*/
|
|
275
282
|
export declare function workflow<
|
|
276
283
|
InputSchema extends AnyZodSchema | undefined = undefined,
|
|
@@ -288,4 +295,4 @@ export declare function workflow<
|
|
|
288
295
|
* while maintaining backward compatibility with existing callers.
|
|
289
296
|
*/
|
|
290
297
|
aliases?: string[];
|
|
291
|
-
} ): WorkflowFunctionWrapper<
|
|
298
|
+
} ): WorkflowFunctionWrapper<InputSchema, OutputSchema>;
|
|
@@ -1,26 +1,15 @@
|
|
|
1
1
|
// THIS RUNS IN THE TEMPORAL'S SANDBOX ENVIRONMENT
|
|
2
|
-
import { proxyActivities, inWorkflowContext, executeChild, workflowInfo, uuid4, ParentClosePolicy } from '@temporalio/workflow';
|
|
2
|
+
import { proxyActivities, inWorkflowContext, executeChild, workflowInfo, uuid4, ParentClosePolicy, upsertMemo } from '@temporalio/workflow';
|
|
3
3
|
import { WorkflowValidator } from './validations/index.js';
|
|
4
4
|
import { toUrlSafeBase64 } from '#helpers/string';
|
|
5
5
|
import { WorkflowContext } from '#helpers/workflow_context';
|
|
6
|
-
import { TraceInfo } from '#helpers/trace_info';
|
|
7
6
|
import { deepMerge } from '#helpers/object';
|
|
8
7
|
import { defaultOptions } from './workflow_activity_options.js';
|
|
9
8
|
import { createWorkflow } from '#helpers/component';
|
|
9
|
+
import { enforceActivityOptions } from '#helpers/activity_options';
|
|
10
10
|
import { FatalError } from '#errors';
|
|
11
11
|
import * as C from '#consts';
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
* Execute the workflow without temporal, using the fn handler function.
|
|
15
|
-
* This is important to allow for workflows to have unit tests
|
|
16
|
-
*/
|
|
17
|
-
const executeWithoutTemporal = async ( { input, validator, handler, contextOverrides = {} } ) => {
|
|
18
|
-
validator.validateInput( input );
|
|
19
|
-
const output = await handler( input, deepMerge( WorkflowContext.build(), contextOverrides ) );
|
|
20
|
-
validator.validateOutput( output );
|
|
21
|
-
return output;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
13
|
/**
|
|
25
14
|
* Add a global dispatcher function to be used to invoke activities.
|
|
26
15
|
* This will replace direct activity invocation in the user code by the webpack loader.
|
|
@@ -29,7 +18,7 @@ const executeWithoutTemporal = async ( { input, validator, handler, contextOverr
|
|
|
29
18
|
* so Temporal's reusable VM can delete it when switching workflow scopes.
|
|
30
19
|
*/
|
|
31
20
|
const createGlobalDispatcher = ( { runId, workflowType, activities } ) => {
|
|
32
|
-
const dispatcher = async ( activityType, ...args ) => activities[`${workflowType}#${activityType}`]( ...args )
|
|
21
|
+
const dispatcher = async ( activityType, ...args ) => activities[`${workflowType}#${activityType}`]( ...args );
|
|
33
22
|
dispatcher.runId = runId;
|
|
34
23
|
globalThis[C.INVOKE_ACTIVITY_SYMBOL] = dispatcher;
|
|
35
24
|
};
|
|
@@ -47,19 +36,20 @@ const checkGlobalContextContamination = runId => {
|
|
|
47
36
|
export function workflow( { name, description, inputSchema, outputSchema, fn, options = {}, aliases = [] } ) {
|
|
48
37
|
WorkflowValidator.validateDefinition( { name, description, inputSchema, outputSchema, fn, options, aliases } );
|
|
49
38
|
|
|
50
|
-
// Disable trace can only be defined at the definition level
|
|
51
|
-
const disableTrace = options.disableTrace ?? defaultOptions.disableTrace;
|
|
52
39
|
const validator = new WorkflowValidator( { name, inputSchema, outputSchema } );
|
|
53
40
|
|
|
54
|
-
const handler = async ( input,
|
|
55
|
-
validator.
|
|
41
|
+
const handler = async ( input, rawInvocationOptions = {} ) => {
|
|
42
|
+
const invocationOptions = validator.parseInvocationOptions( rawInvocationOptions );
|
|
56
43
|
|
|
57
44
|
// If called outside Temporal workflow context, just execute the handler function
|
|
58
45
|
if ( !inWorkflowContext() ) {
|
|
59
|
-
return
|
|
46
|
+
return validator.parseOutput(
|
|
47
|
+
await fn( validator.parseInput( input ), deepMerge( WorkflowContext.build(), invocationOptions?.context ) )
|
|
48
|
+
);
|
|
60
49
|
}
|
|
61
50
|
|
|
62
51
|
const { workflowId, runId, memo, root } = workflowInfo();
|
|
52
|
+
const isRoot = !root;
|
|
63
53
|
|
|
64
54
|
checkGlobalContextContamination( runId );
|
|
65
55
|
|
|
@@ -69,48 +59,30 @@ export function workflow( { name, description, inputSchema, outputSchema, fn, op
|
|
|
69
59
|
const parentClosePolicy = ParentClosePolicy[invocationOptions?.detached ? 'ABANDON' : 'TERMINATE'];
|
|
70
60
|
const childWorkflowId = `${workflowId}-${toUrlSafeBase64( uuid4() )}`;
|
|
71
61
|
const args = [ input, { activityOptions: invocationOptions?.activityOptions } ];
|
|
72
|
-
return executeChild( name, { args, workflowId: childWorkflowId, parentClosePolicy, memo } )
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const isRoot = !root; // Check if this is the root most workflow
|
|
76
|
-
|
|
77
|
-
// Trace info is only added in the root and only when trace is not disabled
|
|
78
|
-
if ( isRoot && !disableTrace ) {
|
|
79
|
-
memo.traceInfo = TraceInfo.build();
|
|
62
|
+
return executeChild( name, { args, workflowId: childWorkflowId, parentClosePolicy, memo } );
|
|
80
63
|
}
|
|
81
64
|
|
|
82
|
-
// Resolve the activity options: invocation options > definition options > parent options > default options
|
|
83
|
-
const activityOptions = deepMerge(
|
|
65
|
+
// Resolve the activity options: invocation options > definition options > parent options > default options, then enforce final SDK options
|
|
66
|
+
const activityOptions = enforceActivityOptions( deepMerge(
|
|
84
67
|
defaultOptions.activityOptions, // default
|
|
85
|
-
memo?.
|
|
68
|
+
memo?.activityOptions, // parent options
|
|
86
69
|
options?.activityOptions, // definition options
|
|
87
70
|
invocationOptions.activityOptions // invocation options
|
|
88
|
-
);
|
|
89
|
-
// Resolved activity options are added to memo so child workflow executions can continue the policy chain.
|
|
90
|
-
memo.parentActivityOptions = activityOptions;
|
|
91
|
-
const activities = proxyActivities( activityOptions );
|
|
71
|
+
) );
|
|
92
72
|
|
|
73
|
+
const activities = proxyActivities( activityOptions );
|
|
93
74
|
createGlobalDispatcher( { runId, workflowType: name, activities } );
|
|
94
75
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
76
|
+
upsertMemo( {
|
|
77
|
+
activityOptions, // Resolved activity options are added to memo so child workflow executions can continue the policy chain
|
|
78
|
+
...( isRoot && memo.traceInfo && {
|
|
79
|
+
trace: await activities[C.ACTIVITY_GET_TRACE_DESTINATIONS]( memo.traceInfo )
|
|
80
|
+
} )
|
|
81
|
+
} );
|
|
100
82
|
|
|
101
|
-
|
|
102
|
-
validator.
|
|
103
|
-
|
|
104
|
-
validator.validateOutput( output );
|
|
105
|
-
|
|
106
|
-
return { [C.WORKFLOW_WRAPPER_VERSION_FIELD]: 1, output, ...traceDestinations };
|
|
107
|
-
} catch ( error ) {
|
|
108
|
-
if ( traceDestinations ) {
|
|
109
|
-
// Append the trace destinations so it is carried to interceptor
|
|
110
|
-
error[C.METADATA_ACCESS_SYMBOL] = traceDestinations;
|
|
111
|
-
}
|
|
112
|
-
throw error;
|
|
113
|
-
}
|
|
83
|
+
return validator.parseOutput(
|
|
84
|
+
await fn( validator.parseInput( input ), WorkflowContext.build() )
|
|
85
|
+
);
|
|
114
86
|
};
|
|
115
87
|
|
|
116
88
|
return createWorkflow( { name, description, inputSchema, outputSchema, options, aliases, handler } );
|