@aikirun/workflow 0.14.0 → 0.16.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/README.md CHANGED
@@ -44,6 +44,21 @@ const handle = await onboardingWorkflowV1.start(aikiClient, {
44
44
  const result = await handle.waitForStatus("completed");
45
45
  ```
46
46
 
47
+ ## Scheduling
48
+
49
+ Run workflows on a schedule using cron expressions or intervals:
50
+
51
+ ```typescript
52
+ import { schedule } from "@aikirun/workflow";
53
+
54
+ const dailyReport = schedule({
55
+ type: "cron",
56
+ expression: "0 9 * * *", // Every day at 9 AM
57
+ });
58
+
59
+ await dailyReport.activate(aikiClient, onboardingWorkflowV1, { email: "daily@example.com" });
60
+ ```
61
+
47
62
  ## Features
48
63
 
49
64
  - **Durable Execution** - Workflows survive crashes and restarts
@@ -53,6 +68,7 @@ const result = await handle.waitForStatus("completed");
53
68
  - **Child Workflows** - Compose workflows together
54
69
  - **Automatic Retries** - Configurable retry strategies
55
70
  - **Versioning** - Run multiple versions simultaneously
71
+ - **Scheduling** - Trigger workflows on cron or interval schedules
56
72
 
57
73
  ## Documentation
58
74
 
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
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 { WorkflowRun, TerminalWorkflowRunStatus, WorkflowRunState, WorkflowRunId, WorkflowOptions } from '@aikirun/types/workflow-run';
4
+ import { WorkflowRun, TerminalWorkflowRunStatus, WorkflowRunState, WorkflowRunId, WorkflowStartOptions, WorkflowDefinitionOptions } from '@aikirun/types/workflow-run';
5
5
  import { StandardSchemaV1 } from '@standard-schema/spec';
6
6
  import { DurationObject, Duration } from '@aikirun/types/duration';
7
7
  import { SleepResult } from '@aikirun/types/sleep';
@@ -10,6 +10,7 @@ import { Serializable } from '@aikirun/types/serializable';
10
10
  import { DistributiveOmit, RequireAtLeastOneProp } from '@aikirun/types/utils';
11
11
  import { TaskId } from '@aikirun/types/task';
12
12
  import { WorkflowRunStateRequest, WorkflowRunTransitionTaskStateRequestV1 } from '@aikirun/types/workflow-run-api';
13
+ import { OverlapPolicy, ScheduleActivateOptions, ScheduleId } from '@aikirun/types/schedule';
13
14
 
14
15
  type NonEmptyArray<T> = [T, ...T[]];
15
16
 
@@ -30,11 +31,11 @@ type PathFromObjectInternal<T, IncludeArrayKeys extends boolean> = And<[
30
31
  type ExtractObjectType<T> = T extends object ? T : never;
31
32
  type TypeOfValueAtPath<T extends object, Path extends PathFromObject<T>> = Path extends keyof T ? T[Path] : Path extends `${infer First}.${infer Rest}` ? First extends keyof T ? undefined extends T[First] ? Rest extends PathFromObject<ExtractObjectType<T[First]>> ? TypeOfValueAtPath<ExtractObjectType<T[First]>, Rest> | undefined : never : Rest extends PathFromObject<ExtractObjectType<T[First]>> ? TypeOfValueAtPath<ExtractObjectType<T[First]>, Rest> : never : never : never;
32
33
 
33
- declare function workflowRunHandle<Input, Output, AppContext, TEventsDefinition extends EventsDefinition>(client: Client<AppContext>, id: WorkflowRunId, eventsDefinition?: TEventsDefinition, logger?: Logger): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
34
- declare function workflowRunHandle<Input, Output, AppContext, TEventsDefinition extends EventsDefinition>(client: Client<AppContext>, run: WorkflowRun<Input, Output>, eventsDefinition?: TEventsDefinition, logger?: Logger): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
35
- interface WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition extends EventsDefinition = EventsDefinition> {
34
+ declare function workflowRunHandle<Input, Output, AppContext, TEvents extends EventsDefinition>(client: Client<AppContext>, id: WorkflowRunId, eventsDefinition?: TEvents, logger?: Logger): Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
35
+ declare function workflowRunHandle<Input, Output, AppContext, TEvents extends EventsDefinition>(client: Client<AppContext>, run: WorkflowRun<Input, Output>, eventsDefinition?: TEvents, logger?: Logger): Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
36
+ interface WorkflowRunHandle<Input, Output, AppContext, TEvents extends EventsDefinition = EventsDefinition> {
36
37
  run: Readonly<WorkflowRun<Input, Output>>;
37
- events: EventSenders<TEventsDefinition>;
38
+ events: EventSenders<TEvents>;
38
39
  refresh: () => Promise<void>;
39
40
  /**
40
41
  * Waits for the child workflow run to reach a terminal status by polling.
@@ -145,16 +146,16 @@ interface EventDefinition<Data> {
145
146
  schema?: StandardSchemaV1<Data>;
146
147
  }
147
148
  type EventsDefinition = Record<string, EventDefinition<unknown>>;
148
- type EventData<TEventDefinition> = TEventDefinition extends EventDefinition<infer Data> ? Data : never;
149
- type EventWaiters<TEventsDefinition extends EventsDefinition> = {
150
- [K in keyof TEventsDefinition]: EventWaiter<EventData<TEventsDefinition[K]>>;
149
+ type EventData<TEvent> = TEvent extends EventDefinition<infer Data> ? Data : never;
150
+ type EventWaiters<TEvents extends EventsDefinition> = {
151
+ [K in keyof TEvents]: EventWaiter<EventData<TEvents[K]>>;
151
152
  };
152
153
  interface EventWaiter<Data> {
153
154
  wait(options?: EventWaitOptions<false>): Promise<EventWaitState<Data, false>>;
154
155
  wait(options: EventWaitOptions<true>): Promise<EventWaitState<Data, true>>;
155
156
  }
156
- type EventSenders<TEventsDefinition extends EventsDefinition> = {
157
- [K in keyof TEventsDefinition]: EventSender<EventData<TEventsDefinition[K]>>;
157
+ type EventSenders<TEvents extends EventsDefinition> = {
158
+ [K in keyof TEvents]: EventSender<EventData<TEvents[K]>>;
158
159
  };
159
160
  interface EventSender<Data> {
160
161
  with(): EventSenderBuilder<Data>;
@@ -164,8 +165,8 @@ interface EventSenderBuilder<Data> {
164
165
  opt<Path extends PathFromObject<EventSendOptions>>(path: Path, value: TypeOfValueAtPath<EventSendOptions, Path>): EventSenderBuilder<Data>;
165
166
  send: (...args: Data extends void ? [] : [Data]) => Promise<void>;
166
167
  }
167
- type EventMulticasters<TEventsDefinition extends EventsDefinition> = {
168
- [K in keyof TEventsDefinition]: EventMulticaster<EventData<TEventsDefinition[K]>>;
168
+ type EventMulticasters<TEvents extends EventsDefinition> = {
169
+ [K in keyof TEvents]: EventMulticaster<EventData<TEvents[K]>>;
169
170
  };
170
171
  interface EventMulticaster<Data> {
171
172
  with(): EventMulticasterBuilder<Data>;
@@ -175,26 +176,26 @@ interface EventMulticasterBuilder<Data> {
175
176
  opt<Path extends PathFromObject<EventSendOptions>>(path: Path, value: TypeOfValueAtPath<EventSendOptions, Path>): EventMulticasterBuilder<Data>;
176
177
  send: <AppContext>(client: Client<AppContext>, runId: string | string[], ...args: Data extends void ? [] : [Data]) => Promise<void>;
177
178
  }
178
- declare function createEventWaiters<TEventsDefinition extends EventsDefinition>(handle: WorkflowRunHandle<unknown, unknown, unknown, TEventsDefinition>, eventsDefinition: TEventsDefinition, logger: Logger): EventWaiters<TEventsDefinition>;
179
- declare function createEventSenders<TEventsDefinition extends EventsDefinition>(api: ApiClient, workflowRunId: string, eventsDefinition: TEventsDefinition, logger: Logger, onSend: (run: WorkflowRun<unknown, unknown>) => void): EventSenders<TEventsDefinition>;
179
+ declare function createEventWaiters<TEvents extends EventsDefinition>(handle: WorkflowRunHandle<unknown, unknown, unknown, TEvents>, eventsDefinition: TEvents, logger: Logger): EventWaiters<TEvents>;
180
+ declare function createEventSenders<TEvents extends EventsDefinition>(api: ApiClient, workflowRunId: string, eventsDefinition: TEvents, logger: Logger, onSend: (run: WorkflowRun<unknown, unknown>) => void): EventSenders<TEvents>;
180
181
 
181
- interface WorkflowRunContext<Input, AppContext, TEventDefinition extends EventsDefinition> {
182
+ interface WorkflowRunContext<Input, AppContext, TEvents extends EventsDefinition> {
182
183
  id: WorkflowRunId;
183
184
  name: WorkflowName;
184
185
  versionId: WorkflowVersionId;
185
- options: WorkflowOptions;
186
+ options: WorkflowStartOptions;
186
187
  logger: Logger;
187
188
  sleep: (name: string, duration: Duration) => Promise<SleepResult>;
188
- events: EventWaiters<TEventDefinition>;
189
+ events: EventWaiters<TEvents>;
189
190
  [INTERNAL]: {
190
- handle: WorkflowRunHandle<Input, unknown, AppContext, TEventDefinition>;
191
+ handle: WorkflowRunHandle<Input, unknown, AppContext, TEvents>;
191
192
  options: {
192
193
  spinThresholdMs: number;
193
194
  };
194
195
  };
195
196
  }
196
197
 
197
- type ChildWorkflowRunHandle<Input, Output, AppContext, TEventsDefinition extends EventsDefinition = EventsDefinition> = Omit<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>, "waitForStatus"> & {
198
+ type ChildWorkflowRunHandle<Input, Output, AppContext, TEvents extends EventsDefinition = EventsDefinition> = Omit<WorkflowRunHandle<Input, Output, AppContext, TEvents>, "waitForStatus"> & {
198
199
  /**
199
200
  * Waits for the child workflow run to reach a terminal status.
200
201
  *
@@ -239,47 +240,44 @@ interface ChildWorkflowRunWaitOptions<Timed extends boolean> {
239
240
  timeout?: Timed extends true ? DurationObject : never;
240
241
  }
241
242
 
242
- interface WorkflowVersionParams<Input, Output, AppContext, TEventsDefinition extends EventsDefinition> {
243
- handler: (run: Readonly<WorkflowRunContext<Input, AppContext, TEventsDefinition>>, input: Input, context: AppContext) => Promise<Output>;
244
- events?: TEventsDefinition;
245
- opts?: WorkflowOptions;
243
+ interface WorkflowVersionParams<Input, Output, AppContext, TEvents extends EventsDefinition> {
244
+ handler: (run: Readonly<WorkflowRunContext<Input, AppContext, TEvents>>, input: Input, context: AppContext) => Promise<Output>;
245
+ events?: TEvents;
246
+ opts?: WorkflowDefinitionOptions;
246
247
  schema?: RequireAtLeastOneProp<{
247
248
  input?: StandardSchemaV1<Input>;
248
249
  output?: StandardSchemaV1<Output>;
249
250
  }>;
250
251
  }
251
- interface WorkflowVersion<Input, Output, AppContext, TEventsDefinition extends EventsDefinition = EventsDefinition> {
252
+ interface WorkflowVersion<Input, Output, AppContext, TEvents extends EventsDefinition = EventsDefinition> {
252
253
  name: WorkflowName;
253
254
  versionId: WorkflowVersionId;
254
- events: EventMulticasters<TEventsDefinition>;
255
- with(): WorkflowBuilder<Input, Output, AppContext, TEventsDefinition>;
256
- start: (client: Client<AppContext>, ...args: Input extends void ? [] : [Input]) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
257
- startAsChild: <ParentInput, ParentEventsDefinition extends EventsDefinition>(parentRun: WorkflowRunContext<ParentInput, AppContext, ParentEventsDefinition>, ...args: Input extends void ? [] : [Input]) => Promise<ChildWorkflowRunHandle<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>>;
255
+ events: EventMulticasters<TEvents>;
256
+ with(): WorkflowBuilder<Input, Output, AppContext, TEvents>;
257
+ start: (client: Client<AppContext>, ...args: Input extends void ? [] : [Input]) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
258
+ startAsChild: <ParentInput, ParentEvents extends EventsDefinition>(parentRun: WorkflowRunContext<ParentInput, AppContext, ParentEvents>, ...args: Input extends void ? [] : [Input]) => Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEvents>>;
259
+ getHandleById: (client: Client<AppContext>, runId: string) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
260
+ getHandleByReferenceId: (client: Client<AppContext>, referenceId: string) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
260
261
  [INTERNAL]: {
261
- eventsDefinition: TEventsDefinition;
262
- handler: (run: WorkflowRunContext<Input, AppContext, TEventsDefinition>, input: Input, context: AppContext) => Promise<void>;
262
+ eventsDefinition: TEvents;
263
+ handler: (run: WorkflowRunContext<Input, AppContext, TEvents>, input: Input, context: AppContext) => Promise<void>;
263
264
  };
264
265
  }
265
- interface WorkflowBuilder<Input, Output, AppContext, TEventsDefinition extends EventsDefinition> {
266
- opt<Path extends PathFromObject<WorkflowOptions>>(path: Path, value: TypeOfValueAtPath<WorkflowOptions, Path>): WorkflowBuilder<Input, Output, AppContext, TEventsDefinition>;
267
- start: WorkflowVersion<Input, Output, AppContext, TEventsDefinition>["start"];
268
- startAsChild: WorkflowVersion<Input, Output, AppContext, TEventsDefinition>["startAsChild"];
269
- }
270
- declare class WorkflowVersionImpl<Input, Output, AppContext, TEventsDefinition extends EventsDefinition> implements WorkflowVersion<Input, Output, AppContext, TEventsDefinition> {
266
+ declare class WorkflowVersionImpl<Input, Output, AppContext, TEvents extends EventsDefinition> implements WorkflowVersion<Input, Output, AppContext, TEvents> {
271
267
  readonly name: WorkflowName;
272
268
  readonly versionId: WorkflowVersionId;
273
269
  private readonly params;
274
- readonly events: EventMulticasters<TEventsDefinition>;
275
- readonly [INTERNAL]: WorkflowVersion<Input, Output, AppContext, TEventsDefinition>[typeof INTERNAL];
276
- constructor(name: WorkflowName, versionId: WorkflowVersionId, params: WorkflowVersionParams<Input, Output, AppContext, TEventsDefinition>);
277
- with(): WorkflowBuilder<Input, Output, AppContext, TEventsDefinition>;
278
- start(client: Client<AppContext>, ...args: Input extends void ? [] : [Input]): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
279
- startAsChild(parentRun: WorkflowRunContext<unknown, AppContext, EventsDefinition>, ...args: Input extends void ? [] : [Input]): Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
270
+ readonly events: EventMulticasters<TEvents>;
271
+ readonly [INTERNAL]: WorkflowVersion<Input, Output, AppContext, TEvents>[typeof INTERNAL];
272
+ constructor(name: WorkflowName, versionId: WorkflowVersionId, params: WorkflowVersionParams<Input, Output, AppContext, TEvents>);
273
+ with(): WorkflowBuilder<Input, Output, AppContext, TEvents>;
274
+ start(client: Client<AppContext>, ...args: Input extends void ? [] : [Input]): Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
275
+ startWithOpts(client: Client<AppContext>, startOpts: WorkflowStartOptions, ...args: Input extends void ? [] : [Input]): Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
276
+ startAsChild(parentRun: WorkflowRunContext<unknown, AppContext, EventsDefinition>, ...args: Input extends void ? [] : [Input]): Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEvents>>;
277
+ startAsChildWithOpts(parentRun: WorkflowRunContext<unknown, AppContext, EventsDefinition>, startOpts: WorkflowStartOptions, ...args: Input extends void ? [] : [Input]): Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEvents>>;
280
278
  private assertUniqueChildRunReferenceId;
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>>;
279
+ getHandleById(client: Client<AppContext>, runId: string): Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
280
+ getHandleByReferenceId(client: Client<AppContext>, referenceId: string): Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
283
281
  private handler;
284
282
  private tryExecuteWorkflow;
285
283
  private assertRetryAllowed;
@@ -287,6 +285,11 @@ declare class WorkflowVersionImpl<Input, Output, AppContext, TEventsDefinition e
287
285
  private createFailedState;
288
286
  private createAwaitingRetryState;
289
287
  }
288
+ interface WorkflowBuilder<Input, Output, AppContext, TEvents extends EventsDefinition> {
289
+ opt<Path extends PathFromObject<WorkflowStartOptions>>(path: Path, value: TypeOfValueAtPath<WorkflowStartOptions, Path>): WorkflowBuilder<Input, Output, AppContext, TEvents>;
290
+ start: WorkflowVersion<Input, Output, AppContext, TEvents>["start"];
291
+ startAsChild: WorkflowVersion<Input, Output, AppContext, TEvents>["startAsChild"];
292
+ }
290
293
 
291
294
  declare function workflowRegistry(): WorkflowRegistry;
292
295
  type Workflow$1 = WorkflowVersion<unknown, unknown, unknown>;
@@ -302,6 +305,34 @@ interface WorkflowRegistry {
302
305
 
303
306
  declare function createSleeper(handle: WorkflowRunHandle<unknown, unknown, unknown>, logger: Logger): (name: string, duration: Duration) => Promise<SleepResult>;
304
307
 
308
+ interface CronScheduleParams {
309
+ type: "cron";
310
+ expression: string;
311
+ timezone?: string;
312
+ overlapPolicy?: OverlapPolicy;
313
+ }
314
+ interface IntervalScheduleParams {
315
+ type: "interval";
316
+ every: DurationObject;
317
+ overlapPolicy?: OverlapPolicy;
318
+ }
319
+ type ScheduleParams = CronScheduleParams | IntervalScheduleParams;
320
+ interface ScheduleHandle {
321
+ id: ScheduleId;
322
+ pause(): Promise<void>;
323
+ resume(): Promise<void>;
324
+ delete(): Promise<void>;
325
+ }
326
+ interface ScheduleBuilder {
327
+ opt<Path extends PathFromObject<ScheduleActivateOptions>>(path: Path, value: TypeOfValueAtPath<ScheduleActivateOptions, Path>): ScheduleBuilder;
328
+ activate<Input, Output, AppContext, TEvents extends EventsDefinition>(client: Client<AppContext>, workflow: WorkflowVersion<Input, Output, AppContext, TEvents>, ...args: Input extends void ? [] : [Input]): Promise<ScheduleHandle>;
329
+ }
330
+ type ScheduleDefinition = ScheduleParams & {
331
+ with(): ScheduleBuilder;
332
+ activate<Input, Output, AppContext, TEvents extends EventsDefinition>(client: Client<AppContext>, workflow: WorkflowVersion<Input, Output, AppContext, TEvents>, ...args: Input extends void ? [] : [Input]): Promise<ScheduleHandle>;
333
+ };
334
+ declare function schedule(params: ScheduleParams): ScheduleDefinition;
335
+
305
336
  /**
306
337
  * Defines a durable workflow with versioning and multiple task execution.
307
338
  *
@@ -355,11 +386,11 @@ interface WorkflowParams {
355
386
  }
356
387
  interface Workflow {
357
388
  name: WorkflowName;
358
- v: <Input extends Serializable, Output extends Serializable, AppContext = null, TEventsDefinition extends EventsDefinition = Record<string, never>>(versionId: string, params: WorkflowVersionParams<Input, Output, AppContext, TEventsDefinition>) => WorkflowVersion<Input, Output, AppContext, TEventsDefinition>;
389
+ v: <Input extends Serializable, Output extends Serializable, AppContext = null, TEvents extends EventsDefinition = Record<string, never>>(versionId: string, params: WorkflowVersionParams<Input, Output, AppContext, TEvents>) => WorkflowVersion<Input, Output, AppContext, TEvents>;
359
390
  [INTERNAL]: {
360
391
  getAllVersions: () => WorkflowVersion<unknown, unknown, unknown>[];
361
392
  getVersion: (versionId: WorkflowVersionId) => WorkflowVersion<unknown, unknown, unknown> | undefined;
362
393
  };
363
394
  }
364
395
 
365
- export { type EventMulticaster, type EventMulticasters, type EventSender, type EventSenders, type EventWaiter, type EventWaiters, type Workflow, type WorkflowParams, type WorkflowRegistry, type WorkflowRunContext, type WorkflowRunHandle, type WorkflowRunWaitOptions, type WorkflowVersion, WorkflowVersionImpl, type WorkflowVersionParams, createEventSenders, createEventWaiters, createSleeper, event, workflow, workflowRegistry, workflowRunHandle };
396
+ export { type EventMulticaster, type EventMulticasters, type EventSender, type EventSenders, type EventWaiter, type EventWaiters, type ScheduleDefinition, type ScheduleHandle, type ScheduleParams, type Workflow, type WorkflowParams, type WorkflowRegistry, type WorkflowRunContext, type WorkflowRunHandle, type WorkflowRunWaitOptions, type WorkflowVersion, WorkflowVersionImpl, type WorkflowVersionParams, createEventSenders, createEventWaiters, createSleeper, event, schedule, workflow, workflowRegistry, workflowRunHandle };
package/dist/index.js CHANGED
@@ -292,8 +292,8 @@ function getRetryParams(attempts, strategy) {
292
292
  import { INTERNAL } from "@aikirun/types/symbols";
293
293
  import { SchemaValidationError } from "@aikirun/types/validator";
294
294
  import {
295
- WorkflowRunConflictError,
296
295
  WorkflowRunFailedError,
296
+ WorkflowRunRevisionConflictError,
297
297
  WorkflowRunSuspendedError
298
298
  } from "@aikirun/types/workflow-run";
299
299
  function event(params) {
@@ -361,7 +361,7 @@ function createEventWaiter(handle, eventName, schema, logger) {
361
361
  ...timeoutInMs !== void 0 ? { "aiki.timeoutInMs": timeoutInMs } : {}
362
362
  });
363
363
  } catch (error) {
364
- if (error instanceof WorkflowRunConflictError) {
364
+ if (error instanceof WorkflowRunRevisionConflictError) {
365
365
  throw new WorkflowRunSuspendedError(handle.run.id);
366
366
  }
367
367
  throw error;
@@ -392,10 +392,9 @@ function createEventSender(api, workflowRunId, eventName, schema, logger, onSend
392
392
  send: (...args) => createEventSender(api, workflowRunId, eventName, schema, logger, onSend, optsBuilder.build()).send(...args)
393
393
  });
394
394
  async function send(...args) {
395
- const dataRaw = isNonEmptyArray(args) ? args[0] : void 0;
396
- let data = dataRaw;
395
+ let data = args[0];
397
396
  if (schema) {
398
- const schemaValidation = schema["~standard"].validate(dataRaw);
397
+ const schemaValidation = schema["~standard"].validate(data);
399
398
  const schemaValidationResult = schemaValidation instanceof Promise ? await schemaValidation : schemaValidation;
400
399
  if (schemaValidationResult.issues) {
401
400
  logger.error("Invalid event data", { "aiki.issues": schemaValidationResult.issues });
@@ -443,10 +442,9 @@ function createEventMulticaster(workflowName, workflowVersionId, eventName, sche
443
442
  )
444
443
  });
445
444
  async function send(client, runId, ...args) {
446
- const dataRaw = isNonEmptyArray(args) ? args[0] : void 0;
447
- let data = dataRaw;
445
+ let data = args[0];
448
446
  if (schema) {
449
- const schemaValidation = schema["~standard"].validate(dataRaw);
447
+ const schemaValidation = schema["~standard"].validate(data);
450
448
  const schemaValidationResult = schemaValidation instanceof Promise ? await schemaValidation : schemaValidation;
451
449
  if (schemaValidationResult.issues) {
452
450
  client.logger.error("Invalid event data", {
@@ -487,8 +485,8 @@ function createEventMulticaster(workflowName, workflowVersionId, eventName, sche
487
485
  import { INTERNAL as INTERNAL2 } from "@aikirun/types/symbols";
488
486
  import {
489
487
  isTerminalWorkflowRunStatus,
490
- WorkflowRunConflictError as WorkflowRunConflictError2,
491
- WorkflowRunNotExecutableError
488
+ WorkflowRunNotExecutableError,
489
+ WorkflowRunRevisionConflictError as WorkflowRunRevisionConflictError2
492
490
  } from "@aikirun/types/workflow-run";
493
491
  async function workflowRunHandle(client, runOrId, eventsDefinition, logger) {
494
492
  const run = typeof runOrId !== "string" ? runOrId : (await client.api.workflowRun.getByIdV1({ id: runOrId })).run;
@@ -624,7 +622,7 @@ var WorkflowRunHandleImpl = class {
624
622
  this._run = run;
625
623
  } catch (error) {
626
624
  if (isConflictError(error)) {
627
- throw new WorkflowRunConflictError2(this.run.id);
625
+ throw new WorkflowRunRevisionConflictError2(this.run.id);
628
626
  }
629
627
  throw error;
630
628
  }
@@ -640,7 +638,7 @@ var WorkflowRunHandleImpl = class {
640
638
  return { taskId };
641
639
  } catch (error) {
642
640
  if (isConflictError(error)) {
643
- throw new WorkflowRunConflictError2(this.run.id);
641
+ throw new WorkflowRunRevisionConflictError2(this.run.id);
644
642
  }
645
643
  throw error;
646
644
  }
@@ -658,7 +656,10 @@ function isConflictError(error) {
658
656
 
659
657
  // run/sleeper.ts
660
658
  import { INTERNAL as INTERNAL3 } from "@aikirun/types/symbols";
661
- import { WorkflowRunConflictError as WorkflowRunConflictError3, WorkflowRunSuspendedError as WorkflowRunSuspendedError2 } from "@aikirun/types/workflow-run";
659
+ import {
660
+ WorkflowRunRevisionConflictError as WorkflowRunRevisionConflictError3,
661
+ WorkflowRunSuspendedError as WorkflowRunSuspendedError2
662
+ } from "@aikirun/types/workflow-run";
662
663
  var MAX_SLEEP_YEARS = 10;
663
664
  var MAX_SLEEP_MS = MAX_SLEEP_YEARS * 365 * 24 * 60 * 60 * 1e3;
664
665
  function createSleeper(handle, logger) {
@@ -680,7 +681,7 @@ function createSleeper(handle, logger) {
680
681
  "aiki.durationMs": durationMs
681
682
  });
682
683
  } catch (error) {
683
- if (error instanceof WorkflowRunConflictError3) {
684
+ if (error instanceof WorkflowRunRevisionConflictError3) {
684
685
  throw new WorkflowRunSuspendedError2(handle.run.id);
685
686
  }
686
687
  throw error;
@@ -728,7 +729,7 @@ function createSleeper(handle, logger) {
728
729
  "aiki.durationMs": durationMs
729
730
  });
730
731
  } catch (error) {
731
- if (error instanceof WorkflowRunConflictError3) {
732
+ if (error instanceof WorkflowRunRevisionConflictError3) {
732
733
  throw new WorkflowRunSuspendedError2(handle.run.id);
733
734
  }
734
735
  throw error;
@@ -737,11 +738,72 @@ function createSleeper(handle, logger) {
737
738
  };
738
739
  }
739
740
 
741
+ // schedule.ts
742
+ function schedule(params) {
743
+ async function activateWithOpts(client, workflow2, options, ...args) {
744
+ const input = args[0];
745
+ let scheduleSpec;
746
+ if (params.type === "interval") {
747
+ const { every, ...rest } = params;
748
+ scheduleSpec = {
749
+ ...rest,
750
+ everyMs: toMilliseconds(every)
751
+ };
752
+ } else {
753
+ scheduleSpec = params;
754
+ }
755
+ const { schedule: schedule2 } = await client.api.schedule.activateV1({
756
+ workflowName: workflow2.name,
757
+ workflowVersionId: workflow2.versionId,
758
+ spec: scheduleSpec,
759
+ input,
760
+ options
761
+ });
762
+ client.logger.info("Schedule activated", {
763
+ scheduleSpec,
764
+ workflowName: workflow2.name,
765
+ workflowVersionId: workflow2.versionId,
766
+ referenceId: options?.reference?.id
767
+ });
768
+ const scheduleId = schedule2.id;
769
+ return {
770
+ id: scheduleId,
771
+ pause: async () => {
772
+ await client.api.schedule.pauseV1({ id: scheduleId });
773
+ },
774
+ resume: async () => {
775
+ await client.api.schedule.resumeV1({ id: scheduleId });
776
+ },
777
+ delete: async () => {
778
+ await client.api.schedule.deleteV1({ id: scheduleId });
779
+ }
780
+ };
781
+ }
782
+ function createBuilder(optsBuilder) {
783
+ return {
784
+ opt: (path, value) => createBuilder(optsBuilder.with(path, value)),
785
+ async activate(client, workflow2, ...args) {
786
+ return activateWithOpts(client, workflow2, optsBuilder.build(), ...args);
787
+ }
788
+ };
789
+ }
790
+ return {
791
+ ...params,
792
+ with() {
793
+ const optsOverrider = objectOverrider({});
794
+ return createBuilder(optsOverrider());
795
+ },
796
+ async activate(client, workflow2, ...args) {
797
+ return activateWithOpts(client, workflow2, {}, ...args);
798
+ }
799
+ };
800
+ }
801
+
740
802
  // workflow.ts
741
803
  import { INTERNAL as INTERNAL6 } from "@aikirun/types/symbols";
742
804
 
743
- // ../../lib/path/index.ts
744
- function getWorkflowRunPath(name, versionId, referenceId) {
805
+ // ../../lib/address/index.ts
806
+ function getWorkflowRunAddress(name, versionId, referenceId) {
745
807
  return `${name}/${versionId}/${referenceId}`;
746
808
  }
747
809
 
@@ -750,8 +812,8 @@ import { INTERNAL as INTERNAL5 } from "@aikirun/types/symbols";
750
812
  import { TaskFailedError } from "@aikirun/types/task";
751
813
  import { SchemaValidationError as SchemaValidationError2 } from "@aikirun/types/validator";
752
814
  import {
753
- WorkflowRunConflictError as WorkflowRunConflictError5,
754
815
  WorkflowRunFailedError as WorkflowRunFailedError2,
816
+ WorkflowRunRevisionConflictError as WorkflowRunRevisionConflictError5,
755
817
  WorkflowRunSuspendedError as WorkflowRunSuspendedError4
756
818
  } from "@aikirun/types/workflow-run";
757
819
 
@@ -759,7 +821,7 @@ import {
759
821
  import { INTERNAL as INTERNAL4 } from "@aikirun/types/symbols";
760
822
  import {
761
823
  isTerminalWorkflowRunStatus as isTerminalWorkflowRunStatus2,
762
- WorkflowRunConflictError as WorkflowRunConflictError4,
824
+ WorkflowRunRevisionConflictError as WorkflowRunRevisionConflictError4,
763
825
  WorkflowRunSuspendedError as WorkflowRunSuspendedError3
764
826
  } from "@aikirun/types/workflow-run";
765
827
  async function childWorkflowRunHandle(client, run, parentRun, logger, eventsDefinition) {
@@ -780,7 +842,7 @@ function createStatusWaiter(handle, parentRun, logger) {
780
842
  let nextWaitIndex = 0;
781
843
  async function waitForStatus(expectedStatus, options) {
782
844
  const parentRunHandle = parentRun[INTERNAL4].handle;
783
- const waitResults = parentRunHandle.run.childWorkflowRuns[handle.run.path]?.statusWaitResults ?? [];
845
+ const waitResults = parentRunHandle.run.childWorkflowRuns[handle.run.address]?.statusWaitResults ?? [];
784
846
  const waitResult = waitResults[nextWaitIndex];
785
847
  if (waitResult) {
786
848
  nextWaitIndex++;
@@ -838,7 +900,7 @@ function createStatusWaiter(handle, parentRun, logger) {
838
900
  ...timeoutInMs !== void 0 ? { "aiki.timeoutInMs": timeoutInMs } : {}
839
901
  });
840
902
  } catch (error) {
841
- if (error instanceof WorkflowRunConflictError4) {
903
+ if (error instanceof WorkflowRunRevisionConflictError4) {
842
904
  throw new WorkflowRunSuspendedError3(parentRun.id);
843
905
  }
844
906
  throw error;
@@ -849,7 +911,7 @@ function createStatusWaiter(handle, parentRun, logger) {
849
911
  }
850
912
 
851
913
  // workflow-version.ts
852
- var WorkflowVersionImpl = class _WorkflowVersionImpl {
914
+ var WorkflowVersionImpl = class {
853
915
  constructor(name, versionId, params) {
854
916
  this.name = name;
855
917
  this.versionId = versionId;
@@ -864,28 +926,18 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
864
926
  events;
865
927
  [INTERNAL5];
866
928
  with() {
867
- const optsOverrider = objectOverrider(this.params.opts ?? {});
868
- const createBuilder = (optsBuilder) => {
869
- return {
870
- opt: (path, value) => createBuilder(optsBuilder.with(path, value)),
871
- start: (client, ...args) => new _WorkflowVersionImpl(this.name, this.versionId, {
872
- ...this.params,
873
- opts: optsBuilder.build()
874
- }).start(client, ...args),
875
- startAsChild: (parentRun, ...args) => new _WorkflowVersionImpl(this.name, this.versionId, {
876
- ...this.params,
877
- opts: optsBuilder.build()
878
- }).startAsChild(parentRun, ...args)
879
- };
880
- };
881
- return createBuilder(optsOverrider());
929
+ const startOpts = this.params.opts ?? {};
930
+ const startOptsOverrider = objectOverrider(startOpts);
931
+ return new WorkflowBuilderImpl(this, startOptsOverrider());
882
932
  }
883
933
  async start(client, ...args) {
884
- const inputRaw = isNonEmptyArray(args) ? args[0] : void 0;
885
- let input = inputRaw;
934
+ return this.startWithOpts(client, this.params.opts ?? {}, ...args);
935
+ }
936
+ async startWithOpts(client, startOpts, ...args) {
937
+ let input = args[0];
886
938
  const schema = this.params.schema?.input;
887
939
  if (schema) {
888
- const schemaValidation = schema["~standard"].validate(inputRaw);
940
+ const schemaValidation = schema["~standard"].validate(input);
889
941
  const schemaValidationResult = schemaValidation instanceof Promise ? await schemaValidation : schemaValidation;
890
942
  if (schemaValidationResult.issues) {
891
943
  client.logger.error("Invalid workflow data", { "aiki.issues": schemaValidationResult.issues });
@@ -897,7 +949,7 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
897
949
  name: this.name,
898
950
  versionId: this.versionId,
899
951
  input,
900
- options: this.params.opts
952
+ options: startOpts
901
953
  });
902
954
  client.logger.info("Created workflow", {
903
955
  "aiki.workflowName": this.name,
@@ -907,15 +959,18 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
907
959
  return workflowRunHandle(client, run, this[INTERNAL5].eventsDefinition);
908
960
  }
909
961
  async startAsChild(parentRun, ...args) {
962
+ return this.startAsChildWithOpts(parentRun, this.params.opts ?? {}, ...args);
963
+ }
964
+ async startAsChildWithOpts(parentRun, startOpts, ...args) {
910
965
  const parentRunHandle = parentRun[INTERNAL5].handle;
911
966
  parentRunHandle[INTERNAL5].assertExecutionAllowed();
912
967
  const { client } = parentRunHandle[INTERNAL5];
913
- const inputRaw = isNonEmptyArray(args) ? args[0] : void 0;
968
+ const inputRaw = args[0];
914
969
  const input = await this.parse(parentRunHandle, this.params.schema?.input, inputRaw, parentRun.logger);
915
970
  const inputHash = await hashInput(input);
916
- const reference = this.params.opts?.reference;
917
- const path = getWorkflowRunPath(this.name, this.versionId, reference?.id ?? inputHash);
918
- const existingRunInfo = parentRunHandle.run.childWorkflowRuns[path];
971
+ const reference = startOpts.reference;
972
+ const address = getWorkflowRunAddress(this.name, this.versionId, reference?.id ?? inputHash);
973
+ const existingRunInfo = parentRunHandle.run.childWorkflowRuns[address];
919
974
  if (existingRunInfo) {
920
975
  await this.assertUniqueChildRunReferenceId(
921
976
  parentRunHandle,
@@ -946,9 +1001,9 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
946
1001
  versionId: this.versionId,
947
1002
  input,
948
1003
  parentWorkflowRunId: parentRun.id,
949
- options: this.params.opts
1004
+ options: startOpts
950
1005
  });
951
- parentRunHandle.run.childWorkflowRuns[path] = {
1006
+ parentRunHandle.run.childWorkflowRuns[address] = {
952
1007
  id: newRun.id,
953
1008
  name: newRun.name,
954
1009
  versionId: newRun.versionId,
@@ -971,8 +1026,8 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
971
1026
  }
972
1027
  async assertUniqueChildRunReferenceId(parentRunHandle, existingRunInfo, inputHash, reference, logger) {
973
1028
  if (existingRunInfo.inputHash !== inputHash && reference) {
974
- const onConflict = reference.onConflict ?? "error";
975
- if (onConflict !== "error") {
1029
+ const conflictPolicy = reference.conflictPolicy ?? "error";
1030
+ if (conflictPolicy !== "error") {
976
1031
  return;
977
1032
  }
978
1033
  logger.error("Reference ID already used by another child workflow", {
@@ -1026,7 +1081,7 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
1026
1081
  const output = await this.parse(handle, this.params.schema?.output, outputRaw, run.logger);
1027
1082
  return output;
1028
1083
  } catch (error) {
1029
- if (error instanceof WorkflowRunSuspendedError4 || error instanceof WorkflowRunFailedError2 || error instanceof WorkflowRunConflictError5) {
1084
+ if (error instanceof WorkflowRunSuspendedError4 || error instanceof WorkflowRunFailedError2 || error instanceof WorkflowRunRevisionConflictError5) {
1030
1085
  throw error;
1031
1086
  }
1032
1087
  const attempts = handle.run.attempts;
@@ -1123,6 +1178,21 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
1123
1178
  };
1124
1179
  }
1125
1180
  };
1181
+ var WorkflowBuilderImpl = class _WorkflowBuilderImpl {
1182
+ constructor(workflow2, startOptsBuilder) {
1183
+ this.workflow = workflow2;
1184
+ this.startOptsBuilder = startOptsBuilder;
1185
+ }
1186
+ opt(path, value) {
1187
+ return new _WorkflowBuilderImpl(this.workflow, this.startOptsBuilder.with(path, value));
1188
+ }
1189
+ start(client, ...args) {
1190
+ return this.workflow.startWithOpts(client, this.startOptsBuilder.build(), ...args);
1191
+ }
1192
+ startAsChild(parentRun, ...args) {
1193
+ return this.workflow.startAsChildWithOpts(parentRun, this.startOptsBuilder.build(), ...args);
1194
+ }
1195
+ };
1126
1196
 
1127
1197
  // workflow.ts
1128
1198
  function workflow(params) {
@@ -1163,6 +1233,7 @@ export {
1163
1233
  createEventWaiters,
1164
1234
  createSleeper,
1165
1235
  event,
1236
+ schedule,
1166
1237
  workflow,
1167
1238
  workflowRegistry,
1168
1239
  workflowRunHandle
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aikirun/workflow",
3
- "version": "0.14.0",
3
+ "version": "0.16.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,7 @@
18
18
  "build": "tsup"
19
19
  },
20
20
  "dependencies": {
21
- "@aikirun/types": "0.14.0",
21
+ "@aikirun/types": "0.16.0",
22
22
  "@standard-schema/spec": "^1.1.0"
23
23
  },
24
24
  "publishConfig": {