@contract-kit/provider-inngest
v0.1.2
Published
Inngest provider for contract-kit - adds inngest port for background jobs and events
Maintainers
Readme
@contract-kit/provider-inngest
Inngest provider for contract-kit that extends your application ports with background job and event capabilities using Inngest.
Installation
npm install @contract-kit/provider-inngest inngest
# or
bun add @contract-kit/provider-inngest inngestTypeScript Requirements
This package requires TypeScript 5.0 or higher for proper type inference.
Usage
Basic Setup
import { createServer } from "@contract-kit/server";
import { inngestProvider } from "@contract-kit/provider-inngest";
// Set environment variables:
// INNGEST_APP_NAME=my-app (optional, defaults to "contract-kit-app")
// INNGEST_EVENT_KEY=your-event-key (optional, required for Inngest Cloud)
const app = createServer({
ports: basePorts,
providers: [inngestProvider],
createContext: ({ ports }) => ({
ports,
// ... other context
}),
routes: [
// ... your routes
],
});Sending Events in Use Cases
Once the provider is registered, your ports will include an inngest property:
// In your use case
async function inviteUser(ctx: AppCtx, input: InviteUserInput) {
// Create the invite
const invite = await ctx.ports.db.invites.create({
inviterId: ctx.userId!,
inviteeEmail: input.email,
});
// Send an event to trigger background job
await ctx.ports.inngest.send({
name: "user.invited",
data: {
inviterId: ctx.userId!,
inviteeEmail: input.email,
inviteId: invite.id,
},
});
return invite;
}Configuration
The Inngest provider reads configuration from environment variables with the INNGEST_ prefix:
| Variable | Required | Description | Default |
|----------|----------|-------------|---------|
| INNGEST_APP_NAME | No | Friendly application name shown in Inngest | "contract-kit-app" |
| INNGEST_EVENT_KEY | No | Event key / signing key for Inngest Cloud | - |
Note: INNGEST_EVENT_KEY is required when using Inngest Cloud for production deployments.
Inngest Port API
The provider extends your ports with the following inngest interface:
send<TData>(args: { name: string; data: TData }): Promise<void>
Send an event to Inngest.
await ctx.ports.inngest.send({
name: "user.invited",
data: {
inviterId: ctx.userId!,
inviteeEmail: input.email,
inviteId: createdInvite.id,
},
});client: Inngest
Access the underlying Inngest client for advanced operations like defining functions.
// Define Inngest functions using the client directly
const myFunction = ctx.ports.inngest.client.createFunction(
{ id: "my-function" },
{ event: "user.invited" },
async ({ event, step }) => {
// Your function logic
}
);TypeScript Support
To get proper type inference for the inngest port, extend your ports type:
import type { InngestPort } from "@contract-kit/provider-inngest";
// Your base ports
const basePorts = definePorts({
db: dbAdapter,
});
// After using inngestProvider, your ports will have this shape:
type AppPorts = typeof basePorts & {
inngest: InngestPort;
};Wiring Domain Events → Inngest Jobs
This provider does NOT automatically subscribe to domain events. This is intentional to keep the provider generic and reusable.
To wire domain events to Inngest jobs, create a separate jobs provider in your application:
// app/providers/jobs.ts
import { createProvider } from "@contract-kit/ports";
import type { AppPorts } from "@/lib/ports";
export const jobsProvider = createProvider<AppPorts, never>({
name: "jobs",
async register({ ports }) {
// Define your job-specific methods
ports.extend("jobs", {
enqueueInviteEmail: async (event) => {
await ports.inngest.send({
name: "user.invited",
data: event
});
},
});
},
async onAppStart({ ports }) {
// Subscribe to domain events and enqueue jobs
ports.eventBus.subscribe("user.invited", async (event) => {
await ports.jobs.enqueueInviteEmail(event);
});
},
});Then use it in your app:
const app = createServer({
ports: basePorts,
providers: [
eventBusProvider,
inngestProvider,
jobsProvider, // Wire domain events → Inngest
],
// ...
});This pattern clearly separates:
- Framework-level provider (
inngestProvider) → Inngest integration - App-level provider (
jobsProvider) → Business job logic
Inngest Functions
Inngest functions (the handlers that process events) should be defined separately from your Contract Kit application, typically in a separate API route or serverless function:
// app/api/inngest/route.ts (Next.js App Router example)
import { serve } from "inngest/next";
import { inngest } from "@/lib/inngest"; // Your Inngest client
// Define your functions
const sendInviteEmail = inngest.createFunction(
{ id: "send-invite-email" },
{ event: "user.invited" },
async ({ event, step }) => {
await step.run("send-email", async () => {
// Send email logic
});
}
);
export const { GET, POST, PUT } = serve({
client: inngest,
functions: [sendInviteEmail],
});Lifecycle
The Inngest provider:
- During
register:- Creates Inngest client
- Adds the
inngestport
- No cleanup needed: Inngest client doesn't require explicit shutdown
Error Handling
The provider will throw errors in these cases:
- Missing required configuration (though all fields have defaults or are optional)
- Invalid configuration values
Make sure to handle these during application startup.
Local Development
For local development, you can run the Inngest Dev Server:
npx inngest-cli@latest devThis provides a local UI at http://localhost:8288 where you can:
- View events
- Trigger functions
- Debug execution
License
MIT
