@output.ai/core 0.0.7 → 0.0.9

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/README.md +85 -59
  2. package/package.json +10 -3
  3. package/src/configs.js +1 -1
  4. package/src/consts.js +4 -3
  5. package/src/errors.js +11 -0
  6. package/src/index.d.ts +302 -30
  7. package/src/index.js +3 -2
  8. package/src/interface/metadata.js +3 -3
  9. package/src/interface/step.js +18 -4
  10. package/src/interface/utils.js +41 -4
  11. package/src/interface/utils.spec.js +71 -0
  12. package/src/interface/validations/ajv_provider.js +3 -0
  13. package/src/interface/validations/runtime.js +69 -0
  14. package/src/interface/validations/runtime.spec.js +50 -0
  15. package/src/interface/validations/static.js +67 -0
  16. package/src/interface/validations/static.spec.js +101 -0
  17. package/src/interface/webhook.js +15 -14
  18. package/src/interface/workflow.js +45 -40
  19. package/src/internal_activities/index.js +16 -5
  20. package/src/worker/catalog_workflow/catalog.js +105 -0
  21. package/src/worker/catalog_workflow/index.js +21 -0
  22. package/src/worker/catalog_workflow/index.spec.js +139 -0
  23. package/src/worker/catalog_workflow/workflow.js +13 -0
  24. package/src/worker/index.js +41 -5
  25. package/src/worker/interceptors/activity.js +3 -2
  26. package/src/worker/internal_utils.js +60 -0
  27. package/src/worker/internal_utils.spec.js +134 -0
  28. package/src/worker/loader.js +30 -44
  29. package/src/worker/loader.spec.js +68 -0
  30. package/src/worker/sinks.js +2 -1
  31. package/src/worker/tracer/index.js +35 -3
  32. package/src/worker/tracer/index.test.js +115 -0
  33. package/src/worker/tracer/tracer_tree.js +29 -5
  34. package/src/worker/tracer/tracer_tree.test.js +116 -0
  35. package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.js +133 -0
  36. package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.spec.js +77 -0
  37. package/src/worker/webpack_loaders/workflow_rewriter/consts.js +3 -0
  38. package/src/worker/webpack_loaders/workflow_rewriter/index.mjs +58 -0
  39. package/src/worker/webpack_loaders/workflow_rewriter/index.spec.js +129 -0
  40. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.js +70 -0
  41. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.spec.js +33 -0
  42. package/src/worker/webpack_loaders/workflow_rewriter/tools.js +245 -0
  43. package/src/worker/webpack_loaders/workflow_rewriter/tools.spec.js +144 -0
  44. package/src/errors.d.ts +0 -3
  45. package/src/worker/temp/__workflows_entrypoint.js +0 -6
package/README.md CHANGED
@@ -1,64 +1,100 @@
1
1
  # Core
2
2
 
3
- Provides tools to run a workflow, which is a well defined logical unit of work.
3
+ Provides tools to develop and run a workflow, which is a well defined logical unit of work.
4
4
 
5
- ## step()
5
+ ## Structure
6
6
 
7
- Defines a step, which is a enclosed unit of work which can import external dependencies.
7
+ Workflows are defined using core functions "workflow" and "step", separate files:
8
8
 
9
- ```ts
10
- import { step } from 'flow-core';
9
+ ```
10
+ workflows
11
+ └ example
12
+ ├ workflow.ts|js <- workflow entry point
13
+ ├ steps.ts|js <- file with each step of this workflow
14
+ └ prompt.prompt <- a prompt file
15
+ └ other-example
11
16
 
