effect-inngest 0.3.0-beta.3 → 0.4.0-beta1

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 (58) 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 +7 -7
  10. package/dist/Group.js +1 -0
  11. package/dist/HttpApi.js +2 -1
  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/checkpoint/Abort.d.ts +1 -0
  17. package/dist/internal/checkpoint/Abort.js +5 -0
  18. package/dist/internal/checkpoint/State.d.ts +1 -1
  19. package/dist/internal/checkpoint/State.js +8 -1
  20. package/dist/internal/codec/StepResult.js +2 -12
  21. package/dist/internal/driver.js +1 -0
  22. package/dist/internal/errors.js +1 -1
  23. package/dist/internal/execution/ExecutionResponse.js +33 -4
  24. package/dist/internal/execution/HandlerRun.js +2 -1
  25. package/dist/internal/handler.js +37 -24
  26. package/dist/internal/protocol.js +3 -0
  27. package/dist/internal/runtime/HandlerContext.d.ts +0 -2
  28. package/dist/internal/runtime/HandlerContext.js +0 -3
  29. package/dist/internal/runtime/StepTools.d.ts +8 -16
  30. package/dist/internal/runtime/StepTools.js +2 -8
  31. package/dist/internal/runtime/steps/InvokeStep.js +1 -2
  32. package/dist/internal/runtime/steps/StepRun.js +25 -19
  33. package/dist/internal/serve/HttpApp.js +2 -1
  34. package/dist/internal/utils/safe-stringify.js +50 -0
  35. package/package.json +17 -1
  36. package/src/Client.ts +1 -1
  37. package/src/Cron.ts +33 -0
  38. package/src/Events.ts +1 -1
  39. package/src/Function.ts +58 -34
  40. package/src/Group.ts +10 -7
  41. package/src/HttpApi.ts +7 -1
  42. package/src/Inngest.ts +85 -0
  43. package/src/index.ts +21 -7
  44. package/src/internal/checkpoint/Abort.ts +5 -0
  45. package/src/internal/checkpoint/State.ts +8 -0
  46. package/src/internal/codec/StepResult.ts +1 -43
  47. package/src/internal/driver.ts +13 -2
  48. package/src/internal/errors.ts +1 -3
  49. package/src/internal/execution/ExecutionResponse.ts +44 -1
  50. package/src/internal/execution/HandlerRun.ts +3 -2
  51. package/src/internal/handler.ts +39 -34
  52. package/src/internal/protocol.ts +3 -0
  53. package/src/internal/runtime/HandlerContext.ts +2 -5
  54. package/src/internal/runtime/StepTools.ts +4 -31
  55. package/src/internal/runtime/steps/InvokeStep.ts +1 -4
  56. package/src/internal/runtime/steps/StepRun.ts +28 -44
  57. package/src/internal/serve/HttpApp.ts +1 -0
  58. package/src/internal/utils/safe-stringify.ts +84 -0
