npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@beignet/provider-inngest

v0.0.3

Published

Inngest provider for Beignet - adds inngest port for background jobs and events

Downloads

410

Readme

@beignet/provider-inngest

Inngest-backed JobDispatcherPort provider for Beignet applications.

The provider installs the app-facing ctx.ports.jobs dispatcher for durable background jobs using Inngest and exposes ctx.ports.inngest only as an escape hatch for raw Inngest access.

Install

bun add @beignet/provider-inngest @beignet/core inngest

Setup

import { createNextServer } from "@beignet/next";
import { definePorts } from "@beignet/core/ports";
import { inngestProvider } from "@beignet/provider-inngest";
import { routes } from "@/server/routes";

// Set environment variables:
// INNGEST_APP_NAME=my-app (optional, defaults to "beignet-app")
// INNGEST_EVENT_KEY=your-event-key (optional, required for Inngest Cloud)

const appPorts = definePorts({});

export const server = await createNextServer({
  ports: appPorts,
  providers: [inngestProvider],
  createContext: ({ ports }) => ({
    ports,
  }),
  routes,
});

Usage

Once the provider is registered, your ports include:

  • jobs: the canonical JobDispatcherPort for app code.
  • inngest: the raw Inngest escape hatch for advanced usage.

Define jobs with @beignet/core/jobs, then dispatch them through ctx.ports.jobs:

import { createJobHandlers, retry } from "@beignet/core/jobs";
import { z } from "zod";

const jobs = createJobHandlers<AppCtx>();

export const SendInviteEmailJob = jobs.defineJob("mail.invite.send", {
  payload: z.object({
    inviteId: z.string(),
    inviteeEmail: z.string().email(),
  }),
  retry: retry.exponential({
    attempts: 3,
  }),
  async handle({ payload, ctx }) {
    await ctx.ports.mailer.send({
      to: payload.inviteeEmail,
      subject: "You were invited",
      text: `Invite id: ${payload.inviteId}`,
    });
  },
});

async function inviteUser(ctx: AppCtx, input: InviteUserInput) {
  const invite = await ctx.ports.db.invites.create({
    inviterId: ctx.actor.id,
    inviteeEmail: input.email,
  });

  await ctx.ports.jobs.dispatch(SendInviteEmailJob, {
    inviteId: invite.id,
    inviteeEmail: input.email,
  });

  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 | "beignet-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.

Ports

jobs: JobDispatcherPort

The jobs port is the recommended application API. It validates and parses the job payload with the job definition before sending an Inngest event using the job name.

await ctx.ports.jobs.dispatch(SendInviteEmailJob, {
  inviteId: invite.id,
  inviteeEmail: input.email,
});

inngest: InngestPort

The inngest port is an escape hatch for direct Inngest usage.

send<TData>(args: { name: string; data: TData }): Promise<void>

Send a raw event to Inngest. Prefer ctx.ports.jobs.dispatch(...) for first-class Beignet jobs.

await ctx.ports.inngest.send({
  name: "user.invited",
  data: {
    inviterId: ctx.actor.id,
    inviteeEmail: input.email,
    inviteId: createdInvite.id,
  },
});

client: Inngest

Access the underlying Inngest client for advanced operations.

// 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
  }
);

Devtools

When @beignet/devtools is registered before this provider, calls to ctx.ports.jobs.dispatch(...) and ctx.ports.inngest.send(...) are recorded automatically under the jobs watcher. Successful enqueues are recorded as scheduled; failed enqueues are recorded as failed with schedule-phase error details.

Pass an instrumentation target to createInngestJobFunction(...) to record worker execution as started, completed, and failed events:

const sendInviteEmail = createInngestJobFunction({
  client: inngest,
  job: SendInviteEmailJob,
  ctx: () => createBackgroundContext(),
  instrumentation: appPorts.devtools,
});

TypeScript support

To get proper type inference, include both provider-contributed ports in your app ports type:

import { definePorts } from "@beignet/core/ports";
import type { JobDispatcherPort } from "@beignet/core/ports";
import type { InngestPort } from "@beignet/provider-inngest";

// Your base ports, if any
const basePorts = definePorts({});

type AppPorts = typeof basePorts & {
  jobs: JobDispatcherPort;
  inngest: InngestPort;
};

Wiring domain events → Inngest jobs

This provider does NOT automatically subscribe to domain events. That is intentional: events are facts that happened, while jobs are explicit work to do.

To wire a domain event to a durable job, register a listener in your application and dispatch the job from the listener:

// features/users/listeners.ts
import { createEventHandlers } from "@beignet/core/events";
import { UserInvited } from "@/features/users/domain/events";
import { SendInviteEmailJob } from "@/features/users/jobs";
import type { AppCtx } from "@/app-context";

const events = createEventHandlers<AppCtx>();

export const sendInviteEmail = events.defineListener(UserInvited, {
  name: "mail.send-invite-email",
  async handle({ payload, ctx }) {
    await ctx.ports.jobs.dispatch(SendInviteEmailJob, {
      inviteId: payload.inviteId,
      inviteeEmail: payload.inviteeEmail,
    });
  },
});

Register that listener against your event bus during infrastructure startup. In tests, use createInlineJobDispatcher(...) from @beignet/core/jobs; in production, install inngestProvider.

Inngest functions

Use createInngestJobFunction(...) to turn a first-class Beignet job into an Inngest function. The helper subscribes to job.name, validates incoming event data with parseJobPayload, and then calls job.handle(...).

If the job defines a retry policy, the helper maps Beignet's total retry.attempts value to Inngest's function-level retries option. Inngest supports retry values from 0 to 20, so Beignet accepts total attempt counts from 1 to 21 for Inngest-backed jobs.

Inngest-backed jobs support Beignet's retry attempt count only. Custom Beignet backoff fields, jitter, and retryIf classification are outbox-worker semantics; createInngestJobFunction(...) fails fast if a job policy includes retry behavior that the adapter cannot honor.

Define functions separately from your Beignet server, usually in a serverless function or route handler:

// app/api/inngest/route.ts (Next.js App Router example)
import { createInngestJobFunction } from "@beignet/provider-inngest";
import { serve } from "inngest/next";
import { inngest } from "@/infra/inngest";
import { SendInviteEmailJob } from "@/features/users/jobs";
import { createBackgroundContext } from "@/infra/background-context";

const sendInviteEmail = createInngestJobFunction({
  client: inngest,
  job: SendInviteEmailJob,
  ctx: () => createBackgroundContext(),
});

export const { GET, POST, PUT } = serve({
  client: inngest,
  functions: [sendInviteEmail],
});

createBackgroundContext() is application-owned. Put it near your infrastructure wiring and return the ports, logger, auth assumptions, and devtools context your background workers need.

Lifecycle

The Inngest provider:

  1. During setup:
    • Creates Inngest client
    • Returns the jobs port
    • Returns the inngest escape hatch port
  2. 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 dev

This provides a local UI at http://localhost:8288 where you can:

  • View events
  • Trigger functions
  • Debug execution

License

MIT