@aikirun/workflow 0.10.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/dist/index.d.ts +9 -7
- package/dist/index.js +82 -36
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { WorkflowName, WorkflowVersionId } from '@aikirun/types/workflow';
|
|
2
2
|
import { Client, Logger, ApiClient } from '@aikirun/types/client';
|
|
3
3
|
import { INTERNAL } from '@aikirun/types/symbols';
|
|
4
|
-
import { Schema } from '@aikirun/types/validator';
|
|
5
4
|
import { WorkflowRun, TerminalWorkflowRunStatus, WorkflowRunState, WorkflowRunId, WorkflowOptions } from '@aikirun/types/workflow-run';
|
|
5
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
6
6
|
import { DurationObject, Duration } from '@aikirun/types/duration';
|
|
7
7
|
import { SleepResult } from '@aikirun/types/sleep';
|
|
8
8
|
import { EventSendOptions, EventWaitOptions, EventWaitState } from '@aikirun/types/event';
|
|
@@ -138,11 +138,11 @@ type WorkflowRunWaitResult<Status extends TerminalWorkflowRunStatus, Output, Tim
|
|
|
138
138
|
declare function event(): EventDefinition<void>;
|
|
139
139
|
declare function event<Data extends Serializable>(params?: EventParams<Data>): EventDefinition<Data>;
|
|
140
140
|
interface EventParams<Data> {
|
|
141
|
-
schema?:
|
|
141
|
+
schema?: StandardSchemaV1<Data>;
|
|
142
142
|
}
|
|
143
143
|
interface EventDefinition<Data> {
|
|
144
144
|
_type: Data;
|
|
145
|
-
schema?:
|
|
145
|
+
schema?: StandardSchemaV1<Data>;
|
|
146
146
|
}
|
|
147
147
|
type EventsDefinition = Record<string, EventDefinition<unknown>>;
|
|
148
148
|
type EventData<TEventDefinition> = TEventDefinition extends EventDefinition<infer Data> ? Data : never;
|
|
@@ -244,8 +244,8 @@ interface WorkflowVersionParams<Input, Output, AppContext, TEventsDefinition ext
|
|
|
244
244
|
events?: TEventsDefinition;
|
|
245
245
|
opts?: WorkflowOptions;
|
|
246
246
|
schema?: RequireAtLeastOneProp<{
|
|
247
|
-
input?:
|
|
248
|
-
output?:
|
|
247
|
+
input?: StandardSchemaV1<Input>;
|
|
248
|
+
output?: StandardSchemaV1<Output>;
|
|
249
249
|
}>;
|
|
250
250
|
}
|
|
251
251
|
interface WorkflowVersion<Input, Output, AppContext, TEventsDefinition extends EventsDefinition = EventsDefinition> {
|
|
@@ -255,7 +255,8 @@ interface WorkflowVersion<Input, Output, AppContext, TEventsDefinition extends E
|
|
|
255
255
|
with(): WorkflowBuilder<Input, Output, AppContext, TEventsDefinition>;
|
|
256
256
|
start: (client: Client<AppContext>, ...args: Input extends void ? [] : [Input]) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
257
257
|
startAsChild: <ParentInput, ParentEventsDefinition extends EventsDefinition>(parentRun: WorkflowRunContext<ParentInput, AppContext, ParentEventsDefinition>, ...args: Input extends void ? [] : [Input]) => Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
258
|
-
|
|
258
|
+
getHandleById: (client: Client<AppContext>, runId: string) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
259
|
+
getHandleByReferenceId: (client: Client<AppContext>, referenceId: string) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
259
260
|
[INTERNAL]: {
|
|
260
261
|
eventsDefinition: TEventsDefinition;
|
|
261
262
|
handler: (run: WorkflowRunContext<Input, AppContext, TEventsDefinition>, input: Input, context: AppContext) => Promise<void>;
|
|
@@ -277,7 +278,8 @@ declare class WorkflowVersionImpl<Input, Output, AppContext, TEventsDefinition e
|
|
|
277
278
|
start(client: Client<AppContext>, ...args: Input extends void ? [] : [Input]): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
278
279
|
startAsChild(parentRun: WorkflowRunContext<unknown, AppContext, EventsDefinition>, ...args: Input extends void ? [] : [Input]): Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
279
280
|
private assertUniqueChildRunReferenceId;
|
|
280
|
-
|
|
281
|
+
getHandleById(client: Client<AppContext>, runId: string): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
282
|
+
getHandleByReferenceId(client: Client<AppContext>, referenceId: string): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
281
283
|
private handler;
|
|
282
284
|
private tryExecuteWorkflow;
|
|
283
285
|
private assertRetryAllowed;
|
package/dist/index.js
CHANGED
|
@@ -289,6 +289,7 @@ function getRetryParams(attempts, strategy) {
|
|
|
289
289
|
|
|
290
290
|
// run/event.ts
|
|
291
291
|
import { INTERNAL } from "@aikirun/types/symbols";
|
|
292
|
+
import { SchemaValidationError } from "@aikirun/types/validator";
|
|
292
293
|
import {
|
|
293
294
|
WorkflowRunConflictError,
|
|
294
295
|
WorkflowRunFailedError,
|
|
@@ -325,17 +326,24 @@ function createEventWaiter(handle, eventName, schema, logger) {
|
|
|
325
326
|
logger.debug("Timed out waiting for event");
|
|
326
327
|
return { timeout: true };
|
|
327
328
|
}
|
|
328
|
-
let data;
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
329
|
+
let data = event2.data;
|
|
330
|
+
if (schema) {
|
|
331
|
+
const schemaValidation = schema["~standard"].validate(event2.data);
|
|
332
|
+
const schemaValidationResult = schemaValidation instanceof Promise ? await schemaValidation : schemaValidation;
|
|
333
|
+
if (!schemaValidationResult.issues) {
|
|
334
|
+
data = schemaValidationResult.value;
|
|
335
|
+
} else {
|
|
336
|
+
logger.error("Invalid event data", { "aiki.issues": schemaValidationResult.issues });
|
|
337
|
+
await handle[INTERNAL].transitionState({
|
|
338
|
+
status: "failed",
|
|
339
|
+
cause: "self",
|
|
340
|
+
error: {
|
|
341
|
+
name: "SchemaValidationError",
|
|
342
|
+
message: JSON.stringify(schemaValidationResult.issues)
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
throw new WorkflowRunFailedError(handle.run.id, handle.run.attempts);
|
|
346
|
+
}
|
|
339
347
|
}
|
|
340
348
|
logger.debug("Event received");
|
|
341
349
|
return { timeout: false, data };
|
|
@@ -382,9 +390,16 @@ function createEventSender(api, workflowRunId, eventName, schema, logger, onSend
|
|
|
382
390
|
send: (...args) => createEventSender(api, workflowRunId, eventName, schema, logger, onSend, optsBuilder.build()).send(...args)
|
|
383
391
|
});
|
|
384
392
|
async function send(...args) {
|
|
385
|
-
const
|
|
393
|
+
const dataRaw = isNonEmptyArray(args) ? args[0] : void 0;
|
|
394
|
+
let data = dataRaw;
|
|
386
395
|
if (schema) {
|
|
387
|
-
schema.
|
|
396
|
+
const schemaValidation = schema["~standard"].validate(dataRaw);
|
|
397
|
+
const schemaValidationResult = schemaValidation instanceof Promise ? await schemaValidation : schemaValidation;
|
|
398
|
+
if (schemaValidationResult.issues) {
|
|
399
|
+
logger.error("Invalid event data", { "aiki.issues": schemaValidationResult.issues });
|
|
400
|
+
throw new SchemaValidationError("Invalid event data", schemaValidationResult.issues);
|
|
401
|
+
}
|
|
402
|
+
data = schemaValidationResult.value;
|
|
388
403
|
}
|
|
389
404
|
const { run } = await api.workflowRun.sendEventV1({
|
|
390
405
|
id: workflowRunId,
|
|
@@ -426,26 +441,33 @@ function createEventMulticaster(workflowName, workflowVersionId, eventName, sche
|
|
|
426
441
|
)
|
|
427
442
|
});
|
|
428
443
|
async function send(client, runId, ...args) {
|
|
429
|
-
const
|
|
444
|
+
const dataRaw = isNonEmptyArray(args) ? args[0] : void 0;
|
|
445
|
+
let data = dataRaw;
|
|
430
446
|
if (schema) {
|
|
431
|
-
schema.
|
|
447
|
+
const schemaValidation = schema["~standard"].validate(dataRaw);
|
|
448
|
+
const schemaValidationResult = schemaValidation instanceof Promise ? await schemaValidation : schemaValidation;
|
|
449
|
+
if (schemaValidationResult.issues) {
|
|
450
|
+
client.logger.error("Invalid event data", {
|
|
451
|
+
"aiki.workflowName": workflowName,
|
|
452
|
+
"aiki.workflowVersionId": workflowVersionId,
|
|
453
|
+
"aiki.eventName": eventName,
|
|
454
|
+
"aiki.issues": schemaValidationResult.issues
|
|
455
|
+
});
|
|
456
|
+
throw new SchemaValidationError("Invalid event data", schemaValidationResult.issues);
|
|
457
|
+
}
|
|
458
|
+
data = schemaValidationResult.value;
|
|
432
459
|
}
|
|
433
460
|
const runIds = Array.isArray(runId) ? runId : [runId];
|
|
434
461
|
if (!isNonEmptyArray(runIds)) {
|
|
435
462
|
return;
|
|
436
463
|
}
|
|
437
|
-
const logger = client.logger.child({
|
|
438
|
-
"aiki.workflowName": workflowName,
|
|
439
|
-
"aiki.workflowVersionId": workflowVersionId,
|
|
440
|
-
"aiki.eventName": eventName
|
|
441
|
-
});
|
|
442
464
|
await client.api.workflowRun.multicastEventV1({
|
|
443
465
|
ids: runIds,
|
|
444
466
|
eventName,
|
|
445
467
|
data,
|
|
446
468
|
options
|
|
447
469
|
});
|
|
448
|
-
logger.info("Multicasted event to workflows", {
|
|
470
|
+
client.logger.info("Multicasted event to workflows", {
|
|
449
471
|
"aiki.workflowName": workflowName,
|
|
450
472
|
"aiki.workflowVersionId": workflowVersionId,
|
|
451
473
|
"aiki.workflowRunIds": runIds,
|
|
@@ -721,6 +743,7 @@ function getWorkflowRunPath(name, versionId, referenceId) {
|
|
|
721
743
|
// workflow-version.ts
|
|
722
744
|
import { INTERNAL as INTERNAL5 } from "@aikirun/types/symbols";
|
|
723
745
|
import { TaskFailedError } from "@aikirun/types/task";
|
|
746
|
+
import { SchemaValidationError as SchemaValidationError2 } from "@aikirun/types/validator";
|
|
724
747
|
import {
|
|
725
748
|
WorkflowRunConflictError as WorkflowRunConflictError5,
|
|
726
749
|
WorkflowRunFailedError as WorkflowRunFailedError2,
|
|
@@ -854,7 +877,17 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
854
877
|
}
|
|
855
878
|
async start(client, ...args) {
|
|
856
879
|
const inputRaw = isNonEmptyArray(args) ? args[0] : void 0;
|
|
857
|
-
|
|
880
|
+
let input = inputRaw;
|
|
881
|
+
const schema = this.params.schema?.input;
|
|
882
|
+
if (schema) {
|
|
883
|
+
const schemaValidation = schema["~standard"].validate(inputRaw);
|
|
884
|
+
const schemaValidationResult = schemaValidation instanceof Promise ? await schemaValidation : schemaValidation;
|
|
885
|
+
if (schemaValidationResult.issues) {
|
|
886
|
+
client.logger.error("Invalid workflow data", { "aiki.issues": schemaValidationResult.issues });
|
|
887
|
+
throw new SchemaValidationError2("Invalid workflow data", schemaValidationResult.issues);
|
|
888
|
+
}
|
|
889
|
+
input = schemaValidationResult.value;
|
|
890
|
+
}
|
|
858
891
|
const { run } = await client.api.workflowRun.createV1({
|
|
859
892
|
name: this.name,
|
|
860
893
|
versionId: this.versionId,
|
|
@@ -873,7 +906,7 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
873
906
|
parentRunHandle[INTERNAL5].assertExecutionAllowed();
|
|
874
907
|
const { client } = parentRunHandle[INTERNAL5];
|
|
875
908
|
const inputRaw = isNonEmptyArray(args) ? args[0] : void 0;
|
|
876
|
-
const input = await this.parse(parentRunHandle, this.params.schema?.input, inputRaw);
|
|
909
|
+
const input = await this.parse(parentRunHandle, this.params.schema?.input, inputRaw, parentRun.logger);
|
|
877
910
|
const inputHash = await hashInput(input);
|
|
878
911
|
const reference = this.params.opts?.reference;
|
|
879
912
|
const path = getWorkflowRunPath(this.name, this.versionId, reference?.id ?? inputHash);
|
|
@@ -888,7 +921,7 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
888
921
|
);
|
|
889
922
|
const { run: existingRun } = await client.api.workflowRun.getByIdV1({ id: existingRunInfo.id });
|
|
890
923
|
if (existingRun.state.status === "completed") {
|
|
891
|
-
await this.parse(parentRunHandle, this.params.schema?.output, existingRun.state.output);
|
|
924
|
+
await this.parse(parentRunHandle, this.params.schema?.output, existingRun.state.output, parentRun.logger);
|
|
892
925
|
}
|
|
893
926
|
const logger2 = parentRun.logger.child({
|
|
894
927
|
"aiki.childWorkflowName": existingRun.name,
|
|
@@ -952,9 +985,17 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
952
985
|
throw error;
|
|
953
986
|
}
|
|
954
987
|
}
|
|
955
|
-
async
|
|
988
|
+
async getHandleById(client, runId) {
|
|
956
989
|
return workflowRunHandle(client, runId, this[INTERNAL5].eventsDefinition);
|
|
957
990
|
}
|
|
991
|
+
async getHandleByReferenceId(client, referenceId) {
|
|
992
|
+
const { run } = await client.api.workflowRun.getByReferenceIdV1({
|
|
993
|
+
name: this.name,
|
|
994
|
+
versionId: this.versionId,
|
|
995
|
+
referenceId
|
|
996
|
+
});
|
|
997
|
+
return workflowRunHandle(client, run, this[INTERNAL5].eventsDefinition);
|
|
998
|
+
}
|
|
958
999
|
async handler(run, input, context) {
|
|
959
1000
|
const { logger } = run;
|
|
960
1001
|
const { handle } = run[INTERNAL5];
|
|
@@ -975,7 +1016,7 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
975
1016
|
while (true) {
|
|
976
1017
|
try {
|
|
977
1018
|
const outputRaw = await this.params.handler(run, input, context);
|
|
978
|
-
const output = await this.parse(handle, this.params.schema?.output, outputRaw);
|
|
1019
|
+
const output = await this.parse(handle, this.params.schema?.output, outputRaw, run.logger);
|
|
979
1020
|
return output;
|
|
980
1021
|
} catch (error) {
|
|
981
1022
|
if (error instanceof WorkflowRunSuspendedError4 || error instanceof WorkflowRunFailedError2 || error instanceof WorkflowRunConflictError5) {
|
|
@@ -1024,20 +1065,25 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
1024
1065
|
throw error;
|
|
1025
1066
|
}
|
|
1026
1067
|
}
|
|
1027
|
-
async parse(handle, schema, data) {
|
|
1068
|
+
async parse(handle, schema, data, logger) {
|
|
1028
1069
|
if (!schema) {
|
|
1029
1070
|
return data;
|
|
1030
1071
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
status: "failed",
|
|
1036
|
-
cause: "self",
|
|
1037
|
-
error: createSerializableError(error)
|
|
1038
|
-
});
|
|
1039
|
-
throw new WorkflowRunFailedError2(handle.run.id, handle.run.attempts);
|
|
1072
|
+
const schemaValidation = schema["~standard"].validate(data);
|
|
1073
|
+
const schemaValidationResult = schemaValidation instanceof Promise ? await schemaValidation : schemaValidation;
|
|
1074
|
+
if (!schemaValidationResult.issues) {
|
|
1075
|
+
return schemaValidationResult.value;
|
|
1040
1076
|
}
|
|
1077
|
+
logger.error("Invalid workflow data", { "aiki.issues": schemaValidationResult.issues });
|
|
1078
|
+
await handle[INTERNAL5].transitionState({
|
|
1079
|
+
status: "failed",
|
|
1080
|
+
cause: "self",
|
|
1081
|
+
error: {
|
|
1082
|
+
name: "SchemaValidationError",
|
|
1083
|
+
message: JSON.stringify(schemaValidationResult.issues)
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
throw new WorkflowRunFailedError2(handle.run.id, handle.run.attempts);
|
|
1041
1087
|
}
|
|
1042
1088
|
createFailedState(error) {
|
|
1043
1089
|
if (error instanceof TaskFailedError) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aikirun/workflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Workflow SDK for Aiki - define durable workflows with tasks, sleeps, waits, and event handling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"build": "tsup"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@aikirun/types": "0.
|
|
21
|
+
"@aikirun/types": "0.11.0",
|
|
22
|
+
"@standard-schema/spec": "^1.1.0"
|
|
22
23
|
},
|
|
23
24
|
"publishConfig": {
|
|
24
25
|
"access": "public"
|