@aikirun/workflow 0.14.0 → 0.15.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,22 @@ 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
+ name: "daily-report",
56
+ type: "cron",
57
+ expression: "0 9 * * *", // Every day at 9 AM
58
+ });
59
+
60
+ await dailyReport.activate(aikiClient, onboardingWorkflowV1, { email: "daily@example.com" });
61
+ ```
62
+
47
63
  ## Features
48
64
 
49
65
  - **Durable Execution** - Workflows survive crashes and restarts
@@ -53,6 +69,7 @@ const result = await handle.waitForStatus("completed");
53
69
  - **Child Workflows** - Compose workflows together
54
70
  - **Automatic Retries** - Configurable retry strategies
55
71
  - **Versioning** - Run multiple versions simultaneously
72
+ - **Scheduling** - Trigger workflows on cron or interval schedules
56
73
 
57
74
  ## Documentation
58
75
 
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, ScheduleName, 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,33 @@ 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
+ name: ScheduleName;
323
+ pause(): Promise<void>;
324
+ resume(): Promise<void>;
325
+ delete(): Promise<void>;
326
+ }
327
+ type ScheduleDefinition = ScheduleParams & {
328
+ name: ScheduleName;
329
+ activate<Input, Output, AppContext, TEvents extends EventsDefinition>(client: Client<AppContext>, workflow: WorkflowVersion<Input, Output, AppContext, TEvents>, ...args: Input extends void ? [] : [Input]): Promise<ScheduleHandle>;
330
+ };
331
+ declare function schedule(params: {
332
+ name: string;
333
+ } & ScheduleParams): ScheduleDefinition;
334
+
305
335
  /**
306
336
  * Defines a durable workflow with versioning and multiple task execution.
307
337
  *
@@ -355,11 +385,11 @@ interface WorkflowParams {
355
385
  }
356
386
  interface Workflow {
357
387
  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>;
388
+ 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
389
  [INTERNAL]: {
360
390
  getAllVersions: () => WorkflowVersion<unknown, unknown, unknown>[];
361
391
  getVersion: (versionId: WorkflowVersionId) => WorkflowVersion<unknown, unknown, unknown> | undefined;
362
392
  };
363
393
  }
364
394
 
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 };
395
+ 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
@@ -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", {
@@ -737,11 +735,59 @@ function createSleeper(handle, logger) {
737
735
  };
738
736
  }
739
737
 
738
+ // schedule.ts
739
+ function schedule(params) {
740
+ const { name, ...scheduleParams } = params;
741
+ return {
742
+ name,
743
+ ...scheduleParams,
744
+ async activate(client, workflow2, ...args) {
745
+ const input = args[0];
746
+ let scheduleSpec;
747
+ if (scheduleParams.type === "interval") {
748
+ const { every, ...rest } = scheduleParams;
749
+ scheduleSpec = {
750
+ ...rest,
751
+ everyMs: toMilliseconds(every)
752
+ };
753
+ } else {
754
+ scheduleSpec = scheduleParams;
755
+ }
756
+ const { schedule: schedule2 } = await client.api.schedule.activateV1({
757
+ name,
758
+ workflowName: workflow2.name,
759
+ workflowVersionId: workflow2.versionId,
760
+ spec: scheduleSpec,
761
+ input
762
+ });
763
+ client.logger.info("Schedule activated", {
764
+ scheduleSpec,
765
+ workflowName: workflow2.name,
766
+ workflowVersionId: workflow2.versionId
767
+ });
768
+ const scheduleId = schedule2.id;
769
+ return {
770
+ id: scheduleId,
771
+ name,
772
+ pause: async () => {
773
+ await client.api.schedule.pauseV1({ id: scheduleId });
774
+ },
775
+ resume: async () => {
776
+ await client.api.schedule.resumeV1({ id: scheduleId });
777
+ },
778
+ delete: async () => {
779
+ await client.api.schedule.deleteV1({ id: scheduleId });
780
+ }
781
+ };
782
+ }
783
+ };
784
+ }
785
+
740
786
  // workflow.ts
741
787
  import { INTERNAL as INTERNAL6 } from "@aikirun/types/symbols";
742
788
 
743
- // ../../lib/path/index.ts
744
- function getWorkflowRunPath(name, versionId, referenceId) {
789
+ // ../../lib/address/index.ts
790
+ function getWorkflowRunAddress(name, versionId, referenceId) {
745
791
  return `${name}/${versionId}/${referenceId}`;
746
792
  }
747
793
 
@@ -780,7 +826,7 @@ function createStatusWaiter(handle, parentRun, logger) {
780
826
  let nextWaitIndex = 0;
781
827
  async function waitForStatus(expectedStatus, options) {
782
828
  const parentRunHandle = parentRun[INTERNAL4].handle;
783
- const waitResults = parentRunHandle.run.childWorkflowRuns[handle.run.path]?.statusWaitResults ?? [];
829
+ const waitResults = parentRunHandle.run.childWorkflowRuns[handle.run.address]?.statusWaitResults ?? [];
784
830
  const waitResult = waitResults[nextWaitIndex];
785
831
  if (waitResult) {
786
832
  nextWaitIndex++;
@@ -849,7 +895,7 @@ function createStatusWaiter(handle, parentRun, logger) {
849
895
  }
850
896
 
851
897
  // workflow-version.ts
852
- var WorkflowVersionImpl = class _WorkflowVersionImpl {
898
+ var WorkflowVersionImpl = class {
853
899
  constructor(name, versionId, params) {
854
900
  this.name = name;
855
901
  this.versionId = versionId;
@@ -864,28 +910,18 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
864
910
  events;
865
911
  [INTERNAL5];
866
912
  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());
913
+ const startOpts = this.params.opts ?? {};
914
+ const startOptsOverrider = objectOverrider(startOpts);
915
+ return new WorkflowBuilderImpl(this, startOptsOverrider());
882
916
  }
883
917
  async start(client, ...args) {
884
- const inputRaw = isNonEmptyArray(args) ? args[0] : void 0;
885
- let input = inputRaw;
918
+ return this.startWithOpts(client, this.params.opts ?? {}, ...args);
919
+ }
920
+ async startWithOpts(client, startOpts, ...args) {
921
+ let input = args[0];
886
922
  const schema = this.params.schema?.input;
887
923
  if (schema) {
888
- const schemaValidation = schema["~standard"].validate(inputRaw);
924
+ const schemaValidation = schema["~standard"].validate(input);
889
925
  const schemaValidationResult = schemaValidation instanceof Promise ? await schemaValidation : schemaValidation;
890
926
  if (schemaValidationResult.issues) {
891
927
  client.logger.error("Invalid workflow data", { "aiki.issues": schemaValidationResult.issues });
@@ -897,7 +933,7 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
897
933
  name: this.name,
898
934
  versionId: this.versionId,
899
935
  input,
900
- options: this.params.opts
936
+ options: startOpts
901
937
  });
902
938
  client.logger.info("Created workflow", {
903
939
  "aiki.workflowName": this.name,
@@ -907,15 +943,18 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
907
943
  return workflowRunHandle(client, run, this[INTERNAL5].eventsDefinition);
908
944
  }
909
945
  async startAsChild(parentRun, ...args) {
946
+ return this.startAsChildWithOpts(parentRun, this.params.opts ?? {}, ...args);
947
+ }
948
+ async startAsChildWithOpts(parentRun, startOpts, ...args) {
910
949
  const parentRunHandle = parentRun[INTERNAL5].handle;
911
950
  parentRunHandle[INTERNAL5].assertExecutionAllowed();
912
951
  const { client } = parentRunHandle[INTERNAL5];
913
- const inputRaw = isNonEmptyArray(args) ? args[0] : void 0;
952
+ const inputRaw = args[0];
914
953
  const input = await this.parse(parentRunHandle, this.params.schema?.input, inputRaw, parentRun.logger);
915
954
  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];
955
+ const reference = startOpts.reference;
956
+ const address = getWorkflowRunAddress(this.name, this.versionId, reference?.id ?? inputHash);
957
+ const existingRunInfo = parentRunHandle.run.childWorkflowRuns[address];
919
958
  if (existingRunInfo) {
920
959
  await this.assertUniqueChildRunReferenceId(
921
960
  parentRunHandle,
@@ -946,9 +985,9 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
946
985
  versionId: this.versionId,
947
986
  input,
948
987
  parentWorkflowRunId: parentRun.id,
949
- options: this.params.opts
988
+ options: startOpts
950
989
  });
951
- parentRunHandle.run.childWorkflowRuns[path] = {
990
+ parentRunHandle.run.childWorkflowRuns[address] = {
952
991
  id: newRun.id,
953
992
  name: newRun.name,
954
993
  versionId: newRun.versionId,
@@ -971,8 +1010,8 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
971
1010
  }
972
1011
  async assertUniqueChildRunReferenceId(parentRunHandle, existingRunInfo, inputHash, reference, logger) {
973
1012
  if (existingRunInfo.inputHash !== inputHash && reference) {
974
- const onConflict = reference.onConflict ?? "error";
975
- if (onConflict !== "error") {
1013
+ const conflictPolicy = reference.conflictPolicy ?? "error";
1014
+ if (conflictPolicy !== "error") {
976
1015
  return;
977
1016
  }
978
1017
  logger.error("Reference ID already used by another child workflow", {
@@ -1123,6 +1162,21 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
1123
1162
  };
1124
1163
  }
1125
1164
  };
1165
+ var WorkflowBuilderImpl = class _WorkflowBuilderImpl {
1166
+ constructor(workflow2, startOptsBuilder) {
1167
+ this.workflow = workflow2;
1168
+ this.startOptsBuilder = startOptsBuilder;
1169
+ }
1170
+ opt(path, value) {
1171
+ return new _WorkflowBuilderImpl(this.workflow, this.startOptsBuilder.with(path, value));
1172
+ }
1173
+ start(client, ...args) {
1174
+ return this.workflow.startWithOpts(client, this.startOptsBuilder.build(), ...args);
1175
+ }
1176
+ startAsChild(parentRun, ...args) {
1177
+ return this.workflow.startAsChildWithOpts(parentRun, this.startOptsBuilder.build(), ...args);
1178
+ }
1179
+ };
1126
1180
 
1127
1181
  // workflow.ts
1128
1182
  function workflow(params) {
@@ -1163,6 +1217,7 @@ export {
1163
1217
  createEventWaiters,
1164
1218
  createSleeper,
1165
1219
  event,
1220
+ schedule,
1166
1221
  workflow,
1167
1222
  workflowRegistry,
1168
1223
  workflowRunHandle
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aikirun/workflow",
3
- "version": "0.14.0",
3
+ "version": "0.15.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.15.0",
22
22
  "@standard-schema/spec": "^1.1.0"
23
23
  },
24
24
  "publishConfig": {