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
@@ -1,43 +1,19 @@
1
- import { Effect, Match, Option, Schema } from "effect";
1
+ import { Effect, Match } from "effect";
2
2
  import type { StepError } from "../../errors.js";
3
3
  import * as StepResult from "../../codec/StepResult.js";
4
4
  import type { ExecutionInput } from "../../domain/ExecutionInput.js";
5
5
  import { CurrentExecutionInput } from "../../domain/ExecutionInput.js";
6
6
  import * as StepCommand from "../../domain/StepCommand.js";
7
+ import * as SafeStringify from "../../utils/safe-stringify.js";
7
8
  import { HandlerFiberScope } from "../HandlerFiberScope.js";
8
- import type { JsonSchema, RunOptions } from "../StepTools.js";
9
9
  import { StepIdentity, type StepReservation } from "../StepIdentity.js";
10
10
  import { StepCommandBus } from "../StepCommandBus.js";
11
11
 
12
- export function run<Err, R>(args: {
12
+ export function run<A, Err, R>(args: {
13
13
  readonly input: ExecutionInput;
14
14
  readonly id: StepReservation;
15
- readonly effect: Effect.Effect<void, Err, R>;
16
- }): Effect.Effect<void, StepError | Err, R | StepIdentity | StepCommandBus | CurrentExecutionInput | HandlerFiberScope>;
17
- export function run<S extends JsonSchema, Err, R>(args: {
18
- readonly input: ExecutionInput;
19
- readonly id: StepReservation;
20
- readonly effect: Effect.Effect<S["Type"], Err, R>;
21
- readonly options: RunOptions<S>;
22
- }): Effect.Effect<
23
- S["Type"],
24
- StepError | Err,
25
- R | StepIdentity | StepCommandBus | CurrentExecutionInput | HandlerFiberScope
26
- >;
27
- export function run<S extends JsonSchema, Err, R>(args: {
28
- readonly input: ExecutionInput;
29
- readonly id: StepReservation;
30
- readonly effect: Effect.Effect<S["Type"] | void, Err, R>;
31
- readonly options?: RunOptions<S>;
32
- }): Effect.Effect<
33
- void | S["Type"],
34
- StepError | Err,
35
- R | StepIdentity | StepCommandBus | CurrentExecutionInput | HandlerFiberScope
36
- > {
37
- const memoCodec: StepResult.OptionalMemoCodec<S["Type"]> = args.options
38
- ? Option.some(Schema.toCodecJson(args.options.schema))
39
- : Option.none();
40
-
15
+ readonly effect: Effect.Effect<A, Err, R>;
16
+ }): Effect.Effect<A, StepError | Err, R | StepIdentity | StepCommandBus | CurrentExecutionInput | HandlerFiberScope> {
41
17
  return Effect.gen(function* () {
42
18
  const identity = yield* StepIdentity;
43
19
  const bus = yield* StepCommandBus;
@@ -45,47 +21,55 @@ export function run<S extends JsonSchema, Err, R>(args: {
45
21
  const memo = args.input.memoForStep(info);
46
22
 
47
23
  return yield* Match.value(memo).pipe(
48
- Match.tag("MemoData", ({ data }) => StepResult.decodeStepRunMemo(memoCodec, info.id)(data)),
24
+ Match.tag("MemoData", ({ data }) => Effect.succeed(data as A)),
49
25
  Match.tag("MemoError", ({ error }) => StepResult.failStepRunMemoError(info.id, error)),
50
26
  Match.tag("MemoTimeout", () => StepResult.failStepRunMemoTimeout(info.id)),
51
27
  Match.tag("MemoInput", ({ input }) => StepResult.failUnexpectedStepRunMemoInput(info.id, input)),
52
28
  Match.tag("MemoNone", () =>
53
29
  Effect.gen(function* () {
54
30
  if (!args.input.shouldExecuteStep(info)) {
55
- return yield* Effect.void;
31
+ return yield* Effect.interrupt;
56
32
  }
57
33
 
58
34
  const planned = StepCommand.StepRunPlanned.make({ info, sequence: args.id.sequence });
59
35
 
60
36
  if (args.input.shouldPlanStep(info)) {
61
37
  yield* bus.plan(planned);
62
- return yield* Effect.void;
38
+ return yield* Effect.interrupt;
63
39
  }
64
40
 
65
41
  if (yield* bus.planCheckpointedRunBoundary(planned)) {
66
- return yield* Effect.void;
42
+ return yield* Effect.interrupt;
67
43
  }
68
44
 
69
45
  return yield* args.effect.pipe(
70
46
  Effect.matchEffect({
71
47
  onFailure: (error) =>
72
- bus.fail(
73
- StepCommand.stepRunFailureForAttempt({
74
- info,
75
- error,
76
- attempt: args.input.run.attempt,
77
- maxAttempts: args.input.run.maxAttempts,
78
- }),
79
- ),
48
+ Effect.gen(function* () {
49
+ yield* bus.fail(
50
+ StepCommand.stepRunFailureForAttempt({
51
+ info,
52
+ error,
53
+ attempt: args.input.run.attempt,
54
+ maxAttempts: args.input.run.maxAttempts,
55
+ }),
56
+ );
57
+ return yield* Effect.interrupt;
58
+ }),
80
59
  onSuccess: (value) =>
81
60
  Effect.gen(function* () {
82
- const data = yield* StepResult.encodeStepRunMemo(memoCodec, info.id)(value);
61
+ const data = SafeStringify.normalize(value);
83
62
 
84
63
  yield* bus.complete(StepCommand.StepRunResult.make({ info, data }));
85
- return yield* StepResult.decodeStepRunMemo(memoCodec, info.id)(data);
64
+ return data as A;
86
65
  }),
87
66
  }),
88
- Effect.catchDefect((defect) => bus.fail(StepCommand.StepRunError.make({ info, error: defect }))),
67
+ Effect.catchDefect((defect) =>
68
+ Effect.gen(function* () {
69
+ yield* bus.fail(StepCommand.StepRunError.make({ info, error: defect }));
70
+ return yield* Effect.interrupt;
71
+ }),
72
+ ),
89
73
  );
90
74
  }),
91
75
  ),
@@ -0,0 +1,84 @@
1
+ import { Array as Arr, Option, Predicate } from "effect";
2
+
3
+ export type Replacer = (this: unknown, key: string, value: unknown) => unknown;
4
+ export type CycleReplacer = (this: unknown, key: string, value: unknown) => unknown;
5
+
6
+ interface State {
7
+ readonly stack: Array<unknown>;
8
+ readonly keys: Array<string>;
9
+ }
10
+
11
+ const findReference = (state: State, value: unknown): Option.Option<number> =>
12
+ Arr.findFirstIndex(state.stack, (candidate) => Object.is(candidate, value));
13
+
14
+ const isTracked = (state: State, value: unknown): boolean => Option.isSome(findReference(state, value));
15
+
16
+ const pushReference = (state: State, key: string, value: unknown): void => {
17
+ state.stack.push(value);
18
+ state.keys.push(key);
19
+ };
20
+
21
+ const trimToParent = (state: State, key: string, parentIndex: number): void => {
22
+ state.stack.splice(parentIndex + 1);
23
+ state.keys.splice(parentIndex, Infinity, key);
24
+ };
25
+
26
+ const refreshParent = (state: State, key: string, parent: unknown): void => {
27
+ Option.match(findReference(state, parent), {
28
+ onNone: () => {
29
+ if (Predicate.isObjectOrArray(parent)) {
30
+ pushReference(state, key, parent);
31
+ }
32
+ },
33
+ onSome: (parentIndex) => trimToParent(state, key, parentIndex),
34
+ });
35
+ };
36
+
37
+ const defaultCycleReplacer = (state: State): CycleReplacer =>
38
+ function (_key, value) {
39
+ const valueIndex = Option.getOrElse(findReference(state, value), () => -1);
40
+ if (Object.is(state.stack[0], value)) {
41
+ return "[Circular ~]";
42
+ }
43
+ return `[Circular ~.${state.keys.slice(0, valueIndex).join(".")}]`;
44
+ };
45
+
46
+ export function stringify(
47
+ obj: unknown,
48
+ replacer?: Replacer,
49
+ spaces?: string | number,
50
+ cycleReplacer?: CycleReplacer,
51
+ ): string | undefined {
52
+ return JSON.stringify(obj, getSerialize(replacer, cycleReplacer), spaces);
53
+ }
54
+
55
+ export const normalize = (value: unknown): unknown => {
56
+ const json = stringify(value, (_key, child) => {
57
+ if (!Predicate.isBigInt(child)) {
58
+ return child;
59
+ }
60
+ });
61
+
62
+ return Predicate.isUndefined(json) ? null : JSON.parse(json);
63
+ };
64
+
65
+ export function getSerialize(replacer?: Replacer, cycleReplacer?: CycleReplacer): Replacer {
66
+ const state: State = { stack: [], keys: [] };
67
+ const replaceCycle = cycleReplacer ?? defaultCycleReplacer(state);
68
+
69
+ return function (key, value) {
70
+ if (Arr.isArrayNonEmpty(state.stack)) {
71
+ refreshParent(state, key, this);
72
+
73
+ if (Predicate.isObjectKeyword(value) && isTracked(state, value)) {
74
+ value = replaceCycle.call(this, key, value);
75
+ }
76
+ } else {
77
+ state.stack.push(value);
78
+ }
79
+
80
+ return replacer ? replacer.call(this, key, value) : value;
81
+ };
82
+ }
83
+
84
+ export default stringify;