@yieldstar/core 0.4.6 → 0.6.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.
Files changed (79) hide show
  1. package/dist/base/durable-value.d.ts +71 -0
  2. package/dist/base/durable-value.d.ts.map +1 -0
  3. package/dist/base/durable-value.test.d.ts +2 -0
  4. package/dist/base/durable-value.test.d.ts.map +1 -0
  5. package/dist/base/effect.d.ts +136 -0
  6. package/dist/base/effect.d.ts.map +1 -0
  7. package/dist/base/errors.d.ts +23 -0
  8. package/dist/base/errors.d.ts.map +1 -0
  9. package/dist/base/errors.test.d.ts +2 -0
  10. package/dist/base/errors.test.d.ts.map +1 -0
  11. package/dist/base/event.d.ts +6 -1
  12. package/dist/base/event.d.ts.map +1 -1
  13. package/dist/base/execution.d.ts +244 -0
  14. package/dist/base/execution.d.ts.map +1 -0
  15. package/dist/base/heap.d.ts +15 -3
  16. package/dist/base/heap.d.ts.map +1 -1
  17. package/dist/base/invoker.d.ts +47 -2
  18. package/dist/base/invoker.d.ts.map +1 -1
  19. package/dist/base/runtime.d.ts +27 -4
  20. package/dist/base/runtime.d.ts.map +1 -1
  21. package/dist/base/step.d.ts +26 -5
  22. package/dist/base/step.d.ts.map +1 -1
  23. package/dist/base/store.d.ts +431 -0
  24. package/dist/base/store.d.ts.map +1 -0
  25. package/dist/base/store.test.d.ts +2 -0
  26. package/dist/base/store.test.d.ts.map +1 -0
  27. package/dist/base/workflow.d.ts +17 -0
  28. package/dist/base/workflow.d.ts.map +1 -1
  29. package/dist/index.d.ts +24 -4
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +1986 -111
  32. package/dist/lib/effect-state.d.ts +78 -0
  33. package/dist/lib/effect-state.d.ts.map +1 -0
  34. package/dist/lib/execution-dispatcher.d.ts +102 -0
  35. package/dist/lib/execution-dispatcher.d.ts.map +1 -0
  36. package/dist/lib/execution-state.d.ts +248 -0
  37. package/dist/lib/execution-state.d.ts.map +1 -0
  38. package/dist/lib/execution-state.test.d.ts +2 -0
  39. package/dist/lib/execution-state.test.d.ts.map +1 -0
  40. package/dist/lib/wait-for-outcome.d.ts +15 -0
  41. package/dist/lib/wait-for-outcome.d.ts.map +1 -0
  42. package/dist/lib/workflow-runner.d.ts +14 -7
  43. package/dist/lib/workflow-runner.d.ts.map +1 -1
  44. package/dist/utils/map.d.ts +1 -1
  45. package/dist/utils/map.d.ts.map +1 -1
  46. package/package.json +13 -3
  47. package/src/base/durable-value.test.ts +285 -0
  48. package/src/base/durable-value.ts +442 -0
  49. package/src/base/effect.ts +165 -0
  50. package/src/base/errors.test.ts +210 -0
  51. package/src/base/errors.ts +72 -0
  52. package/src/base/event.ts +6 -1
  53. package/src/base/execution.ts +303 -0
  54. package/src/base/heap.ts +17 -3
  55. package/src/base/invoker.ts +60 -2
  56. package/src/base/runtime.ts +28 -7
  57. package/src/base/step.ts +37 -7
  58. package/src/base/store.test.ts +176 -0
  59. package/src/base/store.ts +1123 -0
  60. package/src/base/workflow.ts +17 -0
  61. package/src/index.ts +174 -3
  62. package/src/lib/effect-state.ts +254 -0
  63. package/src/lib/execution-dispatcher.ts +393 -0
  64. package/src/lib/execution-state.test.ts +249 -0
  65. package/src/lib/execution-state.ts +650 -0
  66. package/src/lib/wait-for-outcome.ts +40 -0
  67. package/src/lib/workflow-runner.ts +78 -34
  68. package/src/utils/map.test.ts +1 -1
  69. package/src/utils/map.ts +8 -2
  70. package/dist/base/map.d.ts +0 -21
  71. package/dist/base/map.d.ts.map +0 -1
  72. package/dist/base/map.test.d.ts +0 -2
  73. package/dist/base/map.test.d.ts.map +0 -1
  74. package/dist/base/schedule.d.ts +0 -71
  75. package/dist/base/schedule.d.ts.map +0 -1
  76. package/dist/base/types.d.ts +0 -24
  77. package/dist/base/types.d.ts.map +0 -1
  78. package/src/base/scheduler.ts +0 -8
  79. package/tsconfig.tsbuildinfo +0 -1