12
- export const aSingleStep = step( {
13
- name: 'aSingleStep',
14
- fn: async (): Promise<string> => {
15
- // do stuff
16
- }
17
- } );
18
17
  ```
19
18
 
20
- All step needs a name, and the name will be used in the context of the workflow (see below).
19
+ Think that workflows is the orchestrator and steps are executors. So the workflow only call the steps and the steps call the IO operations, like APIs, DBs, LLMs, etc.
21
20
 
22
- ## workflow()
21
+ ## Workflow code
23
22
 
24
- Defines a logical structure of step invocations. No external dependencies can be imported in the file containing the workflow.
23
+ ### workflow.js
25
24
 
26
- ```ts
27
- import { workflow } from 'flow-core';
28
- import type { WorkflowContext } from 'flow-core';
29
- import type { PromptWorkflowInput, PromptWorkflowOutput } from './types';
25
+ ```js
26
+ import { workflow } from '@output.ai/workflow';
27
+ import { guessByName } from './steps.js';
30
28
 
31
29
  export default workflow( {
32
- name: 'prompt',
33
- description: 'A workflow to demonstrate the prompt feature',
34
- fn: async ( input: PromptWorkflowInput, context: WorkflowContext ): Promise<PromptWorkflowOutput> => {
35
- const result = await context.steps.aSingleStep();
36
-
37
- return { result };
30
+ name: 'guessMyProfession',
31
+ description: 'Guess a person profession by its name',
32
+ inputSchema: {
33
+ type: 'object',
34
+ required: [ 'name' ],
35
+ properties: {
36
+ name: { type: 'string'}
37
+ }
38
+ },
39
+ outputSchema: {
40
+ type: 'object',
41
+ required: [ 'profession' ],
42
+ properties: {
43
+ profession: { type: 'string'}
44
+ }
45
+ },
46
+ fn: async input => {
47
+ const profession = await guessByName( input.name );
48
+ return { profession };
38
49
  }
39
- } );
50
+ })
40
51
  ```
41
52
 
42
- The workflow Context has the following properties:
53
+ ### steps.js
43
54
 
44
- ### .steps.*()
55
+ ```js
56
+ import { api } from './api.js'
45
57
 
46
- Each step defined in the step file is available here as js function with the "name" it was defined there. The input arguments are the input arguments of its `fn` function.
58
+ export const guessByName = step( {
59
+ name: 'guessByName',
60
+ inputSchema: {
61
+ type: 'string'
62
+ },
63
+ outputSchema: {
64
+ type: 'string'
65
+ },
66
+ fn: async name => {
67
+ const res = await api.consumer( name );
68
+ return res.body;
69
+ }
70
+ } )
71
+ ```
47
72
 
48
- ### .tools.webhook()
73
+ ## webhooks
49
74
 
50
- Provides a webhook feature where a POST is made to a given url and the workflow is stopped until another POST is made back to the workflows API:
75
+ workflows can call webhooks that will stop their execution until an answer is given back.
51
76
 
52
77
  ```js
53
- const result = await context.tools.webhook( {
54
- name: 'needFeedback',
55
- description: 'Get a feedback',
56
- url: 'http://xxx.xxx/feedback',
57
- payload: { /* a given payload */ }
58
- } );
78
+ import { workflow, createWebhook } from '@output.ai/workflow';
79
+ import { guessByName } from './steps.js';
80
+
81
+ export default workflow( {
82
+ ...
83
+ fn: async input => {
84
+ ...
85
+
86
+ const result = await createWebhook( {
87
+ url: 'http://xxx.xxx/feedback',
88
+ payload: {
89
+ progressSoFar: 'plenty'
90
+ }
91
+ } );
92
+
93
+ }
94
+ })
59
95
  ```
60
96
 
61
- the url will receive the following payload:
97
+ The url of the example will receive the payload, plus the workflowId:
62
98
 
63
99
  ```js
64
100
  {
@@ -67,38 +103,28 @@ the url will receive the following payload:
67
103
  }
68
104
  ```
69
105
 
70
- To resume the workflow, a POST has to be made to a given url, with a response payload and the workflowId.
106
+ To resume the workflow, a POST has to be made with a response payload and the workflowId.
71
107
 
72
- The host is localhost:3001 if running locally, there is not remote host yet.
108
+ - Production: `https://output-api-production.onrender.com/workflow/feedback`
109
+ - Staging: `https://output-api-staging.onrender.com/workflow/feedback`
110
+ - Local: `http://localhost:3001/workflow/feedback`
73
111
 
74
- The format is:
75
- ```
76
- POST https://locahost:3001/workflow/feedback
112
+ Example:
113
+
114
+ ```bash
115
+ POST http://locahost:3001/workflow/feedback
77
116
  {
78
117
  workflowId,
79
118
  payload: {}
80
119
  }
