effect-inngest 0.3.0-beta.4 → 0.4.0-beta2
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 +69 -75
- package/dist/Client.js +1 -1
- package/dist/Cron.d.ts +17 -0
- package/dist/Cron.js +24 -0
- package/dist/Events.d.ts +1 -1
- package/dist/Events.js +1 -1
- package/dist/Function.d.ts +28 -26
- package/dist/Function.js +19 -11
- package/dist/Group.d.ts +8 -8
- package/dist/Group.js +1 -0
- package/dist/HttpApi.d.ts +3 -3
- package/dist/Inngest.d.ts +60 -0
- package/dist/Inngest.js +61 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4 -2
- package/dist/internal/codec/StepResult.js +2 -12
- package/dist/internal/driver.js +1 -0
- package/dist/internal/execution/HandlerRun.js +2 -1
- package/dist/internal/runtime/HandlerContext.d.ts +0 -2
- package/dist/internal/runtime/HandlerContext.js +0 -3
- package/dist/internal/runtime/StepTools.d.ts +8 -16
- package/dist/internal/runtime/StepTools.js +2 -8
- package/dist/internal/runtime/steps/InvokeStep.js +1 -2
- package/dist/internal/runtime/steps/StepRun.js +25 -19
- package/dist/internal/utils/safe-stringify.js +50 -0
- package/package.json +17 -1
- package/src/Client.ts +1 -1
- package/src/Cron.ts +33 -0
- package/src/Events.ts +1 -1
- package/src/Function.ts +62 -34
- package/src/Group.ts +10 -7
- package/src/Inngest.ts +85 -0
- package/src/index.ts +21 -7
- package/src/internal/codec/StepResult.ts +1 -43
- package/src/internal/driver.ts +13 -2
- package/src/internal/execution/HandlerRun.ts +3 -2
- package/src/internal/runtime/HandlerContext.ts +2 -5
- package/src/internal/runtime/StepTools.ts +4 -31
- package/src/internal/runtime/steps/InvokeStep.ts +1 -4
- package/src/internal/runtime/steps/StepRun.ts +28 -44
- package/src/internal/utils/safe-stringify.ts +84 -0
package/dist/Group.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { InngestClient } from "./Client.js";
|
|
2
2
|
import { InngestFunction } from "./Function.js";
|
|
3
3
|
import { HandlerContext } from "./internal/runtime/HandlerContext.js";
|
|
4
|
+
import { StepTools } from "./internal/runtime/StepTools.js";
|
|
4
5
|
import { Context, Effect, Layer } from "effect";
|
|
5
6
|
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
6
7
|
import * as _$effect_unstable_http_HttpServerRequest0 from "effect/unstable/http/HttpServerRequest";
|
|
@@ -24,7 +25,7 @@ type TypeId = typeof TypeId;
|
|
|
24
25
|
* @since 0.1.0
|
|
25
26
|
* @category models
|
|
26
27
|
*/
|
|
27
|
-
type HandlerFn<F extends InngestFunction.Any> = (context: HandlerContext<F>) => Effect.Effect<
|
|
28
|
+
type HandlerFn<F extends InngestFunction.Any> = (context: HandlerContext<F>) => Effect.Effect<unknown, unknown, unknown>;
|
|
28
29
|
/**
|
|
29
30
|
* @since 0.1.0
|
|
30
31
|
* @category models
|
|
@@ -41,12 +42,13 @@ type HandlerFrom<Fns extends InngestFunction.Any, Tag extends InngestFunction.Ta
|
|
|
41
42
|
* @since 0.1.0
|
|
42
43
|
* @category models
|
|
43
44
|
*/
|
|
44
|
-
type
|
|
45
|
+
type RuntimeRequirements = InngestClient | StepTools;
|
|
46
|
+
type HandlersRequirements<H> = H extends Record<string, (...args: ReadonlyArray<unknown>) => Effect.Effect<unknown, unknown, infer R>> ? Exclude<R, RuntimeRequirements> : never;
|
|
45
47
|
/**
|
|
46
48
|
* @since 0.1.0
|
|
47
49
|
* @category models
|
|
48
50
|
*/
|
|
49
|
-
type HandlerRequirements<Handler> = Handler extends ((...args: ReadonlyArray<unknown>) => Effect.Effect<unknown, unknown, infer R>) ? R : never;
|
|
51
|
+
type HandlerRequirements<Handler> = Handler extends ((...args: ReadonlyArray<unknown>) => Effect.Effect<unknown, unknown, infer R>) ? Exclude<R, RuntimeRequirements> : never;
|
|
50
52
|
/**
|
|
51
53
|
* A nominal type representing a registered handler for a specific function tag.
|
|
52
54
|
* @since 0.1.0
|
|
@@ -63,7 +65,7 @@ interface Handler<Tag extends string> {
|
|
|
63
65
|
* @since 0.1.0
|
|
64
66
|
* @category models
|
|
65
67
|
*/
|
|
66
|
-
type ToHandler<F extends InngestFunction.Any> = F extends InngestFunction<infer Tag, infer _Triggers
|
|
68
|
+
type ToHandler<F extends InngestFunction.Any> = F extends InngestFunction<infer Tag, infer _Triggers> ? Handler<Tag> : never;
|
|
67
69
|
/**
|
|
68
70
|
* @since 0.1.0
|
|
69
71
|
* @category models
|
|
@@ -88,9 +90,7 @@ interface InngestGroup<Fns extends InngestFunction.Any> {
|
|
|
88
90
|
*/
|
|
89
91
|
readonly accessHandler: <Tag extends InngestFunction.Tag<Fns>>(tag: Tag) => Effect.Effect<(context: HandlerContext<Extract<Fns, {
|
|
90
92
|
readonly _tag: Tag;
|
|
91
|
-
}>>) => Effect.Effect<
|
|
92
|
-
readonly _tag: Tag;
|
|
93
|
-
}>>, unknown>, never, Handler<Tag>>;
|
|
93
|
+
}>>) => Effect.Effect<unknown, unknown>, never, Handler<Tag>>;
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
96
|
* @since 0.1.0
|
|
@@ -127,7 +127,7 @@ declare const make: <Fns extends ReadonlyArray<InngestFunction.Any>>(...fns: Fns
|
|
|
127
127
|
* )
|
|
128
128
|
* ```
|
|
129
129
|
*/
|
|
130
|
-
declare const toHttpApp: (group: InngestGroup.Any) => Effect.Effect<_$effect_unstable_http_HttpServerResponse0.HttpServerResponse, never, InngestClient | _$effect_unstable_http_HttpServerRequest0.HttpServerRequest
|
|
130
|
+
declare const toHttpApp: (group: InngestGroup.Any) => Effect.Effect<_$effect_unstable_http_HttpServerResponse0.HttpServerResponse, never, InngestClient | HttpClient.HttpClient | _$effect_unstable_http_HttpServerRequest0.HttpServerRequest>;
|
|
131
131
|
/**
|
|
132
132
|
* Create a standalone web handler from an InngestGroup.
|
|
133
133
|
*
|
package/dist/Group.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
|
+
import "./internal/runtime/StepTools.js";
|
|
2
3
|
import "./internal/runtime/HandlerContext.js";
|
|
3
4
|
import { toHttpApp as toHttpApp$1, toWebHandler as toWebHandler$1 } from "./internal/serve/HttpApp.js";
|
|
4
5
|
import { Context, Effect, Layer } from "effect";
|
package/dist/HttpApi.d.ts
CHANGED
|
@@ -49,13 +49,13 @@ declare const InngestApiGroup_base: HttpApiGroup.HttpApiGroup<"inngest", HttpApi
|
|
|
49
49
|
readonly authentication_succeeded: Schema.optional<Schema.Union<readonly [Schema.Literal<false>, Schema.Null]>>;
|
|
50
50
|
readonly capabilities: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
|
|
51
51
|
readonly functions: Schema.optionalKey<Schema.$Array<Schema.Unknown>>;
|
|
52
|
-
}>]>>, HttpApiEndpoint.Json<typeof
|
|
52
|
+
}>]>>, HttpApiEndpoint.Json<typeof FunctionNotFoundError | typeof InvalidRequestError | typeof SignatureError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"register", "PUT", "/", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
53
53
|
readonly message: Schema.String;
|
|
54
54
|
readonly modified: Schema.Boolean;
|
|
55
|
-
}>>, HttpApiEndpoint.Json<typeof
|
|
55
|
+
}>>, HttpApiEndpoint.Json<typeof FunctionNotFoundError | typeof InvalidRequestError | typeof SignatureError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"execute", "POST", "/", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
56
56
|
readonly fnId: Schema.String;
|
|
57
57
|
readonly stepId: Schema.optional<Schema.String>;
|
|
58
|
-
}>>, HttpApiEndpoint.Json<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Unknown>, HttpApiEndpoint.Json<typeof
|
|
58
|
+
}>>, HttpApiEndpoint.Json<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Unknown>, HttpApiEndpoint.Json<typeof FunctionNotFoundError | typeof InvalidRequestError | typeof SignatureError>, never, never>, false>;
|
|
59
59
|
/**
|
|
60
60
|
* @since 0.1.0
|
|
61
61
|
* @category api
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { InngestClient } from "./Client.js";
|
|
2
|
+
import { EventType as EventType$1 } from "./Event.js";
|
|
3
|
+
import { InngestFunction } from "./Function.js";
|
|
4
|
+
import { EventSchema } from "./internal/codec/EventPayload.js";
|
|
5
|
+
import { SendEventError, StepError } from "./internal/errors.js";
|
|
6
|
+
import { StepInput } from "./internal/domain/StepInput.js";
|
|
7
|
+
import { InvokeOptions, OutgoingEvent, StepTools, WaitForEventOptions } from "./internal/runtime/StepTools.js";
|
|
8
|
+
import { Duration, Effect, Option } from "effect";
|
|
9
|
+
|
|
10
|
+
//#region src/Inngest.d.ts
|
|
11
|
+
declare namespace Inngest_d_exports {
|
|
12
|
+
export { EventType, invoke, run, sendEvent, sleep, sleepUntil, waitForEvent };
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Execute an Effect as a durable, memoized step.
|
|
16
|
+
*
|
|
17
|
+
* @since 0.1.0
|
|
18
|
+
* @category steps
|
|
19
|
+
*/
|
|
20
|
+
declare const run: <A, Err, R>(id: StepInput, effect: Effect.Effect<A, Err, R>) => Effect.Effect<A, StepError | Err, R | StepTools>;
|
|
21
|
+
/**
|
|
22
|
+
* Sleep durably for a duration.
|
|
23
|
+
*
|
|
24
|
+
* @since 0.1.0
|
|
25
|
+
* @category steps
|
|
26
|
+
*/
|
|
27
|
+
declare const sleep: (id: StepInput, duration: Duration.Input) => Effect.Effect<void, never, StepTools>;
|
|
28
|
+
/**
|
|
29
|
+
* Sleep durably until a timestamp.
|
|
30
|
+
*
|
|
31
|
+
* @since 0.1.0
|
|
32
|
+
* @category steps
|
|
33
|
+
*/
|
|
34
|
+
declare const sleepUntil: (id: StepInput, timestamp: Date | number | string) => Effect.Effect<void, never, StepTools>;
|
|
35
|
+
/**
|
|
36
|
+
* Wait for a matching event.
|
|
37
|
+
*
|
|
38
|
+
* @since 0.1.0
|
|
39
|
+
* @category steps
|
|
40
|
+
*/
|
|
41
|
+
declare const waitForEvent: <E extends EventSchema>(id: StepInput, event: E, options: WaitForEventOptions) => Effect.Effect<Option.Option<EventType$1<E>>, StepError, StepTools>;
|
|
42
|
+
/**
|
|
43
|
+
* Invoke another Inngest function.
|
|
44
|
+
*
|
|
45
|
+
* @since 0.1.0
|
|
46
|
+
* @category steps
|
|
47
|
+
*/
|
|
48
|
+
declare const invoke: <F extends InngestFunction.Any>(id: StepInput, options: InvokeOptions<F>) => Effect.Effect<unknown, StepError, StepTools>;
|
|
49
|
+
/**
|
|
50
|
+
* Send one or more Inngest events.
|
|
51
|
+
*
|
|
52
|
+
* @since 0.1.0
|
|
53
|
+
* @category steps
|
|
54
|
+
*/
|
|
55
|
+
declare const sendEvent: (id: StepInput, payload: OutgoingEvent | ReadonlyArray<OutgoingEvent>) => Effect.Effect<{
|
|
56
|
+
readonly ids: ReadonlyArray<string>;
|
|
57
|
+
}, SendEventError, StepTools | InngestClient>;
|
|
58
|
+
type EventType<E extends EventSchema> = EventType$1<E>;
|
|
59
|
+
//#endregion
|
|
60
|
+
export { Inngest_d_exports };
|
package/dist/Inngest.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { StepTools } from "./internal/runtime/StepTools.js";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
//#region src/Inngest.ts
|
|
5
|
+
/**
|
|
6
|
+
* Durable workflow operations for Inngest handlers.
|
|
7
|
+
*
|
|
8
|
+
* @since 0.1.0
|
|
9
|
+
*/
|
|
10
|
+
var Inngest_exports = /* @__PURE__ */ __exportAll({
|
|
11
|
+
invoke: () => invoke,
|
|
12
|
+
run: () => run,
|
|
13
|
+
sendEvent: () => sendEvent,
|
|
14
|
+
sleep: () => sleep,
|
|
15
|
+
sleepUntil: () => sleepUntil,
|
|
16
|
+
waitForEvent: () => waitForEvent
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Execute an Effect as a durable, memoized step.
|
|
20
|
+
*
|
|
21
|
+
* @since 0.1.0
|
|
22
|
+
* @category steps
|
|
23
|
+
*/
|
|
24
|
+
const run = (id, effect) => Effect.flatMap(StepTools, (step) => step.run(id, effect));
|
|
25
|
+
/**
|
|
26
|
+
* Sleep durably for a duration.
|
|
27
|
+
*
|
|
28
|
+
* @since 0.1.0
|
|
29
|
+
* @category steps
|
|
30
|
+
*/
|
|
31
|
+
const sleep = (id, duration) => Effect.flatMap(StepTools, (step) => step.sleep(id, duration));
|
|
32
|
+
/**
|
|
33
|
+
* Sleep durably until a timestamp.
|
|
34
|
+
*
|
|
35
|
+
* @since 0.1.0
|
|
36
|
+
* @category steps
|
|
37
|
+
*/
|
|
38
|
+
const sleepUntil = (id, timestamp) => Effect.flatMap(StepTools, (step) => step.sleepUntil(id, timestamp));
|
|
39
|
+
/**
|
|
40
|
+
* Wait for a matching event.
|
|
41
|
+
*
|
|
42
|
+
* @since 0.1.0
|
|
43
|
+
* @category steps
|
|
44
|
+
*/
|
|
45
|
+
const waitForEvent = (id, event, options) => Effect.flatMap(StepTools, (step) => step.waitForEvent(id, event, options));
|
|
46
|
+
/**
|
|
47
|
+
* Invoke another Inngest function.
|
|
48
|
+
*
|
|
49
|
+
* @since 0.1.0
|
|
50
|
+
* @category steps
|
|
51
|
+
*/
|
|
52
|
+
const invoke = (id, options) => Effect.flatMap(StepTools, (step) => step.invoke(id, options));
|
|
53
|
+
/**
|
|
54
|
+
* Send one or more Inngest events.
|
|
55
|
+
*
|
|
56
|
+
* @since 0.1.0
|
|
57
|
+
* @category steps
|
|
58
|
+
*/
|
|
59
|
+
const sendEvent = (id, payload) => Effect.flatMap(StepTools, (step) => step.sendEvent(id, payload));
|
|
60
|
+
//#endregion
|
|
61
|
+
export { Inngest_exports };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Client_d_exports } from "./Client.js";
|
|
2
2
|
import { Event_d_exports } from "./Event.js";
|
|
3
3
|
import { Events_d_exports } from "./Events.js";
|
|
4
|
+
import { Cron_d_exports } from "./Cron.js";
|
|
4
5
|
import { Function_d_exports } from "./Function.js";
|
|
5
6
|
import { NonRetriableError, RetryAfterError } from "./internal/errors.js";
|
|
6
7
|
import { Group_d_exports } from "./Group.js";
|
|
7
8
|
import { HttpApi_d_exports } from "./HttpApi.js";
|
|
8
|
-
|
|
9
|
+
import { Inngest_d_exports } from "./Inngest.js";
|
|
10
|
+
export { Inngest_d_exports as Inngest, Client_d_exports as InngestClient, Cron_d_exports as InngestCron, Event_d_exports as InngestEvent, Events_d_exports as InngestEvents, Function_d_exports as InngestFunction, Group_d_exports as InngestGroup, HttpApi_d_exports as InngestHttpApi, NonRetriableError, RetryAfterError };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { Function_exports } from "./Function.js";
|
|
2
1
|
import { Event_exports } from "./Event.js";
|
|
2
|
+
import { Cron_exports } from "./Cron.js";
|
|
3
|
+
import { Function_exports } from "./Function.js";
|
|
3
4
|
import { Client_exports } from "./Client.js";
|
|
4
5
|
import { NonRetriableError, RetryAfterError } from "./internal/errors.js";
|
|
5
6
|
import { Events_exports } from "./Events.js";
|
|
6
7
|
import { Group_exports } from "./Group.js";
|
|
8
|
+
import { Inngest_exports } from "./Inngest.js";
|
|
7
9
|
import { HttpApi_exports } from "./HttpApi.js";
|
|
8
|
-
export { Client_exports as InngestClient, Event_exports as InngestEvent, Events_exports as InngestEvents, Function_exports as InngestFunction, Group_exports as InngestGroup, HttpApi_exports as InngestHttpApi, NonRetriableError, RetryAfterError };
|
|
10
|
+
export { Inngest_exports as Inngest, Client_exports as InngestClient, Cron_exports as InngestCron, Event_exports as InngestEvent, Events_exports as InngestEvents, Function_exports as InngestFunction, Group_exports as InngestGroup, HttpApi_exports as InngestHttpApi, NonRetriableError, RetryAfterError };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StepError } from "../errors.js";
|
|
2
|
-
import { Effect, Function,
|
|
2
|
+
import { Effect, Function, Predicate } from "effect";
|
|
3
3
|
//#region src/internal/codec/StepResult.ts
|
|
4
4
|
const messageFromCause = (cause) => {
|
|
5
5
|
if (Predicate.hasProperty(cause, "cause")) {
|
|
@@ -25,16 +25,6 @@ const mapMemoDecodeError = Function.dual(2, (effect, stepId) => effect.pipe(Effe
|
|
|
25
25
|
stepId,
|
|
26
26
|
cause
|
|
27
27
|
}))));
|
|
28
|
-
const decodeMemo = Function.dual(3, (value, schema, stepId) => Schema.decodeUnknownEffect(schema)(value).pipe(mapMemoDecodeError(stepId)));
|
|
29
|
-
const encodeMemo = Function.dual(3, (value, schema, stepId) => Schema.encodeUnknownEffect(Schema.toCodecJson(schema))(value).pipe(mapMemoDecodeError(stepId)));
|
|
30
|
-
const decodeStepRunMemo = (schema, stepId) => (value) => Option.match(schema, {
|
|
31
|
-
onNone: () => Effect.void,
|
|
32
|
-
onSome: (codec) => decodeMemo(codec, stepId)(value)
|
|
33
|
-
});
|
|
34
|
-
const encodeStepRunMemo = (schema, stepId) => (value) => Option.match(schema, {
|
|
35
|
-
onNone: () => Predicate.isUndefined(value) ? Effect.succeed(void 0) : decodeMemo(Schema.Json, stepId)(value),
|
|
36
|
-
onSome: (codec) => encodeMemo(codec, stepId)(value)
|
|
37
|
-
});
|
|
38
28
|
const failStepRunMemoError = (stepId, error) => Effect.fail(StepError.make({
|
|
39
29
|
stepId,
|
|
40
30
|
message: Predicate.hasProperty(error, "message") ? String(error.message) : "Step failed",
|
|
@@ -52,4 +42,4 @@ const failUnexpectedStepRunMemoInput = (stepId, input) => Effect.fail(StepError.
|
|
|
52
42
|
cause: input
|
|
53
43
|
}));
|
|
54
44
|
//#endregion
|
|
55
|
-
export {
|
|
45
|
+
export { failMemoDecode, failStepRunMemoError, failStepRunMemoTimeout, failUnexpectedStepRunMemoInput, mapMemoDecodeError };
|
package/dist/internal/driver.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { CurrentCheckpoint } from "../runtime/CheckpointContext.js";
|
|
2
|
+
import { normalize } from "../utils/safe-stringify.js";
|
|
2
3
|
import { make } from "../runtime/HandlerContext.js";
|
|
3
4
|
import { Effect, Option, Schema } from "effect";
|
|
4
5
|
//#region src/internal/execution/HandlerRun.ts
|
|
5
6
|
var HandlerSucceeded = class extends Schema.TaggedClass()("HandlerSucceeded", { value: Schema.Unknown }) {};
|
|
6
7
|
Schema.TaggedClass()("CheckpointDeadlineElapsed", {});
|
|
7
|
-
const run = (args) => make({ fn: args.fn }).pipe(Effect.flatMap(args.handler), Effect.map((value) => HandlerSucceeded.make({ value })));
|
|
8
|
+
const run = (args) => make({ fn: args.fn }).pipe(Effect.flatMap(args.handler), Effect.map((value) => HandlerSucceeded.make({ value: normalize(value) })));
|
|
8
9
|
const withCheckpointDeadline = (effect) => Effect.gen(function* () {
|
|
9
10
|
const checkpoint = yield* CurrentCheckpoint;
|
|
10
11
|
return yield* Option.match(checkpoint, {
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { InngestFunction } from "../../Function.js";
|
|
2
2
|
import { ExecutionInput } from "../domain/ExecutionInput.js";
|
|
3
|
-
import { StepTools } from "./StepTools.js";
|
|
4
3
|
import { Effect } from "effect";
|
|
5
4
|
|
|
6
5
|
//#region src/internal/runtime/HandlerContext.d.ts
|
|
7
6
|
interface HandlerContext<F extends InngestFunction.Any = InngestFunction.Any> {
|
|
8
7
|
readonly event: InngestFunction.EventType<F>;
|
|
9
|
-
readonly step: StepTools.Service;
|
|
10
8
|
readonly run: ExecutionInput["run"];
|
|
11
9
|
}
|
|
12
10
|
//#endregion
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import { CurrentExecutionInput } from "../domain/ExecutionInput.js";
|
|
2
2
|
import { decodeInvocation } from "../codec/EventPayload.js";
|
|
3
|
-
import { StepTools } from "./StepTools.js";
|
|
4
3
|
import { Effect } from "effect";
|
|
5
4
|
//#region src/internal/runtime/HandlerContext.ts
|
|
6
5
|
const make = (args) => Effect.gen(function* () {
|
|
7
6
|
const input = yield* CurrentExecutionInput;
|
|
8
|
-
const step = yield* StepTools;
|
|
9
7
|
return {
|
|
10
8
|
event: yield* decodeInvocation({
|
|
11
9
|
fn: args.fn,
|
|
12
10
|
input
|
|
13
11
|
}),
|
|
14
|
-
step,
|
|
15
12
|
run: input.run
|
|
16
13
|
};
|
|
17
14
|
});
|
|
@@ -8,13 +8,9 @@ import { StepInput } from "../domain/StepInput.js";
|
|
|
8
8
|
import { HandlerFiberScope } from "./HandlerFiberScope.js";
|
|
9
9
|
import { StepCommandBus } from "./StepCommandBus.js";
|
|
10
10
|
import { StepIdentity } from "./StepIdentity.js";
|
|
11
|
-
import { Context, Duration, Effect, Layer, Option
|
|
11
|
+
import { Context, Duration, Effect, Layer, Option } from "effect";
|
|
12
12
|
|
|
13
13
|
//#region src/internal/runtime/StepTools.d.ts
|
|
14
|
-
type JsonSchema<A = unknown> = Schema.Codec<A, unknown, never, never>;
|
|
15
|
-
interface RunOptions<S extends JsonSchema> {
|
|
16
|
-
readonly schema: S;
|
|
17
|
-
}
|
|
18
14
|
interface WaitForEventOptions {
|
|
19
15
|
readonly timeout: Duration.Input;
|
|
20
16
|
readonly if?: string;
|
|
@@ -29,8 +25,7 @@ type InvokeOptions<F extends InngestFunction.Any> = [InngestFunction.EventPayloa
|
|
|
29
25
|
readonly data: InngestFunction.EventPayload<F>;
|
|
30
26
|
};
|
|
31
27
|
interface Run {
|
|
32
|
-
<Err, R>(id: StepInput, effect: Effect.Effect<
|
|
33
|
-
<S extends JsonSchema, Err, R>(id: StepInput, effect: Effect.Effect<Schema.Schema.Type<S>, Err, R>, options: RunOptions<S>): Effect.Effect<Schema.Schema.Type<S>, StepError | Err, R>;
|
|
28
|
+
<A, Err, R>(id: StepInput, effect: Effect.Effect<A, Err, R>): Effect.Effect<A, StepError | Err, R>;
|
|
34
29
|
}
|
|
35
30
|
interface Sleep {
|
|
36
31
|
(id: StepInput, duration: Duration.Input): Effect.Effect<void>;
|
|
@@ -42,7 +37,7 @@ interface WaitForEvent {
|
|
|
42
37
|
<E extends EventSchema>(id: StepInput, event: E, options: WaitForEventOptions): Effect.Effect<Option.Option<EventType<E>>, StepError>;
|
|
43
38
|
}
|
|
44
39
|
interface Invoke {
|
|
45
|
-
<F extends InngestFunction.Any>(id: StepInput, options: InvokeOptions<F>): Effect.Effect<
|
|
40
|
+
<F extends InngestFunction.Any>(id: StepInput, options: InvokeOptions<F>): Effect.Effect<unknown, StepError>;
|
|
46
41
|
}
|
|
47
42
|
interface OutgoingEvent {
|
|
48
43
|
readonly name: string;
|
|
@@ -66,18 +61,15 @@ declare namespace StepTools {
|
|
|
66
61
|
declare const StepTools_base: Context.ServiceClass<StepTools, "effect-inngest/internal/runtime/StepTools", StepTools.Service>;
|
|
67
62
|
declare class StepTools extends StepTools_base {
|
|
68
63
|
static readonly make: Effect.Effect<{
|
|
69
|
-
run:
|
|
70
|
-
<Err, R>(id: StepInput, effect: Effect.Effect<void, Err, R>): Effect.Effect<void, StepError | Err, R>;
|
|
71
|
-
<S extends JsonSchema, Err, R>(id: StepInput, effect: Effect.Effect<Schema.Schema.Type<S>, Err, R>, options: RunOptions<S>): Effect.Effect<Schema.Schema.Type<S>, StepError | Err, R>;
|
|
72
|
-
};
|
|
64
|
+
run: <A, Err, R>(id: StepInput, effect: Effect.Effect<A, Err, R>) => Effect.Effect<A, StepError | Err, Exclude<R, InngestConfig | CurrentExecutionInput | HandlerFiberScope | StepCommandBus | StepIdentity>>;
|
|
73
65
|
sleep: Sleep;
|
|
74
66
|
sleepUntil: SleepUntil;
|
|
75
67
|
waitForEvent: WaitForEvent;
|
|
76
68
|
invoke: Invoke;
|
|
77
69
|
sendEvent: SendEvent;
|
|
78
|
-
}, never, InngestConfig | CurrentExecutionInput |
|
|
79
|
-
static readonly layer: Layer.Layer<StepTools, never, InngestConfig | CurrentExecutionInput |
|
|
80
|
-
static readonly live: Layer.Layer<StepTools, never, InngestConfig | CurrentExecutionInput |
|
|
70
|
+
}, never, InngestConfig | CurrentExecutionInput | HandlerFiberScope | StepCommandBus | StepIdentity>;
|
|
71
|
+
static readonly layer: Layer.Layer<StepTools, never, InngestConfig | CurrentExecutionInput | HandlerFiberScope | StepCommandBus | StepIdentity>;
|
|
72
|
+
static readonly live: Layer.Layer<StepTools, never, InngestConfig | CurrentExecutionInput | HandlerFiberScope | StepIdentity>;
|
|
81
73
|
}
|
|
82
74
|
//#endregion
|
|
83
|
-
export { StepTools };
|
|
75
|
+
export { InvokeOptions, OutgoingEvent, StepTools, WaitForEventOptions };
|
|
@@ -10,7 +10,7 @@ import { sleep } from "./steps/SleepStep.js";
|
|
|
10
10
|
import { sleepUntil } from "./steps/SleepUntilStep.js";
|
|
11
11
|
import { run } from "./steps/StepRun.js";
|
|
12
12
|
import { waitForEvent } from "./steps/WaitForEventStep.js";
|
|
13
|
-
import { Context, Effect, Layer,
|
|
13
|
+
import { Context, Effect, Layer, pipe } from "effect";
|
|
14
14
|
//#region src/internal/runtime/StepTools.ts
|
|
15
15
|
var StepTools = class extends Context.Service()("effect-inngest/internal/runtime/StepTools") {
|
|
16
16
|
static make = Effect.gen(function* () {
|
|
@@ -21,13 +21,7 @@ var StepTools = class extends Context.Service()("effect-inngest/internal/runtime
|
|
|
21
21
|
const bus = yield* StepCommandBus;
|
|
22
22
|
const handlerFiberScope = yield* HandlerFiberScope;
|
|
23
23
|
const runtime = pipe(Context.make(StepIdentity, identity), Context.add(StepCommandBus, bus), Context.add(CurrentExecutionInput, input), Context.add(CurrentCheckpoint, checkpoint), Context.add(InngestConfig, config), Context.add(HandlerFiberScope, handlerFiberScope));
|
|
24
|
-
function run$1(id, effect
|
|
25
|
-
if (Predicate.isNotUndefined(options)) return run({
|
|
26
|
-
input,
|
|
27
|
-
id: identity.reserve(id),
|
|
28
|
-
effect,
|
|
29
|
-
options
|
|
30
|
-
}).pipe(Effect.provide(runtime));
|
|
24
|
+
function run$1(id, effect) {
|
|
31
25
|
return run({
|
|
32
26
|
input,
|
|
33
27
|
id: identity.reserve(id),
|
|
@@ -4,7 +4,6 @@ import { StepError } from "../../errors.js";
|
|
|
4
4
|
import { InvokeFunction } from "../../domain/StepCommand.js";
|
|
5
5
|
import { StepCommandBus } from "../StepCommandBus.js";
|
|
6
6
|
import { StepIdentity } from "../StepIdentity.js";
|
|
7
|
-
import { decodeMemo } from "../../codec/StepResult.js";
|
|
8
7
|
import { Duration, Effect, Match, Predicate, Schema } from "effect";
|
|
9
8
|
//#region src/internal/runtime/steps/InvokeStep.ts
|
|
10
9
|
const invoke = (args) => Effect.gen(function* () {
|
|
@@ -13,7 +12,7 @@ const invoke = (args) => Effect.gen(function* () {
|
|
|
13
12
|
const bus = yield* StepCommandBus;
|
|
14
13
|
const info = yield* identity.resolve(args.id);
|
|
15
14
|
const memo = args.input.memoForStep(info);
|
|
16
|
-
return yield* Match.value(memo).pipe(Match.tag("MemoData", ({ data }) =>
|
|
15
|
+
return yield* Match.value(memo).pipe(Match.tag("MemoData", ({ data }) => Effect.succeed(data)), Match.tag("MemoError", ({ error }) => Effect.fail(StepError.make({
|
|
17
16
|
stepId: info.id,
|
|
18
17
|
message: Predicate.hasProperty(error, "message") ? String(error.message) : "Invoke failed",
|
|
19
18
|
cause: error
|
|
@@ -1,46 +1,52 @@
|
|
|
1
1
|
import { StepRunError, StepRunPlanned, StepRunResult, stepRunFailureForAttempt } from "../../domain/StepCommand.js";
|
|
2
2
|
import { StepCommandBus } from "../StepCommandBus.js";
|
|
3
3
|
import { StepIdentity } from "../StepIdentity.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { failStepRunMemoError, failStepRunMemoTimeout, failUnexpectedStepRunMemoInput } from "../../codec/StepResult.js";
|
|
5
|
+
import { normalize } from "../../utils/safe-stringify.js";
|
|
6
|
+
import { Effect, Match } from "effect";
|
|
6
7
|
//#region src/internal/runtime/steps/StepRun.ts
|
|
7
8
|
function run(args) {
|
|
8
|
-
const memoCodec = args.options ? Option.some(Schema.toCodecJson(args.options.schema)) : Option.none();
|
|
9
9
|
return Effect.gen(function* () {
|
|
10
10
|
const identity = yield* StepIdentity;
|
|
11
11
|
const bus = yield* StepCommandBus;
|
|
12
12
|
const info = yield* identity.resolve(args.id);
|
|
13
13
|
const memo = args.input.memoForStep(info);
|
|
14
|
-
return yield* Match.value(memo).pipe(Match.tag("MemoData", ({ data }) =>
|
|
15
|
-
if (!args.input.shouldExecuteStep(info)) return yield* Effect.
|
|
14
|
+
return yield* Match.value(memo).pipe(Match.tag("MemoData", ({ data }) => Effect.succeed(data)), Match.tag("MemoError", ({ error }) => failStepRunMemoError(info.id, error)), Match.tag("MemoTimeout", () => failStepRunMemoTimeout(info.id)), Match.tag("MemoInput", ({ input }) => failUnexpectedStepRunMemoInput(info.id, input)), Match.tag("MemoNone", () => Effect.gen(function* () {
|
|
15
|
+
if (!args.input.shouldExecuteStep(info)) return yield* Effect.interrupt;
|
|
16
16
|
const planned = StepRunPlanned.make({
|
|
17
17
|
info,
|
|
18
18
|
sequence: args.id.sequence
|
|
19
19
|
});
|
|
20
20
|
if (args.input.shouldPlanStep(info)) {
|
|
21
21
|
yield* bus.plan(planned);
|
|
22
|
-
return yield* Effect.
|
|
22
|
+
return yield* Effect.interrupt;
|
|
23
23
|
}
|
|
24
|
-
if (yield* bus.planCheckpointedRunBoundary(planned)) return yield* Effect.
|
|
24
|
+
if (yield* bus.planCheckpointedRunBoundary(planned)) return yield* Effect.interrupt;
|
|
25
25
|
return yield* args.effect.pipe(Effect.matchEffect({
|
|
26
|
-
onFailure: (error) =>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
onFailure: (error) => Effect.gen(function* () {
|
|
27
|
+
yield* bus.fail(stepRunFailureForAttempt({
|
|
28
|
+
info,
|
|
29
|
+
error,
|
|
30
|
+
attempt: args.input.run.attempt,
|
|
31
|
+
maxAttempts: args.input.run.maxAttempts
|
|
32
|
+
}));
|
|
33
|
+
return yield* Effect.interrupt;
|
|
34
|
+
}),
|
|
32
35
|
onSuccess: (value) => Effect.gen(function* () {
|
|
33
|
-
const data =
|
|
36
|
+
const data = normalize(value);
|
|
34
37
|
yield* bus.complete(StepRunResult.make({
|
|
35
38
|
info,
|
|
36
39
|
data
|
|
37
40
|
}));
|
|
38
|
-
return
|
|
41
|
+
return data;
|
|
39
42
|
})
|
|
40
|
-
}), Effect.catchDefect((defect) =>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
}), Effect.catchDefect((defect) => Effect.gen(function* () {
|
|
44
|
+
yield* bus.fail(StepRunError.make({
|
|
45
|
+
info,
|
|
46
|
+
error: defect
|
|
47
|
+
}));
|
|
48
|
+
return yield* Effect.interrupt;
|
|
49
|
+
})));
|
|
44
50
|
})), Match.exhaustive);
|
|
45
51
|
});
|
|
46
52
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Array, Option, Predicate } from "effect";
|
|
2
|
+
//#region src/internal/utils/safe-stringify.ts
|
|
3
|
+
const findReference = (state, value) => Array.findFirstIndex(state.stack, (candidate) => Object.is(candidate, value));
|
|
4
|
+
const isTracked = (state, value) => Option.isSome(findReference(state, value));
|
|
5
|
+
const pushReference = (state, key, value) => {
|
|
6
|
+
state.stack.push(value);
|
|
7
|
+
state.keys.push(key);
|
|
8
|
+
};
|
|
9
|
+
const trimToParent = (state, key, parentIndex) => {
|
|
10
|
+
state.stack.splice(parentIndex + 1);
|
|
11
|
+
state.keys.splice(parentIndex, Infinity, key);
|
|
12
|
+
};
|
|
13
|
+
const refreshParent = (state, key, parent) => {
|
|
14
|
+
Option.match(findReference(state, parent), {
|
|
15
|
+
onNone: () => {
|
|
16
|
+
if (Predicate.isObjectOrArray(parent)) pushReference(state, key, parent);
|
|
17
|
+
},
|
|
18
|
+
onSome: (parentIndex) => trimToParent(state, key, parentIndex)
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
const defaultCycleReplacer = (state) => function(_key, value) {
|
|
22
|
+
const valueIndex = Option.getOrElse(findReference(state, value), () => -1);
|
|
23
|
+
if (Object.is(state.stack[0], value)) return "[Circular ~]";
|
|
24
|
+
return `[Circular ~.${state.keys.slice(0, valueIndex).join(".")}]`;
|
|
25
|
+
};
|
|
26
|
+
function stringify(obj, replacer, spaces, cycleReplacer) {
|
|
27
|
+
return JSON.stringify(obj, getSerialize(replacer, cycleReplacer), spaces);
|
|
28
|
+
}
|
|
29
|
+
const normalize = (value) => {
|
|
30
|
+
const json = stringify(value, (_key, child) => {
|
|
31
|
+
if (!Predicate.isBigInt(child)) return child;
|
|
32
|
+
});
|
|
33
|
+
return Predicate.isUndefined(json) ? null : JSON.parse(json);
|
|
34
|
+
};
|
|
35
|
+
function getSerialize(replacer, cycleReplacer) {
|
|
36
|
+
const state = {
|
|
37
|
+
stack: [],
|
|
38
|
+
keys: []
|
|
39
|
+
};
|
|
40
|
+
const replaceCycle = cycleReplacer ?? defaultCycleReplacer(state);
|
|
41
|
+
return function(key, value) {
|
|
42
|
+
if (Array.isArrayNonEmpty(state.stack)) {
|
|
43
|
+
refreshParent(state, key, this);
|
|
44
|
+
if (Predicate.isObjectKeyword(value) && isTracked(state, value)) value = replaceCycle.call(this, key, value);
|
|
45
|
+
} else state.stack.push(value);
|
|
46
|
+
return replacer ? replacer.call(this, key, value) : value;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { normalize };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-inngest",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-beta2",
|
|
4
4
|
"description": "Native Effect client library for Inngest - build durable, type-safe workflows",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"background-jobs",
|
|
@@ -42,6 +42,10 @@
|
|
|
42
42
|
"types": "./dist/Client.d.ts",
|
|
43
43
|
"import": "./src/Client.ts"
|
|
44
44
|
},
|
|
45
|
+
"./Cron": {
|
|
46
|
+
"types": "./dist/Cron.d.ts",
|
|
47
|
+
"import": "./src/Cron.ts"
|
|
48
|
+
},
|
|
45
49
|
"./Event": {
|
|
46
50
|
"types": "./dist/Event.d.ts",
|
|
47
51
|
"import": "./src/Event.ts"
|
|
@@ -62,6 +66,10 @@
|
|
|
62
66
|
"types": "./dist/HttpApi.d.ts",
|
|
63
67
|
"import": "./src/HttpApi.ts"
|
|
64
68
|
},
|
|
69
|
+
"./Inngest": {
|
|
70
|
+
"types": "./dist/Inngest.d.ts",
|
|
71
|
+
"import": "./src/Inngest.ts"
|
|
72
|
+
},
|
|
65
73
|
"./internal/*": null
|
|
66
74
|
},
|
|
67
75
|
"publishConfig": {
|
|
@@ -75,6 +83,10 @@
|
|
|
75
83
|
"types": "./dist/Client.d.ts",
|
|
76
84
|
"import": "./dist/Client.js"
|
|
77
85
|
},
|
|
86
|
+
"./Cron": {
|
|
87
|
+
"types": "./dist/Cron.d.ts",
|
|
88
|
+
"import": "./dist/Cron.js"
|
|
89
|
+
},
|
|
78
90
|
"./Event": {
|
|
79
91
|
"types": "./dist/Event.d.ts",
|
|
80
92
|
"import": "./dist/Event.js"
|
|
@@ -95,6 +107,10 @@
|
|
|
95
107
|
"types": "./dist/HttpApi.d.ts",
|
|
96
108
|
"import": "./dist/HttpApi.js"
|
|
97
109
|
},
|
|
110
|
+
"./Inngest": {
|
|
111
|
+
"types": "./dist/Inngest.d.ts",
|
|
112
|
+
"import": "./dist/Inngest.js"
|
|
113
|
+
},
|
|
98
114
|
"./internal/*": null
|
|
99
115
|
}
|
|
100
116
|
},
|
package/src/Client.ts
CHANGED
|
@@ -253,7 +253,7 @@ const makeClient = (config: ClientConfig, httpClient: HttpClient.HttpClient): Ef
|
|
|
253
253
|
);
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
const key = config.eventKey
|
|
256
|
+
const key = config.eventKey || "NO_EVENT_KEY_SET";
|
|
257
257
|
const url = new URL(`e/${key}`, eventBaseUrl).toString();
|
|
258
258
|
const eventNames = events.map((e) => e.name);
|
|
259
259
|
const now = yield* Clock.currentTimeMillis;
|
package/src/Cron.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public cron trigger definitions.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import { Predicate } from "effect";
|
|
7
|
+
|
|
8
|
+
export const TypeId: unique symbol = Symbol.for("effect-inngest/Cron");
|
|
9
|
+
export type TypeId = typeof TypeId;
|
|
10
|
+
|
|
11
|
+
export interface CronOptions {
|
|
12
|
+
readonly jitter?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface CronDefinition<Schedule extends string = string> {
|
|
16
|
+
readonly [TypeId]: TypeId;
|
|
17
|
+
readonly cron: Schedule;
|
|
18
|
+
readonly jitter?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function make<const Schedule extends string>(
|
|
22
|
+
schedule: Schedule,
|
|
23
|
+
options?: CronOptions,
|
|
24
|
+
): CronDefinition<Schedule> {
|
|
25
|
+
return {
|
|
26
|
+
[TypeId]: TypeId,
|
|
27
|
+
cron: schedule,
|
|
28
|
+
...(Predicate.isNotUndefined(options?.jitter) ? { jitter: options.jitter } : {}),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const isCron = (value: unknown): value is CronDefinition =>
|
|
33
|
+
Predicate.hasProperty(value, TypeId) && value[TypeId] === TypeId;
|