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/src/Events.ts CHANGED
@@ -82,7 +82,7 @@ export const FunctionCancelled = InngestEvent.make(
82
82
  );
83
83
 
84
84
  /**
85
- * Sent when a function is invoked via step.invoke().
85
+ * Sent when a function is invoked via Inngest.invoke().
86
86
  * @since 0.1.0
87
87
  */
88
88
  export const FunctionInvoked = InngestEvent.make(
package/src/Function.ts CHANGED
@@ -6,7 +6,9 @@ import { pipeArguments, type Pipeable } from "effect/Pipeable";
6
6
  import * as Checkpoint from "./internal/checkpoint.js";
7
7
  import type { CheckpointingOption } from "./internal/checkpoint.js";
8
8
  import { InngestDuration } from "./internal/wire/Duration.js";
9
- import type * as InngestEvent from "./Event.js";
9
+ import * as InngestEvent from "./Event.js";
10
+ import type * as InngestCron from "./Cron.js";
11
+ import { isCron } from "./Cron.js";
10
12
 
11
13
  export type { CheckpointingOption } from "./internal/checkpoint.js";
12
14
 
@@ -36,6 +38,11 @@ export interface EventTrigger<E extends EventSchema = EventSchema> {
36
38
  readonly if?: string;
37
39
  }
38
40
 
41
+ export interface NormalizedEventTrigger<E extends EventSchema = EventSchema> {
42
+ readonly event: E;
43
+ readonly if?: string;
44
+ }
45
+
39
46
  /**
40
47
  * A cron-based trigger configuration.
41
48
  *
@@ -44,6 +51,7 @@ export interface EventTrigger<E extends EventSchema = EventSchema> {
44
51
  */
45
52
  export interface CronTrigger {
46
53
  readonly cron: string;
54
+ readonly jitter?: string;
47
55
  }
48
56
 
49
57
  /**
@@ -52,13 +60,23 @@ export interface CronTrigger {
52
60
  * @since 0.1.0
53
61
  * @category triggers
54
62
  */
55
- export type Trigger<E extends EventSchema = EventSchema> = EventTrigger<E> | CronTrigger;
63
+ export type NormalizedTrigger<E extends EventSchema = EventSchema> = NormalizedEventTrigger<E> | CronTrigger;
64
+
65
+ export type Trigger<E extends EventSchema = EventSchema> =
66
+ | E
67
+ | InngestCron.CronDefinition
68
+ | EventTrigger<E>
69
+ | CronTrigger;
70
+
71
+ export type TriggerDefinition<E extends EventSchema = EventSchema> = Trigger<E>;
56
72
 
57
73
  /**
58
74
  * @since 0.1.0
59
75
  * @category triggers
60
76
  */
61
- export type TriggerInput<E extends EventSchema = EventSchema> = Trigger<E> | ReadonlyArray<Trigger<E>>;
77
+ export type TriggerInput<E extends EventSchema = EventSchema> =
78
+ | TriggerDefinition<E>
79
+ | ReadonlyArray<TriggerDefinition<E>>;
62
80
 
63
81
  export interface ConcurrencyOption {
64
82
  /**
@@ -356,6 +374,7 @@ export interface FunctionRegistration {
356
374
  event?: string;
357
375
  cron?: string;
358
376
  expression?: string;
377
+ jitter?: string;
359
378
  }>;
360
379
  readonly steps: {
361
380
  readonly step: {
@@ -421,15 +440,13 @@ export interface FunctionRegistration {
421
440
  */
422
441
  export interface InngestFunction<
423
442
  Tag extends string,
424
- Triggers extends Trigger,
425
- Success extends Schema.Codec<unknown, unknown, never, never>,
443
+ Triggers extends NormalizedTrigger,
426
444
  Options extends FunctionOptions = FunctionOptions,
427
445
  > extends Pipeable {
428
446
  readonly [TypeId]: TypeId;
429
447
  readonly _tag: Tag;
430
448
  readonly key: string;
431
449
  readonly triggers: ReadonlyArray<Triggers>;
432
- readonly success: Success;
433
450
  readonly options: Options;
434
451
  readonly toRegistration: (config: RegistrationConfig) => FunctionRegistration;
435
452
  }
@@ -439,11 +456,11 @@ export interface InngestFunction<
439
456
  * @category models
440
457
  */
441
458
  export declare namespace InngestFunction {
442
- export type Any = InngestFunction<string, Trigger, Schema.Codec<any, any, never, never>, FunctionOptions>;
443
- export type Tag<F> = F extends InngestFunction<infer T, any, any, any> ? T : never;
444
- export type Triggers<F> = F extends InngestFunction<any, infer T, any, any> ? T : never;
459
+ export type Any = InngestFunction<string, NormalizedTrigger, FunctionOptions>;
460
+ export type Tag<F> = F extends InngestFunction<infer T, any, any> ? T : never;
461
+ export type Triggers<F> = F extends InngestFunction<any, infer T, any> ? T : never;
445
462
  export type Events<F> =
446
- F extends InngestFunction<any, infer T, any, any> ? (T extends EventTrigger<infer E> ? E : never) : never;
463
+ F extends InngestFunction<any, infer T, any> ? (T extends NormalizedEventTrigger<infer E> ? E : never) : never;
447
464
  export type EventPayload<F> = EventEnvelope<Events<F>>;
448
465
  export type HasBatchEvents<O> = O extends { readonly batchEvents: infer BatchEvents }
449
466
  ? Exclude<BatchEvents, undefined> extends BatchEventsOption
@@ -452,12 +469,10 @@ export declare namespace InngestFunction {
452
469
  : false;
453
470
  export type EventType<F> = HasBatchEvents<Options<F>> extends true ? ReadonlyArray<EventPayload<F>> : EventPayload<F>;
454
471
 
455
- export type SuccessSchema<F> = F extends InngestFunction<any, any, infer S, any> ? S : never;
456
- export type Success<F> = Schema.Schema.Type<SuccessSchema<F>>;
457
- export type Options<F> = F extends InngestFunction<any, any, any, infer O> ? O : never;
472
+ export type Options<F> = F extends InngestFunction<any, any, infer O> ? O : never;
458
473
  }
459
474
 
460
- const isEventTrigger = (t: Trigger): t is EventTrigger => Predicate.hasProperty(t, "event");
475
+ const isEventTrigger = (t: NormalizedTrigger): t is NormalizedEventTrigger => Predicate.hasProperty(t, "event");
461
476
 
462
477
  const encodeDuration = (input: Duration.Input): string =>
463
478
  Schema.encodeSync(InngestDuration)(Duration.fromInputUnsafe(input));
@@ -480,7 +495,7 @@ const Proto = {
480
495
  if (isEventTrigger(t)) {
481
496
  triggers.push({ event: t.event.identifier, expression: t.if });
482
497
  } else {
483
- triggers.push({ cron: t.cron });
498
+ triggers.push({ cron: t.cron, ...(Predicate.isNotUndefined(t.jitter) ? { jitter: t.jitter } : {}) });
484
499
  }
485
500
  }
486
501
 
@@ -597,7 +612,30 @@ const Proto = {
597
612
  },
598
613
  };
599
614
 
600
- type NormalizeTriggers<T extends TriggerInput> = T extends ReadonlyArray<Trigger> ? T[number] : T;
615
+ export type NormalizeTrigger<T> = T extends EventSchema
616
+ ? NormalizedEventTrigger<T>
617
+ : T extends InngestCron.CronDefinition
618
+ ? CronTrigger
619
+ : T extends EventTrigger<infer E>
620
+ ? NormalizedEventTrigger<E>
621
+ : T extends CronTrigger
622
+ ? T
623
+ : never;
624
+
625
+ export type NormalizeTriggers<T extends TriggerInput> =
626
+ T extends ReadonlyArray<infer Item> ? NormalizeTrigger<Item> : NormalizeTrigger<T>;
627
+
628
+ const normalizeTrigger = (trigger: TriggerDefinition): NormalizedTrigger => {
629
+ if (InngestEvent.isEventSchema(trigger)) {
630
+ return { event: trigger };
631
+ }
632
+
633
+ if (isCron(trigger)) {
634
+ return { cron: trigger.cron, ...(Predicate.isNotUndefined(trigger.jitter) ? { jitter: trigger.jitter } : {}) };
635
+ }
636
+
637
+ return trigger;
638
+ };
601
639
 
602
640
  /**
603
641
  * @since 0.1.0
@@ -606,46 +644,36 @@ type NormalizeTriggers<T extends TriggerInput> = T extends ReadonlyArray<Trigger
606
644
  * ```ts
607
645
  * // Event trigger
608
646
  * const Fn1 = InngestFunction.make("Hello", {
609
- * trigger: { event: HelloEvent },
610
- * success: Schema.Void,
647
+ * trigger: HelloEvent,
611
648
  * })
612
649
  *
613
650
  * // Event trigger with CEL filter
614
651
  * const Fn2 = InngestFunction.make("Hello", {
615
652
  * trigger: { event: HelloEvent, if: "event.data.name != ''" },
616
- * success: Schema.Void,
617
653
  * })
618
654
  *
619
655
  * // Cron trigger
620
656
  * const Fn3 = InngestFunction.make("Scheduled", {
621
- * trigger: { cron: "0 * * * *" },
622
- * success: Schema.Void,
657
+ * trigger: InngestCron.make("0 * * * *"),
623
658
  * })
624
659
  *
625
660
  * // Multiple triggers
626
661
  * const Fn4 = InngestFunction.make("Multi", {
627
662
  * trigger: [
628
- * { event: HelloEvent },
629
- * { cron: "0 0 * * *" },
663
+ * HelloEvent,
664
+ * InngestCron.make("0 0 * * *"),
630
665
  * ],
631
- * success: Schema.Void,
632
666
  * })
633
667
  * ```
634
668
  */
635
- export function make<
636
- const Tag extends string,
637
- T extends TriggerInput,
638
- S extends Schema.Codec<unknown, unknown, never, never>,
639
- const O extends FunctionOptions = {},
640
- >(
669
+ export function make<const Tag extends string, T extends TriggerInput, const O extends FunctionOptions = {}>(
641
670
  tag: Tag,
642
- options: { readonly trigger: T; readonly success: S } & O,
643
- ): InngestFunction<Tag, NormalizeTriggers<T>, S, O> {
671
+ options: { readonly trigger: T } & O,
672
+ ): InngestFunction<Tag, NormalizeTriggers<T>, O> {
644
673
  const fn = Object.create(Proto);
645
674
  fn._tag = tag;
646
675
  fn.key = `effect-inngest/Function/${tag}`;
647
- fn.triggers = Arr.ensure(options.trigger);
648
- fn.success = options.success;
676
+ fn.triggers = Arr.map(Arr.ensure(options.trigger), normalizeTrigger);
649
677
  fn.options = options;
650
678
  return fn;
651
679
  }
package/src/Group.ts CHANGED
@@ -8,6 +8,7 @@ import type { InngestFunction } from "./Function.js";
8
8
  import * as ServeHttp from "./internal/serve/HttpApp.js";
9
9
 
10
10
  import { type HandlerContext } from "./internal/runtime/HandlerContext.js";
11
+ import { StepTools } from "./internal/runtime/StepTools.js";
11
12
 
12
13
  /**
13
14
  * Re-export HandlerContext.
@@ -34,7 +35,7 @@ export type TypeId = typeof TypeId;
34
35
  */
35
36
  export type HandlerFn<F extends InngestFunction.Any> = (
36
37
  context: HandlerContext<F>,
37
- ) => Effect.Effect<InngestFunction.Success<F>, unknown, unknown>;
38
+ ) => Effect.Effect<unknown, unknown, unknown>;
38
39
 
39
40
  /**
40
41
  * @since 0.1.0
@@ -59,8 +60,12 @@ export type HandlerFrom<Fns extends InngestFunction.Any, Tag extends InngestFunc
59
60
  * @since 0.1.0
60
61
  * @category models
61
62
  */
63
+ type RuntimeRequirements = InngestClient | StepTools;
64
+
62
65
  export type HandlersRequirements<H> =
63
- H extends Record<string, (...args: ReadonlyArray<unknown>) => Effect.Effect<unknown, unknown, infer R>> ? R : never;
66
+ H extends Record<string, (...args: ReadonlyArray<unknown>) => Effect.Effect<unknown, unknown, infer R>>
67
+ ? Exclude<R, RuntimeRequirements>
68
+ : never;
64
69
 
65
70
  /**
66
71
  * @since 0.1.0
@@ -69,7 +74,7 @@ export type HandlersRequirements<H> =
69
74
  export type HandlerRequirements<Handler> = Handler extends (
70
75
  ...args: ReadonlyArray<unknown>
71
76
  ) => Effect.Effect<unknown, unknown, infer R>
72
- ? R
77
+ ? Exclude<R, RuntimeRequirements>
73
78
  : never;
74
79
 
75
80
  /**
@@ -90,7 +95,7 @@ export interface Handler<Tag extends string> {
90
95
  * @category models
91
96
  */
92
97
  export type ToHandler<F extends InngestFunction.Any> =
93
- F extends InngestFunction<infer Tag, infer _Triggers, infer _Success> ? Handler<Tag> : never;
98
+ F extends InngestFunction<infer Tag, infer _Triggers> ? Handler<Tag> : never;
94
99
 
95
100
  /**
96
101
  * @since 0.1.0
@@ -128,9 +133,7 @@ export interface InngestGroup<Fns extends InngestFunction.Any> {
128
133
  readonly accessHandler: <Tag extends InngestFunction.Tag<Fns>>(
129
134
  tag: Tag,
130
135
  ) => Effect.Effect<
131
- (
132
- context: HandlerContext<Extract<Fns, { readonly _tag: Tag }>>,
133
- ) => Effect.Effect<InngestFunction.Success<Extract<Fns, { readonly _tag: Tag }>>, unknown>,
136
+ (context: HandlerContext<Extract<Fns, { readonly _tag: Tag }>>) => Effect.Effect<unknown, unknown>,
134
137
  never,
135
138
  Handler<Tag>
136
139
  >;
package/src/Inngest.ts ADDED
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Durable workflow operations for Inngest handlers.
3
+ *
4
+ * @since 0.1.0
5
+ */
6
+ import { Duration, Effect, Option } from "effect";
7
+ import type { InngestClient } from "./Client.js";
8
+ import type * as InngestEvent from "./Event.js";
9
+ import type { InngestFunction } from "./Function.js";
10
+ import type * as EventPayload from "./internal/codec/EventPayload.js";
11
+ import type { StepInput } from "./internal/domain/StepInput.js";
12
+ import type { SendEventError, StepError } from "./internal/errors.js";
13
+ import {
14
+ StepTools,
15
+ type InvokeOptions,
16
+ type OutgoingEvent,
17
+ type WaitForEventOptions,
18
+ } from "./internal/runtime/StepTools.js";
19
+
20
+ /**
21
+ * Execute an Effect as a durable, memoized step.
22
+ *
23
+ * @since 0.1.0
24
+ * @category steps
25
+ */
26
+ export const run = <A, Err, R>(
27
+ id: StepInput,
28
+ effect: Effect.Effect<A, Err, R>,
29
+ ): Effect.Effect<A, StepError | Err, R | StepTools> => Effect.flatMap(StepTools, (step) => step.run(id, effect));
30
+
31
+ /**
32
+ * Sleep durably for a duration.
33
+ *
34
+ * @since 0.1.0
35
+ * @category steps
36
+ */
37
+ export const sleep = (id: StepInput, duration: Duration.Input): Effect.Effect<void, never, StepTools> =>
38
+ Effect.flatMap(StepTools, (step) => step.sleep(id, duration));
39
+
40
+ /**
41
+ * Sleep durably until a timestamp.
42
+ *
43
+ * @since 0.1.0
44
+ * @category steps
45
+ */
46
+ export const sleepUntil = (id: StepInput, timestamp: Date | number | string): Effect.Effect<void, never, StepTools> =>
47
+ Effect.flatMap(StepTools, (step) => step.sleepUntil(id, timestamp));
48
+
49
+ /**
50
+ * Wait for a matching event.
51
+ *
52
+ * @since 0.1.0
53
+ * @category steps
54
+ */
55
+ export const waitForEvent = <E extends EventPayload.EventSchema>(
56
+ id: StepInput,
57
+ event: E,
58
+ options: WaitForEventOptions,
59
+ ): Effect.Effect<Option.Option<InngestEvent.EventType<E>>, StepError, StepTools> =>
60
+ Effect.flatMap(StepTools, (step) => step.waitForEvent(id, event, options));
61
+
62
+ /**
63
+ * Invoke another Inngest function.
64
+ *
65
+ * @since 0.1.0
66
+ * @category steps
67
+ */
68
+ export const invoke = <F extends InngestFunction.Any>(
69
+ id: StepInput,
70
+ options: InvokeOptions<F>,
71
+ ): Effect.Effect<unknown, StepError, StepTools> => Effect.flatMap(StepTools, (step) => step.invoke(id, options));
72
+
73
+ /**
74
+ * Send one or more Inngest events.
75
+ *
76
+ * @since 0.1.0
77
+ * @category steps
78
+ */
79
+ export const sendEvent = (
80
+ id: StepInput,
81
+ payload: OutgoingEvent | ReadonlyArray<OutgoingEvent>,
82
+ ): Effect.Effect<{ readonly ids: ReadonlyArray<string> }, SendEventError, StepTools | InngestClient> =>
83
+ Effect.flatMap(StepTools, (step) => step.sendEvent(id, payload));
84
+
85
+ export type EventType<E extends EventPayload.EventSchema> = InngestEvent.EventType<E>;
package/src/index.ts CHANGED
@@ -2,13 +2,13 @@
2
2
  * This module provides types and functions for defining Inngest functions.
3
3
  *
4
4
  * Functions are the core building blocks of Inngest applications. Each function
5
- * defines what events trigger it, what it returns on success, and optional
6
- * configuration like retries, concurrency limits, rate limiting, and more.
5
+ * defines what events trigger it and optional configuration like retries,
6
+ * concurrency limits, rate limiting, and more.
7
7
  *
8
8
  * @example
9
9
  * ```ts
10
10
  * import { Effect, Schema } from "effect"
11
- * import { InngestEvent, InngestFunction, InngestGroup } from "effect-inngest"
11
+ * import { InngestEvent, InngestFunction, InngestGroup, Inngest } from "effect-inngest"
12
12
  *
13
13
  * const UserCreated = InngestEvent.make(
14
14
  * "user/created",
@@ -20,8 +20,7 @@
20
20
  *
21
21
  * // Define functions
22
22
  * const SendWelcomeEmail = InngestFunction.make("send-welcome-email", {
23
- * trigger: { event: UserCreated },
24
- * success: Schema.Void,
23
+ * trigger: UserCreated,
25
24
  * retries: 3,
26
25
  * })
27
26
  *
@@ -50,6 +49,14 @@ export * as InngestFunction from "./Function.js";
50
49
  */
51
50
  export * as InngestEvent from "./Event.js";
52
51
 
52
+ /**
53
+ * Public cron trigger helpers.
54
+ *
55
+ * @module InngestCron
56
+ * @since 0.1.0
57
+ */
58
+ export * as InngestCron from "./Cron.js";
59
+
53
60
  /**
54
61
  * This module provides types and functions for grouping Inngest functions
55
62
  * and creating handler layers.
@@ -109,6 +116,14 @@ export * as InngestGroup from "./Group.js";
109
116
  */
110
117
  export * as InngestClient from "./Client.js";
111
118
 
119
+ /**
120
+ * Durable workflow operations used inside handlers.
121
+ *
122
+ * @module Inngest
123
+ * @since 0.1.0
124
+ */
125
+ export * as Inngest from "./Inngest.js";
126
+
112
127
  /**
113
128
  * This module provides integration with `@effect/platform` HttpApi.
114
129
  *
@@ -152,8 +167,7 @@ export * as InngestHttpApi from "./HttpApi.js";
152
167
  *
153
168
  * // React to function failures
154
169
  * const HandleFailure = InngestFunction.make("handle-failure", {
155
- * trigger: { event: InngestEvents.FunctionFailed },
156
- * success: Schema.Void,
170
+ * trigger: InngestEvents.FunctionFailed,
157
171
  * })
158
172
  * ```
159
173
  *
@@ -1,8 +1,6 @@
1
- import { Effect, Function, Option, Predicate, Schema } from "effect";
1
+ import { Effect, Function, Predicate } from "effect";
2
2
  import { StepError } from "../errors.js";
3
3
 
4
- export type OptionalMemoCodec<A> = Option.Option<Schema.Codec<A, Schema.Json, never, never>>;
5
-
6
4
  const messageFromCause = (cause: unknown): string => {
7
5
  if (Predicate.hasProperty(cause, "cause")) {
8
6
  const nested = messageFromCause(cause.cause);
@@ -38,46 +36,6 @@ export const mapMemoDecodeError: {
38
36
  effect.pipe(Effect.mapError((cause) => memoDecodeError({ stepId, cause }))),
39
37
  );
40
38
 
41
- export const decodeMemo: {
42
- <A>(
43
- schema: Schema.Codec<A, Schema.Json, never, never>,
44
- stepId: string,
45
- ): (value: unknown) => Effect.Effect<A, StepError>;
46
- <A>(value: unknown, schema: Schema.Codec<A, Schema.Json, never, never>, stepId: string): Effect.Effect<A, StepError>;
47
- } = Function.dual(3, <A>(value: unknown, schema: Schema.Codec<A, Schema.Json, never, never>, stepId: string) =>
48
- Schema.decodeUnknownEffect(schema)(value).pipe(mapMemoDecodeError(stepId)),
49
- );
50
-
51
- export const encodeMemo: {
52
- <A, I>(
53
- schema: Schema.Codec<A, I, never, never>,
54
- stepId: string,
55
- ): (value: unknown) => Effect.Effect<Schema.Json, StepError>;
56
- <A, I>(
57
- value: unknown,
58
- schema: Schema.Codec<A, I, never, never>,
59
- stepId: string,
60
- ): Effect.Effect<Schema.Json, StepError>;
61
- } = Function.dual(3, <A, I>(value: unknown, schema: Schema.Codec<A, I, never, never>, stepId: string) =>
62
- Schema.encodeUnknownEffect(Schema.toCodecJson(schema))(value).pipe(mapMemoDecodeError(stepId)),
63
- );
64
-
65
- export const decodeStepRunMemo =
66
- <A>(schema: OptionalMemoCodec<A>, stepId: string) =>
67
- (value: unknown): Effect.Effect<A | void, StepError> =>
68
- Option.match(schema, {
69
- onNone: () => Effect.void,
70
- onSome: (codec) => decodeMemo(codec, stepId)(value),
71
- });
72
-
73
- export const encodeStepRunMemo =
74
- <A>(schema: OptionalMemoCodec<A>, stepId: string) =>
75
- (value: unknown): Effect.Effect<Schema.Json | undefined, StepError> =>
76
- Option.match(schema, {
77
- onNone: () => (Predicate.isUndefined(value) ? Effect.succeed(undefined) : decodeMemo(Schema.Json, stepId)(value)),
78
- onSome: (codec) => encodeMemo(codec, stepId)(value),
79
- });
80
-
81
39
  export const failStepRunMemoError = (stepId: string, error: unknown): Effect.Effect<never, StepError> =>
82
40
  Effect.fail(
83
41
  StepError.make({
@@ -8,15 +8,26 @@ import * as ExecutionScope from "./execution/ExecutionScope.js";
8
8
  import * as HandlerRun from "./execution/HandlerRun.js";
9
9
  import * as ExecutionResponse from "./execution/ExecutionResponse.js";
10
10
  import { ExecutionResult } from "./execution/ExecutionResult.js";
11
+ import { CurrentExecutionInput } from "./domain/ExecutionInput.js";
12
+ import { InngestConfig } from "../Client.js";
13
+ import { HandlerFiberScope } from "./runtime/HandlerFiberScope.js";
14
+ import { StepCommandBus } from "./runtime/StepCommandBus.js";
15
+ import { StepIdentity } from "./runtime/StepIdentity.js";
16
+ import { StepTools } from "./runtime/StepTools.js";
11
17
 
12
18
  export { ExecutionResult };
13
19
 
14
20
  export const execute = <F extends InngestFunction.Any, R>(args: {
15
21
  readonly fn: F;
16
- readonly handler: (ctx: HandlerContext<F>) => Effect.Effect<InngestFunction.Success<F>, unknown, R>;
22
+ readonly handler: (ctx: HandlerContext<F>) => Effect.Effect<unknown, unknown, R>;
17
23
  readonly request: Protocol.SDKRequestBody;
18
24
  readonly checkpointConfig?: Option.Option<CheckpointConfig>;
19
- }): Effect.Effect<ExecutionResult, never, R | InngestClient> =>
25
+ }): Effect.Effect<
26
+ ExecutionResult,
27
+ never,
28
+ | Exclude<R, CurrentExecutionInput | HandlerFiberScope | InngestConfig | StepCommandBus | StepIdentity | StepTools>
29
+ | InngestClient
30
+ > =>
20
31
  HandlerRun.run({ fn: args.fn, handler: args.handler }).pipe(
21
32
  HandlerRun.withCheckpointDeadline,
22
33
  Effect.scoped,
@@ -2,6 +2,7 @@ import { Effect, Option, Schema } from "effect";
2
2
  import type { InngestFunction } from "../../Function.js";
3
3
  import * as HandlerContext from "../runtime/HandlerContext.js";
4
4
  import { CurrentCheckpoint } from "../runtime/CheckpointContext.js";
5
+ import * as SafeStringify from "../utils/safe-stringify.js";
5
6
 
6
7
  export class HandlerSucceeded extends Schema.TaggedClass<HandlerSucceeded>()("HandlerSucceeded", {
7
8
  value: Schema.Unknown,
@@ -16,11 +17,11 @@ export type HandlerCompletion = HandlerSucceeded | CheckpointDeadlineElapsed;
16
17
 
17
18
  export const run = <F extends InngestFunction.Any, R>(args: {
18
19
  readonly fn: F;
19
- readonly handler: (ctx: HandlerContext.HandlerContext<F>) => Effect.Effect<InngestFunction.Success<F>, unknown, R>;
20
+ readonly handler: (ctx: HandlerContext.HandlerContext<F>) => Effect.Effect<unknown, unknown, R>;
20
21
  }) =>
21
22
  HandlerContext.make({ fn: args.fn }).pipe(
22
23
  Effect.flatMap(args.handler),
23
- Effect.map((value) => HandlerSucceeded.make({ value })),
24
+ Effect.map((value) => HandlerSucceeded.make({ value: SafeStringify.normalize(value) })),
24
25
  );
25
26
 
26
27
  export const withCheckpointDeadline = <E, R>(effect: Effect.Effect<HandlerCompletion, E, R>) =>
@@ -2,20 +2,17 @@ import { Effect } from "effect";
2
2
  import type { InngestFunction } from "../../Function.js";
3
3
  import * as EventPayload from "../codec/EventPayload.js";
4
4
  import { CurrentExecutionInput, type ExecutionInput } from "../domain/ExecutionInput.js";
5
- import { StepTools } from "./StepTools.js";
6
5
 
7
6
  export 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
 
13
11
  export const make = <F extends InngestFunction.Any>(args: {
14
12
  readonly fn: F;
15
- }): Effect.Effect<HandlerContext<F>, EventPayload.EventDecodeError, StepTools | CurrentExecutionInput> =>
13
+ }): Effect.Effect<HandlerContext<F>, EventPayload.EventDecodeError, CurrentExecutionInput> =>
16
14
  Effect.gen(function* () {
17
15
  const input = yield* CurrentExecutionInput;
18
- const step = yield* StepTools;
19
16
  const event = yield* EventPayload.decodeInvocation({ fn: args.fn, input });
20
- return { event, step, run: input.run };
17
+ return { event, run: input.run };
21
18
  });
@@ -1,4 +1,4 @@
1
- import { Context, Duration, Effect, Layer, Option, Predicate, Schema, pipe } from "effect";
1
+ import { Context, Duration, Effect, Layer, Option, pipe } from "effect";
2
2
  import { InngestClient, InngestConfig } from "../../Client.js";
3
3
  import type * as InngestEvent from "../../Event.js";
4
4
  import type { InngestFunction } from "../../Function.js";
@@ -17,12 +17,6 @@ import * as SleepUntilStep from "./steps/SleepUntilStep.js";
17
17
  import * as StepRun from "./steps/StepRun.js";
18
18
  import * as WaitForEventStep from "./steps/WaitForEventStep.js";
19
19
 
20
- export type JsonSchema<A = unknown> = Schema.Codec<A, unknown, never, never>;
21
-
22
- export interface RunOptions<S extends JsonSchema> {
23
- readonly schema: S;
24
- }
25
-
26
20
  export interface WaitForEventOptions {
27
21
  readonly timeout: Duration.Input;
28
22
  readonly if?: string;
@@ -40,12 +34,7 @@ export type InvokeOptions<F extends InngestFunction.Any> = [InngestFunction.Even
40
34
  : InvokeOptionsBase<F> & { readonly data: InngestFunction.EventPayload<F> };
41
35
 
42
36
  export interface Run {
43
- <Err, R>(id: StepInput, effect: Effect.Effect<void, Err, R>): Effect.Effect<void, StepError | Err, R>;
44
- <S extends JsonSchema, Err, R>(
45
- id: StepInput,
46
- effect: Effect.Effect<Schema.Schema.Type<S>, Err, R>,
47
- options: RunOptions<S>,
48
- ): Effect.Effect<Schema.Schema.Type<S>, StepError | Err, R>;
37
+ <A, Err, R>(id: StepInput, effect: Effect.Effect<A, Err, R>): Effect.Effect<A, StepError | Err, R>;
49
38
  }
50
39
 
51
40
  export interface Sleep {
@@ -65,10 +54,7 @@ export interface WaitForEvent {
65
54
  }
66
55
 
67
56
  export interface Invoke {
68
- <F extends InngestFunction.Any>(
69
- id: StepInput,
70
- options: InvokeOptions<F>,
71
- ): Effect.Effect<InngestFunction.Success<F>, StepError>;
57
+ <F extends InngestFunction.Any>(id: StepInput, options: InvokeOptions<F>): Effect.Effect<unknown, StepError>;
72
58
  }
73
59
 
74
60
  export interface OutgoingEvent {
@@ -113,20 +99,7 @@ export class StepTools extends Context.Service<StepTools, StepTools.Service>()(
113
99
  Context.add(HandlerFiberScope, handlerFiberScope),
114
100
  );
115
101
 
116
- function run<Err, R>(id: StepInput, effect: Effect.Effect<void, Err, R>): Effect.Effect<void, StepError | Err, R>;
117
- function run<S extends JsonSchema, Err, R>(
118
- id: StepInput,
119
- effect: Effect.Effect<Schema.Schema.Type<S>, Err, R>,
120
- options: RunOptions<S>,
121
- ): Effect.Effect<Schema.Schema.Type<S>, StepError | Err, R>;
122
- function run<S extends JsonSchema, Err, R>(
123
- id: StepInput,
124
- effect: Effect.Effect<void | Schema.Schema.Type<S>, Err, R>,
125
- options?: RunOptions<S>,
126
- ) {
127
- if (Predicate.isNotUndefined(options)) {
128
- return StepRun.run({ input, id: identity.reserve(id), effect, options }).pipe(Effect.provide(runtime));
129
- }
102
+ function run<A, Err, R>(id: StepInput, effect: Effect.Effect<A, Err, R>) {
130
103
  return StepRun.run({ input, id: identity.reserve(id), effect }).pipe(Effect.provide(runtime));
131
104
  }
132
105
 
@@ -2,7 +2,6 @@ import { Duration, Effect, Match, Predicate, Schema } from "effect";
2
2
  import { InngestConfig } from "../../../Client.js";
3
3
  import type { InngestFunction } from "../../../Function.js";
4
4
  import { StepError } from "../../errors.js";
5
- import * as StepResult from "../../codec/StepResult.js";
6
5
  import { InngestDuration } from "../../wire/Duration.js";
7
6
  import type { ExecutionInput } from "../../domain/ExecutionInput.js";
8
7
  import * as StepCommand from "../../domain/StepCommand.js";
@@ -23,9 +22,7 @@ export const invoke = <F extends InngestFunction.Any>(args: {
23
22
  const memo = args.input.memoForStep(info);
24
23
 
25
24
  return yield* Match.value(memo).pipe(
26
- Match.tag("MemoData", ({ data }) =>
27
- StepResult.decodeMemo(Schema.toCodecJson(args.options.function.success), info.id)(data),
28
- ),
25
+ Match.tag("MemoData", ({ data }) => Effect.succeed(data)),
29
26
  Match.tag("MemoError", ({ error }) =>
30
27
  Effect.fail(
31
28
  StepError.make({