package/README.md CHANGED
@@ -25,7 +25,7 @@
25
25
  Effect Inngest brings the power of [Effect](https://effect.website) to [Inngest's](https://inngest.com) durable execution platform. Define event schemas once, and types flow automatically through triggers, handlers, and step operations — no manual annotations needed.
26
26
 
27
27
  ```typescript
28
- import { InngestClient, InngestEvent, InngestFunction, InngestGroup } from "effect-inngest";
28
+ import { InngestClient, InngestEvent, InngestFunction, InngestGroup, Inngest, InngestCron } from "effect-inngest";
29
29
  import { Effect, Schema, Layer } from "effect";
30
30
 
31
31
  const UserSignup = InngestEvent.make(
@@ -38,8 +38,7 @@ const UserSignup = InngestEvent.make(
38
38
 
39
39
  // Create a function — event type is inferred from the trigger
40
40
  const ProcessSignup = InngestFunction.make("process-signup", {
41
- trigger: { event: UserSignup },
42
- success: Schema.Void,
41
+ trigger: UserSignup,
43
42
  });
44
43
 
45
44
  // Create group and implement handler
@@ -48,12 +47,12 @@ const Group = InngestGroup.make(ProcessSignup);
48
47
  const UserOnboarded = InngestEvent.make("user/onboarded", Schema.Struct({ userId: Schema.String }));
49
48
 
50
49
  const Handlers = Group.toLayer({
51
- "process-signup": ({ event, step }) =>
50
+ "process-signup": ({ event }) =>
52
51
  Effect.gen(function* () {
53
52
  // event is typed as { name: "user/signup", data: { userId, email } }
54
- yield* step.run("send-welcome", sendWelcomeEmail(event.data.email));
55
- yield* step.sleep("delay", "1 hour");
56
- yield* step.sendEvent("notify", UserOnboarded.make({ userId: event.data.userId }));
53
+ yield* Inngest.run("send-welcome", sendWelcomeEmail(event.data.email));
54
+ yield* Inngest.sleep("delay", "1 hour");
55
+ yield* Inngest.sendEvent("notify", UserOnboarded.make({ userId: event.data.userId }));
57
56
  }),
58
57
  });
59
58
  ```
@@ -65,9 +64,9 @@ const Handlers = Group.toLayer({
65
64
  ## Features
66
65
 
67
66
  - 🧙‍♂️ **Full type inference** — Payload types flow from schemas through triggers to handlers
68
- - ⚡ **Effect-native steps** — `step.run`, `step.sleep`, `step.waitForEvent` return proper Effects
67
+ - ⚡ **Effect-native steps** — `Inngest.run`, `Inngest.sleep`, `Inngest.waitForEvent` return proper Effects
69
68
  - 🔌 **Dependency injection** — Use Effect's Layer system for services in handlers
70
- - 🛡️ **Schema validation** — Define events once with Effect Schema, validated everywhere
69
+ - 🛡️ **Event validation** — Define events once with Effect Schema, validated at the boundary
71
70
  - 🚀 **Zero boilerplate** — No code generation, no manual type annotations
72
71
  - 🔄 **Parallel execution** — Run steps concurrently with `Effect.all`
73
72
  - 🌐 **Multi-runtime** — Works with Bun, Node.js, and Cloudflare Workers
@@ -109,7 +108,7 @@ import { BunHttpServer, BunRuntime } from "@effect/platform-bun";
109
108
  import * as HttpMiddleware from "@effect/platform/HttpMiddleware";
110
109
  import * as HttpServer from "@effect/platform/HttpServer";
111
110
  import { Duration, Effect, Layer, Schema } from "effect";
112
- import { InngestClient, InngestEvent, InngestFunction, InngestGroup } from "effect-inngest";
111
+ import { InngestClient, InngestEvent, InngestFunction, InngestGroup, Inngest, InngestCron } from "effect-inngest";
113
112
 
114
113
  // 1. Define your Inngest event definitions
115
114
  const UserSignup = InngestEvent.make(
@@ -124,39 +123,38 @@ const UserWelcomeSent = InngestEvent.make("user/welcome-sent", Schema.Struct({ u
124
123
 
125
124
  // 2. Define your functions
126
125
  const ProcessSignup = InngestFunction.make("process-signup", {
127
- trigger: { event: UserSignup },
128
- success: Schema.Struct({ welcomed: Schema.Boolean }),
126
+ trigger: UserSignup,
129
127
  });
130
128
 
131
129
  const DailyDigest = InngestFunction.make("daily-digest", {
132
- trigger: { cron: "0 9 * * *" },
133
- success: Schema.Void,
130
+ trigger: InngestCron.make("0 9 * * *"),
134
131
  });
135
132
 
136
133
  // 3. Create function group and implement handlers
137
134
  const App = InngestGroup.make(ProcessSignup, DailyDigest);
138
135
 
139
136
  const Handlers = App.toLayer({
140
- "process-signup": ({ event, step }) =>
137
+ "process-signup": ({ event }) =>
141
138
  Effect.gen(function* () {
142
139
  // event is typed as { name: "user/signup", data: { userId, email } }
143
140
  yield* Effect.log(`Processing signup for ${event.data.email}`);
144
141
 
145
- // Durable value-returning steps need a replay schema
146
- const user = yield* step.run("create-user", Effect.succeed({ id: event.data.userId, email: event.data.email }), {
147
- schema: Schema.Struct({ id: Schema.String, email: Schema.String }),
148
- });
142
+ // Durable value-returning steps are normalized through JSON on the wire
143
+ const user = yield* Inngest.run(
144
+ "create-user",
145
+ Effect.succeed({ id: event.data.userId, email: event.data.email }),
146
+ );
149
147
 
150
148
  // Sleep durably
151
- yield* step.sleep("welcome-delay", Duration.seconds(5));
149
+ yield* Inngest.sleep("welcome-delay", Duration.seconds(5));
152
150
 
153
151
  // Send follow-up event
154
- yield* step.sendEvent("notify", UserWelcomeSent.make({ userId: user.id }));
152
+ yield* Inngest.sendEvent("notify", UserWelcomeSent.make({ userId: user.id }));
155
153
 
156
154
  return { welcomed: true };
157
155
  }),
158
156
 
159
- "daily-digest": ({ step }) => step.run("send-digest", Effect.log("Sending daily digest...")),
157
+ "daily-digest": () => Inngest.run("send-digest", Effect.log("Sending daily digest...")),
160
158
  });
161
159
 
162
160
  // 4. Create client and start server
@@ -200,7 +198,7 @@ import { FetchHttpClient } from "@effect/platform";
200
198
  import { BunHttpServer, BunRuntime } from "@effect/platform-bun";
201
199
  import { Duration, Effect, Layer, Schema } from "effect";
202
200
  import { InngestApiGroup, layerGroup } from "effect-inngest/HttpApi";
203
- import { InngestClient, InngestEvent, InngestFunction, InngestGroup } from "effect-inngest";
201
+ import { InngestClient, InngestEvent, InngestFunction, InngestGroup, Inngest, InngestCron } from "effect-inngest";
204
202
 
205
203
  // 1. Define your events
206
204
  const UserSignup = InngestEvent.make(
@@ -215,30 +213,29 @@ const UserWelcomeSent = InngestEvent.make("user/welcome-sent", Schema.Struct({ u
215
213
 
216
214
  // 2. Define functions
217
215
  const ProcessSignup = InngestFunction.make("process-signup", {
218
- trigger: { event: UserSignup },
219
- success: Schema.Struct({ welcomed: Schema.Boolean }),
216
+ trigger: UserSignup,
220
217
  });
221
218
 
222
219
  const DailyDigest = InngestFunction.make("daily-digest", {
223
- trigger: { cron: "0 9 * * *" },
224
- success: Schema.Void,
220
+ trigger: InngestCron.make("0 9 * * *"),
225
221
  });
226
222
 
227
223
  // 3. Create group and handlers
228
224
  const App = InngestGroup.make(ProcessSignup, DailyDigest);
229
225
 
230
226
  const Handlers = App.toLayer({
231
- "process-signup": ({ event, step }) =>
227
+ "process-signup": ({ event }) =>
232
228
  Effect.gen(function* () {
233
229
  yield* Effect.log(`Processing signup for ${event.data.email}`);
234
- const user = yield* step.run("create-user", Effect.succeed({ id: event.data.userId, email: event.data.email }), {
235
- schema: Schema.Struct({ id: Schema.String, email: Schema.String }),
236
- });
237
- yield* step.sleep("welcome-delay", Duration.seconds(5));
238
- yield* step.sendEvent("notify", UserWelcomeSent.make({ userId: user.id }));
230
+ const user = yield* Inngest.run(
231
+ "create-user",
232
+ Effect.succeed({ id: event.data.userId, email: event.data.email }),
233
+ );
234
+ yield* Inngest.sleep("welcome-delay", Duration.seconds(5));
235
+ yield* Inngest.sendEvent("notify", UserWelcomeSent.make({ userId: user.id }));
239
236
  return { welcomed: true };
240
237
  }),
241
- "daily-digest": ({ step }) => step.run("send-digest", Effect.log("Sending daily digest...")),
238
+ "daily-digest": () => Inngest.run("send-digest", Effect.log("Sending daily digest...")),
242
239
  });
243
240
 
244
241
  // 4. Create client
@@ -298,46 +295,44 @@ const UserWelcomeSent = InngestEvent.make("user/welcome-sent", Schema.Struct({ u
298
295
  ### 2. Define your functions
299
296
 
300
297
  ```typescript
301
- import { InngestFunction } from "effect-inngest";
298
+ import { InngestCron, InngestFunction } from "effect-inngest";
302
299
 
303
300
  // Event-triggered function
304
301
  const ProcessSignup = InngestFunction.make("process-signup", {
305
- trigger: [{ event: UserSignup }], // pass multiple triggers as Array.
306
- success: Schema.Struct({ welcomeEmailSent: Schema.Boolean }),
302
+ trigger: UserSignup,
307
303
  });
308
304
 
309
305
  // Cron-triggered function
310
306
  const DailyReport = InngestFunction.make("daily-report", {
311
- trigger: { cron: "0 9 * * *" },
312
- success: Schema.Void,
307
+ trigger: InngestCron.make("0 9 * * *"),
313
308
  });
314
309
  ```
315
310
 
316
311
  ### 3. Create a function group and implement handlers
317
312
 
318
313
  ```typescript
319
- import { InngestGroup } from "effect-inngest";
314
+ import { InngestGroup, Inngest } from "effect-inngest";
320
315
  import { Effect, Duration } from "effect";
321
316
 
322
317
  const AppFunctions = InngestGroup.make(ProcessSignup, DailyReport);
323
318
 
324
319
  const HandlersLive = AppFunctions.toLayer({
325
- "process-signup": ({ event, step }) =>
320
+ "process-signup": ({ event }) =>
326
321
  Effect.gen(function* () {
327
- yield* step.run("create-user", createUser(event));
328
- yield* step.sleep("delay", Duration.minutes(5));
329
- yield* step.sendEvent("welcome", UserWelcomeSent.make({ userId: event.data.userId }));
322
+ yield* Inngest.run("create-user", createUser(event));
323
+ yield* Inngest.sleep("delay", Duration.minutes(5));
324
+ yield* Inngest.sendEvent("welcome", UserWelcomeSent.make({ userId: event.data.userId }));
330
325
  return { welcomeEmailSent: true };
331
326
  }),
332
327
 
333
- "daily-report": ({ step }) => step.run("generate", Effect.log("Generating report...")),
328
+ "daily-report": () => Inngest.run("generate", Effect.log("Generating report...")),
334
329
  });
335
330
  ```
336
331
 
337
332
  ### 4. Create a web handler
338
333
 
339
334
  ```typescript
340
- import { InngestClient, InngestGroup } from "effect-inngest";
335
+ import { InngestClient, InngestGroup, Inngest } from "effect-inngest";
341
336
  import { FetchHttpClient } from "@effect/platform";
342
337
  import { Layer } from "effect";
343
338
 
@@ -363,31 +358,31 @@ Bun.serve({ port: 3000, fetch: handler });
363
358
  All step operations are durable — they're memoized and survive retries:
364
359
 
365
360
  ```typescript
366
- ({ step }) =>
361
+ () =>
367
362
  Effect.gen(function* () {
368
- // Run an Effect with memoization. Value-returning steps require a replay schema.
369
- const user = yield* step.run("fetch-user", fetchUser(userId), { schema: User });
363
+ // Run an Effect with memoization. Values are replayed as normalized JSON.
364
+ const user = yield* Inngest.run("fetch-user", fetchUser(userId));
370
365
 
371
366
  // Sleep for a duration
372
- yield* step.sleep("wait", Duration.hours(24));
367
+ yield* Inngest.sleep("wait", Duration.hours(24));
373
368
 
374
369
  // Sleep until a timestamp
375
- yield* step.sleepUntil("deadline", new Date("2024-12-31"));
370
+ yield* Inngest.sleepUntil("deadline", new Date("2024-12-31"));
376
371
 
377
372
  // Wait for an event (returns Option)
378
- const payment = yield* step.waitForEvent("await-payment", PaymentReceived, {
373
+ const payment = yield* Inngest.waitForEvent("await-payment", PaymentReceived, {
379
374
  timeout: Duration.days(7),
380
375
  if: `async.data.orderId == "${orderId}"`,
381
376
  });
382
377
 
383
378
  // Invoke another function
384
- const result = yield* step.invoke("process", {
379
+ const result = yield* Inngest.invoke("process", {
385
380
  function: ProcessOrder,
386
- data: { orderId: "123" },
381
+ data: OrderPlaced.make({ orderId: "123", items: [], total: 0 }),
387
382
  });
388
383
 
389
384
  // Send events
390
- yield* step.sendEvent("notify", OrderShipped.make({ orderId }));
385
+ yield* Inngest.sendEvent("notify", OrderShipped.make({ orderId }));
391
386
  });
392
387
  ```
393
388
 
@@ -400,9 +395,9 @@ const [user, orders, prefs] =
400
395
  yield *
401
396
  Effect.all(
402
397
  [
403
- step.run("user", fetchUser(id), { schema: User }),
404
- step.run("orders", fetchOrders(id), { schema: Schema.Array(Order) }),
405
- step.run("prefs", fetchPreferences(id), { schema: Preferences }),
398
+ Inngest.run("user", fetchUser(id)),
399
+ Inngest.run("orders", fetchOrders(id)),
400
+ Inngest.run("prefs", fetchPreferences(id)),
406
401
  ],
407
402
  { concurrency: "unbounded" },
408
403
  );
@@ -425,10 +420,10 @@ class EmailService extends Context.Tag("EmailService")<
425
420
 
426
421
  // Use in handler
427
422
  const HandlersLive = AppFunctions.toLayer({
428
- "process-signup": ({ event, step }) =>
423
+ "process-signup": ({ event }) =>
429
424
  Effect.gen(function* () {
430
425
  const email = yield* EmailService;
431
- yield* step.run("send", email.send(event.data.email, "Welcome!"));
426
+ yield* Inngest.run("send", email.send(event.data.email, "Welcome!"));
432
427
  return { welcomeEmailSent: true };
433
428
  }),
434
429
  });
@@ -451,7 +446,7 @@ Configure retries, concurrency, rate limiting, and more:
451
446
 
452
447
  ```typescript
453
448
  const ProcessOrder = InngestFunction.make("process-order", {
454
- trigger: { event: OrderPlaced },
449
+ trigger: OrderPlaced,
455
450
  retries: 5,
456
451
  concurrency: { limit: 10, key: "event.data.userId" },
457
452
  rateLimit: { limit: 100, period: Duration.minutes(1) },
@@ -498,15 +493,14 @@ yield * Effect.fail(RetryAfterError.make({ message: "Rate limited", retryAfter:
498
493
 
499
494
  ### Step Methods
500
495
 
501
- | Method | Description |
502
- | ------------------------------------------------ | ----------------------------------------------- |
503
- | `step.run(id, effect)` | Execute a void effect with memoization |
504
- | `step.run(id, effect, { schema })` | Execute a value-returning effect with replay IO |
505
- | `step.sleep(id, duration)` | Sleep for a duration |
506
- | `step.sleepUntil(id, timestamp)` | Sleep until a timestamp |
507
- | `step.waitForEvent(id, InngestEvent, opts)` | Wait for an event with timeout |
508
- | `step.invoke(id, opts)` | Invoke another function |
509
- | `step.sendEvent(id, InngestEvent.make(payload))` | Send events to Inngest |
496
+ | Method | Description |
497
+ | --------------------------------------------------- | ---------------------------------- |
498
+ | `Inngest.run(id, effect)` | Execute an Effect with memoization |
499
+ | `Inngest.sleep(id, duration)` | Sleep for a duration |
500
+ | `Inngest.sleepUntil(id, timestamp)` | Sleep until a timestamp |
501
+ | `Inngest.waitForEvent(id, InngestEvent, opts)` | Wait for an event with timeout |
502
+ | `Inngest.invoke(id, opts)` | Invoke another function |
503
+ | `Inngest.sendEvent(id, InngestEvent.make(payload))` | Send events to Inngest |
510
504
 
511
505
  ---
512
506
 
@@ -520,11 +514,11 @@ See the [`examples/`](./examples) directory:
520
514
 
521
515
  This library is under active development. The following Inngest features are **not yet supported**:
522
516
 
523
- | Feature | Status |
524
- | ---------------------- | -------------------- |
525
- | Middleware | 🚧 Not yet supported |
526
- | AI Steps (`step.ai.*`) | 🚧 Not yet supported |
527
- | Encryption | 🚧 Not yet supported |
517
+ | Feature | Status |
518
+ | ------------------------- | -------------------- |
519
+ | Middleware | 🚧 Not yet supported |
520
+ | AI Steps (`Inngest.ai.*`) | 🚧 Not yet supported |
521
+ | Encryption | 🚧 Not yet supported |
528
522
 
529
523
  ---
530
524
 
package/dist/Client.js CHANGED
@@ -86,7 +86,7 @@ const makeClient = (config, httpClient) => Effect.gen(function* () {
86
86
  message: "Event key is required to send events in cloud mode",
87
87
  events: events.map((e) => e.name)
88
88
  }));
89
- const key = config.eventKey ?? "NO_EVENT_KEY_SET";
89
+ const key = config.eventKey || "NO_EVENT_KEY_SET";
90
90
  const url = new URL(`e/${key}`, eventBaseUrl).toString();
91
91
  const eventNames = events.map((e) => e.name);
92
92
  const now = yield* Clock.currentTimeMillis;
package/dist/Cron.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ declare namespace Cron_d_exports {
2
+ export { CronDefinition, CronOptions, TypeId, isCron, make };
3
+ }
4
+ declare const TypeId: unique symbol;
5
+ type TypeId = typeof TypeId;
6
+ interface CronOptions {
7
+ readonly jitter?: string;
8
+ }
9
+ interface CronDefinition<Schedule extends string = string> {
10
+ readonly [TypeId]: TypeId;
11
+ readonly cron: Schedule;
12
+ readonly jitter?: string;
13
+ }
14
+ declare function make<const Schedule extends string>(schedule: Schedule, options?: CronOptions): CronDefinition<Schedule>;
15
+ declare const isCron: (value: unknown) => value is CronDefinition;
16
+ //#endregion
17
+ export { CronDefinition, Cron_d_exports };
package/dist/Cron.js ADDED
@@ -0,0 +1,24 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
+ import { Predicate } from "effect";
3
+ //#region src/Cron.ts
4
+ /**
5
+ * Public cron trigger definitions.
6
+ *
7
+ * @since 0.1.0
8
+ */
9
+ var Cron_exports = /* @__PURE__ */ __exportAll({
10
+ TypeId: () => TypeId,
11
+ isCron: () => isCron,
12
+ make: () => make
13
+ });
14
+ const TypeId = Symbol.for("effect-inngest/Cron");
15
+ function make(schedule, options) {
16
+ return {
17
+ [TypeId]: TypeId,
18
+ cron: schedule,
19
+ ...Predicate.isNotUndefined(options?.jitter) ? { jitter: options.jitter } : {}
20
+ };
21
+ }
22
+ const isCron = (value) => Predicate.hasProperty(value, TypeId) && value[TypeId] === TypeId;
23
+ //#endregion
24
+ export { Cron_exports, isCron };
package/dist/Events.d.ts CHANGED
@@ -65,7 +65,7 @@ declare const FunctionCancelled: EventDefinition<"inngest/function.cancelled", S
65
65
  readonly correlation_id: Schema.optional<Schema.String>;
66
66
  }>>;
67
67
  /**
68
- * Sent when a function is invoked via step.invoke().
68
+ * Sent when a function is invoked via Inngest.invoke().
69
69
  * @since 0.1.0
70
70
  */
71
71
  declare const FunctionInvoked: EventDefinition<"inngest/function.invoked", Schema.StructWithRest<Schema.Struct<{
package/dist/Events.js CHANGED
@@ -75,7 +75,7 @@ const FunctionCancelled = make("inngest/function.cancelled", Schema.Struct({
75
75
  correlation_id: Schema.optional(Schema.String)
76
76
  }));
77
77
  /**
78
- * Sent when a function is invoked via step.invoke().
78
+ * Sent when a function is invoked via Inngest.invoke().
79
79
  * @since 0.1.0
80
80
  */
81
81
  const FunctionInvoked = make("inngest/function.invoked", Schema.StructWithRest(Schema.Struct({ _inngest: Schema.optionalKey(Schema.Record(Schema.String, Schema.Unknown)) }), [Schema.Record(Schema.String, Schema.Unknown)]));
@@ -1,11 +1,12 @@
1
1
  import { CheckpointingOption } from "./internal/checkpoint/Config.js";
2
2
  import { EventDefinition, EventType } from "./Event.js";
3
- import { Duration, Schema } from "effect";
3
+ import { CronDefinition } from "./Cron.js";
4
+ import { Duration } from "effect";
4
5
  import { Pipeable } from "effect/Pipeable";
5
6
 
6
7
  //#region src/Function.d.ts
7
8
  declare namespace Function_d_exports {
8
- export { BatchEventsOption, CancellationOption, CheckpointingOption, ConcurrencyOption, CronTrigger, DebounceOption, EventSchema, EventTrigger, FunctionOptions, FunctionRegistration, InngestFunction, PriorityOption, RateLimitOption, RegistrationConfig, Retries, SingletonOption, ThrottleOption, TimeoutsOption, Trigger, TriggerInput, TypeId, make };
9
+ export { BatchEventsOption, CancellationOption, CheckpointingOption, ConcurrencyOption, CronTrigger, DebounceOption, EventSchema, EventTrigger, FunctionOptions, FunctionRegistration, InngestFunction, PriorityOption, RateLimitOption, RegistrationConfig, Retries, SingletonOption, ThrottleOption, TimeoutsOption, Trigger, TriggerDefinition, TriggerInput, TypeId, make };
9
10
  }
10
11
  /**
11
12
  * @since 0.1.0
@@ -29,6 +30,10 @@ interface EventTrigger<E extends EventSchema = EventSchema> {
29
30
  readonly event: E;
30
31
  readonly if?: string;
31
32
  }
33
+ interface NormalizedEventTrigger<E extends EventSchema = EventSchema> {
34
+ readonly event: E;
35
+ readonly if?: string;
36
+ }
32
37
  /**
33
38
  * A cron-based trigger configuration.
34
39
  *
@@ -37,6 +42,7 @@ interface EventTrigger<E extends EventSchema = EventSchema> {
37
42
  */
38
43
  interface CronTrigger {
39
44
  readonly cron: string;
45
+ readonly jitter?: string;
40
46
  }
41
47
  /**
42
48
  * A trigger configuration for a function.
@@ -44,12 +50,14 @@ interface CronTrigger {
44
50
  * @since 0.1.0
45
51
  * @category triggers
46
52
  */
47
- type Trigger<E extends EventSchema = EventSchema> = EventTrigger<E> | CronTrigger;
53
+ type NormalizedTrigger<E extends EventSchema = EventSchema> = NormalizedEventTrigger<E> | CronTrigger;
54
+ type Trigger<E extends EventSchema = EventSchema> = E | CronDefinition | EventTrigger<E>;
55
+ type TriggerDefinition<E extends EventSchema = EventSchema> = Trigger<E>;
48
56
  /**
49
57
  * @since 0.1.0
50
58
  * @category triggers
51
59
  */
52
- type TriggerInput<E extends EventSchema = EventSchema> = Trigger<E> | ReadonlyArray<Trigger<E>>;
60
+ type TriggerInput<E extends EventSchema = EventSchema> = TriggerDefinition<E> | ReadonlyArray<TriggerDefinition<E>>;
53
61
  interface ConcurrencyOption {
54
62
  /**
55
63
  * The concurrency limit for this option, adding a limit on how many concurrent
@@ -305,6 +313,7 @@ interface FunctionRegistration {
305
313
  event?: string;
306
314
  cron?: string;
307
315
  expression?: string;
316
+ jitter?: string;
308
317
  }>;
309
318
  readonly steps: {
310
319
  readonly step: {
@@ -378,12 +387,11 @@ interface FunctionRegistration {
378
387
  * @since 0.1.0
379
388
  * @category models
380
389
  */
381
- interface InngestFunction<Tag extends string, Triggers extends Trigger, Success extends Schema.Codec<unknown, unknown, never, never>, Options extends FunctionOptions = FunctionOptions> extends Pipeable {
390
+ interface InngestFunction<Tag extends string, Triggers extends NormalizedTrigger, Options extends FunctionOptions = FunctionOptions> extends Pipeable {
382
391
  readonly [TypeId]: TypeId;
383
392
  readonly _tag: Tag;
384
393
  readonly key: string;
385
394
  readonly triggers: ReadonlyArray<Triggers>;
386
- readonly success: Success;
387
395
  readonly options: Options;
388
396
  readonly toRegistration: (config: RegistrationConfig) => FunctionRegistration;
389
397
  }
@@ -392,20 +400,19 @@ interface InngestFunction<Tag extends string, Triggers extends Trigger, Success
392
400
  * @category models
393
401
  */
394
402
  declare namespace InngestFunction {
395
- type Any = InngestFunction<string, Trigger, Schema.Codec<any, any, never, never>, FunctionOptions>;
396
- type Tag<F> = F extends InngestFunction<infer T, any, any, any> ? T : never;
397
- type Triggers<F> = F extends InngestFunction<any, infer T, any, any> ? T : never;
398
- type Events<F> = F extends InngestFunction<any, infer T, any, any> ? (T extends EventTrigger<infer E> ? E : never) : never;
403
+ type Any = InngestFunction<string, NormalizedTrigger, FunctionOptions>;
404
+ type Tag<F> = F extends InngestFunction<infer T, any, any> ? T : never;
405
+ type Triggers<F> = F extends InngestFunction<any, infer T, any> ? T : never;
406
+ type Events<F> = F extends InngestFunction<any, infer T, any> ? (T extends NormalizedEventTrigger<infer E> ? E : never) : never;
399
407
  type EventPayload<F> = EventEnvelope<Events<F>>;
400
408
  type HasBatchEvents<O> = O extends {
401
409
  readonly batchEvents: infer BatchEvents;
402
410
  } ? Exclude<BatchEvents, undefined> extends BatchEventsOption ? true : false : false;
403
411
  type EventType<F> = HasBatchEvents<Options<F>> extends true ? ReadonlyArray<EventPayload<F>> : EventPayload<F>;
404
- type SuccessSchema<F> = F extends InngestFunction<any, any, infer S, any> ? S : never;
405
- type Success<F> = Schema.Schema.Type<SuccessSchema<F>>;
406
- type Options<F> = F extends InngestFunction<any, any, any, infer O> ? O : never;
412
+ type Options<F> = F extends InngestFunction<any, any, infer O> ? O : never;
407
413
  }
408
- type NormalizeTriggers<T extends TriggerInput> = T extends ReadonlyArray<Trigger> ? T[number] : T;
414
+ type NormalizeTrigger<T> = T extends EventSchema ? NormalizedEventTrigger<T> : T extends CronDefinition ? CronTrigger : T extends EventTrigger<infer E> ? NormalizedEventTrigger<E> : T extends CronTrigger ? T : never;
415
+ type NormalizeTriggers<T extends TriggerInput> = T extends ReadonlyArray<infer Item> ? NormalizeTrigger<Item> : NormalizeTrigger<T>;
409
416
  /**
410
417
  * @since 0.1.0
411
418
  * @category constructors
@@ -413,35 +420,30 @@ type NormalizeTriggers<T extends TriggerInput> = T extends ReadonlyArray<Trigger
413
420
  * ```ts
414
421
  * // Event trigger
415
422
  * const Fn1 = InngestFunction.make("Hello", {
416
- * trigger: { event: HelloEvent },
417
- * success: Schema.Void,
423
+ * trigger: HelloEvent,
418
424
  * })
419
425
  *
420
426
  * // Event trigger with CEL filter
421
427
  * const Fn2 = InngestFunction.make("Hello", {
422
428
  * trigger: { event: HelloEvent, if: "event.data.name != ''" },
423
- * success: Schema.Void,
424
429
  * })
425
430
  *
426
431
  * // Cron trigger
427
432
  * const Fn3 = InngestFunction.make("Scheduled", {
428
- * trigger: { cron: "0 * * * *" },
429
- * success: Schema.Void,
433
+ * trigger: InngestCron.make("0 * * * *"),
430
434
  * })
431
435
  *
432
436
  * // Multiple triggers
433
437
  * const Fn4 = InngestFunction.make("Multi", {
434
438
  * trigger: [
435
- * { event: HelloEvent },
436
- * { cron: "0 0 * * *" },
439
+ * HelloEvent,
440
+ * InngestCron.make("0 0 * * *"),
437
441
  * ],
438
- * success: Schema.Void,
439
442
  * })
440
443
  * ```
441
444
  */
442
- declare function make<const Tag extends string, T extends TriggerInput, S extends Schema.Codec<unknown, unknown, never, never>, const O extends FunctionOptions = {}>(tag: Tag, options: {
445
+ declare function make<const Tag extends string, T extends TriggerInput, const O extends FunctionOptions = {}>(tag: Tag, options: {
443
446
  readonly trigger: T;
444
- readonly success: S;
445
- } & O): InngestFunction<Tag, NormalizeTriggers<T>, S, O>;
447
+ } & O): InngestFunction<Tag, NormalizeTriggers<T>, O>;
446
448
  //#endregion
447
- export { BatchEventsOption, CancellationOption, type CheckpointingOption, ConcurrencyOption, CronTrigger, DebounceOption, EventSchema, EventTrigger, FunctionOptions, FunctionRegistration, Function_d_exports, InngestFunction, PriorityOption, RateLimitOption, RegistrationConfig, Retries, SingletonOption, ThrottleOption, TimeoutsOption, Trigger, TriggerInput, TypeId, make };
449
+ export { BatchEventsOption, CancellationOption, type CheckpointingOption, ConcurrencyOption, CronTrigger, DebounceOption, EventSchema, EventTrigger, FunctionOptions, FunctionRegistration, Function_d_exports, InngestFunction, PriorityOption, RateLimitOption, RegistrationConfig, Retries, SingletonOption, ThrottleOption, TimeoutsOption, Trigger, TriggerDefinition, TriggerInput, TypeId, make };
package/dist/Function.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
2
  import { InngestDuration } from "./internal/wire/Duration.js";
3
3
  import { resolveConfig, toRegistration } from "./internal/checkpoint/Config.js";
4
+ import { isEventSchema } from "./Event.js";
5
+ import { isCron } from "./Cron.js";
4
6
  import { Array, Duration, Option, Predicate, Schema } from "effect";
5
7
  import { pipeArguments } from "effect/Pipeable";
6
8
  //#region src/Function.ts
@@ -29,7 +31,10 @@ const Proto = {
29
31
  event: t.event.identifier,
30
32
  expression: t.if
31
33
  });
32
- else triggers.push({ cron: t.cron });
34
+ else triggers.push({
35
+ cron: t.cron,
36
+ ...Predicate.isNotUndefined(t.jitter) ? { jitter: t.jitter } : {}
37
+ });
33
38
  const opts = this.options;
34
39
  const cancel = opts.cancelOn?.map((c) => ({
35
40
  event: c.event.identifier,
@@ -108,6 +113,14 @@ const Proto = {
108
113
  };
109
114
  }
110
115
  };
116
+ const normalizeTrigger = (trigger) => {
117
+ if (isEventSchema(trigger)) return { event: trigger };
118
+ if (isCron(trigger)) return {
119
+ cron: trigger.cron,
120
+ ...Predicate.isNotUndefined(trigger.jitter) ? { jitter: trigger.jitter } : {}
121
+ };
122
+ return trigger;
123
+ };
111
124
  /**
112
125
  * @since 0.1.0
113
126
  * @category constructors
@@ -115,29 +128,25 @@ const Proto = {
115
128
  * ```ts
116
129
  * // Event trigger
117
130
  * const Fn1 = InngestFunction.make("Hello", {
118
- * trigger: { event: HelloEvent },
119
- * success: Schema.Void,
131
+ * trigger: HelloEvent,
120
132
  * })
121
133
  *
122
134
  * // Event trigger with CEL filter
123
135
  * const Fn2 = InngestFunction.make("Hello", {
124
136
  * trigger: { event: HelloEvent, if: "event.data.name != ''" },
125
- * success: Schema.Void,
126
137
  * })
127
138
  *
128
139
  * // Cron trigger
129
140
  * const Fn3 = InngestFunction.make("Scheduled", {
130
- * trigger: { cron: "0 * * * *" },
131
- * success: Schema.Void,
141
+ * trigger: InngestCron.make("0 * * * *"),
132
142
  * })
133
143
  *
134
144
  * // Multiple triggers
135
145
  * const Fn4 = InngestFunction.make("Multi", {
136
146
  * trigger: [
137
- * { event: HelloEvent },
138
- * { cron: "0 0 * * *" },
147
+ * HelloEvent,
148
+ * InngestCron.make("0 0 * * *"),
139
149
  * ],
140
- * success: Schema.Void,
141
150
  * })
142
151
  * ```
143
152
  */
@@ -145,8 +154,7 @@ function make(tag, options) {
145
154
  const fn = Object.create(Proto);
146
155
  fn._tag = tag;
147
156
  fn.key = `effect-inngest/Function/${tag}`;
148
- fn.triggers = Array.ensure(options.trigger);
149
- fn.success = options.success;
157
+ fn.triggers = Array.map(Array.ensure(options.trigger), normalizeTrigger);
150
158
  fn.options = options;
151
159
  return fn;
152
160
  }