yieldstar 0.5.0 → 0.6.1
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 +43 -52
- package/dist/exports/errors.d.ts.map +1 -1
- package/dist/exports/sdk-http.d.ts +8 -0
- package/dist/exports/sdk-http.d.ts.map +1 -1
- package/dist/exports/sdk-local.d.ts +19 -2
- package/dist/exports/sdk-local.d.ts.map +1 -1
- package/dist/exports/workflow.d.ts +14 -2
- package/dist/exports/workflow.d.ts.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +664 -214
- package/dist/internal/effect-call.d.ts +60 -0
- package/dist/internal/effect-call.d.ts.map +1 -0
- package/dist/internal/runtime-call.d.ts +39 -0
- package/dist/internal/runtime-call.d.ts.map +1 -0
- package/dist/internal/serialise.d.ts.map +1 -1
- package/dist/internal/step-record.d.ts +13 -0
- package/dist/internal/step-record.d.ts.map +1 -0
- package/dist/internal/step-runner.d.ts +77 -14
- package/dist/internal/step-runner.d.ts.map +1 -1
- package/package.json +2 -3
- package/src/exports/errors.ts +4 -0
- package/src/exports/sdk-http.ts +60 -27
- package/src/exports/sdk-local.ts +41 -15
- package/src/exports/workflow.ts +157 -101
- package/src/index.ts +34 -2
- package/src/internal/effect-call.ts +217 -0
- package/src/internal/runtime-call.ts +95 -0
- package/src/internal/step-record.ts +110 -0
- package/src/internal/step-runner.ts +515 -191
- package/src/internal/serialise.ts +0 -47
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Logger } from "pino";
|
|
2
|
+
import { StepResponse, type DurableObject, type DurableValue, type EffectClient } from "@yieldstar/core";
|
|
3
|
+
/** What `lookup` reports about an effect ID (RFC 005). */
|
|
4
|
+
export type EffectLookup<T> = {
|
|
5
|
+
status: "settled";
|
|
6
|
+
result: T;
|
|
7
|
+
} | {
|
|
8
|
+
status: "not-found";
|
|
9
|
+
} | {
|
|
10
|
+
status: "unknown";
|
|
11
|
+
};
|
|
12
|
+
/** The effect request a step yields once its descriptor is valid. */
|
|
13
|
+
export type EffectCallRequest = {
|
|
14
|
+
stepKey: string;
|
|
15
|
+
effectId: string;
|
|
16
|
+
operation: string;
|
|
17
|
+
input: DurableObject;
|
|
18
|
+
retryIn: number;
|
|
19
|
+
lookup(effectId: string): Promise<unknown>;
|
|
20
|
+
perform(effectId: string): Promise<unknown>;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* - `settled`: the effect's result, which the step records.
|
|
24
|
+
* - `rejected`: the effect exists with a different operation or input.
|
|
25
|
+
* - `suspended`: the step watches the effect and is due again at `wakeAt`.
|
|
26
|
+
*/
|
|
27
|
+
export type EffectCallOutcome = {
|
|
28
|
+
status: "settled";
|
|
29
|
+
result: DurableValue;
|
|
30
|
+
} | {
|
|
31
|
+
status: "rejected";
|
|
32
|
+
code: "EFFECT_REQUEST_MISMATCH";
|
|
33
|
+
} | {
|
|
34
|
+
status: "suspended";
|
|
35
|
+
wakeAt: number;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Yielded by `step.effect`. The driver runs the effect with
|
|
39
|
+
* `executeEffectCall` and resumes the step with its outcome.
|
|
40
|
+
*/
|
|
41
|
+
export declare class StepEffectCall extends StepResponse {
|
|
42
|
+
static type: string;
|
|
43
|
+
readonly type = "effect-call";
|
|
44
|
+
readonly request: EffectCallRequest;
|
|
45
|
+
constructor(request: EffectCallRequest);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Runs an effect step's protocol against the runtime's `EffectClient`. Every
|
|
49
|
+
* failure that must not be recorded rejects with an `InfrastructureError`
|
|
50
|
+
* whose cause is an `EffectDeliveryError`, so the delivery is retried.
|
|
51
|
+
*/
|
|
52
|
+
export declare function executeEffectCall(request: EffectCallRequest, context: {
|
|
53
|
+
effects: EffectClient;
|
|
54
|
+
executionId: string;
|
|
55
|
+
clock: () => number;
|
|
56
|
+
/** Checked before every callback, so a lost lease makes no external call. */
|
|
57
|
+
assertLease: () => void;
|
|
58
|
+
logger: Logger;
|
|
59
|
+
}): Promise<EffectCallOutcome>;
|
|
60
|
+
//# sourceMappingURL=effect-call.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect-call.d.ts","sourceRoot":"","sources":["../../src/internal/effect-call.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAIL,YAAY,EAEZ,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,EAElB,MAAM,iBAAiB,CAAC;AAEzB,0DAA0D;AAC1D,MAAM,MAAM,YAAY,CAAC,CAAC,IACtB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,CAAC,CAAA;CAAE,GAChC;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAE1B,qEAAqE;AACrE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GAC3C;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,yBAAyB,CAAA;CAAE,GACvD;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5C;;;GAGG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,MAAM,CAAC,IAAI,SAAiB;IAC5B,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;gBAExB,OAAO,EAAE,iBAAiB;CAIvC;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE;IACP,OAAO,EAAE,YAAY,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,MAAM,CAAC;IACpB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC,iBAAiB,CAAC,CAqH5B"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { StepResponse, type ExecutionClient, type StoreClient } from "@yieldstar/core";
|
|
2
|
+
export type RuntimeClients = {
|
|
3
|
+
stores: StoreClient;
|
|
4
|
+
executions: ExecutionClient;
|
|
5
|
+
};
|
|
6
|
+
export type RuntimeCallResult<T> = {
|
|
7
|
+
ok: true;
|
|
8
|
+
value: T;
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
error: unknown;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Yielded by a step that needs a runtime client. Steps never call runtime
|
|
15
|
+
* clients themselves: the driver makes the call outside workflow code and
|
|
16
|
+
* resumes the step with a `RuntimeCallResult`. Only failures that belong to
|
|
17
|
+
* workflow code (see `isWorkflowFacingError`) resume the step; any other
|
|
18
|
+
* failure is an infrastructure error and ends the delivery without an outcome.
|
|
19
|
+
*/
|
|
20
|
+
export declare class StepRuntimeCall<T = unknown> extends StepResponse {
|
|
21
|
+
static type: string;
|
|
22
|
+
readonly type = "runtime-call";
|
|
23
|
+
readonly call: (clients: RuntimeClients) => Promise<T>;
|
|
24
|
+
constructor(call: (clients: RuntimeClients) => Promise<T>);
|
|
25
|
+
}
|
|
26
|
+
/** Marks an error thrown by a workflow-supplied callback run by a client. */
|
|
27
|
+
export declare class StepCallbackError extends Error {
|
|
28
|
+
constructor(cause: unknown);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Wraps a workflow-supplied callback (updater, selector, claim, initial state)
|
|
32
|
+
* that a runtime client will run, so its errors reach workflow code rather
|
|
33
|
+
* than being mistaken for infrastructure errors.
|
|
34
|
+
*/
|
|
35
|
+
export declare function workflowCallback<A extends unknown[], R>(fn: (...args: A) => R, assertResult?: (result: R) => void): (...args: A) => R;
|
|
36
|
+
export declare function executeRuntimeCall<T>(request: StepRuntimeCall<T>, clients: RuntimeClients): Promise<RuntimeCallResult<T>>;
|
|
37
|
+
/** Runs a heap operation, tagging its failure as an infrastructure error. */
|
|
38
|
+
export declare function infrastructure<T>(fn: () => Promise<T>): Promise<T>;
|
|
39
|
+
//# sourceMappingURL=runtime-call.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-call.d.ts","sourceRoot":"","sources":["../../src/internal/runtime-call.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EAGZ,KAAK,eAAe,EACpB,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,eAAe,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAC3B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACtB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAElC;;;;;;GAMG;AACH,qBAAa,eAAe,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,YAAY;IAC5D,MAAM,CAAC,IAAI,SAAkB;IAC7B,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;gBAE3C,IAAI,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC;CAI1D;AAED,6EAA6E;AAC7E,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,KAAK,EAAE,OAAO;CAI3B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC,EACrD,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,EACrB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,GACjC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,CAUnB;AAED,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,EAC3B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAS/B;AAWD,6EAA6E;AAC7E,wBAAsB,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAMxE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialise.d.ts","sourceRoot":"","sources":["../../src/internal/serialise.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,YAAY,
|
|
1
|
+
{"version":3,"file":"serialise.d.ts","sourceRoot":"","sources":["../../src/internal/serialise.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,YAAY,EAIb,MAAM,iBAAiB,CAAC;AAGzB,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAShE;AAED,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAyBxE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StepResponse } from "@yieldstar/core";
|
|
2
|
+
/**
|
|
3
|
+
* Encodes a step response for its step record, and returns the response that
|
|
4
|
+
* workflow code must see: the record decoded again, so that a first run sees
|
|
5
|
+
* exactly what replay reads. A result the codec rejects is recorded as a step
|
|
6
|
+
* error with `WorkflowValueError` (`INVALID_STEP_VALUE`).
|
|
7
|
+
*/
|
|
8
|
+
export declare function encodeStepRecord(response: StepResponse, stepKey: string): {
|
|
9
|
+
json: string;
|
|
10
|
+
response: StepResponse;
|
|
11
|
+
};
|
|
12
|
+
export declare function decodeStepRecord(json: string): StepResponse;
|
|
13
|
+
//# sourceMappingURL=step-record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step-record.d.ts","sourceRoot":"","sources":["../../src/internal/step-record.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,YAAY,EAOb,MAAM,iBAAiB,CAAC;AAEzB;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,MAAM,GACd;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,CAAA;CAAE,CAG1C;AA8CD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAmC3D"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { defineStore, type Draft, type StandardSchemaV1, StepResponse, StepError, StepResult, type
|
|
1
|
+
import { defineStore, type Draft, type DurableObject, type DurableStoreSchema, type IfDurable, type StandardSchemaV1, StepResponse, StepError, StepResult, type StoreDefinition, type StoreDeleteFromResult, type StoreKey, type StoreSelector, type StoreSnapshot, type StoreState, type StoreUpdateFromResult, type StoreUpdateResult, type Durable } from "@yieldstar/core";
|
|
2
2
|
import type { WorkflowEvent } from "@yieldstar/core";
|
|
3
|
+
import { type EffectLookup } from "./effect-call";
|
|
4
|
+
export type { EffectLookup };
|
|
3
5
|
/**
|
|
4
6
|
* @description A library of step generators, each of which:
|
|
5
7
|
* @yields a StepResponse to workflow consumers
|
|
@@ -14,31 +16,92 @@ export type WorkflowStore<T> = {
|
|
|
14
16
|
readonly id: string;
|
|
15
17
|
readonly key: StoreKey;
|
|
16
18
|
get(key?: string): AsyncGenerator<StepResponse, StoreSnapshot<T>>;
|
|
17
|
-
select<R>(key: string, selector: StoreSelector<T, R>): AsyncGenerator<StepResponse, R>;
|
|
19
|
+
select<R>(key: string, selector: StoreSelector<T, R> & DurableSelector<T, R>): AsyncGenerator<StepResponse, R>;
|
|
18
20
|
update(key: string, updater: (draft: Draft<T>) => void | T): AsyncGenerator<StepResponse, StoreUpdateResult<T>>;
|
|
19
21
|
updateFrom(key: string, snapshot: StoreSnapshot<T>, updater: (draft: Draft<T>) => void | T): AsyncGenerator<StepResponse, StoreUpdateFromResult<T>>;
|
|
20
22
|
deleteFrom(key: string, snapshot: StoreSnapshot<T>): AsyncGenerator<StepResponse, StoreDeleteFromResult>;
|
|
21
|
-
when<R>(selector: StoreSelector<T, R | undefined | null | false>): AsyncGenerator<StepResponse, NonNullable<R>>;
|
|
22
|
-
when<R>(key: string, selector: StoreSelector<T, R | undefined | null | false>): AsyncGenerator<StepResponse, NonNullable<R>>;
|
|
23
|
-
take<R>(key: string, selector: StoreSelector<T, R | undefined | null | false>, claim: (draft: Draft<T>, selected: NonNullable<R>) => void): AsyncGenerator<StepResponse, NonNullable<R>>;
|
|
23
|
+
when<R>(selector: StoreSelector<T, R | undefined | null | false> & DurableMatchSelector<T, R>): AsyncGenerator<StepResponse, NonNullable<R>>;
|
|
24
|
+
when<R>(key: string, selector: StoreSelector<T, R | undefined | null | false> & DurableMatchSelector<T, R>): AsyncGenerator<StepResponse, NonNullable<R>>;
|
|
25
|
+
take<R>(key: string, selector: StoreSelector<T, R | undefined | null | false> & DurableMatchSelector<T, R>, claim: (draft: Draft<T>, selected: NonNullable<R>) => void): AsyncGenerator<StepResponse, NonNullable<R>>;
|
|
24
26
|
};
|
|
27
|
+
/** A store selector whose result, which the step records, is durable. */
|
|
28
|
+
type DurableSelector<T, R> = IfDurable<R, StoreSelector<T, Durable<R>>>;
|
|
29
|
+
/**
|
|
30
|
+
* A `when` or `take` selector whose match is durable. `false` is excluded
|
|
31
|
+
* before the check so that `R` is inferred as it would be without it.
|
|
32
|
+
*/
|
|
33
|
+
type DurableMatchSelector<T, R> = IfDurable<Exclude<R, false>, StoreSelector<T, Durable<Exclude<R, false>> | undefined | null | false>>;
|
|
25
34
|
export type StepRunner = ReturnType<typeof createStepRunner>;
|
|
26
35
|
export declare function createStepRunner(params: {
|
|
27
36
|
event: WorkflowEvent;
|
|
28
|
-
|
|
37
|
+
clock: () => number;
|
|
29
38
|
}): {
|
|
30
39
|
run: typeof run;
|
|
31
|
-
delay:
|
|
40
|
+
delay: {
|
|
41
|
+
(retryInterval: number): any;
|
|
42
|
+
(key: string, retryInterval: number): any;
|
|
43
|
+
};
|
|
32
44
|
poll: typeof poll;
|
|
33
|
-
store: <Schema extends StandardSchemaV1>(definition: StoreDefinition<Schema
|
|
45
|
+
store: <Schema extends StandardSchemaV1>(definition: StoreDefinition<Schema> & {
|
|
46
|
+
schema: DurableStoreSchema<Schema>;
|
|
47
|
+
}, params?: {
|
|
34
48
|
id?: string;
|
|
35
|
-
|
|
36
|
-
|
|
49
|
+
}) => WorkflowStore<StoreState<Schema>>;
|
|
50
|
+
start: <Params extends Record<string, any>>(stepKey: string, target: {
|
|
51
|
+
workflowId: string;
|
|
52
|
+
params?: Params & Durable<Params>;
|
|
53
|
+
}) => AsyncGenerator<StepResponse, {
|
|
54
|
+
executionId: string;
|
|
55
|
+
}, StepResult | StepError>;
|
|
56
|
+
effect: <T, Input extends Record<string, any> = DurableObject>(stepKey: string, descriptor: EffectDescriptor<T, Input> & DurableEffectResult<T>) => AsyncGenerator<StepResponse, T, StepResult | StepError>;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Describes one external operation for `step.effect`. `effectId` names the
|
|
60
|
+
* operation in the external system, so every caller that means it, in any
|
|
61
|
+
* execution or runtime, uses the same ID, and no caller reuses it for another
|
|
62
|
+
* operation. The external system must guarantee that repeated `perform` calls
|
|
63
|
+
* for one ID make one operation with one result, that `not-found` proves no
|
|
64
|
+
* call exists or can still finish, and that `settled` never changes.
|
|
65
|
+
*/
|
|
66
|
+
export type EffectDescriptor<T, Input = DurableObject> = {
|
|
67
|
+
effectId: string;
|
|
68
|
+
/** Names the version of the behaviour of `input`, `lookup` and `perform`. */
|
|
69
|
+
operation: string;
|
|
70
|
+
input: Input & Durable<Input>;
|
|
71
|
+
/** Milliseconds before an uncertain outcome is looked up again. */
|
|
72
|
+
retryIn: number;
|
|
73
|
+
/** Reports what the external system knows about `effectId`. */
|
|
74
|
+
lookup(effectId: string): Promise<EffectLookup<T>>;
|
|
75
|
+
/** Performs the operation under `effectId`. */
|
|
76
|
+
perform(effectId: string): Promise<T>;
|
|
37
77
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Checks the effect's result type without taking part in its inference. A
|
|
80
|
+
* `perform` that resolves with nothing settles the effect with `undefined`.
|
|
81
|
+
*/
|
|
82
|
+
type DurableEffectResult<T> = [T] extends [void] ? unknown : IfDurable<T, {
|
|
83
|
+
perform(effectId: string): Promise<Durable<T>>;
|
|
84
|
+
}>;
|
|
85
|
+
export type StepRunOptions<S extends StandardSchemaV1> = {
|
|
86
|
+
/**
|
|
87
|
+
* Validates the step's decoded value, on the first run and on every
|
|
88
|
+
* replay; the step returns the schema's output. The step function must
|
|
89
|
+
* return the schema's input as a durable value.
|
|
90
|
+
*/
|
|
91
|
+
schema: S;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* A step function whose result, or the value its promise resolves to, is a
|
|
95
|
+
* durable value. Checking the whole function type keeps the result's type as
|
|
96
|
+
* TypeScript infers it, and names the offending property in the error.
|
|
97
|
+
*/
|
|
98
|
+
export type DurableStepFn<F> = F extends () => infer R ? () => R extends PromiseLike<infer U> ? PromiseLike<DurableUnion<U>> : DurableUnion<R> : never;
|
|
99
|
+
type DurableUnion<T> = T extends unknown ? Durable<T> : never;
|
|
100
|
+
declare function run<F extends () => unknown>(fn: F & DurableStepFn<F>): AsyncGenerator<StepResponse, Awaited<ReturnType<F>>, StepResponse>;
|
|
101
|
+
declare function run<F extends () => unknown>(key: string, fn: F & DurableStepFn<F>): AsyncGenerator<StepResponse, Awaited<ReturnType<F>>, StepResponse>;
|
|
102
|
+
declare function run<S extends StandardSchemaV1>(fn: () => StepSchemaInput<S> | PromiseLike<StepSchemaInput<S>>, options: StepRunOptions<S>): AsyncGenerator<StepResponse, StandardSchemaV1.InferOutput<S>, StepResponse>;
|
|
103
|
+
declare function run<S extends StandardSchemaV1>(key: string, fn: () => StepSchemaInput<S> | PromiseLike<StepSchemaInput<S>>, options: StepRunOptions<S>): AsyncGenerator<StepResponse, StandardSchemaV1.InferOutput<S>, StepResponse>;
|
|
104
|
+
type StepSchemaInput<S extends StandardSchemaV1> = Durable<StandardSchemaV1.InferInput<S>>;
|
|
42
105
|
type PollOpts = {
|
|
43
106
|
maxAttempts: number;
|
|
44
107
|
retryInterval: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step-runner.d.ts","sourceRoot":"","sources":["../../src/internal/step-runner.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"step-runner.d.ts","sourceRoot":"","sources":["../../src/internal/step-runner.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yieldstar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Daniel Grant",
|
|
6
6
|
"repository": {
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"nanoid": "^5.1.5",
|
|
16
16
|
"pino": "^9.9.0",
|
|
17
|
-
"
|
|
18
|
-
"@yieldstar/core": "0.5.0"
|
|
17
|
+
"@yieldstar/core": "0.6.1"
|
|
19
18
|
},
|
|
20
19
|
"devDependencies": {
|
|
21
20
|
"@types/node": "^22.18.0"
|
package/src/exports/errors.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { registerErrorClass } from "@yieldstar/core";
|
|
2
|
+
|
|
1
3
|
export class RetryableError extends Error {
|
|
2
4
|
maxAttempts: number;
|
|
3
5
|
retryInterval: number;
|
|
@@ -11,3 +13,5 @@ export class RetryableError extends Error {
|
|
|
11
13
|
this.retryInterval = opts.retryInterval;
|
|
12
14
|
}
|
|
13
15
|
}
|
|
16
|
+
|
|
17
|
+
registerErrorClass("RetryableError", RetryableError);
|
package/src/exports/sdk-http.ts
CHANGED
|
@@ -2,12 +2,13 @@ import type {
|
|
|
2
2
|
EventParamsOf,
|
|
3
3
|
WorkflowRouter,
|
|
4
4
|
TriggerEvent,
|
|
5
|
-
ExecutionEvent,
|
|
6
5
|
WorkflowGeneratorReturnType,
|
|
6
|
+
ExecutionAdmissionErrorCode,
|
|
7
|
+
} from "@yieldstar/core";
|
|
8
|
+
import {
|
|
9
|
+
ExecutionAdmissionError,
|
|
10
|
+
durableValueCodec,
|
|
7
11
|
} from "@yieldstar/core";
|
|
8
|
-
import { nanoid } from "nanoid";
|
|
9
|
-
import { deserializeError } from "serialize-error";
|
|
10
|
-
import { errorWithOriginalStack } from "@yieldstar/core";
|
|
11
12
|
|
|
12
13
|
type TriggerAck = {
|
|
13
14
|
executionId: string;
|
|
@@ -19,60 +20,92 @@ type TriggerResponse<W extends WorkflowRouter, K extends string & keyof W> = {
|
|
|
19
20
|
waitForResult: () => Promise<WorkflowGeneratorReturnType<W[K]>>;
|
|
20
21
|
};
|
|
21
22
|
|
|
23
|
+
const admissionErrorCodes: ExecutionAdmissionErrorCode[] = [
|
|
24
|
+
"EXECUTION_ID_CONFLICT",
|
|
25
|
+
"INVALID_EXECUTION_EVENT",
|
|
26
|
+
];
|
|
27
|
+
|
|
22
28
|
export function createHttpSdkFactory<W extends WorkflowRouter>() {
|
|
23
29
|
return (params: {
|
|
24
30
|
url: string;
|
|
25
31
|
fetchOptions?: Omit<RequestInit, "body" | "method">;
|
|
26
32
|
}) => {
|
|
27
33
|
return {
|
|
34
|
+
/**
|
|
35
|
+
* Admits an execution through the trigger route. When `executionId` is
|
|
36
|
+
* omitted the runtime chooses one, which the response carries. The body
|
|
37
|
+
* is encoded with the durable value codec, so params and context reach
|
|
38
|
+
* the runtime unchanged.
|
|
39
|
+
* @throws {ExecutionAdmissionError} on `409 Conflict` or an invalid event,
|
|
40
|
+
* including params or context the codec rejects, before any request
|
|
41
|
+
*/
|
|
28
42
|
async trigger<K extends string & keyof W>(
|
|
29
43
|
event: TriggerEvent<K, EventParamsOf<W[K]>>
|
|
30
44
|
): Promise<TriggerResponse<W, K>> {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
const request: Record<string, unknown> = { workflowId: event?.workflowId };
|
|
46
|
+
if (event?.executionId !== undefined) request.executionId = event.executionId;
|
|
47
|
+
if (event && "params" in event) request.params = event.params;
|
|
48
|
+
if (event?.context !== undefined) request.context = event.context;
|
|
49
|
+
const encoding = durableValueCodec.encode(request);
|
|
50
|
+
if (encoding.status === "invalid") {
|
|
51
|
+
throw new ExecutionAdmissionError(
|
|
52
|
+
"INVALID_EXECUTION_EVENT",
|
|
53
|
+
`Event cannot be stored without loss: ${encoding.message}`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
38
56
|
const res = await fetch(`${params.url}/trigger`, {
|
|
39
57
|
...params.fetchOptions,
|
|
40
58
|
method: "POST",
|
|
41
|
-
|
|
59
|
+
headers: { "content-type": "application/json" },
|
|
60
|
+
body: encoding.canonical,
|
|
42
61
|
});
|
|
43
62
|
|
|
44
63
|
if (res.ok) {
|
|
64
|
+
const ack = (await res.json()) as TriggerAck;
|
|
45
65
|
return {
|
|
46
|
-
executionId:
|
|
47
|
-
ack: () =>
|
|
48
|
-
waitForResult: () =>
|
|
49
|
-
this.waitForResult<K>({
|
|
50
|
-
executionId: executionEvent.executionId,
|
|
51
|
-
}),
|
|
66
|
+
executionId: ack.executionId,
|
|
67
|
+
ack: async () => ack,
|
|
68
|
+
waitForResult: () => this.waitForResult<K>(ack),
|
|
52
69
|
};
|
|
53
|
-
} else {
|
|
54
|
-
throw res.statusText;
|
|
55
70
|
}
|
|
71
|
+
|
|
72
|
+
const body = (await res.json().catch(() => undefined)) as
|
|
73
|
+
| { code?: ExecutionAdmissionErrorCode; message?: string }
|
|
74
|
+
| undefined;
|
|
75
|
+
if (body?.code && admissionErrorCodes.includes(body.code)) {
|
|
76
|
+
throw new ExecutionAdmissionError(body.code, body.message ?? res.statusText);
|
|
77
|
+
}
|
|
78
|
+
throw res.statusText;
|
|
56
79
|
},
|
|
57
80
|
async waitForResult<K extends string & keyof W>(
|
|
58
81
|
ack: TriggerAck
|
|
59
82
|
): Promise<WorkflowGeneratorReturnType<W[K]>> {
|
|
60
|
-
// todo: set up subscription first (maybe just use ws)
|
|
61
83
|
const res = await fetch(`${params.url}/events`, {
|
|
62
84
|
method: "POST",
|
|
63
85
|
body: JSON.stringify({ executionId: ack.executionId }),
|
|
64
86
|
...params.fetchOptions,
|
|
65
87
|
});
|
|
66
88
|
|
|
89
|
+
if (res.status !== 500 && !res.ok) {
|
|
90
|
+
throw res.statusText;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const decoding = durableValueCodec.decode(await res.text());
|
|
94
|
+
if (decoding.status === "invalid") {
|
|
95
|
+
throw new Error(`Invalid workflow outcome: ${decoding.message}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
67
98
|
if (res.status === 500) {
|
|
68
|
-
const error =
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
99
|
+
const error =
|
|
100
|
+
decoding.value instanceof Error
|
|
101
|
+
? decoding.value
|
|
102
|
+
: new Error(String(decoding.value));
|
|
103
|
+
// Thrown as revived, so it keeps its registered class and the
|
|
104
|
+
// stack recorded where it was first thrown.
|
|
105
|
+
throw error;
|
|
73
106
|
}
|
|
74
107
|
|
|
75
|
-
return
|
|
108
|
+
return decoding.value as WorkflowGeneratorReturnType<W[K]>;
|
|
76
109
|
},
|
|
77
110
|
};
|
|
78
111
|
};
|
package/src/exports/sdk-local.ts
CHANGED
|
@@ -1,43 +1,69 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
EventParamsOf,
|
|
3
|
+
ExecutionClient,
|
|
3
4
|
WorkflowRouter,
|
|
4
5
|
WorkflowInvoker,
|
|
5
6
|
TriggerEvent,
|
|
6
|
-
ExecutionEvent,
|
|
7
7
|
WorkflowGeneratorReturnType,
|
|
8
8
|
} from "@yieldstar/core";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
ExecutionAdmissionError,
|
|
11
|
+
waitForExecutionOutcome,
|
|
12
|
+
} from "@yieldstar/core";
|
|
10
13
|
|
|
11
14
|
type TriggerAck = {
|
|
12
15
|
executionId: string;
|
|
13
16
|
};
|
|
14
17
|
|
|
15
18
|
export function createLocalSdk<W extends WorkflowRouter>(
|
|
16
|
-
|
|
19
|
+
runtime: { executions: ExecutionClient },
|
|
20
|
+
options?: {
|
|
21
|
+
/** Lets `triggerAndWait` settle as soon as the dispatcher acknowledges. */
|
|
22
|
+
invoker?: WorkflowInvoker;
|
|
23
|
+
/** Milliseconds between reads of the execution record. @default 25 */
|
|
24
|
+
pollInterval?: number;
|
|
25
|
+
}
|
|
17
26
|
) {
|
|
27
|
+
const { executions } = runtime;
|
|
28
|
+
|
|
18
29
|
return {
|
|
30
|
+
/**
|
|
31
|
+
* Admits an execution and resolves once admission commits. A dispatcher
|
|
32
|
+
* delivers it; this does not wait for a worker to start.
|
|
33
|
+
* @throws {ExecutionAdmissionError} when the ID is already in use or the
|
|
34
|
+
* event cannot be stored without loss
|
|
35
|
+
*/
|
|
19
36
|
async trigger<K extends string & keyof W>(
|
|
20
37
|
event: TriggerEvent<K, EventParamsOf<W[K]>>
|
|
21
38
|
): Promise<TriggerAck> {
|
|
22
|
-
const
|
|
23
|
-
executionId: event.executionId
|
|
39
|
+
const admission = await executions.admit({
|
|
40
|
+
executionId: event.executionId,
|
|
24
41
|
workflowId: event.workflowId,
|
|
25
42
|
params: event.params,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
context: new Map(Object.entries(event.context ?? {})),
|
|
44
|
+
});
|
|
45
|
+
if (admission.status === "rejected") {
|
|
46
|
+
throw new ExecutionAdmissionError(admission.code, admission.message);
|
|
47
|
+
}
|
|
48
|
+
return { executionId: admission.executionId };
|
|
29
49
|
},
|
|
50
|
+
/**
|
|
51
|
+
* Admits an execution and waits for its record to reach a terminal
|
|
52
|
+
* status. Resolves with the result, or rejects with the recorded error.
|
|
53
|
+
*/
|
|
30
54
|
async triggerAndWait<K extends string & keyof W>(
|
|
31
55
|
event: TriggerEvent<K, EventParamsOf<W[K]>>
|
|
32
56
|
): Promise<WorkflowGeneratorReturnType<W[K]>> {
|
|
33
|
-
const executionId =
|
|
34
|
-
const
|
|
35
|
-
invoker
|
|
57
|
+
const { executionId } = await this.trigger(event);
|
|
58
|
+
const outcome = await waitForExecutionOutcome(executions, executionId, {
|
|
59
|
+
emitter: options?.invoker?.workflowEndEmitter,
|
|
60
|
+
pollInterval: options?.pollInterval,
|
|
36
61
|
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
62
|
+
if (!outcome) {
|
|
63
|
+
throw new Error(`Execution "${executionId}" has no record`);
|
|
64
|
+
}
|
|
65
|
+
if (outcome.status === "failed") throw outcome.error;
|
|
66
|
+
return outcome.result as WorkflowGeneratorReturnType<W[K]>;
|
|
41
67
|
},
|
|
42
68
|
};
|
|
43
69
|
}
|