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.
Files changed (41) hide show
  1. package/README.md +69 -75
  2. package/dist/Client.js +1 -1
  3. package/dist/Cron.d.ts +17 -0
  4. package/dist/Cron.js +24 -0
  5. package/dist/Events.d.ts +1 -1
  6. package/dist/Events.js +1 -1
  7. package/dist/Function.d.ts +28 -26
  8. package/dist/Function.js +19 -11
  9. package/dist/Group.d.ts +8 -8
  10. package/dist/Group.js +1 -0
  11. package/dist/HttpApi.d.ts +3 -3
  12. package/dist/Inngest.d.ts +60 -0
  13. package/dist/Inngest.js +61 -0
  14. package/dist/index.d.ts +3 -1
  15. package/dist/index.js +4 -2
  16. package/dist/internal/codec/StepResult.js +2 -12
  17. package/dist/internal/driver.js +1 -0
  18. package/dist/internal/execution/HandlerRun.js +2 -1
  19. package/dist/internal/runtime/HandlerContext.d.ts +0 -2
  20. package/dist/internal/runtime/HandlerContext.js +0 -3
  21. package/dist/internal/runtime/StepTools.d.ts +8 -16
  22. package/dist/internal/runtime/StepTools.js +2 -8
  23. package/dist/internal/runtime/steps/InvokeStep.js +1 -2
  24. package/dist/internal/runtime/steps/StepRun.js +25 -19
  25. package/dist/internal/utils/safe-stringify.js +50 -0
  26. package/package.json +17 -1
  27. package/src/Client.ts +1 -1
  28. package/src/Cron.ts +33 -0
  29. package/src/Events.ts +1 -1
  30. package/src/Function.ts +62 -34
  31. package/src/Group.ts +10 -7
  32. package/src/Inngest.ts +85 -0
  33. package/src/index.ts +21 -7
  34. package/src/internal/codec/StepResult.ts +1 -43
  35. package/src/internal/driver.ts +13 -2
  36. package/src/internal/execution/HandlerRun.ts +3 -2
  37. package/src/internal/runtime/HandlerContext.ts +2 -5
  38. package/src/internal/runtime/StepTools.ts +4 -31
  39. package/src/internal/runtime/steps/InvokeStep.ts +1 -4
  40. package/src/internal/runtime/steps/StepRun.ts +28 -44
  41. 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<InngestFunction.Success<F>, unknown, unknown>;
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 HandlersRequirements<H> = H extends Record<string, (...args: ReadonlyArray<unknown>) => Effect.Effect<unknown, unknown, infer R>> ? R : never;
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, infer _Success> ? Handler<Tag> : never;
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<InngestFunction.Success<Extract<Fns, {
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 | HttpClient.HttpClient>;
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 InvalidRequestError | typeof FunctionNotFoundError | typeof SignatureError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"register", "PUT", "/", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
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 InvalidRequestError | typeof FunctionNotFoundError | typeof SignatureError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"execute", "POST", "/", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<Schema.Struct<{
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 InvalidRequestError | typeof FunctionNotFoundError | typeof SignatureError>, never, never>, false>;
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 };
@@ -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
- export { Client_d_exports as InngestClient, 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 };
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, Option, Predicate, Schema } from "effect";
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 { decodeMemo, decodeStepRunMemo, encodeStepRunMemo, failMemoDecode, failStepRunMemoError, failStepRunMemoTimeout, failUnexpectedStepRunMemoInput, mapMemoDecodeError };
45
+ export { failMemoDecode, failStepRunMemoError, failStepRunMemoTimeout, failUnexpectedStepRunMemoInput, mapMemoDecodeError };
@@ -1,4 +1,5 @@
1
1
  import "./protocol.js";
2
+ import "./runtime/StepTools.js";
2
3
  import { provide } from "./execution/ExecutionScope.js";
3
4
  import { run, withCheckpointDeadline } from "./execution/HandlerRun.js";
4
5
  import "./execution/ExecutionResult.js";
@@ -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, Schema } from "effect";
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<void, Err, R>): Effect.Effect<void, StepError | Err, R>;
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<InngestFunction.Success<F>, StepError>;
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 | StepIdentity | StepCommandBus | HandlerFiberScope>;
79
- static readonly layer: Layer.Layer<StepTools, never, InngestConfig | CurrentExecutionInput | StepIdentity | StepCommandBus | HandlerFiberScope>;
80
- static readonly live: Layer.Layer<StepTools, never, InngestConfig | CurrentExecutionInput | StepIdentity | HandlerFiberScope>;
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, Predicate, pipe } from "effect";
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, options) {
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 }) => decodeMemo(Schema.toCodecJson(args.options.function.success), info.id)(data)), Match.tag("MemoError", ({ error }) => Effect.fail(StepError.make({
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 { decodeStepRunMemo, encodeStepRunMemo, failStepRunMemoError, failStepRunMemoTimeout, failUnexpectedStepRunMemoInput } from "../../codec/StepResult.js";
5
- import { Effect, Match, Option, Schema } from "effect";
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 }) => decodeStepRunMemo(memoCodec, info.id)(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.void;
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.void;
22
+ return yield* Effect.interrupt;
23
23
  }
24
- if (yield* bus.planCheckpointedRunBoundary(planned)) return yield* Effect.void;
24
+ if (yield* bus.planCheckpointedRunBoundary(planned)) return yield* Effect.interrupt;
25
25
  return yield* args.effect.pipe(Effect.matchEffect({
26
- onFailure: (error) => bus.fail(stepRunFailureForAttempt({
27
- info,
28
- error,
29
- attempt: args.input.run.attempt,
30
- maxAttempts: args.input.run.maxAttempts
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 = yield* encodeStepRunMemo(memoCodec, info.id)(value);
36
+ const data = normalize(value);
34
37
  yield* bus.complete(StepRunResult.make({
35
38
  info,
36
39
  data
37
40
  }));
38
- return yield* decodeStepRunMemo(memoCodec, info.id)(data);
41
+ return data;
39
42
  })
40
- }), Effect.catchDefect((defect) => bus.fail(StepRunError.make({
41
- info,
42
- error: defect
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.0-beta.4",
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 ?? "NO_EVENT_KEY_SET";
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;