@yieldstar/core 0.1.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.js ADDED
@@ -0,0 +1,151 @@
1
+ // @bun
2
+ // src/base/step.ts
3
+ class StepResponse {
4
+ }
5
+
6
+ class StepKey extends StepResponse {
7
+ static type = "step-key";
8
+ type = "step-key";
9
+ key;
10
+ constructor(key) {
11
+ super();
12
+ this.key = key;
13
+ }
14
+ }
15
+
16
+ class StepCacheCheck extends StepResponse {
17
+ static type = "cache-check";
18
+ type = "cache-check";
19
+ }
20
+
21
+ class StepInvalid extends StepResponse {
22
+ static type = "step-invalid";
23
+ type = "step-invalid";
24
+ }
25
+
26
+ class StepResult extends StepResponse {
27
+ static type = "step-result";
28
+ type = "step-result";
29
+ result;
30
+ constructor(result) {
31
+ super();
32
+ this.result = result;
33
+ }
34
+ }
35
+
36
+ class WorkflowResult extends StepResponse {
37
+ static type = "workflow-result";
38
+ type = "workflow-result";
39
+ result;
40
+ constructor(result) {
41
+ super();
42
+ this.result = result;
43
+ }
44
+ }
45
+
46
+ class WorkflowDelay extends StepResponse {
47
+ static type = "workflow-delay";
48
+ type = "workflow-delay";
49
+ resumeIn;
50
+ constructor(resumeIn) {
51
+ super();
52
+ this.resumeIn = resumeIn;
53
+ }
54
+ }
55
+
56
+ class WorkflowRestart extends StepResponse {
57
+ static type = "workflow-restart";
58
+ type = "workflow-restart";
59
+ constructor() {
60
+ super();
61
+ }
62
+ }
63
+
64
+ class StepError extends StepResponse {
65
+ static type = "step-error";
66
+ type = "step-error";
67
+ err;
68
+ maxAttempts;
69
+ retryInterval;
70
+ backOffStrategy;
71
+ constructor(err, opts) {
72
+ super();
73
+ this.err = err;
74
+ this.maxAttempts = opts?.maxAttempts ? opts.maxAttempts : 1;
75
+ this.retryInterval = opts?.retryInterval ? opts.retryInterval : 60000;
76
+ this.backOffStrategy = opts?.backoffStrategy ? opts.backoffStrategy : "decay";
77
+ }
78
+ }
79
+
80
+ class StepDelay extends StepResponse {
81
+ static type = "step-delay";
82
+ type = "step-delay";
83
+ resumeIn;
84
+ constructor(resumeIn) {
85
+ super();
86
+ this.resumeIn = resumeIn;
87
+ }
88
+ }
89
+ // src/lib/workflow-runner.ts
90
+ class WorkflowRunner {
91
+ heapClient;
92
+ schedulerClient;
93
+ router;
94
+ constructor(params) {
95
+ this.heapClient = params.heapClient;
96
+ this.schedulerClient = params.schedulerClient;
97
+ this.router = params.router;
98
+ }
99
+ run = async (task) => {
100
+ const { workflowId, executionId } = task;
101
+ const workflow = this.router[workflowId];
102
+ if (!workflow) {
103
+ throw new Error(`No workflow registered for "${workflowId}"`);
104
+ }
105
+ try {
106
+ const response = await this.runWorkflows({ executionId, workflow });
107
+ switch (response.type) {
108
+ case "workflow-result":
109
+ return response;
110
+ case "workflow-delay":
111
+ this.schedulerClient.requestWakeUp({
112
+ workflowId,
113
+ executionId,
114
+ resumeIn: response.resumeIn
115
+ });
116
+ break;
117
+ }
118
+ } catch (err) {
119
+ throw err;
120
+ }
121
+ };
122
+ async runWorkflows(params) {
123
+ const { executionId, workflow } = params;
124
+ const workflowIterator = workflow({
125
+ heapClient: this.heapClient,
126
+ executionId
127
+ });
128
+ const iteratorResult = await workflowIterator.next();
129
+ const stageResponse = iteratorResult.value;
130
+ if (iteratorResult.done) {
131
+ return stageResponse;
132
+ }
133
+ if (stageResponse instanceof StepDelay) {
134
+ return new WorkflowDelay(stageResponse.resumeIn - Date.now());
135
+ }
136
+ throw new Error("Workflow runner critical error");
137
+ }
138
+ }
139
+ export {
140
+ WorkflowRunner,
141
+ WorkflowResult,
142
+ WorkflowRestart,
143
+ WorkflowDelay,
144
+ StepResult,
145
+ StepResponse,
146
+ StepKey,
147
+ StepInvalid,
148
+ StepError,
149
+ StepDelay,
150
+ StepCacheCheck
151
+ };
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@yieldstar/core",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "src/index.ts",
7
+ "scripts": {
8
+ "build": "bun build src/index.ts --outfile dist/index.js --target bun --packages=external"
9
+ },
10
+ "devDependencies": {
11
+ "@types/bun": "latest"
12
+ },
13
+ "peerDependencies": {
14
+ "typescript": "^5.0.0"
15
+ }
16
+ }
@@ -0,0 +1,18 @@
1
+ export type HeapRecord = {
2
+ stepResponseJson: string;
3
+ meta: { attempt: number; done: boolean };
4
+ };
5
+
6
+ export abstract class HeapClient {
7
+ abstract readStep(params: {
8
+ executionId: string;
9
+ stepKey: string;
10
+ }): Promise<HeapRecord | null>;
11
+ abstract writeStep(params: {
12
+ executionId: string;
13
+ stepKey: string;
14
+ stepAttempt: number;
15
+ stepDone: boolean;
16
+ stepResponseJson: string;
17
+ }): Promise<void>;
18
+ }
@@ -0,0 +1,7 @@
1
+ import type { EventEmitter } from "node:events";
2
+ import type { Task } from "./runtime";
3
+
4
+ export type WorkflowInvoker = {
5
+ workflowEndEmitter: EventEmitter;
6
+ execute(task: Task): Promise<void>;
7
+ };
@@ -0,0 +1,7 @@
1
+ import type { WorkflowResult } from "./step";
2
+
3
+ export type Task = { workflowId: string; executionId: string; params?: any };
4
+
5
+ export type TaskProcessor = <T = any>(
6
+ task: Task
7
+ ) => Promise<void | WorkflowResult<T>>;
@@ -0,0 +1,7 @@
1
+ export interface SchedulerClient {
2
+ requestWakeUp(params: {
3
+ workflowId: string;
4
+ executionId: string;
5
+ resumeIn: number;
6
+ }): Promise<void>;
7
+ }
@@ -0,0 +1,96 @@
1
+ export abstract class StepResponse {
2
+ abstract type: string;
3
+ }
4
+
5
+ export class StepKey extends StepResponse {
6
+ static type = "step-key";
7
+ readonly type = "step-key";
8
+ key: string | null;
9
+ constructor(key: string | null) {
10
+ super();
11
+ this.key = key;
12
+ }
13
+ }
14
+
15
+ export class StepCacheCheck extends StepResponse {
16
+ static type = "cache-check";
17
+ readonly type = "cache-check";
18
+ }
19
+
20
+ export class StepInvalid extends StepResponse {
21
+ static type = "step-invalid";
22
+ readonly type = "step-invalid";
23
+ }
24
+
25
+ export class StepResult extends StepResponse {
26
+ static type = "step-result";
27
+ readonly type = "step-result";
28
+ result: any;
29
+ constructor(result: any) {
30
+ super();
31
+ this.result = result;
32
+ }
33
+ }
34
+
35
+ export class WorkflowResult<T extends any> extends StepResponse {
36
+ static type = "workflow-result";
37
+ readonly type = "workflow-result";
38
+ result: T;
39
+ constructor(result: T) {
40
+ super();
41
+ this.result = result;
42
+ }
43
+ }
44
+
45
+ export class WorkflowDelay extends StepResponse {
46
+ static type = "workflow-delay";
47
+ readonly type = "workflow-delay";
48
+ resumeIn: number;
49
+ constructor(resumeIn: number) {
50
+ super();
51
+ this.resumeIn = resumeIn;
52
+ }
53
+ }
54
+
55
+ export class WorkflowRestart extends StepResponse {
56
+ static type = "workflow-restart";
57
+ readonly type = "workflow-restart";
58
+ constructor() {
59
+ super();
60
+ }
61
+ }
62
+
63
+ export class StepError extends StepResponse {
64
+ static type = "step-error";
65
+ readonly type = "step-error";
66
+ err: any;
67
+ maxAttempts: number;
68
+ retryInterval: number;
69
+ backOffStrategy: "linear" | "decay";
70
+ constructor(
71
+ err: any,
72
+ opts?: {
73
+ maxAttempts: number;
74
+ retryInterval?: number;
75
+ backoffStrategy?: "linear" | "decay";
76
+ }
77
+ ) {
78
+ super();
79
+ this.err = err;
80
+ this.maxAttempts = opts?.maxAttempts ? opts.maxAttempts : 1;
81
+ this.retryInterval = opts?.retryInterval ? opts.retryInterval : 60000;
82
+ this.backOffStrategy = opts?.backoffStrategy
83
+ ? opts.backoffStrategy
84
+ : "decay";
85
+ }
86
+ }
87
+
88
+ export class StepDelay extends StepResponse {
89
+ static type = "step-delay";
90
+ readonly type = "step-delay";
91
+ resumeIn: number;
92
+ constructor(resumeIn: number) {
93
+ super();
94
+ this.resumeIn = resumeIn;
95
+ }
96
+ }
@@ -0,0 +1,15 @@
1
+ import { HeapClient } from "./heap";
2
+ import { StepResponse, WorkflowResult } from "./step";
3
+
4
+ export type WorkflowGenerator<T = any> = (params: {
5
+ executionId: string;
6
+ heapClient: HeapClient;
7
+ }) => AsyncGenerator<StepResponse, WorkflowResult<T>, StepResponse>;
8
+
9
+ export type WorkflowGeneratorReturnType<CG> = CG extends WorkflowGenerator<
10
+ infer T
11
+ >
12
+ ? T
13
+ : never;
14
+
15
+ export type WorkflowRouter = Record<string, WorkflowGenerator>;
package/src/index.ts ADDED
@@ -0,0 +1,24 @@
1
+ export type { HeapClient, HeapRecord } from "./base/heap";
2
+ export type { WorkflowInvoker } from "./base/invoker";
3
+ export type { Task, TaskProcessor } from "./base/runtime";
4
+ export type { SchedulerClient } from "./base/scheduler";
5
+ export type {
6
+ WorkflowGenerator,
7
+ WorkflowGeneratorReturnType,
8
+ WorkflowRouter,
9
+ } from "./base/workflow";
10
+
11
+ export {
12
+ StepCacheCheck,
13
+ StepDelay,
14
+ StepError,
15
+ StepInvalid,
16
+ StepKey,
17
+ StepResponse,
18
+ StepResult,
19
+ WorkflowDelay,
20
+ WorkflowRestart,
21
+ WorkflowResult,
22
+ } from "./base/step";
23
+
24
+ export { WorkflowRunner } from "./lib/workflow-runner";
@@ -0,0 +1,79 @@
1
+ import type {
2
+ WorkflowGenerator,
3
+ HeapClient,
4
+ SchedulerClient,
5
+ TaskProcessor,
6
+ } from "..";
7
+ import { StepDelay, WorkflowDelay, WorkflowResult } from "..";
8
+
9
+ export class WorkflowRunner<
10
+ Router extends Record<string, WorkflowGenerator<any>>
11
+ > {
12
+ private heapClient: HeapClient;
13
+ private schedulerClient: SchedulerClient;
14
+ private router: Router;
15
+
16
+ constructor(params: {
17
+ heapClient: HeapClient;
18
+ schedulerClient: SchedulerClient;
19
+ router: Router;
20
+ }) {
21
+ this.heapClient = params.heapClient;
22
+ this.schedulerClient = params.schedulerClient;
23
+ this.router = params.router;
24
+ }
25
+
26
+ run: TaskProcessor = async (task) => {
27
+ const { workflowId, executionId } = task;
28
+ const workflow = this.router[workflowId];
29
+
30
+ if (!workflow) {
31
+ throw new Error(`No workflow registered for "${workflowId}"`);
32
+ }
33
+
34
+ try {
35
+ const response = await this.runWorkflows({ executionId, workflow });
36
+
37
+ switch (response.type) {
38
+ case "workflow-result":
39
+ return response;
40
+
41
+ case "workflow-delay":
42
+ this.schedulerClient.requestWakeUp({
43
+ workflowId,
44
+ executionId,
45
+ resumeIn: response.resumeIn,
46
+ });
47
+ break;
48
+ }
49
+ } catch (err) {
50
+ // todo: distinguish between a workflow error and a system error
51
+ throw err;
52
+ }
53
+ };
54
+
55
+ private async runWorkflows<T>(params: {
56
+ executionId: string;
57
+ workflow: WorkflowGenerator<T>;
58
+ }): Promise<WorkflowResult<T> | WorkflowDelay> {
59
+ const { executionId, workflow } = params;
60
+
61
+ const workflowIterator = workflow({
62
+ heapClient: this.heapClient,
63
+ executionId,
64
+ });
65
+
66
+ const iteratorResult = await workflowIterator.next();
67
+ const stageResponse = iteratorResult.value;
68
+
69
+ if (iteratorResult.done) {
70
+ return stageResponse as WorkflowResult<T>;
71
+ }
72
+
73
+ if (stageResponse instanceof StepDelay) {
74
+ return new WorkflowDelay(stageResponse.resumeIn - Date.now());
75
+ }
76
+
77
+ throw new Error("Workflow runner critical error");
78
+ }
79
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Enable latest features
4
+ "lib": ["ESNext"],
5
+ "target": "ESNext",
6
+ "module": "ESNext",
7
+ "moduleDetection": "force",
8
+ "allowJs": true,
9
+
10
+ // Bundler mode
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "noEmit": true,
15
+
16
+ // Best practices
17
+ "strict": true,
18
+ "skipLibCheck": true,
19
+ "noFallthroughCasesInSwitch": true,
20
+
21
+ // Some stricter flags (disabled by default)
22
+ "noUnusedLocals": false,
23
+ "noUnusedParameters": false,
24
+ "noPropertyAccessFromIndexSignature": false
25
+ }
26
+ }