@@ -1,58 +1,80 @@
1
1
  import type { Logger } from "pino";
2
2
  import type {
3
3
  WorkflowGenerator,
4
- HeapClient,
5
- SchedulerClient,
6
- EventProcessor,
7
4
  WorkflowEvent,
8
5
  EventParams,
6
+ ExecutionLease,
7
+ WorkflowRunOutcome,
9
8
  } from "..";
10
- import { StepDelay, WorkflowDelay, WorkflowResult } from "..";
9
+ import {
10
+ InfrastructureError,
11
+ StepDelay,
12
+ StepEffectWait,
13
+ StepStoreWait,
14
+ WorkflowResult,
15
+ } from "..";
16
+ import type { Runtime } from "../base/runtime";
17
+ import type { DeliveryOptions } from "../base/invoker";
11
18
  import { EventContext } from "../base/event";
12
19
 
13
20
  export class WorkflowRunner<
14
21
  Router extends Record<string, WorkflowGenerator<any, any, any>>
15
22
  > {
16
- private heapClient: HeapClient;
17
- private schedulerClient: SchedulerClient;
23
+ private runtime: Runtime;
18
24
  private router: Router;
25
+ private logger: Logger;
19
26
 
20
- constructor(params: {
21
- heapClient: HeapClient;
22
- schedulerClient: SchedulerClient;
23
- router: Router;
24
- logger: Logger;
25
- }) {
26
- this.heapClient = params.heapClient;
27
- this.schedulerClient = params.schedulerClient;
28
- this.router = params.router;
27
+ constructor(runtime: Runtime, options: { router: Router; logger: Logger }) {
28
+ this.runtime = runtime;
29
+ this.router = options.router;
30
+ this.logger = options.logger;
29
31
  }
30
32
 
31
- run: EventProcessor = async (event, logger) => {
33
+ /**
34
+ * Runs one delivery under `options.lease` and resolves with its outcome.
35
+ * Rejects only with an infrastructure error, which must not be acknowledged
36
+ * as an outcome; a lost lease is one, and so is an aborted `options.signal`.
37
+ */
38
+ run = async (
39
+ event: WorkflowEvent,
40
+ options: DeliveryOptions & { logger?: Logger }
41
+ ): Promise<WorkflowRunOutcome> => {
42
+ const { lease, signal, logger = this.logger } = options;
32
43
  const workflow = this.router[event.workflowId];
33
44
 
34
45
  if (!workflow) {
35
- throw new Error(`No workflow registered for "${event.workflowId}"`);
46
+ return {
47
+ status: "failed",
48
+ error: new Error(`No workflow registered for "${event.workflowId}"`),
49
+ };
36
50
  }
37
51
 
52
+ let response:
53
+ | WorkflowResult<unknown>
54
+ | StepDelay
55
+ | StepEffectWait
56
+ | StepStoreWait;
38
57
  try {
39
- const response = await this.runWorkflows({
58
+ response = await this.runWorkflows({
40
59
  workflow,
41
60
  logger,
42
61
  event,
62
+ lease,
63
+ signal,
43
64
  });
44
-
45
- switch (response.type) {
46
- case "workflow-result":
47
- return response;
48
-
49
- case "workflow-delay":
50
- this.schedulerClient.requestWakeUp(event, response.resumeIn);
51
- break;
52
- }
53
65
  } catch (err) {
54
- // todo: distinguish between a workflow error and a system error
55
- throw err;
66
+ if (InfrastructureError.is(err)) throw err;
67
+ return { status: "failed", error: toError(err) };
68
+ }
69
+
70
+ switch (response.type) {
71
+ case "workflow-result":
72
+ return { status: "completed", result: response.result };
73
+ case "step-delay":
74
+ case "effect-wait":
75
+ return { status: "suspended", wakeAt: response.wakeAt };
76
+ case "store-wait":
77
+ return { status: "suspended" };
56
78
  }
57
79
  };
58
80
 
@@ -63,17 +85,26 @@ export class WorkflowRunner<
63
85
  >(params: {
64
86
  workflow: WorkflowGenerator<Params, Result, Context>;
65
87
  event: WorkflowEvent<Params, Context>;
88
+ lease: ExecutionLease;
89
+ signal: AbortSignal;
66
90
  logger: Logger;
67
- }): Promise<WorkflowResult<Result> | WorkflowDelay> {
68
- const { workflow, event, logger } = params;
91
+ }): Promise<
92
+ WorkflowResult<Result> | StepDelay | StepEffectWait | StepStoreWait
93
+ > {
94
+ const { workflow, event, lease, signal, logger } = params;
69
95
 
70
96
  const workflowIterator = workflow({
71
97
  event,
72
- heapClient: this.heapClient,
98
+ lease,
99
+ signal,
100
+ heapClient: this.runtime.heap,
101
+ storeClient: this.runtime.stores,
102
+ executionClient: this.runtime.executions,
103
+ effectClient: this.runtime.effects,
104
+ clock: this.runtime.clock,
73
105
  logger,
74
106
  });
75
107
 
76
-
77
108
  const iteratorResult = await workflowIterator.next();
78
109
  const stageResponse = iteratorResult.value;
79
110
 
@@ -81,8 +112,17 @@ export class WorkflowRunner<
81
112
  return stageResponse as WorkflowResult<Result>;
82
113
  }
83
114
 
115
+ // A delay's `wakeAt` is the absolute time it elapses, which is exactly
116
+ // the `wakeAt` the suspended outcome reports.
84
117
  if (stageResponse instanceof StepDelay) {
85
- return new WorkflowDelay(stageResponse.resumeIn - Date.now());
118
+ return stageResponse;
119
+ }
120
+
121
+ if (
122
+ stageResponse instanceof StepEffectWait ||
123
+ stageResponse instanceof StepStoreWait
124
+ ) {
125
+ return stageResponse;
86
126
  }
87
127
 
88
128
  throw new Error(
@@ -90,3 +130,7 @@ export class WorkflowRunner<
90
130
  );
91
131
  }
92
132
  }
133
+
134
+ function toError(value: unknown): Error {
135
+ return value instanceof Error ? value : new Error(String(value));
136
+ }
@@ -1,4 +1,4 @@
1
- import { expect, test } from "bun:test";
1
+ import { expect, test } from "vitest";
2
2
  import { ReadOnlyMap, FreezableMap } from "./map";
3
3
 
4
4
  test("ReadOnlyMap", () => {
package/src/utils/map.ts CHANGED
@@ -3,8 +3,14 @@ import { errorWithOriginalStack } from "./error";
3
3
  export class ReadOnlyMap<K, V> implements ReadonlyMap<K, V> {
4
4
  private sourceMap: Map<K, V>;
5
5
 
6
- constructor(sourceMap: Map<K, V>) {
7
- this.sourceMap = sourceMap;
6
+ constructor(sourceMap: Map<K, V> | Record<any, any> | undefined) {
7
+ if (sourceMap instanceof Map) {
8
+ this.sourceMap = sourceMap;
9
+ } else if (typeof sourceMap === "object" && sourceMap !== null) {
10
+ this.sourceMap = new Map(Object.entries(sourceMap)) as Map<K, V>;
11
+ } else {
12
+ this.sourceMap = new Map();
13
+ }
8
14
  }
9
15
 
10
16
  get(key: K): V | undefined {
@@ -1,21 +0,0 @@
1
- export declare class ReadOnlyMap<K, V> implements ReadonlyMap<K, V> {
2
- private sourceMap;
3
- constructor(sourceMap: Map<K, V>);
4
- get(key: K): V | undefined;
5
- has(key: K): boolean;
6
- get size(): number;
7
- entries(): ReturnType<Map<K, V>["entries"]>;
8
- keys(): ReturnType<Map<K, V>["keys"]>;
9
- values(): ReturnType<Map<K, V>["values"]>;
10
- forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
11
- [Symbol.iterator](): ReturnType<Map<K, V>[typeof Symbol.iterator]>;
12
- }
13
- export declare class FreezableMap<K, V> extends Map<K, V> {
14
- private frozen;
15
- freeze(): void;
16
- isFrozen(): boolean;
17
- set(key: K, value: V): this;
18
- delete(key: K): boolean;
19
- clear(): void;
20
- }
21
- //# sourceMappingURL=map.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"map.d.ts","sourceRoot":"","sources":["../../src/base/map.ts"],"names":[],"mappings":"AAAA,qBAAa,WAAW,CAAC,CAAC,EAAE,CAAC,CAAE,YAAW,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC;IACzD,OAAO,CAAC,SAAS,CAAY;gBAEjB,SAAS,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IAIhC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAI1B,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAIpB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAI3C,IAAI,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAIrC,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAIzC,OAAO,CACL,UAAU,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,EACtD,OAAO,CAAC,EAAE,GAAG,GACZ,IAAI;IAIP,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC;CAGnE;AAED,qBAAa,YAAY,CAAC,CAAC,EAAE,CAAC,CAAE,SAAQ,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,MAAM,CAAS;IAEvB,MAAM,IAAI,IAAI;IAId,QAAQ,IAAI,OAAO;IAInB,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAO3B,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAOvB,KAAK,IAAI,IAAI;CAMd"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=map.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"map.test.d.ts","sourceRoot":"","sources":["../../src/base/map.test.ts"],"names":[],"mappings":""}
@@ -1,71 +0,0 @@
1
- /**
2
- * Object-based schedule definition with specific time units
3
- */
4
- export interface ScheduleObject {
5
- /** Execute every X seconds */
6
- seconds?: number;
7
- /** Execute every X minutes */
8
- minutes?: number;
9
- /** Execute every X hours */
10
- hours?: number;
11
- /** Execute every X days */
12
- days?: number;
13
- /** Execute every X weeks */
14
- weeks?: number;
15
- /** Execute every X months */
16
- months?: number;
17
- /** Specific days of the week to run (0 = Sunday, 6 = Saturday) */
18
- daysOfWeek?: number[];
19
- /** Specific days of the month to run (1-31) */
20
- daysOfMonth?: number[];
21
- /** Specific months to run (0 = January, 11 = December) */
22
- monthsOfYear?: number[];
23
- }
24
- /**
25
- * Schedule definition for a workflow execution
26
- */
27
- export interface ScheduleDefinition<T = Record<string, any>> {
28
- /** Unique identifier for this schedule */
29
- id: string;
30
- /** ID of the workflow to execute */
31
- workflowId: string;
32
- /** Parameters to pass to the workflow execution */
33
- params?: T;
34
- /**
35
- * Schedule definition - can be:
36
- * - Cron expression (e.g. "0 9 * * *")
37
- * - Object-based schedule with specific time units
38
- * - Array of specific dates for one-time executions
39
- */
40
- schedule: string | ScheduleObject | Date[];
41
- /** Whether this schedule is currently active */
42
- enabled?: boolean;
43
- /** The date when this schedule should start (defaults to now) */
44
- startDate?: Date;
45
- /** The date when this schedule should stop being executed */
46
- endDate?: Date;
47
- /**
48
- * Retry policy for failed executions
49
- */
50
- retryPolicy?: {
51
- /** Maximum number of retry attempts */
52
- maxAttempts: number;
53
- };
54
- /** Additional metadata for the schedule */
55
- metadata?: Record<string, any>;
56
- }
57
- /**
58
- * Options for creating a new schedule
59
- */
60
- export interface ScheduleOptions<T = Record<string, any>> extends Omit<ScheduleDefinition<T>, "id"> {
61
- /** Optional ID for the schedule (will be auto-generated if not provided) */
62
- id?: string;
63
- }
64
- /**
65
- * Response from creating a new schedule
66
- */
67
- export interface ScheduleCreationResponse {
68
- /** The ID of the created schedule */
69
- scheduleId: string;
70
- }
71
- //# sourceMappingURL=schedule.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../../src/base/schedule.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IACzD,0CAA0C;IAC1C,EAAE,EAAE,MAAM,CAAC;IAEX,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IAEnB,mDAAmD;IACnD,MAAM,CAAC,EAAE,CAAC,CAAC;IAEX;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,EAAE,CAAC;IAE3C,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,iEAAiE;IACjE,SAAS,CAAC,EAAE,IAAI,CAAC;IAEjB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,IAAI,CAAC;IAEf;;OAEG;IACH,WAAW,CAAC,EAAE;QACZ,uCAAuC;QACvC,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IAEF,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CACtD,SAAQ,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;IACzC,4EAA4E;IAC5E,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;CACpB"}
@@ -1,24 +0,0 @@
1
- import type { WorkflowRouter } from "./workflow";
2
- import type { EventParamsOf } from "./workflow";
3
- /**
4
- * Helper type to simplify complex generic types
5
- * This helps TypeScript's inference by "flattening" nested types
6
- */
7
- export type Flatten<T> = {
8
- [P in keyof T]: T[P];
9
- };
10
- /**
11
- * Simplified type to extract the key type from a WorkflowRouter
12
- */
13
- export type WorkflowKey<W extends WorkflowRouter> = keyof W & string;
14
- /**
15
- * Simplified type to extract the parameters type from a workflow
16
- */
17
- export type WorkflowParams<W extends WorkflowRouter, K extends WorkflowKey<W>> = EventParamsOf<W[K]>;
18
- /**
19
- * Standard response type for trigger operations
20
- */
21
- export type TriggerResponse = {
22
- executionId: string;
23
- };
24
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/base/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAA+B,MAAM,YAAY,CAAC;AAE7E;;;GAGG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC;AAElD;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,cAAc,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC;AAErE;;GAEG;AACH,MAAM,MAAM,cAAc,CACxB,CAAC,SAAS,cAAc,EACxB,CAAC,SAAS,WAAW,CAAC,CAAC,CAAC,IACtB,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAExB;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC"}
@@ -1,8 +0,0 @@
1
- import type { WorkflowEvent, EventParams } from "./event";
2
-
3
- export interface SchedulerClient {
4
- requestWakeUp<Params extends EventParams>(
5
- event: WorkflowEvent<Params>,
6
- resumeIn?: number
7
- ): Promise<void>;
8
- }