81
120
  ```
82
121
 
83
- ## Folder structure:
84
-
85
- ```
86
- └ workflows
87
- └ my workflow
88
- ├ index.ts // contains the workflow()
89
- ├ types.ts // contains input, output types, and other misc types
90
- └ steps.ts // contains all steps
91
- ```
122
+ ## Developing
92
123
 
93
- ## Booting
124
+ To develop workflows you need the code, which will be called the worker, the API and the engine (Temporal).
94
125
 
95
- The project with workflows will be a "worker", meaning its workflows can be invoked individually by their names. To do so it has to be started using a npx command.
126
+ After having the API and the engine running, to start the worker just run:
96
127
 
97
- _package.json_
98
128
  ```js
99
- ...
100
- "scripts": {
101
- "start": "npx flow-worker"
102
- },
103
- ...
129
+ `outputai`
104
130
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@output.ai/core",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "The core module of the output framework",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -13,20 +13,27 @@
13
13
  "worker": "node ./src/worker/index.js"
14
14
  },
15
15
  "bin": {
16
- "flow-worker": "./bin/worker.sh"
16
+ "flow-worker": "./bin/worker.sh",
17
+ "outputai": "./bin/worker.sh"
17
18
  },
18
19
  "repository": {
19
20
  "type": "git",
20
21
  "url": "git+https://github.com/growthxai/flow-sdk"
21
22
  },
22
23
  "dependencies": {
24
+ "@babel/generator": "7.26.5",
25
+ "@babel/parser": "7.26.7",
26
+ "@babel/traverse": "7.25.9",
27
+ "@babel/types": "7.26.7",
23
28
  "@temporalio/worker": "1.13.0",
24
29
  "@temporalio/workflow": "1.13.0",
25
- "undici": "7.15.0"
30
+ "ajv": "8.17.1",
31
+ "zod": "4.1.9"
26
32
  },
27
33
  "imports": {
28
34
  "#consts": "./src/consts.js",
29
35
  "#configs": "./src/configs.js",
36
+ "#errors": "./src/errors.js",
30
37
  "#internal_activities": "./src/internal_activities/index.js"
31
38
  }
32
39
  }
package/src/configs.js CHANGED
@@ -5,7 +5,7 @@ export const worker = {
5
5
  maxActivities: 100,
6
6
  maxWorkflows: 100,
7
7
  namespace: process.env.TEMPORAL_NAMESPACE ?? 'default',
8
- taskQueue: process.env.TEMPORAL_TASK_QUEUE ?? 'main'
8
+ taskQueue: process.env.TEMPORAL_TASK_QUEUE
9
9
  };
10
10
 
