@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 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?: Schema<Data>;
141
+ schema?: StandardSchemaV1<Data>;
142
142
  }
143
143
  interface EventDefinition<Data> {
144
144
  _type: Data;
145
- schema?: Schema<Data>;
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?: Schema<Input>;
248
- output?: Schema<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
- getHandle: (client: Client<AppContext>, runId: string) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
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
- getHandle(client: Client<AppContext>, runId: string): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
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
- try {
330
- data = schema ? schema.parse(event2.data) : event2.data;
331
- } catch (error) {
332
- logger.error("Invalid event data", { data: event2.data, error });
333
- await handle[INTERNAL].transitionState({
334
- status: "failed",
335
- cause: "self",
336
- error: createSerializableError(error)
337
- });
338
- throw new WorkflowRunFailedError(handle.run.id, handle.run.attempts);
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 data = isNonEmptyArray(args) ? args[0] : void 0;
393
+ const dataRaw = isNonEmptyArray(args) ? args[0] : void 0;
394
+ let data = dataRaw;
386
395
  if (schema) {
387
- schema.parse(data);
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 data = isNonEmptyArray(args) ? args[0] : void 0;
444
+ const dataRaw = isNonEmptyArray(args) ? args[0] : void 0;
445
+ let data = dataRaw;
430
446
  if (schema) {
431
- schema.parse(data);
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
- const input = this.params.schema?.input ? this.params.schema.input.parse(inputRaw) : inputRaw;
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 getHandle(client, runId) {
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
- try {
1032
- return schema.parse(data);
1033
- } catch (error) {
1034
- await handle[INTERNAL5].transitionState({
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.10.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.10.0"
21
+ "@aikirun/types": "0.11.0",
22
+ "@standard-schema/spec": "^1.1.0"
22
23
  },
23
24
  "publishConfig": {
24
25
  "access": "public"