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/src/Events.ts
CHANGED
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
|
|
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
|
|
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> =
|
|
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
|
|
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,
|
|
443
|
-
export type Tag<F> = F extends InngestFunction<infer T, any, any
|
|
444
|
-
export type Triggers<F> = F extends InngestFunction<any, infer T, any
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
*
|
|
629
|
-
*
|
|
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
|
|
643
|
-
): InngestFunction<Tag, NormalizeTriggers<T>,
|
|
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<
|
|
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>>
|
|
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
|
|
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
|
|
6
|
-
*
|
|
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:
|
|
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:
|
|
156
|
-
* success: Schema.Void,
|
|
170
|
+
* trigger: InngestEvents.FunctionFailed,
|
|
157
171
|
* })
|
|
158
172
|
* ```
|
|
159
173
|
*
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { Effect, Function,
|
|
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({
|
package/src/internal/driver.ts
CHANGED
|
@@ -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<
|
|
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<
|
|
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<
|
|
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,
|
|
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,
|
|
17
|
+
return { event, run: input.run };
|
|
21
18
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Context, Duration, Effect, Layer, Option,
|
|
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<
|
|
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<
|
|
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({
|