11
11
  export const api = {
package/src/consts.js CHANGED
@@ -1,3 +1,4 @@
1
- export const nameSymbol = Symbol( '__name' );
2
- export const sendWebhookPostName = '__internal#sendWebhookPost';
3
- export const workflowsIndexFileName = '__workflows_entrypoint.js';
1
+ export const SEND_WEBHOOK_ACTIVITY_NAME = '__internal#sendWebhookPost';
2
+ export const METADATA_ACCESS_SYMBOL = Symbol( '__metadata' );
3
+ export const WORKFLOWS_INDEX_FILENAME = '__workflows_entrypoint.js';
4
+ export const THIS_LIB_NAME = 'core';
package/src/errors.js CHANGED
@@ -1,3 +1,14 @@
1
+ /**
2
+ * These are errors exposed as tools for the user to break their flow
3
+ * They work in both steps and workflows
4
+ */
5
+
6
+ /**
7
+ * Any generic fatal errors
8
+ */
1
9
  export class FatalError extends Error { }
2
10
 
11
+ /**
12
+ * Any validation error
13
+ */
3
14
  export class ValidationError extends Error { }
package/src/index.d.ts CHANGED
@@ -1,38 +1,310 @@
1
- export interface StepDefinition<TInput = unknown, TOutput = unknown> {
1
+ // JSON Schema TypeScript type mapping (subset sufficient for IntelliSense)
2
+ type Simplify<T> = { [K in keyof T]: T[K] };
3
+ type EnumValues = readonly ( string | number | boolean | null )[];
4
+
5
+ type JSONSchema = {
6
+ type?: 'string' | 'number' | 'integer' | 'boolean' | 'null' | 'object' | 'array';
7
+ enum?: EnumValues;
8
+ const?: string | number | boolean | null;
9
+ anyOf?: readonly JSONSchema[];
10
+ oneOf?: readonly JSONSchema[];
11
+ allOf?: readonly JSONSchema[];
12
+ // object
13
+ properties?: { [key: string]: JSONSchema };
14
+ required?: readonly string[];
15
+ additionalProperties?: boolean | JSONSchema;
16
+ // array
17
+ items?: JSONSchema | readonly JSONSchema[];
18
+ // ignore $ref & others for typing purposes
19
+ $ref?: string;
20
+ } & Record<string, unknown>;
21
+
22
+ type UnionToIntersection<U> = ( U extends unknown ? ( k: U ) => void : never ) extends ( k: infer I ) => void ? I : never;
23
+
24
+ type FromEnum<S> = S extends { enum: infer E extends EnumValues } ? E[number] : never;
25
+ type FromConst<S> = S extends { const: infer C } ? C : never;
26
+
27
+ type FromPrimitive<S> =
28
+ S extends { type: 'string' } ? string :
29
+ S extends { type: 'number' | 'integer' } ? number :
30
+ S extends { type: 'boolean' } ? boolean :
31
+ S extends { type: 'null' } ? null :
32
+ never;
33
+
34
+ type ObjectProps<S extends JSONSchema> = S extends { properties: infer P extends Record<string, JSONSchema> }
35
+ ? { [K in keyof P]: FromSchema<P[K]> }
36
+ : Record<never, never>;
37
+
38
+ type ObjectRequiredKeys<S extends JSONSchema> = S extends { required: readonly ( infer R )[] }
39
+ ? Extract<R & string, keyof ObjectProps<S>>
40
+ : never;
41
+
42
+ type ObjectFrom<S extends JSONSchema> = Simplify<
43
+ Pick<ObjectProps<S>, ObjectRequiredKeys<S>> &
44
+ Partial<Omit<ObjectProps<S>, ObjectRequiredKeys<S>>>
45
+ >;
46
+
47
+ type ArrayFrom<S extends JSONSchema> = S extends { items: infer I }
48
+ ? I extends readonly unknown[]
49
+ ? FromSchema<I[number]>[]
50
+ : FromSchema<I>[]
51
+ : unknown[];
52
+
53
+ export type FromSchema<S extends JSONSchema> =
54
+ // combinators first
55
+ S extends { anyOf: infer A extends readonly JSONSchema[] } ? FromSchema<A[number]> :
56
+ S extends { oneOf: infer A extends readonly JSONSchema[] } ? FromSchema<A[number]> :
57
+ S extends { allOf: infer A extends readonly JSONSchema[] } ? UnionToIntersection<FromSchema<A[number]>> :
58
+ // enum/const
59
+ FromEnum<S> extends never ? ( FromConst<S> extends never ? (
60
+ // object (explicit or by presence of properties)
61
+ S extends { type: 'object' } | { properties: Record<string, JSONSchema> } ? ObjectFrom<S> :
62
+ // array
63
+ S extends { type: 'array' } ? ArrayFrom<S> :
64
+ // primitives
65
+ FromPrimitive<S> extends never ? unknown : FromPrimitive<S>
66
+ ) : FromConst<S> ) : FromEnum<S>;
67
+
68
+ export type OutputFrom<O extends JSONSchema> = FromSchema<O>;
69
+
70
+ // Utility to strip readonly from inferred types
71
+ /** Recursively removes readonly modifiers from object and array types. */
72
+ type DeepMutable<T> =
73
+ T extends readonly ( infer U )[] ? DeepMutable<U>[] :
74
+ T extends object ? { -readonly [K in keyof T]: DeepMutable<T[K]> } :
75
+ T;
76
+
77
+ /*
78
+ * There is 4 overrides of the "step" function"
79
+ * - with fn receiving input and returning output;
80
+ * - with fn receiving input and returning void;
81
+ * - with fn receiving void and returning outout;
82
+ * - with fn receiving void and returning void;
83
+ */
84
+
85
+ /**
86
+ * @callback StepFn
87
+ * @param {any} input - The input, defined by the inputSchema
88
+ * @returns {any} The output defined by the outputSchema
89
+ */
90
+
91
+ /**
92
+ * Creates logical unit of work, called "step", which will be invoked from workflows.
93
+ *
94
+ * @param {object} options - Step options
95
+ * @param {string} options.name - Human-readable step name (only letters, numbers and "_")
96
+ * @param {string} [options.description] - Description of the step
97
+ * @param {JSONSchema} options.inputSchema - JSON Schema for the fn input, will infer a TS type
98
+ * @param {JSONSchema} options.outputSchema - JSON Schema for the fn output, will infer a TS type
99
+ * @param {StepFn} options.fn - The function logic
100
+ * @returns {StepFn} The options.fn function
101
+ */
102
+ export async function step<
103
+ const InputSchema extends JSONSchema,
104
+ const OutputSchema extends JSONSchema
105
+ >( options: {
106
+ name: string;
107
+ description?: string;
108
+ inputSchema: InputSchema;
109
+ outputSchema: OutputSchema;
110
+ fn: ( input: DeepMutable<FromSchema<InputSchema>> ) => Promise<DeepMutable<FromSchema<OutputSchema>>>;
111
+ } ): ( input: DeepMutable<FromSchema<InputSchema>> ) => Promise<DeepMutable<FromSchema<OutputSchema>>>;
112
+
113
+ /**
114
+ * @callback InputOnlyStepFn
115
+ * @param {any} input - The input, defined by the inputSchema
116
+ */
117
+
118
+ /**
119
+ * Creates logical unit of work, called "step", which will be invoked from workflows.
120
+ *
121
+ * @param {object} options - Step options
122
+ * @param {string} options.name - Human-readable step name (only letters, numbers and "_")
123
+ * @param {string} [options.description] - Description of the step
124
+ * @param {JSONSchema} options.inputSchema - JSON Schema for the fn input, will infer a TS type
125
+ * @param {InputOnlyStepFn} options.fn - The function logic
126
+ * @returns {InputOnlyStepFn} The options.fn function
127
+ */
128
+ export async function step<
129
+ const InputSchema extends JSONSchema
130
+ >( options: {
131
+ name: string;
132
+ description?: string;
133
+ inputSchema: InputSchema;
134
+ fn: ( input: DeepMutable<FromSchema<InputSchema>> ) => Promise<void>;
135
+ } ): ( input: DeepMutable<FromSchema<InputSchema>> ) => Promise<void>;
136
+
137
+ /**
138
+ * @callback OutputOnlyStepFn
139
+ * @returns {any} The output defined by the outputSchema
140
+ */
141
+
142
+ /**
143
+ * Creates logical unit of work, called "step", which will be invoked from workflows.
144
+ *
145
+ * @param {object} options - Step options
146
+ * @param {string} options.name - Human-readable step name (only letters, numbers and "_")
147
+ * @param {string} [options.description] - Description of the step
148
+ * @param {JSONSchema} options.outputSchema - JSON Schema for the fn output, will infer a TS type
149
+ * @param {OutputOnlyStepFn} options.fn - The function logic
150
+ * @returns {OutputOnlyStepFn} The options.fn function
151
+ */
152
+ export async function step<
153
+ const OutputSchema extends JSONSchema
154
+ >( options: {
2
155
  name: string;
3
156
  description?: string;
4
- fn: ( input: TInput ) => Promise<TOutput>;
5
- }
6
-
7
- export interface WorkflowContext {
8
- steps: {
9
- [stepName: string]: ( input?: unknown ) => Promise<unknown>;
10
- };
11
- workflowId: string | null;
12
- tools: {
13
- webhook: ( options: {
14
- name: string;
15
- description?: string;
16
- url: string;
17
- payload: object;
18
- } ) => Promise<unknown>;
19
- };
20
- }
21
-
22
- export interface WorkflowDefinition<TInput = unknown, TOutput = unknown> {
157
+ outputSchema: OutputSchema;
158
+ fn: () => Promise<DeepMutable<FromSchema<OutputSchema>>>;
159
+ } ): () => Promise<DeepMutable<FromSchema<OutputSchema>>>;
160
+
161
+ /**
162
+ * @callback VoidStepFn
163
+ */
164
+
165
+ /**
166
+ * Creates logical unit of work, called "step", which will be invoked from workflows.
167
+ *
168
+ * @param {object} options - Step options
169
+ * @param {string} options.name - Human-readable step name (only letters, numbers and "_")
170
+ * @param {string} [options.description] - Description of the step
171
+ * @param {VoidStepFn} options.fn - The function logic
172
+ * @returns {VoidStepFn} The options.fn function
173
+ */
174
+ export async function step( options: {
23
175
  name: string;
24
176
  description?: string;
25
- fn: ( input: TInput, context: WorkflowContext ) => Promise<TOutput>;
26
- }
177
+ fn: () => Promise<void>;
178
+ } ): () => Promise<void>;
179
+
180
+ /*
181
+ * There is 4 overrides of the "workflow" function"
182
+ * - with fn receiving input and returning output;
183
+ * - with fn receiving input and returning void;
184
+ * - with fn receiving void and returning outout;
185
+ * - with fn receiving void and returning void;
186
+ */
187
+
188
+ /**
189
+ * @callback WorkflowFn
190
+ * @param {any} input - The input, defined by the inputSchema
191
+ * @returns {any} The output defined by the outputSchema
192
+ */
193
+
194
+ /**
195
+ * Creates a workflow orchestrator which can invoke steps.
196
+ *
197
+ * @param {object} options - Workflow options
198
+ * @param {string} options.name - Unique workflow name
199
+ * @param {string} [options.description] - Description of the workflow
200
+ * @param {JSONSchema} [options.inputSchema] - JSON Schema for workflow input
201
+ * @param {JSONSchema} [options.outputSchema] - JSON Schema for workflow output
202
+ * @param {WorkflowFn} options.fn - Workflow logic
203
+ * @returns {WorkflowFn} Callable workflow function
204
+ */
205
+ export function workflow<
206
+ const InputSchema extends JSONSchema,
207
+ const OutputSchema extends JSONSchema
208
+ >( options : {
209
+ name: string,
210
+ description?: string,
211
+ inputSchema: InputSchema,
212
+ outputSchema: OutputSchema,
213
+ fn: ( input: DeepMutable<FromSchema<InputSchema>> ) => Promise<DeepMutable<FromSchema<OutputSchema>>>
214
+ } ): ( input: DeepMutable<FromSchema<InputSchema>> ) => Promise<DeepMutable<FromSchema<OutputSchema>>>;
215
+
216
+ /**
217
+ * @callback InputOnlyWorkflowFn
218
+ * @param {any} input - The input, defined by the inputSchema
219
+ */
220
+
221
+ /**
222
+ * Creates a workflow orchestrator which can invoke steps.
223
+ *
224
+ * @param {object} options - Workflow options
225
+ * @param {string} options.name - Unique workflow name
226
+ * @param {string} [options.description] - Description of the workflow
227
+ * @param {JSONSchema} [options.inputSchema] - JSON Schema for workflow input
228
+ * @param {InputOnlyWorkflowFn} options.fn - Workflow logic
229
+ * @returns {InputOnlyWorkflowFn} Callable workflow function
230
+ */
231
+ export function workflow<
232
+ const InputSchema extends JSONSchema
233
+ >( options : {
234
+ name: string,
235
+ description?: string,
236
+ inputSchema: InputSchema,
237
+ fn: ( input: DeepMutable<FromSchema<InputSchema>> ) => Promise<void>
238
+ } ): ( input: DeepMutable<FromSchema<InputSchema>> ) => Promise<void>;
239
+
240
+ /**
241
+ * @callback OutputOnlyWorkflowFn
242
+ * @returns {any} The output defined by the outputSchema
243
+ */
244
+
245
+ /**
246
+ * Creates a workflow orchestrator which can invoke steps.
247
+ *
248
+ * @param {object} options - Workflow options
249
+ * @param {string} options.name - Unique workflow name
250
+ * @param {string} [options.description] - Description of the workflow
251
+ * @param {JSONSchema} [options.outputSchema] - JSON Schema for workflow output
252
+ * @param {OutputOnlyWorkflowFn} options.fn - Workflow logic
253
+ * @returns {OutputOnlyWorkflowFn} Callable workflow function
254
+ */
255
+ export function workflow<
256
+ const OutputSchema extends JSONSchema
257
+ >( options : {
258
+ name: string,
259
+ description?: string,
260
+ outputSchema: OutputSchema,
261
+ fn: () => Promise<DeepMutable<FromSchema<OutputSchema>>>
262
+ } ): () => Promise<DeepMutable<FromSchema<OutputSchema>>>;
263
+
264
+ /**
265
+ * @callback VoidWorkflowFn
266
+ * @param {any} input - The input, defined by the inputSchema
267
+ * @returns {any} The output defined by the outputSchema
268
+ */
27
269
 
28
- export function step<TInput = unknown, TOutput = unknown>(
29
- definition: StepDefinition<TInput, TOutput>
30
- ): ( input: TInput ) => Promise<TOutput>;
270
+ /**
271
+ * Creates a workflow orchestrator which can invoke steps.
272
+ *
273
+ * @param {object} options - Workflow options
274
+ * @param {string} options.name - Unique workflow name
275
+ * @param {string} [options.description] - Description of the workflow
276
+ * @param {VoidWorkflowFn} options.fn - Workflow logic
277
+ * @returns {VoidWorkflowFn} Callable workflow function
278
+ */
279
+ export function workflow( options : {
280
+ name: string,
281
+ description?: string,
282
+ fn: () => Promise<void>
283
+ } ): () => Promise<void>;
31
284
 
32
- export function workflow<TInput = unknown, TOutput = unknown>(
33
- definition: WorkflowDefinition<TInput, TOutput>
34
- ): ( input: TInput ) => Promise<TOutput>;
285
+ /**
286
+ * Create a webhook call that pauses the workflow until resumed via signal.
287
+ *
288
+ * Sends a request via an activity; the workflow will await a corresponding
289
+ * resume signal to continue and return the response payload.
290
+ *
291
+ * @param {object} options - Webhook request options
292
+ * @param {string} options.url - Webhook request url (POST)
293
+ * @param {object} [options.payload] - Webhook request payload
294
+ * @returns {Promise<object>} Resolves with the response payload when resumed
295
+ */
296
+ export function createWebhook( options: { url: string; payload?: object } ): Promise<object>;
35
297
 
36
- export function startWorkflow<TOutput = unknown>( name: string, options?: { input?: TInput } ): Promise<TOutput>;
298
+ /**
299
+ * Error indicating a non-recoverable failure.
300
+ *
301
+ * Use for failures that should not be retried by the workflow runtime.
302
+ */
303
+ export class FatalError extends Error {}
37
304
 
38
- export { FatalError, ValidationError } from './errors.js';
305
+ /**
306
+ * Error indicating invalid input or schema validation issues.
307
+ *
308
+ * Use for problems detected during input validation or contract checks.
309
+ */
310
+ export class ValidationError extends Error {}
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { step } from './interface/step.js';
2
- import { startWorkflow, workflow } from './interface/workflow.js';
2
+ import { workflow } from './interface/workflow.js';
3
+ import { createWebhook } from './interface/webhook.js';
3
4
  import { FatalError, ValidationError } from './errors.js';
4
5
 
5
- export { step, startWorkflow, workflow, FatalError, ValidationError };
6
+ export { step, workflow, createWebhook, FatalError, ValidationError };
@@ -1,4 +1,4 @@
1
- import { nameSymbol } from '#consts';
1
+ import { METADATA_ACCESS_SYMBOL } from '#consts';
2
2
 
3
- export const setName = ( target, name ) =>
4
- Object.defineProperty( target, nameSymbol, { value: name, writable: false, enumerable: false, configurable: false } );
3
+ export const setMetadata = ( target, values ) =>
4
+ Object.defineProperty( target, METADATA_ACCESS_SYMBOL, { value: values, writable: false, enumerable: false, configurable: false } );
@@ -1,6 +1,20 @@
1
- import { setName } from './metadata.js';
1
+ import { setMetadata } from './metadata.js';
2
+ import { validateStep } from './validations/static.js';
3
+ import { validateStepInput, validateStepOutput } from './validations/runtime.js';
4
+ import { invokeFnAndValidateOutputPreservingExecutionModel } from './utils.js';
2
5
 
3
- export function step( { name, description: _description, fn } ) {
4
- setName( fn, name );
5
- return fn;
6
+ export function step( { name, description, inputSchema, outputSchema, fn } ) {
7
+ validateStep( { name, description, inputSchema, outputSchema, fn } );
8
+ const wrapper = input => {
9
+ if ( inputSchema ) {
10
+ validateStepInput( name, inputSchema, input );
11
+ }
12
+ if ( !outputSchema ) {
13
+ return fn( input );
14
+ }
15
+ return invokeFnAndValidateOutputPreservingExecutionModel( fn, input, validateStepOutput.bind( null, name, outputSchema ) );
16
+ };
17
+
18
+ setMetadata( wrapper, { name, description, inputSchema, outputSchema } );
19
+ return wrapper;
6
20
  };