├── .changeset ├── README.md ├── config.json └── dry-weeks-lay.md ├── .devcontainer └── devcontainer.json ├── .envrc ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── actions │ └── setup-and-build │ │ └── action.yml ├── pull_request_template.md └── workflows │ ├── backport.yml │ ├── label-prs.yml │ ├── pr-task-list-checker.yml │ ├── pr.yml │ ├── prerelease.yml │ └── release.yml ├── .gitignore ├── .npmrc ├── .vscode └── settings.json ├── CONTRIBUTING.md ├── README.md ├── examples ├── .gitignore ├── .inngestignore ├── bun │ ├── .gitignore │ ├── README.md │ ├── index.ts │ ├── inngest │ │ ├── client.ts │ │ ├── helloWorld.ts │ │ ├── index.ts │ │ └── types.ts │ ├── package.json │ └── tsconfig.json ├── connect-example │ ├── index.ts │ ├── package.json │ └── tsconfig.json ├── framework-astro │ ├── .gitignore │ ├── README.md │ ├── astro.config.mjs │ ├── package.json │ ├── public │ │ └── favicon.svg │ ├── src │ │ ├── components │ │ │ └── Card.astro │ │ ├── env.d.ts │ │ ├── inngest │ │ │ ├── client.ts │ │ │ ├── helloWorld.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── layouts │ │ │ └── Layout.astro │ │ └── pages │ │ │ ├── api │ │ │ ├── helloAstro.ts │ │ │ └── inngest.ts │ │ │ └── index.astro │ └── tsconfig.json ├── framework-express │ ├── .gitignore │ ├── README.md │ ├── index.ts │ ├── inngest │ │ ├── client.ts │ │ ├── helloWorld.ts │ │ ├── index.ts │ │ └── types.ts │ ├── package.json │ └── tsconfig.json ├── framework-fastify │ ├── .gitignore │ ├── README.md │ ├── index.ts │ ├── inngest │ │ ├── client.ts │ │ ├── helloWorld.ts │ │ ├── index.ts │ │ └── types.ts │ ├── package.json │ └── tsconfig.json ├── framework-google-functions-framework │ ├── .gitignore │ ├── README.md │ ├── index.ts │ ├── inngest │ │ ├── client.ts │ │ ├── helloWorld.ts │ │ ├── index.ts │ │ └── types.ts │ ├── package.json │ └── tsconfig.json ├── framework-hono │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── src │ │ ├── bindings.ts │ │ ├── index.ts │ │ └── inngest │ │ │ ├── client.ts │ │ │ ├── helloWorld.ts │ │ │ ├── index.ts │ │ │ ├── middleware.ts │ │ │ └── types.ts │ ├── tsconfig.json │ └── wrangler.toml ├── framework-koa │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── inngest │ │ │ ├── client.ts │ │ │ ├── helloWorld.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ └── tsconfig.json ├── framework-nestjs │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierrc │ ├── LICENSE │ ├── README.md │ ├── nest-cli.json │ ├── package.json │ ├── src │ │ ├── app.module.ts │ │ ├── app.service.spec.ts │ │ ├── app.service.ts │ │ ├── main.ts │ │ └── modules │ │ │ └── common │ │ │ └── inngest │ │ │ ├── client.ts │ │ │ ├── functions │ │ │ ├── hello.ts │ │ │ └── index.ts │ │ │ └── types │ │ │ ├── events.type.ts │ │ │ ├── hello.type.ts │ │ │ └── index.ts │ ├── test │ │ ├── app.e2e-spec.ts │ │ └── jest-e2e.json │ ├── tsconfig.build.json │ └── tsconfig.json ├── framework-nextjs-app-router │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── next.config.js │ ├── package.json │ ├── public │ │ ├── next.svg │ │ └── vercel.svg │ ├── src │ │ ├── app │ │ │ ├── api │ │ │ │ └── inngest │ │ │ │ │ └── route.ts │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── layout.tsx │ │ │ ├── page.module.css │ │ │ └── page.tsx │ │ └── inngest │ │ │ ├── client.ts │ │ │ ├── helloWorld.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ └── tsconfig.json ├── framework-nextjs-pages-router │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── next.config.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── next.svg │ │ └── vercel.svg │ ├── src │ │ ├── inngest │ │ │ ├── client.ts │ │ │ ├── helloWorld.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── pages │ │ │ ├── _app.tsx │ │ │ ├── _document.tsx │ │ │ ├── api │ │ │ │ ├── hello.ts │ │ │ │ └── inngest.ts │ │ │ └── index.tsx │ │ └── styles │ │ │ ├── Home.module.css │ │ │ └── globals.css │ └── tsconfig.json ├── framework-nitro │ ├── .gitignore │ ├── .npmrc │ ├── README.md │ ├── inngest │ │ ├── client.ts │ │ ├── helloWorld.ts │ │ ├── index.ts │ │ └── types.ts │ ├── nitro.config.ts │ ├── package.json │ ├── server │ │ └── routes │ │ │ ├── api │ │ │ └── inngest.ts │ │ │ └── index.ts │ └── tsconfig.json ├── framework-nuxt │ ├── .gitignore │ ├── .npmrc │ ├── README.md │ ├── app.vue │ ├── inngest │ │ ├── client.ts │ │ ├── helloWorld.ts │ │ ├── index.ts │ │ └── types.ts │ ├── nuxt.config.ts │ ├── package.json │ ├── server │ │ └── api │ │ │ └── inngest.ts │ └── tsconfig.json ├── framework-remix │ ├── .eslintrc.js │ ├── .gitignore │ ├── README.md │ ├── app │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── inngest │ │ │ ├── client.ts │ │ │ ├── helloWorld.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── root.tsx │ │ └── routes │ │ │ ├── api │ │ │ └── inngest.ts │ │ │ └── index.tsx │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── remix.config.js │ ├── remix.env.d.ts │ ├── server.js │ └── tsconfig.json ├── framework-sveltekit │ ├── .gitignore │ ├── .npmrc │ ├── .prettierignore │ ├── .prettierrc │ ├── README.md │ ├── package.json │ ├── src │ │ ├── app.d.ts │ │ ├── app.html │ │ ├── index.test.ts │ │ ├── lib │ │ │ ├── index.ts │ │ │ └── inngest │ │ │ │ ├── client.ts │ │ │ │ ├── helloWorld.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ └── routes │ │ │ ├── +page.svelte │ │ │ └── api │ │ │ └── inngest │ │ │ └── +server.ts │ ├── static │ │ └── favicon.png │ ├── svelte.config.js │ ├── tsconfig.json │ └── vite.config.ts ├── middleware-e2e-encryption │ ├── README.md │ ├── fullEncryptionMiddlware.ts │ ├── package.json │ └── stepEncryptionMiddleware.ts ├── nextjs-christmas-dinner-generator-challenge │ ├── .env.example │ ├── .gitignore │ ├── README.md │ ├── app │ │ ├── actions.ts │ │ ├── api │ │ │ ├── generationStatus │ │ │ │ └── route.ts │ │ │ └── inngest │ │ │ │ └── route.ts │ │ ├── components │ │ │ └── home.tsx │ │ ├── favicon.ico │ │ ├── globals.css │ │ ├── layout.tsx │ │ └── page.tsx │ ├── data │ │ ├── Thefoodprocessor-holiday.json │ │ └── Thefoodprocessor-wine_type.json │ ├── eslint.config.mjs │ ├── inngest │ │ ├── client.ts │ │ ├── events.ts │ │ └── functions.ts │ ├── lib │ │ └── vectorStore.ts │ ├── next.config.ts │ ├── package.json │ ├── postcss.config.mjs │ ├── public │ │ ├── file.svg │ │ ├── globe.svg │ │ ├── next.svg │ │ ├── vercel.svg │ │ └── window.svg │ ├── readme-assets │ │ ├── Screenshot_2024-11-20_at_14.33.46.png │ │ ├── Screenshot_2024-11-20_at_14.34.24.png │ │ ├── Screenshot_2024-11-20_at_14.59.42.png │ │ └── image.png │ ├── scripts │ │ ├── generate-jsons.ts │ │ └── index.ts │ ├── tailwind.config.ts │ └── tsconfig.json ├── node-otel │ ├── .gitignore │ ├── README.md │ ├── index.ts │ ├── inngest │ │ ├── client.ts │ │ ├── helloWorld.ts │ │ ├── index.ts │ │ └── types.ts │ ├── package.json │ └── tsconfig.json ├── node-step-fetch │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── inngest │ │ │ ├── client.ts │ │ │ └── functions.ts │ └── tsconfig.json ├── node │ ├── .gitignore │ ├── README.md │ ├── index.ts │ ├── inngest │ │ ├── client.ts │ │ ├── helloWorld.ts │ │ ├── index.ts │ │ └── types.ts │ ├── package.json │ └── tsconfig.json ├── realtime │ ├── next-realtime-hooks │ │ ├── .gitignore │ │ ├── README.md │ │ ├── app │ │ │ ├── actions.ts │ │ │ ├── api │ │ │ │ └── inngest │ │ │ │ │ └── route.ts │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ ├── eslint.config.mjs │ │ ├── inngest │ │ │ ├── functions │ │ │ │ └── helloWorld.ts │ │ │ └── index.ts │ │ ├── next.config.ts │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── public │ │ │ ├── file.svg │ │ │ ├── globe.svg │ │ │ ├── inngest.svg │ │ │ ├── next.svg │ │ │ ├── vercel.svg │ │ │ └── window.svg │ │ └── tsconfig.json │ └── nodejs │ │ ├── realtime-across-multiple-channels │ │ ├── README.md │ │ ├── index.ts │ │ ├── package.json │ │ └── tsconfig.json │ │ ├── realtime-human-in-the-loop │ │ ├── README.md │ │ ├── index.ts │ │ ├── package.json │ │ └── tsconfig.json │ │ └── realtime-single-run-subscription │ │ ├── README.md │ │ ├── index.ts │ │ ├── package.json │ │ └── tsconfig.json └── step-ai │ └── anthropic-claude-pdf-processing │ ├── .env.example │ ├── README.md │ ├── index.ts │ ├── package.json │ └── tsconfig.json ├── flake.lock ├── flake.nix ├── package.json ├── packages ├── ai │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── eslint.config.mjs │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── adapter.ts │ │ ├── adapters │ │ │ ├── anthropic.ts │ │ │ ├── gemini.ts │ │ │ ├── grok.ts │ │ │ ├── index.ts │ │ │ └── openai.ts │ │ ├── env.ts │ │ ├── index.ts │ │ └── models │ │ │ ├── anthropic.ts │ │ │ ├── deepseek.ts │ │ │ ├── gemini.ts │ │ │ ├── grok.ts │ │ │ ├── index.ts │ │ │ └── openai.ts │ └── tsconfig.json ├── eslint-plugin-internal │ ├── README.md │ ├── index.js │ ├── package.json │ └── process-warn.js ├── eslint-plugin │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── configs │ │ │ ├── index.ts │ │ │ └── recommended.ts │ │ ├── index.ts │ │ └── rules │ │ │ ├── await-inngest-send.test.ts │ │ │ ├── await-inngest-send.ts │ │ │ ├── index.ts │ │ │ ├── no-nested-steps.test.ts │ │ │ ├── no-nested-steps.ts │ │ │ ├── no-variable-mutation-in-step.test.ts │ │ │ └── no-variable-mutation-in-step.ts │ └── tsconfig.json ├── inngest │ ├── .eslintrc.js │ ├── .gitignore │ ├── CHANGELOG.md │ ├── CONTRIBUTING.md │ ├── LICENSE.md │ ├── README.md │ ├── jest.config.js │ ├── jsr.json │ ├── package.json │ ├── scripts │ │ ├── checkDependencies.ts │ │ ├── integrationTestRunner.ts │ │ └── runExample.ts │ ├── src │ │ ├── api │ │ │ ├── api.ts │ │ │ ├── schema.test.ts │ │ │ └── schema.ts │ │ ├── astro.test.ts │ │ ├── astro.ts │ │ ├── bun.test.ts │ │ ├── bun.ts │ │ ├── cloudflare.test.ts │ │ ├── cloudflare.ts │ │ ├── components │ │ │ ├── EventSchemas.test.ts │ │ │ ├── EventSchemas.ts │ │ │ ├── Fetch.ts │ │ │ ├── Inngest.test.ts │ │ │ ├── Inngest.ts │ │ │ ├── InngestCommHandler.test.ts │ │ │ ├── InngestCommHandler.ts │ │ │ ├── InngestFunction.test.ts │ │ │ ├── InngestFunction.ts │ │ │ ├── InngestFunctionReference.ts │ │ │ ├── InngestMiddleware.test.ts │ │ │ ├── InngestMiddleware.ts │ │ │ ├── InngestStepTools.test.ts │ │ │ ├── InngestStepTools.ts │ │ │ ├── NonRetriableError.ts │ │ │ ├── RetryAfterError.ts │ │ │ ├── StepError.ts │ │ │ ├── connect │ │ │ │ ├── buffer.ts │ │ │ │ ├── index.ts │ │ │ │ ├── messages.ts │ │ │ │ ├── os.ts │ │ │ │ ├── protobuf │ │ │ │ │ └── connect.proto │ │ │ │ ├── types.ts │ │ │ │ └── util.ts │ │ │ └── execution │ │ │ │ ├── InngestExecution.ts │ │ │ │ ├── als.test.ts │ │ │ │ ├── als.ts │ │ │ │ ├── otel │ │ │ │ ├── README.md │ │ │ │ ├── access.ts │ │ │ │ ├── consts.ts │ │ │ │ ├── middleware.ts │ │ │ │ ├── processor.ts │ │ │ │ └── util.ts │ │ │ │ ├── v0.ts │ │ │ │ ├── v1.ts │ │ │ │ └── v2.ts │ │ ├── connect.ts │ │ ├── deno │ │ │ ├── fresh.test.ts │ │ │ └── fresh.ts │ │ ├── digitalocean.ts │ │ ├── edge.test.ts │ │ ├── edge.ts │ │ ├── experimental.ts │ │ ├── express.test.ts │ │ ├── express.ts │ │ ├── fastify.test.ts │ │ ├── fastify.ts │ │ ├── h3.test.ts │ │ ├── h3.ts │ │ ├── helpers │ │ │ ├── ServerTiming.ts │ │ │ ├── consts.ts │ │ │ ├── crypto.ts │ │ │ ├── devserver.ts │ │ │ ├── enum.ts │ │ │ ├── env.ts │ │ │ ├── errors.test.ts │ │ │ ├── errors.ts │ │ │ ├── functions.test.ts │ │ │ ├── functions.ts │ │ │ ├── jsonify.test.ts │ │ │ ├── jsonify.ts │ │ │ ├── net.test.ts │ │ │ ├── net.ts │ │ │ ├── promises.test.ts │ │ │ ├── promises.ts │ │ │ ├── stream.ts │ │ │ ├── strings.test.ts │ │ │ ├── strings.ts │ │ │ ├── temporal.ts │ │ │ ├── types.test.ts │ │ │ ├── types.ts │ │ │ └── validators │ │ │ │ ├── index.ts │ │ │ │ └── zod.ts │ │ ├── hono.test.ts │ │ ├── hono.ts │ │ ├── index.ts │ │ ├── koa.test.ts │ │ ├── koa.ts │ │ ├── lambda.test.ts │ │ ├── lambda.ts │ │ ├── middleware │ │ │ ├── dependencyInjection.test.ts │ │ │ ├── dependencyInjection.ts │ │ │ ├── logger.test.ts │ │ │ └── logger.ts │ │ ├── next.test.ts │ │ ├── next.ts │ │ ├── nitro.test.ts │ │ ├── nitro.ts │ │ ├── node.test.ts │ │ ├── node.ts │ │ ├── nuxt.test.ts │ │ ├── nuxt.ts │ │ ├── proto │ │ │ ├── google │ │ │ │ └── protobuf │ │ │ │ │ └── timestamp.ts │ │ │ └── src │ │ │ │ └── components │ │ │ │ └── connect │ │ │ │ └── protobuf │ │ │ │ └── connect.ts │ │ ├── redwood.test.ts │ │ ├── redwood.ts │ │ ├── remix.test.ts │ │ ├── remix.ts │ │ ├── sveltekit.test.ts │ │ ├── sveltekit.ts │ │ ├── test │ │ │ ├── functions │ │ │ │ ├── README.md │ │ │ │ ├── client.ts │ │ │ │ ├── handler.ts │ │ │ │ ├── handling-step-errors │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── hello-world │ │ │ │ │ ├── README.md │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── multiple-triggers │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── package.json │ │ │ │ ├── parallel-reduce │ │ │ │ │ ├── README.md │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── parallel-work │ │ │ │ │ ├── README.md │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── polling │ │ │ │ │ ├── README.md │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── promise-all │ │ │ │ │ ├── README.md │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── promise-race │ │ │ │ │ ├── README.md │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── send-event │ │ │ │ │ ├── README.md │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── sequential-reduce │ │ │ │ │ ├── README.md │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── step-invoke-not-found │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── step-invoke │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── tsconfig.json │ │ │ │ ├── undefined-data │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ │ └── unhandled-step-errors │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.ts │ │ │ └── helpers.ts │ │ └── types.ts │ ├── test │ │ ├── benchmark │ │ │ ├── execution │ │ │ │ ├── index.ts │ │ │ │ ├── memoized-steps.ts │ │ │ │ └── util.ts │ │ │ ├── main.ts │ │ │ └── util.ts │ │ └── composite_project │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ └── index.ts │ │ │ └── tsconfig.json │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── middleware-encryption │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── MIGRATION.md │ ├── README.md │ ├── eslint.config.js │ ├── jest.config.js │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── manual.ts │ │ ├── middleware.test.ts │ │ ├── middleware.ts │ │ ├── stages.ts │ │ └── strategies │ │ │ ├── aes.ts │ │ │ ├── legacy.ts │ │ │ └── libSodium.ts │ ├── tsconfig.build.json │ └── tsconfig.json ├── middleware-sentry │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── eslint.config.mjs │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── middleware.ts │ └── tsconfig.json ├── middleware-validation │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── eslint.config.js │ ├── jest.config.js │ ├── jsr.json │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ ├── index.ts │ │ ├── middleware.test.ts │ │ └── middleware.ts │ ├── tsconfig.build.json │ └── tsconfig.json ├── realtime │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── eslint.config.mjs │ ├── jest.config.js │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── api.ts │ │ ├── channel.ts │ │ ├── env.d.ts │ │ ├── env.ts │ │ ├── hooks.ts │ │ ├── index.test.ts │ │ ├── index.ts │ │ ├── middleware.ts │ │ ├── subscribe │ │ │ ├── StreamFanout.ts │ │ │ ├── TokenSubscription.ts │ │ │ ├── helpers.ts │ │ │ └── index.ts │ │ ├── topic.ts │ │ ├── types.ts │ │ └── util.ts │ └── tsconfig.json └── test │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── eslint.config.js │ ├── jest.config.js │ ├── jsr.json │ ├── package.json │ ├── src │ ├── InngestTestEngine.ts │ ├── InngestTestRun.ts │ ├── index.ts │ ├── spy.ts │ └── util.ts │ ├── tsconfig.build.json │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── scripts ├── generateReleaseConfig.js ├── labelPrs.js └── release ├── jsrVersion.js ├── prerelease.js ├── publish.js └── tag.js /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", 3 | "changelog": [ 4 | "@changesets/changelog-github", 5 | { "repo": "inngest/inngest-js" } 6 | ], 7 | "commit": false, 8 | "fixed": [], 9 | "linked": [], 10 | "access": "public", 11 | "baseBranch": "main", 12 | "updateInternalDependencies": "patch", 13 | "bumpVersionsWithWorkspaceProtocolOnly": true, 14 | "ignore": [], 15 | "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { 16 | "onlyUpdatePeerDependentsWhenOutOfRange": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.changeset/dry-weeks-lay.md: -------------------------------------------------------------------------------- 1 | --- 2 | "inngest": patch 3 | --- 4 | 5 | When executing, use the `serve()` call's client instead of the function's 6 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | pnpm-lock.yaml linguist-generated=true 2 | .changeset linguist-generated=true 3 | 4 | # inngest 5 | packages/inngest/src/components/connect/protobuf/**/*.ts linguist-generated=true 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: "" 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 15 | 1. Create a function with '...' 16 | 2. Send this event '...' 17 | 3. ... 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Code snippets / Logs / Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **System info (please complete the following information):** 26 | 27 | - OS: [e.g. Mac, Windows] 28 | - npm package Version [e.g. 0.7.0] 29 | - Framework [e.g. Next.js, Express] 30 | - Platform [e.g. Vercel, AWS Lambda] 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "" 5 | labels: feature 6 | assignees: "" 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | 4 | 5 | 6 | ## Checklist 7 | 8 | 9 | 10 | 11 | - [ ] Added a [docs PR](https://github.com/inngest/website) that references this PR 12 | - [ ] Added unit/integration tests 13 | - [ ] Added changesets if applicable 14 | 15 | ## Related 16 | 17 | 18 | 19 | 20 | 21 | 22 | - INN- 23 | -------------------------------------------------------------------------------- /.github/workflows/backport.yml: -------------------------------------------------------------------------------- 1 | name: Backport 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - closed 7 | - labeled 8 | 9 | jobs: 10 | backport: 11 | name: Backport 12 | runs-on: ubuntu-latest 13 | # Only react to merged PRs for security reasons. 14 | # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target. 15 | if: > 16 | github.event.pull_request.merged 17 | && ( 18 | github.event.action == 'closed' 19 | || ( 20 | github.event.action == 'labeled' 21 | && contains(github.event.label.name, 'backport') 22 | ) 23 | ) 24 | steps: 25 | - uses: tibdex/backport@v2 26 | with: 27 | github_token: ${{ secrets.CHANGESET_GITHUB_TOKEN }} 28 | body_template: |- 29 | ## Summary 30 | 31 | This is an automated backport of <%= mergeCommitSha %> from #<%= number %> to **<%= base %>**. It was created because a maintainer labeled #<%= number %> with the [backport <%= base %>](https://github.com/inngest/inngest-js/labels/backport%20<%= base %>) label. 32 | 33 | When this PR is merged, it will create a PR to release **<%= base %>** if a changeset is found. 34 | 35 | ## Related 36 | 37 | - #<%= number %> 38 | -------------------------------------------------------------------------------- /.github/workflows/label-prs.yml: -------------------------------------------------------------------------------- 1 | name: Label PR based on changed package 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize, reopened] 6 | 7 | jobs: 8 | label: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | 14 | - uses: ./.github/actions/setup-and-build 15 | with: 16 | install-dependencies: false 17 | build: false 18 | 19 | - run: pnpm install 20 | 21 | - name: Label PR 22 | run: node scripts/labelPrs.js 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.CHANGESET_GITHUB_TOKEN }} # inngest-release-bot 25 | -------------------------------------------------------------------------------- /.github/workflows/pr-task-list-checker.yml: -------------------------------------------------------------------------------- 1 | name: GitHub PR Task List Checker 2 | on: 3 | pull_request: 4 | types: [opened, edited, synchronize, reopened] 5 | jobs: 6 | task-list-checker: 7 | runs-on: ubuntu-latest 8 | if: ${{ github.event.pull_request.user.login != 'dependabot[bot]' }} 9 | steps: 10 | - name: Check for incomplete task list items 11 | uses: Shopify/task-list-checker@main 12 | with: 13 | github-token: ${{ secrets.GITHUB_TOKEN }} 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node packages 2 | node_modules 3 | 4 | # Nix 5 | /.direnv/ 6 | 7 | .idea 8 | 9 | examples/**/*/.env 10 | examples/**/*/dist -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | enable-pre-post-scripts=true 2 | link-workspace-packages=false 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ./packages/inngest/CONTRIBUTING.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ./packages/inngest/README.md -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | yarn.lock 2 | pnpm-lock.yaml 3 | package-lock.json 4 | bun.lockb 5 | -------------------------------------------------------------------------------- /examples/.inngestignore: -------------------------------------------------------------------------------- 1 | # Used to ignore some directories when running integration tests. 2 | # These tests will change anyway to be less reliant on GH Actions. 3 | framework-nestjs 4 | -------------------------------------------------------------------------------- /examples/bun/README.md: -------------------------------------------------------------------------------- 1 | # runtime-bun 2 | 3 | To install dependencies: 4 | 5 | ```bash 6 | bun install 7 | ``` 8 | 9 | To run: 10 | 11 | ```bash 12 | bun run index.ts 13 | ``` 14 | 15 | This project was created using `bun init` in bun v1.0.25. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. 16 | -------------------------------------------------------------------------------- /examples/bun/index.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "inngest/edge"; 2 | import { functions, inngest } from "./inngest"; 3 | 4 | const server = Bun.serve({ 5 | port: 3000, 6 | fetch(request: Request) { 7 | const url = new URL(request.url); 8 | 9 | if (url.pathname === "/api/inngest") { 10 | return serve({ client: inngest, functions })(request); 11 | } 12 | 13 | return new Response("Server"); 14 | }, 15 | }); 16 | 17 | console.log(`Listening on ${server.hostname}:${server.port}`); 18 | -------------------------------------------------------------------------------- /examples/bun/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from 'inngest'; 2 | import { schemas } from './types'; 3 | 4 | export const inngest = new Inngest({ id: 'my-bun-app', schemas }); 5 | -------------------------------------------------------------------------------- /examples/bun/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from './client'; 2 | 3 | export const helloWorld = inngest.createFunction( 4 | { id: 'hello-world' }, 5 | { event: 'demo/event.sent' }, 6 | async ({ event, step }) => { 7 | return { 8 | message: `Hello ${event.name}!`, 9 | }; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /examples/bun/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import { helloWorld } from './helloWorld'; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from './client'; 6 | -------------------------------------------------------------------------------- /examples/bun/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/bun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "runtime-bun", 3 | "module": "index.ts", 4 | "type": "module", 5 | "scripts": { 6 | "dev": "bun run --watch index.ts" 7 | }, 8 | "devDependencies": { 9 | "@types/bun": "latest" 10 | }, 11 | "peerDependencies": { 12 | "typescript": "^5.0.0" 13 | }, 14 | "dependencies": { 15 | "inngest": "^3.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/bun/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["ESNext"], 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | "moduleDetection": "force", 7 | "jsx": "react-jsx", 8 | "allowJs": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "verbatimModuleSyntax": true, 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "skipLibCheck": true, 18 | "strict": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "forceConsistentCasingInFileNames": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/connect-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "connect-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "tsx": "^4.19.2", 13 | "typescript": "^5.7.3" 14 | }, 15 | "dependencies": { 16 | "inngest": "file:../../packages/inngest/inngest.tgz" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/framework-astro/.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | 4 | # generated types 5 | .astro/ 6 | 7 | # dependencies 8 | node_modules/ 9 | 10 | # logs 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # environment variables 17 | .env 18 | .env.production 19 | 20 | # macOS-specific files 21 | .DS_Store 22 | -------------------------------------------------------------------------------- /examples/framework-astro/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'astro/config'; 2 | 3 | // https://astro.build/config 4 | export default defineConfig({ 5 | output: 'server', 6 | }); 7 | -------------------------------------------------------------------------------- /examples/framework-astro/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "inngest-astro", 3 | "type": "module", 4 | "version": "0.0.1", 5 | "scripts": { 6 | "dev": "astro dev --host --port 3000", 7 | "start": "astro dev", 8 | "build": "astro check && astro build", 9 | "preview": "astro preview", 10 | "astro": "astro" 11 | }, 12 | "dependencies": { 13 | "@astrojs/check": "^0.3.4", 14 | "astro": "^4.0.7", 15 | "inngest": "^3.7.4", 16 | "typescript": "^5.3.3" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/framework-astro/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /examples/framework-astro/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/framework-astro/src/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | import { schemas } from "./types"; 3 | 4 | // Create a client to send and receive events 5 | export const inngest = new Inngest({ id: "my-astro-app", schemas }); 6 | -------------------------------------------------------------------------------- /examples/framework-astro/src/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/hello.world" }, 6 | async ({ event, step }) => { 7 | await step.sleep("wait-a-moment", "1s"); 8 | return { event, body: "Hello, World!" }; 9 | } 10 | ); 11 | -------------------------------------------------------------------------------- /examples/framework-astro/src/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import helloWorld from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/framework-astro/src/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/hello.world"; 5 | data: { 6 | message: string; 7 | email?: string; 8 | }; 9 | }; 10 | 11 | export const schemas = new EventSchemas().fromUnion(); 12 | -------------------------------------------------------------------------------- /examples/framework-astro/src/layouts/Layout.astro: -------------------------------------------------------------------------------- 1 | --- 2 | interface Props { 3 | title: string; 4 | } 5 | 6 | const { title } = Astro.props; 7 | --- 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {title} 18 | 19 | 20 | 21 | 22 | 23 | 52 | -------------------------------------------------------------------------------- /examples/framework-astro/src/pages/api/helloAstro.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../../inngest/client"; 2 | 3 | export async function GET() { 4 | // Send your event payload to Inngest 5 | await inngest.send({ 6 | name: "demo/hello.world", 7 | data: { 8 | message: "Hello, Houston!", 9 | email: "testToHouston@example.com", 10 | }, 11 | }); 12 | 13 | return Response.json({ name: "Hello Houston from Inngest!" }); 14 | } 15 | -------------------------------------------------------------------------------- /examples/framework-astro/src/pages/api/inngest.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "inngest/astro"; 2 | import { inngest, functions } from "../../inngest"; 3 | 4 | export const { GET, POST, PUT } = serve({ 5 | client: inngest, 6 | functions, 7 | }); 8 | -------------------------------------------------------------------------------- /examples/framework-astro/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strict" 3 | } -------------------------------------------------------------------------------- /examples/framework-express/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.js 3 | -------------------------------------------------------------------------------- /examples/framework-express/index.ts: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import { serve } from 'inngest/express'; 3 | import { functions, inngest } from './inngest'; 4 | 5 | const app = express(); 6 | 7 | // Parse JSON bodies 8 | app.use( 9 | express.json({ 10 | limit: '5mb', 11 | }) 12 | ); 13 | 14 | app.use('/api/inngest', serve({ client: inngest, functions })); 15 | 16 | app.listen(3000, () => { 17 | console.log('Server running on http://localhost:3000'); 18 | }); 19 | -------------------------------------------------------------------------------- /examples/framework-express/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | import { schemas } from "./types"; 3 | 4 | export const inngest = new Inngest({ id: "my-express-app", schemas }); 5 | -------------------------------------------------------------------------------- /examples/framework-express/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/event.sent" }, 6 | async ({ event, step }) => { 7 | return { 8 | message: `Hello ${event.name}!`, 9 | }; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /examples/framework-express/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import helloWorld from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/framework-express/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/framework-express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "framework-express", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc -p tsconfig.json", 8 | "dev": "tsx index.ts", 9 | "start": "node dist/index.js" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "express": "^4.19.2", 15 | "inngest": "^3.0.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^20.5.2", 19 | "tsx": "^4.7.3", 20 | "typescript": "^5.1.6" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/framework-fastify/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.js 3 | -------------------------------------------------------------------------------- /examples/framework-fastify/index.ts: -------------------------------------------------------------------------------- 1 | import Fastify from "fastify"; 2 | import inngestFastify from "inngest/fastify"; 3 | import { functions, inngest } from "./inngest"; 4 | 5 | const fastify = Fastify({ 6 | logger: true, 7 | }); 8 | 9 | fastify.register(inngestFastify, { 10 | client: inngest, 11 | functions, 12 | options: {}, 13 | }); 14 | 15 | fastify.listen({ port: 3000 }, function (err, address) { 16 | if (err) { 17 | fastify.log.error(err); 18 | process.exit(1); 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /examples/framework-fastify/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | import { schemas } from "./types"; 3 | 4 | export const inngest = new Inngest({ id: "my-fastify-app", schemas }); 5 | -------------------------------------------------------------------------------- /examples/framework-fastify/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/event.sent" }, 6 | async ({ event, step }) => { 7 | return { 8 | message: `Hello ${event.name}!`, 9 | }; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /examples/framework-fastify/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import helloWorld from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/framework-fastify/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/framework-fastify/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "framework-fastify", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc -p tsconfig.json", 8 | "dev": "tsx index.ts", 9 | "start": "node dist/index.js" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "fastify": "^4.21.0", 15 | "inngest": "^3.0.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^20.5.2", 19 | "tsx": "^4.7.3", 20 | "typescript": "^5.1.6" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/framework-google-functions-framework/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | 4 | *.js -------------------------------------------------------------------------------- /examples/framework-google-functions-framework/index.ts: -------------------------------------------------------------------------------- 1 | import * as ff from '@google-cloud/functions-framework'; 2 | import { serve } from 'inngest/express'; 3 | 4 | import { inngest, functions } from './inngest'; 5 | 6 | ff.http( 7 | 'inngest', 8 | serve({ 9 | client: inngest, 10 | functions, 11 | }) 12 | ); 13 | -------------------------------------------------------------------------------- /examples/framework-google-functions-framework/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from 'inngest'; 2 | import { schemas } from './types'; 3 | 4 | export const inngest = new Inngest({ id: 'my-gcp-functions-app', schemas }); 5 | -------------------------------------------------------------------------------- /examples/framework-google-functions-framework/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/event.sent" }, 6 | async ({ event, step }) => { 7 | return { 8 | message: `Hello ${event.name}!`, 9 | }; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /examples/framework-google-functions-framework/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import helloWorld from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/framework-google-functions-framework/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/framework-google-functions-framework/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "framework-google-functions-framework", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "start": "functions-framework --target=inngest --port=3000", 9 | "dev": "nodemon -e ts -x \"npm run build && npm run start\" -i node_modules" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@google-cloud/functions-framework": "^3.3.0", 15 | "inngest": "^3.6.2" 16 | }, 17 | "devDependencies": { 18 | "nodemon": "^3.0.2", 19 | "typescript": "^5.3.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/framework-hono/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .wrangler 4 | .dev.vars 5 | 6 | # Change them to your taste: 7 | package-lock.json 8 | yarn.lock 9 | pnpm-lock.yaml 10 | bun.lockb -------------------------------------------------------------------------------- /examples/framework-hono/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "dev": "wrangler dev --port 3000 src/index.ts", 4 | "deploy": "wrangler deploy --minify src/index.ts" 5 | }, 6 | "dependencies": { 7 | "hono": "^4.3.6", 8 | "inngest": "^3.31.1" 9 | }, 10 | "devDependencies": { 11 | "@cloudflare/workers-types": "^4.20250129.0", 12 | "wrangler": "^3.107.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/framework-hono/src/bindings.ts: -------------------------------------------------------------------------------- 1 | export type Bindings = { 2 | // Add your bindings here to environment variables or Cloudflare resources 3 | }; -------------------------------------------------------------------------------- /examples/framework-hono/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Hono } from "hono"; 2 | import { serve } from "inngest/hono"; 3 | import { type Bindings } from "./bindings"; 4 | import { functions, inngest } from "./inngest"; 5 | 6 | const app = new Hono<{ Bindings: Bindings }>(); 7 | 8 | app.on( 9 | ["GET", "PUT", "POST"], 10 | "/api/inngest", 11 | serve({ 12 | client: inngest, 13 | functions, 14 | }) 15 | ); 16 | 17 | export default app; 18 | -------------------------------------------------------------------------------- /examples/framework-hono/src/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | import { bindingsMiddleware } from "./middleware"; 3 | import { schemas } from "./types"; 4 | 5 | export const inngest = new Inngest({ 6 | id: "my-hono-app", 7 | schemas, 8 | middleware: [bindingsMiddleware], 9 | }); 10 | -------------------------------------------------------------------------------- /examples/framework-hono/src/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export const helloWorld = inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/event.sent" }, 6 | async ({ event, step, env }) => { 7 | // Use "env" to access the Cloudflare Workers environment variables 8 | // (e.g. env.TEST_ENV_VAR) 9 | // This is passed using the bindingsMiddleware in middleware.ts 10 | return { 11 | message: `Hello ${event.name}!`, 12 | }; 13 | } 14 | ); 15 | -------------------------------------------------------------------------------- /examples/framework-hono/src/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import { helloWorld } from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/framework-hono/src/inngest/middleware.ts: -------------------------------------------------------------------------------- 1 | import { type Context } from 'hono'; 2 | import { InngestMiddleware } from "inngest"; 3 | import { type Bindings } from '../bindings'; 4 | 5 | /** 6 | * This middleware is used to pass the Cloudflare Workers environment variables 7 | * to Inngest functions. 8 | */ 9 | export const bindingsMiddleware = new InngestMiddleware({ 10 | name: "Cloudflare Workers bindings", 11 | init({ client, fn }) { 12 | return { 13 | onFunctionRun({ ctx, fn, steps, reqArgs }) { 14 | return { 15 | transformInput({ ctx, fn, steps }) { 16 | const [honoCtx] = reqArgs as [Context<{ Bindings: Bindings }>]; 17 | return { 18 | ctx: { 19 | env: honoCtx.env, 20 | }, 21 | }; 22 | }, 23 | }; 24 | }, 25 | }; 26 | }, 27 | }); -------------------------------------------------------------------------------- /examples/framework-hono/src/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/framework-hono/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "Bundler", 6 | "strict": true, 7 | "lib": [ 8 | "ESNext" 9 | ], 10 | "types": [ 11 | "@cloudflare/workers-types" 12 | ], 13 | "jsx": "react-jsx", 14 | "jsxImportSource": "hono/jsx" 15 | }, 16 | } -------------------------------------------------------------------------------- /examples/framework-hono/wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "framework-hono" 2 | compatibility_flags = [ "nodejs_compat" ] 3 | compatibility_date = "2024-09-23" 4 | 5 | # [vars] 6 | # MY_VAR = "my-variable" 7 | 8 | # Inngest+Cloudflare Worker "Cloud" mode: 9 | # If using "cloud" mode with wrangler you'll have to use ngrok or similar 10 | # As your cloud worker cannot reach the Inngest Dev Server running on localhost 11 | # INNGEST_DEV="https://.ngrok-free.app" 12 | # Also when using "cloud" mode during dev, you may need to also configure 13 | # your serve URL to tell the Inngest Dev Server to use the localhost URL instead 14 | # wrangler's public URL 15 | # INNGEST_SERVE_HOST="http://localhost:8787" 16 | 17 | # [[kv_namespaces]] 18 | # binding = "MY_KV_NAMESPACE" 19 | # id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 20 | 21 | # [[r2_buckets]] 22 | # binding = "MY_BUCKET" 23 | # bucket_name = "my-bucket" 24 | 25 | # [[d1_databases]] 26 | # binding = "DB" 27 | # database_name = "my-database" 28 | # database_id = "" 29 | 30 | # [ai] 31 | # binding = "AI" -------------------------------------------------------------------------------- /examples/framework-koa/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /examples/framework-koa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "framework-koa", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "tsx watch src/index.ts", 8 | "build": "tsc", 9 | "start": "node dist/index.js" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "inngest": "^3.5.0", 15 | "koa": "^2.14.2", 16 | "koa-bodyparser": "^4.4.1" 17 | }, 18 | "devDependencies": { 19 | "@types/koa": "^2.13.11", 20 | "@types/koa-bodyparser": "^4.3.12", 21 | "tsx": "^4.0.0", 22 | "typescript": "^5.2.2" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/framework-koa/src/index.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "inngest/koa"; 2 | import Koa from "koa"; 3 | import bodyParser from "koa-bodyparser"; 4 | import { functions, inngest } from "./inngest"; 5 | 6 | const app = new Koa(); 7 | app.use(bodyParser()); 8 | 9 | const handler = serve({ 10 | client: inngest, 11 | functions, 12 | }); 13 | 14 | app.use((ctx) => { 15 | if (ctx.request.path === "/api/inngest") { 16 | return handler(ctx); 17 | } 18 | }); 19 | 20 | app.listen(3000); 21 | -------------------------------------------------------------------------------- /examples/framework-koa/src/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | import { schemas } from "./types"; 3 | 4 | export const inngest = new Inngest({ id: "my-koa-app", schemas }); 5 | -------------------------------------------------------------------------------- /examples/framework-koa/src/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/event.sent" }, 6 | async ({ event, step }) => { 7 | return { 8 | message: `Hello ${event.name}!`, 9 | }; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /examples/framework-koa/src/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import helloWorld from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/framework-koa/src/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/framework-nestjs/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | tsconfigRootDir: __dirname, 6 | sourceType: 'module', 7 | }, 8 | plugins: ['@typescript-eslint/eslint-plugin'], 9 | extends: [ 10 | 'plugin:@typescript-eslint/recommended', 11 | 'plugin:prettier/recommended', 12 | ], 13 | root: true, 14 | env: { 15 | node: true, 16 | jest: true, 17 | }, 18 | ignorePatterns: ['.eslintrc.js'], 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/explicit-module-boundary-types': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /examples/framework-nestjs/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | pnpm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # OS 15 | .DS_Store 16 | 17 | # Tests 18 | /coverage 19 | /.nyc_output 20 | 21 | # IDEs and editors 22 | /.idea 23 | .project 24 | .classpath 25 | .c9/ 26 | *.launch 27 | .settings/ 28 | *.sublime-workspace 29 | 30 | # IDE - VSCode 31 | .vscode/* 32 | !.vscode/settings.json 33 | !.vscode/tasks.json 34 | !.vscode/launch.json 35 | !.vscode/extensions.json 36 | -------------------------------------------------------------------------------- /examples/framework-nestjs/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } 5 | -------------------------------------------------------------------------------- /examples/framework-nestjs/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 EverEfficient AI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/framework-nestjs/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src", 5 | "compilerOptions": { 6 | "deleteOutDir": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/framework-nestjs/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Logger, Module } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Module({ 5 | imports: [], 6 | controllers: [], 7 | providers: [Logger, AppService], 8 | }) 9 | export class AppModule {} 10 | -------------------------------------------------------------------------------- /examples/framework-nestjs/src/app.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppService } from './app.service'; 3 | 4 | describe('AppService', () => { 5 | let service: AppService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [AppService], 10 | }).compile(); 11 | 12 | service = module.get(AppService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /examples/framework-nestjs/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | helloWorld() { 6 | console.log(`Hello World. This method is called from Inngest function`); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/framework-nestjs/src/main.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from '@nestjs/common'; 2 | import { NestFactory } from '@nestjs/core'; 3 | import { NestExpressApplication } from '@nestjs/platform-express'; 4 | import { serve } from 'inngest/express'; 5 | 6 | import { inngest } from '@modules/common/inngest/client'; 7 | import { getInngestFunctions } from '@modules/common/inngest/functions'; 8 | 9 | import { AppModule } from './app.module'; 10 | import { AppService } from './app.service'; 11 | 12 | async function bootstrap() { 13 | const app = await NestFactory.create(AppModule, { 14 | bodyParser: true, 15 | }); 16 | 17 | // Setup inngest 18 | app.useBodyParser('json', { limit: '10mb' }); 19 | 20 | // Inject Dependencies into inngest functions 21 | 22 | const logger = app.get(Logger); 23 | const appService = app.get(AppService); 24 | 25 | // Pass dependencies into this function 26 | const inngestFunctions = getInngestFunctions({ 27 | appService, 28 | logger, 29 | }); 30 | 31 | // Register inngest endpoint 32 | app.use( 33 | '/api/inngest', 34 | serve({ 35 | client: inngest, 36 | functions: inngestFunctions, 37 | }), 38 | ); 39 | 40 | // Start listening for http requests 41 | await app.listen(3000); 42 | } 43 | 44 | bootstrap(); 45 | -------------------------------------------------------------------------------- /examples/framework-nestjs/src/modules/common/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas, Inngest } from 'inngest'; 2 | 3 | import { Events } from '@modules/common/inngest/types'; 4 | 5 | export const inngest = new Inngest({ 6 | id: 'framework-nestjs', 7 | schemas: new EventSchemas().fromRecord(), 8 | }); 9 | -------------------------------------------------------------------------------- /examples/framework-nestjs/src/modules/common/inngest/functions/hello.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from '@nestjs/common'; 2 | 3 | import { inngest } from '@modules/common/inngest/client'; 4 | 5 | import { AppService } from 'src/app.service'; 6 | 7 | /** 8 | * 9 | * @param dependencies dependencies to be injected in the function 10 | * @returns inngest function that will be supplied to serve middleware 11 | */ 12 | export const hello = (dependencies: { 13 | appService: AppService; 14 | logger: Logger; 15 | }) => { 16 | return inngest.createFunction( 17 | { id: 'hello-world' }, 18 | { event: 'job/hello.world' }, 19 | async ({ event, step }) => { 20 | await step.run('start-single-jobs', async () => { 21 | dependencies.logger.log(`Initiating Job`); 22 | dependencies.appService.helloWorld(); // Call helloWorld() method from app service provider 23 | }); 24 | }, 25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /examples/framework-nestjs/src/modules/common/inngest/functions/index.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from '@nestjs/common'; 2 | 3 | import { AppService } from 'src/app.service'; 4 | import { hello } from './hello'; 5 | 6 | export const getInngestFunctions = (dependencies: { 7 | appService: AppService; 8 | logger: Logger; 9 | // Add Dependencies Here 10 | }) => { 11 | return [ 12 | hello({ 13 | appService: dependencies.appService, 14 | logger: dependencies.logger, 15 | }), 16 | // Call other funtions with dependencies here like above 17 | ]; 18 | }; 19 | -------------------------------------------------------------------------------- /examples/framework-nestjs/src/modules/common/inngest/types/events.type.ts: -------------------------------------------------------------------------------- 1 | import { Hello } from '@modules/common/inngest/types'; 2 | 3 | export type Events = { 4 | 'job/hello.world': Hello; 5 | }; 6 | -------------------------------------------------------------------------------- /examples/framework-nestjs/src/modules/common/inngest/types/hello.type.ts: -------------------------------------------------------------------------------- 1 | export type Hello = { 2 | data: {}; 3 | }; 4 | -------------------------------------------------------------------------------- /examples/framework-nestjs/src/modules/common/inngest/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './events.type'; 2 | export * from './hello.type'; 3 | -------------------------------------------------------------------------------- /examples/framework-nestjs/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /examples/framework-nestjs/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/framework-nestjs/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /examples/framework-nestjs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": false, 16 | "noImplicitAny": false, 17 | "strictBindCallApply": false, 18 | "forceConsistentCasingInFileNames": false, 19 | "noFallthroughCasesInSwitch": false, 20 | "paths": { 21 | "@modules/*": ["src/modules/*"] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "framework-nextjs-pages-router", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "inngest": "^3.0.0", 13 | "next": "13.5.4", 14 | "react": "^18", 15 | "react-dom": "^18" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^20", 19 | "@types/react": "^18", 20 | "@types/react-dom": "^18", 21 | "eslint": "^8", 22 | "eslint-config-next": "13.5.4", 23 | "typescript": "^5" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/src/app/api/inngest/route.ts: -------------------------------------------------------------------------------- 1 | import { functions, inngest } from "@/inngest"; 2 | import { serve } from "inngest/next"; 3 | 4 | /** 5 | * Try to automatically choose the edge runtime if `INNGEST_STREAMING` is set. 6 | * 7 | * See https://innge.st/streaming. 8 | */ 9 | export const runtime = 10 | process.env.INNGEST_STREAMING?.toLowerCase() === "force" ? "edge" : "nodejs"; 11 | 12 | export const { GET, POST, PUT } = serve({ 13 | client: inngest, 14 | functions, 15 | }); 16 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inngest/inngest-js/2949293f64c65ddf30e50e4163eb8c0aec52cc83/examples/framework-nextjs-app-router/src/app/favicon.ico -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import type { Metadata } from 'next' 3 | import { Inter } from 'next/font/google' 4 | 5 | const inter = Inter({ subsets: ['latin'] }) 6 | 7 | export const metadata: Metadata = { 8 | title: 'Create Next App', 9 | description: 'Generated by create next app', 10 | } 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: { 15 | children: React.ReactNode 16 | }) { 17 | return ( 18 | 19 | {children} 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/src/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | import { schemas } from "./types"; 3 | 4 | export const inngest = new Inngest({ id: "my-nextjs-app", schemas }); 5 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/src/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/event.sent" }, 6 | async ({ event, step }) => { 7 | return { 8 | message: `Hello ${event.name}!`, 9 | }; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/src/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import helloWorld from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/src/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/framework-nextjs-app-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "framework-nextjs-pages-router", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "inngest": "^3.0.0", 13 | "next": "13.5.4", 14 | "react": "^18", 15 | "react-dom": "^18" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^20", 19 | "@types/react": "^18", 20 | "@types/react-dom": "^18", 21 | "eslint": "^8", 22 | "eslint-config-next": "13.5.4", 23 | "typescript": "^5" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inngest/inngest-js/2949293f64c65ddf30e50e4163eb8c0aec52cc83/examples/framework-nextjs-pages-router/public/favicon.ico -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/src/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | import { schemas } from "./types"; 3 | 4 | export const inngest = new Inngest({ id: "my-nextjs-app", schemas }); 5 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/src/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/event.sent" }, 6 | async ({ event, step }) => { 7 | return { 8 | message: `Hello ${event.name}!`, 9 | }; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/src/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import helloWorld from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/src/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import '@/styles/globals.css' 2 | import type { AppProps } from 'next/app' 3 | 4 | export default function App({ Component, pageProps }: AppProps) { 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/src/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from 'next/document' 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/src/pages/api/hello.ts: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | 4 | type Data = { 5 | name: string 6 | } 7 | 8 | export default function handler( 9 | req: NextApiRequest, 10 | res: NextApiResponse 11 | ) { 12 | res.status(200).json({ name: 'John Doe' }) 13 | } 14 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/src/pages/api/inngest.ts: -------------------------------------------------------------------------------- 1 | import { functions, inngest } from "@/inngest"; 2 | import { serve } from "inngest/next"; 3 | 4 | export default serve({ 5 | client: inngest, 6 | functions, 7 | }); 8 | -------------------------------------------------------------------------------- /examples/framework-nextjs-pages-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "paths": { 17 | "@/*": ["./src/*"] 18 | } 19 | }, 20 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 21 | "exclude": ["node_modules"] 22 | } 23 | -------------------------------------------------------------------------------- /examples/framework-nitro/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .data 4 | .nitro 5 | .cache 6 | .output 7 | .env 8 | -------------------------------------------------------------------------------- /examples/framework-nitro/.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /examples/framework-nitro/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | import { schemas } from "./types"; 3 | 4 | export const inngest = new Inngest({ id: "my-nitro-app", schemas }); 5 | -------------------------------------------------------------------------------- /examples/framework-nitro/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export const helloWorld = inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/event.sent" }, 6 | async ({ event, step }) => { 7 | return { 8 | message: `Hello ${event.name}!`, 9 | }; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /examples/framework-nitro/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import { helloWorld } from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/framework-nitro/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/framework-nitro/nitro.config.ts: -------------------------------------------------------------------------------- 1 | //https://nitro.unjs.io/config 2 | export default defineNitroConfig({ 3 | srcDir: "server", 4 | compatibilityDate: "2024-11-05", 5 | }); -------------------------------------------------------------------------------- /examples/framework-nitro/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "nitro build", 5 | "dev": "nitro dev", 6 | "prepare": "nitro prepare", 7 | "preview": "node .output/server/index.mjs" 8 | }, 9 | "devDependencies": { 10 | "nitropack": "latest" 11 | }, 12 | "dependencies": { 13 | "inngest": "^3.0.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/framework-nitro/server/routes/api/inngest.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "inngest/nitro"; 2 | import { functions, inngest } from "~~/inngest"; 3 | 4 | export default eventHandler( 5 | serve({ 6 | client: inngest, 7 | functions, 8 | }) 9 | ); 10 | -------------------------------------------------------------------------------- /examples/framework-nitro/server/routes/index.ts: -------------------------------------------------------------------------------- 1 | export default eventHandler((event) => { 2 | return "Start by editing server/routes/index.ts."; 3 | }); 4 | -------------------------------------------------------------------------------- /examples/framework-nitro/tsconfig.json: -------------------------------------------------------------------------------- 1 | // https://nitro.unjs.io/guide/typescript 2 | { 3 | "extends": "./.nitro/types/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /examples/framework-nuxt/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log* 3 | .nuxt 4 | .nitro 5 | .cache 6 | .output 7 | .env 8 | dist 9 | -------------------------------------------------------------------------------- /examples/framework-nuxt/.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /examples/framework-nuxt/app.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /examples/framework-nuxt/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | import { schemas } from "./types"; 3 | 4 | export const inngest = new Inngest({ id: "my-nuxt-app", schemas }); 5 | -------------------------------------------------------------------------------- /examples/framework-nuxt/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/event.sent" }, 6 | async ({ event, step }) => { 7 | return { 8 | message: `Hello ${event.name}!`, 9 | }; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /examples/framework-nuxt/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import helloWorld from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/framework-nuxt/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/framework-nuxt/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | // https://nuxt.com/docs/api/configuration/nuxt-config 2 | export default defineNuxtConfig({ 3 | 4 | }) 5 | -------------------------------------------------------------------------------- /examples/framework-nuxt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "nuxt build", 5 | "dev": "nuxt dev", 6 | "generate": "nuxt generate", 7 | "preview": "nuxt preview", 8 | "postinstall": "nuxt prepare", 9 | "start": "node .output/server/index.mjs" 10 | }, 11 | "devDependencies": { 12 | "nuxt": "^3.0.0" 13 | }, 14 | "dependencies": { 15 | "inngest": "^3.0.0" 16 | }, 17 | "volta": { 18 | "node": "18.16.1", 19 | "yarn": "1.22.19" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/framework-nuxt/server/api/inngest.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "inngest/nuxt"; 2 | import { functions, inngest } from "~~/inngest"; 3 | 4 | export default defineEventHandler(serve({ client: inngest, functions })); 5 | -------------------------------------------------------------------------------- /examples/framework-nuxt/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /examples/framework-remix/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import('eslint').Linter.Config} */ 2 | module.exports = { 3 | extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/framework-remix/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | .cache 4 | .env 5 | .vercel 6 | .output 7 | 8 | /build/ 9 | /public/build 10 | /api/index.js 11 | /api/index.js.map 12 | -------------------------------------------------------------------------------- /examples/framework-remix/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | import { RemixBrowser } from "@remix-run/react"; 2 | import { startTransition, StrictMode } from "react"; 3 | import { hydrateRoot } from "react-dom/client"; 4 | 5 | function hydrate() { 6 | startTransition(() => { 7 | hydrateRoot( 8 | document, 9 | 10 | 11 | 12 | ); 13 | }); 14 | } 15 | 16 | if (window.requestIdleCallback) { 17 | window.requestIdleCallback(hydrate); 18 | } else { 19 | // Safari doesn't support requestIdleCallback 20 | // https://caniuse.com/requestidlecallback 21 | window.setTimeout(hydrate, 1); 22 | } 23 | -------------------------------------------------------------------------------- /examples/framework-remix/app/entry.server.tsx: -------------------------------------------------------------------------------- 1 | import type { EntryContext } from "@remix-run/node"; 2 | import { RemixServer } from "@remix-run/react"; 3 | import { renderToString } from "react-dom/server"; 4 | 5 | export default function handleRequest( 6 | request: Request, 7 | responseStatusCode: number, 8 | responseHeaders: Headers, 9 | remixContext: EntryContext 10 | ) { 11 | const markup = renderToString( 12 | 13 | ); 14 | 15 | responseHeaders.set("Content-Type", "text/html"); 16 | 17 | return new Response("" + markup, { 18 | headers: responseHeaders, 19 | status: responseStatusCode, 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /examples/framework-remix/app/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | import { schemas } from "./types"; 3 | 4 | export const inngest = new Inngest({ id: "my-remix-app", schemas }); 5 | -------------------------------------------------------------------------------- /examples/framework-remix/app/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/event.sent" }, 6 | async ({ event, step }) => { 7 | return { 8 | message: `Hello ${event.name}!`, 9 | }; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /examples/framework-remix/app/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import helloWorld from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/framework-remix/app/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/framework-remix/app/root.tsx: -------------------------------------------------------------------------------- 1 | import type { MetaFunction } from "@remix-run/node"; 2 | import { 3 | Links, 4 | LiveReload, 5 | Meta, 6 | Outlet, 7 | Scripts, 8 | ScrollRestoration, 9 | } from "@remix-run/react"; 10 | 11 | export const meta: MetaFunction = () => ({ 12 | charset: "utf-8", 13 | title: "New Remix App", 14 | viewport: "width=device-width,initial-scale=1", 15 | }); 16 | 17 | export default function App() { 18 | return ( 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /examples/framework-remix/app/routes/api/inngest.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "inngest/remix"; 2 | import { functions, inngest } from "~/inngest"; 3 | 4 | const handler = serve({ client: inngest, functions }); 5 | 6 | export { handler as action, handler as loader }; 7 | -------------------------------------------------------------------------------- /examples/framework-remix/app/routes/index.tsx: -------------------------------------------------------------------------------- 1 | export default function Index() { 2 | return ( 3 |
4 |

Welcome to Remix

5 | 30 |
31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /examples/framework-remix/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "sideEffects": false, 4 | "scripts": { 5 | "build": "remix build", 6 | "dev": "remix dev" 7 | }, 8 | "dependencies": { 9 | "@remix-run/node": "^1.8.0", 10 | "@remix-run/react": "^1.8.0", 11 | "@remix-run/vercel": "^1.8.0", 12 | "@vercel/node": "^2.6.2", 13 | "inngest": "^3.0.0", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0" 16 | }, 17 | "devDependencies": { 18 | "@remix-run/dev": "^1.8.0", 19 | "@remix-run/eslint-config": "^1.8.0", 20 | "@remix-run/serve": "^1.8.0", 21 | "@types/react": "^18.0.25", 22 | "@types/react-dom": "^18.0.8", 23 | "eslint": "^8.27.0", 24 | "typescript": "^4.8.4" 25 | }, 26 | "engines": { 27 | "node": ">=14" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/framework-remix/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inngest/inngest-js/2949293f64c65ddf30e50e4163eb8c0aec52cc83/examples/framework-remix/public/favicon.ico -------------------------------------------------------------------------------- /examples/framework-remix/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | module.exports = { 3 | serverBuildTarget: "vercel", 4 | // When running locally in development mode, we use the built in remix 5 | // server. This does not understand the vercel lambda module format, 6 | // so we default back to the standard build output. 7 | server: process.env.NODE_ENV === "development" ? undefined : "./server.js", 8 | ignoredRouteFiles: ["**/.*"], 9 | // appDirectory: "app", 10 | // assetsBuildDirectory: "public/build", 11 | // serverBuildPath: "api/index.js", 12 | // publicPath: "/build/", 13 | }; 14 | -------------------------------------------------------------------------------- /examples/framework-remix/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /examples/framework-remix/server.js: -------------------------------------------------------------------------------- 1 | import { createRequestHandler } from "@remix-run/vercel"; 2 | import * as build from "@remix-run/dev/server-build"; 3 | 4 | export default createRequestHandler({ build, mode: process.env.NODE_ENV }); 5 | -------------------------------------------------------------------------------- /examples/framework-remix/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2019"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "target": "ES2019", 11 | "strict": true, 12 | "allowJs": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "baseUrl": ".", 15 | "paths": { 16 | "~/*": ["./app/*"] 17 | }, 18 | 19 | // Remix takes care of building everything in `remix build`. 20 | "noEmit": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | vite.config.js.timestamp-* 10 | vite.config.ts.timestamp-* 11 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | resolution-mode=highest 3 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte"], 7 | "pluginSearchDirs": ["."], 8 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 9 | } 10 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "inngest-sveltekit-example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite dev --port 3000", 7 | "build": "vite build", 8 | "preview": "vite preview", 9 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 10 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 11 | "test": "vitest", 12 | "lint": "prettier --plugin-search-dir . --check .", 13 | "format": "prettier --plugin-search-dir . --write ." 14 | }, 15 | "devDependencies": { 16 | "@sveltejs/adapter-auto": "^2.0.0", 17 | "@sveltejs/adapter-vercel": "^3.0.3", 18 | "@sveltejs/kit": "^1.20.4", 19 | "prettier": "^2.8.0", 20 | "prettier-plugin-svelte": "^2.10.1", 21 | "svelte": "^4.0.5", 22 | "svelte-check": "^3.4.3", 23 | "tslib": "^2.4.1", 24 | "typescript": "^5.0.0", 25 | "vite": "^4.4.2", 26 | "vitest": "^0.33.0" 27 | }, 28 | "type": "module", 29 | "dependencies": { 30 | "h3": "^1.7.1", 31 | "inngest": "^3.0.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface Platform {} 9 | } 10 | } 11 | 12 | export {}; 13 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/src/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | describe('sum test', () => { 4 | it('adds 1 + 2 to equal 3', () => { 5 | expect(1 + 2).toBe(3); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/src/lib/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from 'inngest'; 2 | import { schemas } from './types'; 3 | 4 | export const inngest = new Inngest({ id: 'my-sveltekit-app', schemas }); 5 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/src/lib/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from './client'; 2 | 3 | export default inngest.createFunction( 4 | { id: 'hello-world' }, 5 | { event: 'demo/event.sent' }, 6 | ({ event, step }) => { 7 | return { 8 | message: `Hello ${event.name}!` 9 | }; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/src/lib/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import helloWorld from './helloWorld'; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from './client'; 6 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/src/lib/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from 'inngest'; 2 | 3 | type DemoEventSent = { 4 | name: 'demo/event.sent'; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 |

Welcome to SvelteKit

2 |

Visit kit.svelte.dev to read the documentation

3 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/src/routes/api/inngest/+server.ts: -------------------------------------------------------------------------------- 1 | import { functions, inngest } from '$lib/inngest'; 2 | import { serve } from 'inngest/sveltekit'; 3 | 4 | export const { GET, POST, PUT } = serve({ client: inngest, functions }); 5 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inngest/inngest-js/2949293f64c65ddf30e50e4163eb8c0aec52cc83/examples/framework-sveltekit/static/favicon.png -------------------------------------------------------------------------------- /examples/framework-sveltekit/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import { vitePreprocess } from '@sveltejs/kit/vite'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 12 | // If your environment is not supported or you settled on a specific environment, switch out the adapter. 13 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 14 | adapter: adapter() 15 | } 16 | }; 17 | 18 | export default config; 19 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /examples/framework-sveltekit/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vitest/config'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()], 6 | test: { 7 | include: ['src/**/*.{test,spec}.{js,ts}'] 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /examples/middleware-e2e-encryption/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware-e2e-encryption", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "inngest": "^3.0.0" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^20.9.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/.env.example: -------------------------------------------------------------------------------- 1 | POSTGRES_URL=your_neon_database_url_here 2 | OPENAI_API_KEY=your_openai_api_key_here 3 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # env files (can opt-in for committing if needed) 34 | .env* 35 | !.env.example 36 | 37 | # vercel 38 | .vercel 39 | 40 | # typescript 41 | *.tsbuildinfo 42 | next-env.d.ts 43 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/app/actions.ts: -------------------------------------------------------------------------------- 1 | "use server"; 2 | import { inngest } from "@/inngest/client"; 3 | 4 | export async function generateMeal(formData: FormData) { 5 | const participantsCount = Number(formData.get("participantsCount")); 6 | const preferences = 7 | formData.get("preferences")?.toString().split("\n").filter(Boolean) || []; 8 | 9 | const { ids } = await inngest.send({ 10 | name: "meal.generate", 11 | data: { participantsCount, preferences }, 12 | }); 13 | 14 | return ids[0]; 15 | } 16 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/app/api/generationStatus/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | import { NextRequest } from "next/server"; 3 | 4 | async function getRuns(eventId: string) { 5 | const response = await fetch( 6 | process.env.INNGEST_SIGNING_KEY 7 | ? `https://api.inngest.com/v1/events/${eventId}/runs` 8 | : `http://localhost:8288/v1/events/${eventId}/runs`, 9 | { 10 | ...(process.env.INNGEST_SIGNING_KEY 11 | ? { 12 | headers: { 13 | Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`, 14 | }, 15 | } 16 | : {}), 17 | } 18 | ); 19 | const json = await response.json(); 20 | return json.data; 21 | } 22 | 23 | export async function GET(req: NextRequest) { 24 | const id = req.nextUrl.searchParams.get("id"); 25 | 26 | const runs = await getRuns(id as string); 27 | if (runs[0] && runs[0].output) { 28 | const run = runs[0]; 29 | console.log("run", JSON.stringify(run, null, 2)); 30 | return NextResponse.json({ 31 | menu: run.output.mealPlan.choices[0].message.content, 32 | }); 33 | } 34 | 35 | return NextResponse.json({ 36 | menu: null, 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/app/api/inngest/route.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "inngest/next"; 2 | import { inngest } from "@/inngest/client"; 3 | import { generateMeal } from "@/inngest/functions"; 4 | 5 | // Create an API route handler with all functions 6 | export const { GET, POST, PUT } = serve({ 7 | client: inngest, 8 | functions: [generateMeal], 9 | }); 10 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inngest/inngest-js/2949293f64c65ddf30e50e4163eb8c0aec52cc83/examples/nextjs-christmas-dinner-generator-challenge/app/favicon.ico -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --background: #ffffff; 7 | --foreground: #171717; 8 | } 9 | 10 | @media (prefers-color-scheme: dark) { 11 | :root { 12 | --background: #0a0a0a; 13 | --foreground: #ededed; 14 | } 15 | } 16 | 17 | body { 18 | color: var(--foreground); 19 | background: var(--background); 20 | font-family: Arial, Helvetica, sans-serif; 21 | } 22 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Geist, Geist_Mono } from "next/font/google"; 3 | import "./globals.css"; 4 | 5 | const geistSans = Geist({ 6 | variable: "--font-geist-sans", 7 | subsets: ["latin"], 8 | }); 9 | 10 | const geistMono = Geist_Mono({ 11 | variable: "--font-geist-mono", 12 | subsets: ["latin"], 13 | }); 14 | 15 | export const metadata: Metadata = { 16 | title: "Create Next App", 17 | description: "Generated by create next app", 18 | }; 19 | 20 | export default function RootLayout({ 21 | children, 22 | }: Readonly<{ 23 | children: React.ReactNode; 24 | }>) { 25 | return ( 26 | 27 | 30 | {children} 31 | 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/app/page.tsx: -------------------------------------------------------------------------------- 1 | "use server"; 2 | 3 | import { Home } from "./components/home"; 4 | 5 | export default async function HomePage() { 6 | return ; 7 | } 8 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | import { FlatCompat } from "@eslint/eslintrc"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [ 13 | ...compat.extends("next/core-web-vitals", "next/typescript"), 14 | ]; 15 | 16 | export default eslintConfig; 17 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { typedInngest } from "./events"; 2 | 3 | // Export the typed client instead of the untyped one 4 | export const inngest = typedInngest; 5 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/inngest/events.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas, Inngest } from "inngest"; 2 | import { z } from "zod"; 3 | 4 | // Define the meal generation event schema 5 | export const mealGenerateSchema = z.object({ 6 | name: z.literal("meal.generate"), 7 | data: z.object({ 8 | participantsCount: z.number().int().positive(), 9 | preferences: z.array(z.string()), 10 | }), 11 | }); 12 | 13 | // Create type from the schema 14 | export type MealGenerateEvent = z.infer; 15 | 16 | // Define all events type 17 | export type Events = { 18 | "meal.generate": MealGenerateEvent; 19 | }; 20 | 21 | // Create a typed client 22 | export const typedInngest = new Inngest({ 23 | id: "my-app", 24 | schemas: new EventSchemas().fromZod([mealGenerateSchema]), 25 | }); 26 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/inngest/functions.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "@/inngest/client"; 2 | 3 | export const generateMeal = inngest.createFunction( 4 | { id: "generate-meal" }, 5 | { event: "meal.generate" }, 6 | async ({ event, step }) => { 7 | const { participantsCount, preferences } = event.data; 8 | 9 | await step.run("hello", async () => { 10 | console.log("Hello, world!"); 11 | console.log( 12 | `Received ${participantsCount} participants with the following preferences: ${preferences}` 13 | ); 14 | }); 15 | 16 | await step.sleep("sleep-1s", 1000); 17 | 18 | await step.run("final-step", async () => { 19 | console.log("Final step"); 20 | }); 21 | } 22 | ); 23 | 24 | export const functions = [generateMeal]; 25 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/lib/vectorStore.ts: -------------------------------------------------------------------------------- 1 | import { NeonPostgres } from "@langchain/community/vectorstores/neon"; 2 | import { OpenAIEmbeddings } from "@langchain/openai"; 3 | 4 | const embeddings = new OpenAIEmbeddings({ 5 | apiKey: process.env.OPENAI_API_KEY, 6 | dimensions: 512, 7 | model: "text-embedding-3-small", 8 | }); 9 | 10 | // Each workspace has its own vector store 11 | export const loadVectorStore = async (tableName: string) => { 12 | return await NeonPostgres.initialize(embeddings, { 13 | connectionString: process.env.POSTGRES_URL!, 14 | tableName, 15 | columns: { 16 | contentColumnName: "content", 17 | metadataColumnName: "metadata", 18 | vectorColumnName: "embedding", 19 | }, 20 | }); 21 | }; 22 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | /* config options here */ 5 | }; 6 | 7 | export default nextConfig; 8 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs-christmas-dinner-generator-challenge", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "index-vector-store": "ts-node scripts/index.ts", 8 | "generate-jsons": "ts-node scripts/generate-jsons.ts", 9 | "inngest": "npx inngest-cli@latest dev", 10 | "build": "next build", 11 | "start": "next start", 12 | "lint": "next lint" 13 | }, 14 | "dependencies": { 15 | "@langchain/community": "^0.3.11", 16 | "@langchain/core": "^0.3.17", 17 | "@langchain/openai": "^0.3.11", 18 | "@neondatabase/serverless": "^0.10.4", 19 | "@tanstack/react-query": "^5.62.7", 20 | "inngest": "^3.27.5", 21 | "next": "15.1.0", 22 | "react": "^19.0.0", 23 | "react-dom": "^19.0.0" 24 | }, 25 | "devDependencies": { 26 | "@dsnp/parquetjs": "^1.8.5", 27 | "@eslint/eslintrc": "^3", 28 | "@types/node": "^20", 29 | "@types/react": "^19", 30 | "@types/react-dom": "^19", 31 | "eslint": "^9", 32 | "eslint-config-next": "15.1.0", 33 | "glob": "^11.0.0", 34 | "postcss": "^8", 35 | "tailwindcss": "^3.4.1", 36 | "typescript": "^5" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/readme-assets/Screenshot_2024-11-20_at_14.33.46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inngest/inngest-js/2949293f64c65ddf30e50e4163eb8c0aec52cc83/examples/nextjs-christmas-dinner-generator-challenge/readme-assets/Screenshot_2024-11-20_at_14.33.46.png -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/readme-assets/Screenshot_2024-11-20_at_14.34.24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inngest/inngest-js/2949293f64c65ddf30e50e4163eb8c0aec52cc83/examples/nextjs-christmas-dinner-generator-challenge/readme-assets/Screenshot_2024-11-20_at_14.34.24.png -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/readme-assets/Screenshot_2024-11-20_at_14.59.42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inngest/inngest-js/2949293f64c65ddf30e50e4163eb8c0aec52cc83/examples/nextjs-christmas-dinner-generator-challenge/readme-assets/Screenshot_2024-11-20_at_14.59.42.png -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/readme-assets/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inngest/inngest-js/2949293f64c65ddf30e50e4163eb8c0aec52cc83/examples/nextjs-christmas-dinner-generator-challenge/readme-assets/image.png -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | content: [ 5 | "./pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./app/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | extend: { 11 | colors: { 12 | background: "var(--background)", 13 | foreground: "var(--foreground)", 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } satisfies Config; 19 | -------------------------------------------------------------------------------- /examples/nextjs-christmas-dinner-generator-challenge/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /examples/node-otel/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.js 3 | -------------------------------------------------------------------------------- /examples/node-otel/README.md: -------------------------------------------------------------------------------- 1 | # Inngest Node.js Template 2 | 3 | This is a vanilla Node.js server project. It is a minimal zero-external dependencies example of how to run Inngest natively in Node.js. 4 | 5 | ## Getting Started 6 | 7 | Use [`create-next-app`](https://www.npmjs.com/package/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example: 8 | 9 | ```bash 10 | npx create-next-app --example https://github.com/inngest/inngest-js/tree/main/examples/framework-node inngest-node 11 | ``` 12 | 13 | ```bash 14 | yarn create next-app --example https://github.com/inngest/inngest-js/tree/main/examples/framework-node inngest-node 15 | ``` 16 | 17 | ```bash 18 | pnpm create next-app --example https://github.com/inngest/inngest-js/tree/main/examples/framework-node inngest-node 19 | ``` 20 | 21 | Open http://localhost:3000 with your browser to see the result. 22 | 23 | - [Inngest functions](https://www.inngest.com/docs/functions) are available at `inngest/`. 24 | - The [Inngest handler](https://www.inngest.com/docs/sdk/serve) is available at `index.ts`. 25 | 26 | ## Learn More 27 | 28 | - [Inngest Documentation](https://www.inngest.com/docs) - learn about the Inngest SDK, functions, and events 29 | -------------------------------------------------------------------------------- /examples/node-otel/index.ts: -------------------------------------------------------------------------------- 1 | // Import the client first 2 | import { inngest } from './inngest'; 3 | 4 | // Then import everything else 5 | import { createServer } from 'inngest/node'; 6 | import { functions } from './inngest'; 7 | 8 | const server = createServer({ client: inngest, functions }); 9 | 10 | server.listen(3000, () => { 11 | console.log('Server running on http://localhost:3000'); 12 | }); 13 | -------------------------------------------------------------------------------- /examples/node-otel/inngest/client.ts: -------------------------------------------------------------------------------- 1 | // Initialize otel middleware first 2 | import { otelMiddleware } from "inngest/experimental"; 3 | const otel = otelMiddleware(); 4 | 5 | // Then everything else 6 | import { Inngest } from "inngest"; 7 | import { schemas } from "./types"; 8 | 9 | export const inngest = new Inngest({ 10 | id: "my-express-app", 11 | schemas, 12 | middleware: [otel], 13 | }); 14 | -------------------------------------------------------------------------------- /examples/node-otel/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/event.sent" }, 6 | async ({ event, step }) => { 7 | // A random call that will trigger automatic Node instrumentation and create 8 | // a span 9 | await fetch("http://localhost:3000/api/inngest"); 10 | 11 | return { 12 | message: `Hello ${event.name}!`, 13 | }; 14 | } 15 | ); 16 | -------------------------------------------------------------------------------- /examples/node-otel/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import helloWorld from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/node-otel/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/node-otel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "framework-nodejs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc -p tsconfig.json", 8 | "dev": "tsx index.ts", 9 | "start": "node dist/index.js" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@types/node": "^20.5.2", 15 | "tsx": "^4.7.3", 16 | "typescript": "^5.1.6" 17 | }, 18 | "dependencies": { 19 | "inngest": "file:../../packages/inngest/inngest.tgz" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/node-step-fetch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step-fetch", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "build": "tsc", 7 | "start": "node dist/index.js", 8 | "dev": "nodemon --watch src --ext ts --exec ts-node src/index.ts" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "description": "", 14 | "dependencies": { 15 | "express": "^5.1.0", 16 | "inngest": "^3.35.1" 17 | }, 18 | "devDependencies": { 19 | "@types/express": "^5.0.1", 20 | "@types/node": "^22.15.16", 21 | "nodemon": "^3.1.10", 22 | "ts-node": "^10.9.2", 23 | "typescript": "^5.8.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/node-step-fetch/src/index.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import { inngest } from "./inngest/client"; 3 | import { serve } from "inngest/express"; 4 | import { retrieveTextFile } from "./inngest/functions"; 5 | const app = express(); 6 | 7 | // Important: ensure you add JSON middleware to process incoming JSON POST payloads. 8 | app.use(express.json()); 9 | app.use( 10 | // Expose the middleware on our recommended path at `/api/inngest`. 11 | "/api/inngest", 12 | serve({ client: inngest, functions: [retrieveTextFile] }) 13 | ); 14 | 15 | app.listen(3000, () => { 16 | console.log("Server is running on port 3000"); 17 | }); 18 | -------------------------------------------------------------------------------- /examples/node-step-fetch/src/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | 3 | export const inngest = new Inngest({ id: "node-step-fetch" }); 4 | -------------------------------------------------------------------------------- /examples/node-step-fetch/src/inngest/functions.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export const retrieveTextFile = inngest.createFunction( 4 | { id: "retrieveTextFile" }, 5 | { event: "textFile/retrieve" }, 6 | async ({ step }) => { 7 | const response = await step.fetch( 8 | "https://example-files.online-convert.com/document/txt/example.txt" 9 | ); 10 | 11 | await step.run("extract-text", async () => { 12 | const text = await response.text(); 13 | const exampleOccurences = text.match(/example/g); 14 | return exampleOccurences?.length; 15 | }); 16 | } 17 | ); 18 | -------------------------------------------------------------------------------- /examples/node/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.js 3 | -------------------------------------------------------------------------------- /examples/node/README.md: -------------------------------------------------------------------------------- 1 | # Inngest Node.js Template 2 | 3 | This is a vanilla Node.js server project. It is a minimal zero-external dependencies example of how to run Inngest natively in Node.js. 4 | 5 | ## Getting Started 6 | 7 | Use [`create-next-app`](https://www.npmjs.com/package/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example: 8 | 9 | ```bash 10 | npx create-next-app --example https://github.com/inngest/inngest-js/tree/main/examples/framework-node inngest-node 11 | ``` 12 | 13 | ```bash 14 | yarn create next-app --example https://github.com/inngest/inngest-js/tree/main/examples/framework-node inngest-node 15 | ``` 16 | 17 | ```bash 18 | pnpm create next-app --example https://github.com/inngest/inngest-js/tree/main/examples/framework-node inngest-node 19 | ``` 20 | 21 | Open http://localhost:3000 with your browser to see the result. 22 | 23 | - [Inngest functions](https://www.inngest.com/docs/functions) are available at `inngest/`. 24 | - The [Inngest handler](https://www.inngest.com/docs/sdk/serve) is available at `index.ts`. 25 | 26 | ## Learn More 27 | 28 | - [Inngest Documentation](https://www.inngest.com/docs) - learn about the Inngest SDK, functions, and events 29 | -------------------------------------------------------------------------------- /examples/node/index.ts: -------------------------------------------------------------------------------- 1 | import { createServer } from 'inngest/node'; 2 | import { functions, inngest } from './inngest'; 3 | 4 | const server = createServer({ client: inngest, functions }); 5 | 6 | server.listen(3000, () => { 7 | console.log('Server running on http://localhost:3000'); 8 | }); 9 | -------------------------------------------------------------------------------- /examples/node/inngest/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | import { schemas } from "./types"; 3 | 4 | export const inngest = new Inngest({ id: "my-express-app", schemas }); 5 | -------------------------------------------------------------------------------- /examples/node/inngest/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "./client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/event.sent" }, 6 | async ({ event, step }) => { 7 | const result = await step.waitForSignal("wait-for-it", { 8 | signal: "hmm", 9 | timeout: "5m" 10 | }) 11 | 12 | return { 13 | result, 14 | message: `Hello ${event.name}!`, 15 | }; 16 | } 17 | ); 18 | -------------------------------------------------------------------------------- /examples/node/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import helloWorld from "./helloWorld"; 2 | 3 | export const functions = [helloWorld]; 4 | 5 | export { inngest } from "./client"; 6 | -------------------------------------------------------------------------------- /examples/node/inngest/types.ts: -------------------------------------------------------------------------------- 1 | import { EventSchemas } from "inngest"; 2 | 3 | type DemoEventSent = { 4 | name: "demo/event.sent"; 5 | data: { 6 | message: string; 7 | }; 8 | }; 9 | 10 | export const schemas = new EventSchemas().fromUnion(); 11 | -------------------------------------------------------------------------------- /examples/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "framework-nodejs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc -p tsconfig.json", 8 | "dev": "tsx index.ts", 9 | "start": "node dist/index.js" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@types/node": "^20.5.2", 15 | "tsx": "^4.7.3", 16 | "typescript": "^5.1.6" 17 | }, 18 | "dependencies": { 19 | "inngest": "file:../../packages/inngest/inngest.tgz" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # env files (can opt-in for committing if needed) 34 | .env* 35 | 36 | # vercel 37 | .vercel 38 | 39 | # typescript 40 | *.tsbuildinfo 41 | next-env.d.ts 42 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/app/actions.ts: -------------------------------------------------------------------------------- 1 | "use server"; 2 | 3 | import { getInngestApp } from "@/inngest"; 4 | import { helloChannel } from "@/inngest/functions/helloWorld"; 5 | import { getSubscriptionToken, Realtime } from "@inngest/realtime"; 6 | 7 | export type HelloToken = Realtime.Token; 8 | 9 | export async function fetchRealtimeSubscriptionToken(): Promise { 10 | const token = await getSubscriptionToken(getInngestApp(), { 11 | channel: helloChannel(), 12 | topics: ["logs"], 13 | }); 14 | 15 | return token; 16 | } 17 | 18 | export async function pause(): Promise { 19 | const inngest = getInngestApp(); 20 | await inngest.send({ 21 | name: "test/cancel.signal", 22 | }); 23 | } 24 | 25 | export async function resume(): Promise { 26 | const inngest = getInngestApp(); 27 | await inngest.send({ 28 | name: "test/hello.world", 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/app/api/inngest/route.ts: -------------------------------------------------------------------------------- 1 | import { getInngestApp } from "@/inngest"; 2 | import { helloWorld } from "@/inngest/functions/helloWorld"; 3 | import { serve } from "inngest/next"; 4 | 5 | const inngest = getInngestApp(); 6 | 7 | // Create an API that serves zero functions 8 | export const { GET, POST, PUT } = serve({ 9 | client: inngest, 10 | functions: [ 11 | /* your functions will be passed here later! */ 12 | helloWorld, 13 | ], 14 | }); 15 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inngest/inngest-js/2949293f64c65ddf30e50e4163eb8c0aec52cc83/examples/realtime/next-realtime-hooks/app/favicon.ico -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/app/globals.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | 3 | :root { 4 | --background: #ffffff; 5 | --foreground: #171717; 6 | } 7 | 8 | @theme inline { 9 | --color-background: var(--background); 10 | --color-foreground: var(--foreground); 11 | --font-sans: var(--font-geist-sans); 12 | --font-mono: var(--font-geist-mono); 13 | } 14 | 15 | @media (prefers-color-scheme: dark) { 16 | :root { 17 | --background: #0a0a0a; 18 | --foreground: #ededed; 19 | } 20 | } 21 | 22 | body { 23 | background: var(--background); 24 | color: var(--foreground); 25 | font-family: Arial, Helvetica, sans-serif; 26 | } 27 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Geist, Geist_Mono } from "next/font/google"; 3 | import "./globals.css"; 4 | 5 | const geistSans = Geist({ 6 | variable: "--font-geist-sans", 7 | subsets: ["latin"], 8 | }); 9 | 10 | const geistMono = Geist_Mono({ 11 | variable: "--font-geist-mono", 12 | subsets: ["latin"], 13 | }); 14 | 15 | export const metadata: Metadata = { 16 | title: "Inngest Realtime demo", 17 | description: "Inngest Realtime using React Hooks", 18 | }; 19 | 20 | export default function RootLayout({ 21 | children, 22 | }: Readonly<{ 23 | children: React.ReactNode; 24 | }>) { 25 | return ( 26 | 27 | 30 | {children} 31 | 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | import { FlatCompat } from "@eslint/eslintrc"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [ 13 | ...compat.extends("next/core-web-vitals", "next/typescript"), 14 | ]; 15 | 16 | export default eslintConfig; 17 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/inngest/functions/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import { channel, topic } from "@inngest/realtime"; 2 | import { getInngestApp } from ".."; 3 | 4 | const inngest = getInngestApp(); 5 | 6 | export const helloChannel = channel("hello-world").addTopic( 7 | topic("logs").type() 8 | ); 9 | 10 | export const helloWorld = inngest.createFunction( 11 | { id: "hello-world" }, 12 | { event: "test/hello.world" }, 13 | async ({ event, step, publish, runId }) => { 14 | publish(helloChannel().logs(`Hello from ${runId}`)); 15 | 16 | // wait 2 seconds before next iteration while waiting for a potential cancel signal 17 | const result = await step.waitForEvent("cancel-signal", { 18 | event: "test/cancel.signal", 19 | timeout: 2000, 20 | }); 21 | 22 | if (!result) { 23 | await step.sendEvent("retrigger", { 24 | name: "test/hello.world", 25 | data: { email: event.data.email }, 26 | }); 27 | } 28 | 29 | return { message: `Hello!`, runId }; 30 | } 31 | ); 32 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/inngest/index.ts: -------------------------------------------------------------------------------- 1 | import { realtimeMiddleware } from "@inngest/realtime"; 2 | import { Inngest } from "inngest"; 3 | 4 | let app: Inngest | undefined; 5 | 6 | export const getInngestApp = () => { 7 | return (app ??= new Inngest({ 8 | id: typeof window !== "undefined" ? "client" : "server", 9 | middleware: [realtimeMiddleware()], 10 | })); 11 | }; 12 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | /* config options here */ 5 | }; 6 | 7 | export default nextConfig; 8 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "realtime-next", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev --turbopack", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@inngest/realtime": "0.3.1", 13 | "inngest": "^3.35.1", 14 | "next": "15.2.1", 15 | "react": "^19.0.0", 16 | "react-dom": "^19.0.0" 17 | }, 18 | "devDependencies": { 19 | "@eslint/eslintrc": "^3", 20 | "@tailwindcss/postcss": "^4", 21 | "@types/node": "^20", 22 | "@types/react": "^19", 23 | "@types/react-dom": "^19", 24 | "eslint": "^9", 25 | "eslint-config-next": "15.2.1", 26 | "tailwindcss": "^4", 27 | "typescript": "^5" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: ["@tailwindcss/postcss"], 3 | }; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/realtime/next-realtime-hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /examples/realtime/nodejs/realtime-across-multiple-channels/README.md: -------------------------------------------------------------------------------- 1 | # Realtime: stream updates from multiple function runs 2 | 3 | This demo Node.js project shows how to use [Realtime](https://www.inngest.com/docs/features/realtime) to stream updates from 4 | multiple Inngest Function runs by a mix of global and dynamics channels. 5 | 6 | ``` 7 | npm install 8 | ``` 9 | 10 | ``` 11 | npm run dev 12 | ``` 13 | 14 | The app will send periodic `app/post.like` events to the server, causing 15 | publishes and the subscriptions to fire. 16 | -------------------------------------------------------------------------------- /examples/realtime/nodejs/realtime-across-multiple-channels/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "realtime-simple", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "dev": "concurrently -c blue,green \"npm:dev:*\"", 8 | "dev:server": "npx inngest-cli@latest dev --sdk-url http://localhost:3000/api/inngest --retry-interval 1", 9 | "dev:app": "wait-port 8288 && tsx index.ts" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "description": "", 15 | "dependencies": { 16 | "@inngest/realtime": "0.3.1", 17 | "inngest": "^3.35.1", 18 | "zod": "^3.24.2" 19 | }, 20 | "devDependencies": { 21 | "@types/node": "^22.13.10", 22 | "concurrently": "^9.1.2", 23 | "tsx": "^4.19.3", 24 | "wait-port": "^1.1.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/realtime/nodejs/realtime-human-in-the-loop/README.md: -------------------------------------------------------------------------------- 1 | # Realtime: Implementing Human in the loop with `step.waitForEvent()` 2 | 3 | This demos showcases how to combine [Realtime](https://www.inngest.com/docs/features/realtime)'s `publish()` with `step.waitForEvent()` to 4 | enable users to interact with ongoing workflows. 5 | 6 | ``` 7 | npm install 8 | ``` 9 | 10 | ``` 11 | npm run dev 12 | ``` 13 | 14 | The app will send an event kicking off a workflow and prompt in the terminal to choose 15 | to stop or continue the workflow. 16 | -------------------------------------------------------------------------------- /examples/realtime/nodejs/realtime-human-in-the-loop/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "realtime-simple", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "dev": "concurrently -c blue,green \"npm:dev:*\"", 8 | "dev:server": "npx inngest-cli@latest dev --sdk-url http://localhost:3000/api/inngest --retry-interval 1", 9 | "dev:app": "wait-port 8288 && tsx index.ts" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "description": "", 15 | "dependencies": { 16 | "@inngest/realtime": "0.3.1", 17 | "inngest": "^3.35.1", 18 | "zod": "^3.24.2" 19 | }, 20 | "devDependencies": { 21 | "@types/node": "^22.13.10", 22 | "concurrently": "^9.1.2", 23 | "tsx": "^4.19.3", 24 | "wait-port": "^1.1.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/realtime/nodejs/realtime-single-run-subscription/README.md: -------------------------------------------------------------------------------- 1 | # Realtime: stream updates from a single function run 2 | 3 | This demo Node.js project shows how to [stream](https://www.inngest.com/docs/features/realtime) and subscribe to updates from a single Inngest Function run. 4 | 5 | ``` 6 | npm install 7 | ``` 8 | 9 | ``` 10 | npm run dev 11 | ``` 12 | 13 | The app will send 10 `app/process-upload` events while subscribing to a specific run using a `uuid`. 14 | -------------------------------------------------------------------------------- /examples/realtime/nodejs/realtime-single-run-subscription/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "realtime-simple", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "dev": "concurrently -c blue,green \"npm:dev:*\"", 8 | "dev:server": "npx inngest-cli@latest dev --sdk-url http://localhost:3000/api/inngest --retry-interval 1", 9 | "dev:app": "wait-port 8288 && tsx index.ts" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "description": "", 15 | "dependencies": { 16 | "@inngest/realtime": "0.3.1", 17 | "inngest": "^3.35.1", 18 | "zod": "^3.24.2" 19 | }, 20 | "devDependencies": { 21 | "@types/node": "^22.13.10", 22 | "concurrently": "^9.1.2", 23 | "tsx": "^4.19.3", 24 | "wait-port": "^1.1.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/step-ai/anthropic-claude-pdf-processing/.env.example: -------------------------------------------------------------------------------- 1 | ANTHROPIC_API_KEY=your_anthropic_api_key # Get one at https://console.anthropic.com/settings/keys -------------------------------------------------------------------------------- /examples/step-ai/anthropic-claude-pdf-processing/README.md: -------------------------------------------------------------------------------- 1 | # Anthropic Claude PDF Processing with `step.ai.infer()` 2 | 3 | ## Description 4 | 5 | This example demonstrates how to process a PDF document [using Anthropic Claude's capabilities](https://docs.anthropic.com/en/docs/build-with-claude/pdf-support) with `step.ai.infer()`. 6 | 7 | 8 | ## Installation 9 | 10 | 1. Clone the repository: 11 | ```bash 12 | git clone git@github.com:inngest/inngest-js.git 13 | ``` 14 | 2. Navigate to the project directory: 15 | ```bash 16 | cd examples/step-ai/anthropic-claude-pdf-processing 17 | ``` 18 | 3. Install the dependencies: 19 | ```bash 20 | npm install 21 | ``` 22 | 23 | ## Usage 24 | 25 | 1. Build the project: 26 | ```bash 27 | npm run build 28 | ``` 29 | 2. Start the server: 30 | ```bash 31 | GEMINI_API_KEY= npm start 32 | ``` 33 | 3. Ensure you have a `.env` file configured with the necessary environment variables. You can use `.env.example` as a template. 34 | -------------------------------------------------------------------------------- /examples/step-ai/anthropic-claude-pdf-processing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "anthropic-claude-pdf-processing", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "build": "tsc", 7 | "start": "node dist/index.js" 8 | }, 9 | "author": "", 10 | "dependencies": { 11 | "dotenv": "^16.4.7", 12 | "express": "^4.21.2", 13 | "inngest": "3.32.4" 14 | }, 15 | "license": "MIT", 16 | "description": "", 17 | "devDependencies": { 18 | "@types/express": "^5.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "preinstall": "npx only-allow pnpm", 4 | "release:all": "pnpm run build && pnpm run release:publish && pnpm run release:tag", 5 | "build": "pnpm run --if-present --recursive build", 6 | "release:version": "npx changeset version && pnpm run --if-present --recursive release:version", 7 | "release:publish": "pnpm run --if-present --recursive release", 8 | "release:tag": "node scripts/release/tag.js", 9 | "log": "pnpm run --if-present --recursive log" 10 | }, 11 | "devDependencies": { 12 | "@actions/core": "^1.10.0", 13 | "@actions/exec": "^1.1.1", 14 | "@actions/github": "^6.0.0", 15 | "@changesets/changelog-github": "^0.4.8", 16 | "@changesets/cli": "^2.26.2", 17 | "cross-env": "^7.0.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/ai/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | *.tgz 4 | -------------------------------------------------------------------------------- /packages/ai/README.md: -------------------------------------------------------------------------------- 1 | # @inngest/ai 2 | -------------------------------------------------------------------------------- /packages/ai/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import pluginJs from "@eslint/js"; 2 | import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"; 3 | import globals from "globals"; 4 | import tseslint from "typescript-eslint"; 5 | 6 | /** @type {import('eslint').Linter.Config[]} */ 7 | export default [ 8 | { files: ["**/*.{js,mjs,cjs,ts}"] }, 9 | { languageOptions: { globals: globals.browser } }, 10 | pluginJs.configs.recommended, 11 | ...tseslint.configs.recommended, 12 | eslintPluginPrettierRecommended, 13 | { 14 | rules: { 15 | "@typescript-eslint/no-namespace": "off", 16 | "@typescript-eslint/ban-types": "off", 17 | }, 18 | }, 19 | ]; 20 | -------------------------------------------------------------------------------- /packages/ai/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://jsr.io/schema/config-file.v1.json", 3 | "name": "@inngest/ai", 4 | "description": "", 5 | "version": "0.1.4", 6 | "include": [ 7 | "./src/**/*.ts" 8 | ], 9 | "exports": { 10 | ".": "./src/index.ts", 11 | "./models": "./src/models/index.ts", 12 | "./adapters": "./src/adapters/index.ts" 13 | } 14 | } -------------------------------------------------------------------------------- /packages/ai/src/adapters/grok.ts: -------------------------------------------------------------------------------- 1 | import { type AiAdapter } from "../adapter.js"; 2 | import { OpenAiAiAdapter } from "./openai.js"; 3 | 4 | // Grok is an exotic one, it is an OpenAI-compatible API, 5 | // but does not support strict mode Function Calling, requiring an adapter. 6 | export interface GrokAiAdapter extends AiAdapter { 7 | /** 8 | * Format of the IO for this model 9 | */ 10 | format: "grok"; 11 | 12 | "~types": { 13 | input: OpenAiAiAdapter["~types"]["input"]; 14 | output: OpenAiAiAdapter["~types"]["output"]; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /packages/ai/src/adapters/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./anthropic.js"; 2 | export * from "./gemini.js"; 3 | export * from "./openai.js"; 4 | export * from "./grok.js"; 5 | -------------------------------------------------------------------------------- /packages/ai/src/index.ts: -------------------------------------------------------------------------------- 1 | export type { AiAdapter, AiAdapters } from "./adapter.js"; 2 | export * from "./adapters/index.js"; 3 | export * from "./models/index.js"; 4 | export * as models from "./models/index.js"; 5 | -------------------------------------------------------------------------------- /packages/ai/src/models/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./anthropic.js"; 2 | export * from "./gemini.js"; 3 | export * from "./openai.js"; 4 | export * from "./deepseek.js"; 5 | export * from "./grok.js"; 6 | -------------------------------------------------------------------------------- /packages/eslint-plugin-internal/README.md: -------------------------------------------------------------------------------- 1 | A directory for custom ESLint rules specific to this repo. 2 | -------------------------------------------------------------------------------- /packages/eslint-plugin-internal/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | "process-warn": require("./process-warn"), 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/eslint-plugin-internal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@inngest/eslint-plugin-internal", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "index.js", 6 | "scripts": { 7 | "preinstall": "npx only-allow pnpm" 8 | }, 9 | "peerDependencies": { 10 | "eslint": "^8.23.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/eslint-plugin-internal/process-warn.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Adapted from `eslint-plugin-node`'s `no-process-env` rule. 3 | * 4 | * {@link https://github.com/mysticatea/eslint-plugin-node/blob/master/lib/rules/no-process-env.js} 5 | */ 6 | "use strict"; 7 | 8 | //------------------------------------------------------------------------------ 9 | // Rule Definition 10 | //------------------------------------------------------------------------------ 11 | 12 | module.exports = { 13 | meta: { 14 | type: "suggestion", 15 | docs: { 16 | description: "warn on use of `process.env`", 17 | }, 18 | fixable: null, 19 | schema: [], 20 | messages: { 21 | dangerousProcessUsage: 22 | "Ensure process is only used in non-shared locations", 23 | }, 24 | }, 25 | 26 | create(context) { 27 | return { 28 | MemberExpression(node) { 29 | const objectName = node.object.name; 30 | 31 | if (objectName === "process" && !node.computed) { 32 | context.report({ node, messageId: "dangerousProcessUsage" }); 33 | } 34 | }, 35 | }; 36 | }, 37 | }; 38 | -------------------------------------------------------------------------------- /packages/eslint-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /packages/eslint-plugin/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | testMatch: ["/src/**/*.test.ts"], 6 | roots: ["/src"], 7 | }; 8 | -------------------------------------------------------------------------------- /packages/eslint-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@inngest/eslint-plugin", 3 | "version": "0.0.7", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "publishConfig": { 7 | "registry": "https://registry.npmjs.org" 8 | }, 9 | "scripts": { 10 | "build": "tsc", 11 | "postversion": "pnpm run build", 12 | "test": "jest --silent --ci", 13 | "release": "node ../../scripts/release/publish.js", 14 | "log": "node ./test.js" 15 | }, 16 | "files": [ 17 | "dist" 18 | ], 19 | "keywords": [ 20 | "eslint", 21 | "eslintplugin", 22 | "inngest" 23 | ], 24 | "homepage": "https://github.com/inngest/inngest-js/tree/main/packages/eslint-plugin#readme", 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/inngest/inngest-js.git", 28 | "directory": "packages/eslint-plugin" 29 | }, 30 | "author": "Inngest Inc. ", 31 | "license": "ISC", 32 | "dependencies": { 33 | "@typescript-eslint/utils": "^6.11.0", 34 | "typescript": "~5.5.2" 35 | }, 36 | "devDependencies": { 37 | "@typescript-eslint/rule-tester": "^6.11.0", 38 | "eslint": "^8.0.0", 39 | "jest": "^29.3.1", 40 | "ts-jest": "^29.1.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/eslint-plugin/src/configs/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./recommended"; 2 | -------------------------------------------------------------------------------- /packages/eslint-plugin/src/configs/recommended.ts: -------------------------------------------------------------------------------- 1 | export const recommended = { 2 | rules: { 3 | "@inngest/await-inngest-send": "warn", 4 | "@inngest/no-nested-steps": "error", 5 | "@inngest/no-variable-mutation-in-step": "error", 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/eslint-plugin/src/index.ts: -------------------------------------------------------------------------------- 1 | export * as configs from "./configs"; 2 | export { rules } from "./rules"; 3 | -------------------------------------------------------------------------------- /packages/eslint-plugin/src/rules/await-inngest-send.test.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "@typescript-eslint/rule-tester"; 2 | import { awaitInngestSend } from "./await-inngest-send"; 3 | 4 | const ruleTester = new RuleTester({ 5 | parser: "@typescript-eslint/parser", 6 | }); 7 | 8 | ruleTester.run("my-rule", awaitInngestSend, { 9 | valid: [ 10 | 'await inngest.send({ name: "some.event" });', 11 | 'return inngest.send({ name: "some.event" });', 12 | 'void inngest.send({ name: "some.event" });', 13 | ], 14 | invalid: [ 15 | { 16 | code: 'inngest.send({ name: "some.event" });', 17 | errors: [{ messageId: "await-inngest-send" }], 18 | }, 19 | ], 20 | }); 21 | -------------------------------------------------------------------------------- /packages/eslint-plugin/src/rules/index.ts: -------------------------------------------------------------------------------- 1 | import { TSESLint } from "@typescript-eslint/utils"; 2 | import { awaitInngestSend } from "./await-inngest-send"; 3 | import { noNestedSteps } from "./no-nested-steps"; 4 | import { noVariableMutationInStep } from "./no-variable-mutation-in-step"; 5 | 6 | export const rules = { 7 | "await-inngest-send": awaitInngestSend, 8 | "no-nested-steps": noNestedSteps, 9 | "no-variable-mutation-in-step": noVariableMutationInStep, 10 | } satisfies Record>>; 11 | -------------------------------------------------------------------------------- /packages/inngest/.gitignore: -------------------------------------------------------------------------------- 1 | # Built files 2 | dist 3 | 4 | # Generated version file; always created pre-publish 5 | src/version.ts 6 | 7 | # Release-only files; tree must be clean on release, so these can't be modified 8 | .npmrc 9 | 10 | # Local dev files 11 | coverage/ 12 | inngest.tgz 13 | 14 | tsdoc-metadata.json 15 | -------------------------------------------------------------------------------- /packages/inngest/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | testMatch: ["/src/**/*.test.ts", "!**/test/functions/**/*.test.ts"], 6 | roots: ["/src"], 7 | moduleNameMapper: { 8 | "(\\..+)\\.js": "$1", 9 | "^inngest$": "/src", 10 | "^@local$": "/src", 11 | "^@local/(.*)": "/src/$1", 12 | "^@local/(.*)\\.js": "/src/$1", 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /packages/inngest/src/components/NonRetriableError.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * An error that, when thrown, indicates to Inngest that the function should 3 | * cease all execution and not retry. 4 | * 5 | * A `message` must be provided, and an optional `cause` can be provided to 6 | * provide more context to the error. 7 | * 8 | * @public 9 | */ 10 | export class NonRetriableError extends Error { 11 | /** 12 | * The underlying cause of the error, if any. 13 | * 14 | * This will be serialized and sent to Inngest. 15 | */ 16 | public readonly cause?: unknown; 17 | 18 | constructor( 19 | message: string, 20 | options?: { 21 | /** 22 | * The underlying cause of the error, if any. 23 | * 24 | * This will be serialized and sent to Inngest. 25 | */ 26 | cause?: unknown; 27 | } 28 | ) { 29 | super(message); 30 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 31 | this.cause = options?.cause; 32 | 33 | this.name = "NonRetriableError"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/inngest/src/components/StepError.ts: -------------------------------------------------------------------------------- 1 | import { deserializeError } from "../helpers/errors.js"; 2 | import { jsonErrorSchema } from "../types.js"; 3 | 4 | /** 5 | * An error that represents a step exhausting all retries and failing. This is 6 | * thrown by an Inngest step if it fails. 7 | * 8 | * It's synonymous with an `Error`, with the addition of the `stepId` that 9 | * failed. 10 | * 11 | * @public 12 | */ 13 | export class StepError extends Error { 14 | public cause?: unknown; 15 | 16 | constructor( 17 | /** 18 | * The ID of the step that failed. 19 | */ 20 | public readonly stepId: string, 21 | err: unknown 22 | ) { 23 | const parsedErr = jsonErrorSchema.parse(err); 24 | 25 | super(parsedErr.message); 26 | this.name = parsedErr.name; 27 | this.stepId = stepId; 28 | 29 | // Don't show the internal stack trace if we don't have one. 30 | this.stack = parsedErr.stack ?? undefined; 31 | 32 | // Try setting the cause if we have one 33 | this.cause = parsedErr.cause 34 | ? deserializeError(parsedErr.cause) 35 | : undefined; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/inngest/src/components/connect/messages.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ConnectMessage, 3 | GatewayExecutorRequestData, 4 | StartRequest, 5 | StartResponse, 6 | WorkerReplyAckData, 7 | } from "../../proto/src/components/connect/protobuf/connect.js"; 8 | 9 | export function createStartRequest(excludeGateways: string[]) { 10 | return StartRequest.encode( 11 | StartRequest.create({ 12 | excludeGateways, 13 | }) 14 | ).finish(); 15 | } 16 | 17 | export async function parseStartResponse(r: Response) { 18 | const startResp = StartResponse.decode(new Uint8Array(await r.arrayBuffer())); 19 | return startResp; 20 | } 21 | 22 | export function parseConnectMessage(r: Uint8Array) { 23 | const connectMessage = ConnectMessage.decode(r); 24 | return connectMessage; 25 | } 26 | 27 | export function parseGatewayExecutorRequest(r: Uint8Array) { 28 | const gatewayExecutorRequest = GatewayExecutorRequestData.decode(r); 29 | return gatewayExecutorRequest; 30 | } 31 | 32 | export function parseWorkerReplyAck(r: Uint8Array) { 33 | const workerReplyAck = WorkerReplyAckData.decode(r); 34 | return workerReplyAck; 35 | } 36 | -------------------------------------------------------------------------------- /packages/inngest/src/components/execution/otel/access.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A file used to access client processors safely without also importing any 3 | * otel-specific libraries. Useful for ensuring that the otel libraries can be 4 | * tree-shaken if they're not used directly by the user. 5 | */ 6 | 7 | import { type Inngest } from "../../Inngest.js"; 8 | import { type InngestSpanProcessor } from "./processor.js"; 9 | 10 | /** 11 | * A map of Inngest clients to their OTel span processors. This is used to 12 | * ensure that we only create one span processor per client, and that we can 13 | * access the span processor from the client without exposing the OTel 14 | * libraries to the user. 15 | */ 16 | export const clientProcessorMap = new WeakMap< 17 | Inngest.Any, 18 | InngestSpanProcessor 19 | >(); 20 | -------------------------------------------------------------------------------- /packages/inngest/src/components/execution/otel/consts.ts: -------------------------------------------------------------------------------- 1 | export const debugPrefix = "inngest:otel"; 2 | 3 | export enum TraceStateKey { 4 | AppId = "inngest@app", 5 | FunctionId = "inngest@fn", 6 | } 7 | 8 | export enum Attribute { 9 | InngestTraceparent = "inngest.traceparent", 10 | InngestRunId = "sdk.run.id", 11 | InngestAppId1 = "sdk.app.id", 12 | InngestAppId2 = "sys.app.id", 13 | InngestFunctionId = "sys.function.id", 14 | } 15 | -------------------------------------------------------------------------------- /packages/inngest/src/connect.ts: -------------------------------------------------------------------------------- 1 | export * from "./components/connect/index.js"; 2 | -------------------------------------------------------------------------------- /packages/inngest/src/experimental.ts: -------------------------------------------------------------------------------- 1 | // AsyncLocalStorage 2 | export { getAsyncCtx } from "./components/execution/als.js"; 3 | export type { AsyncContext } from "./components/execution/als.js"; 4 | 5 | // OpenTelemetry 6 | export { otelMiddleware } from "./components/execution/otel/middleware.js"; 7 | export type { OTelMiddlewareOptions } from "./components/execution/otel/middleware.js"; 8 | export { PublicInngestSpanProcessor as InngestSpanProcessor } from "./components/execution/otel/processor.js"; 9 | -------------------------------------------------------------------------------- /packages/inngest/src/express.test.ts: -------------------------------------------------------------------------------- 1 | import * as ExpressHandler from "@local/express"; 2 | import { type VercelRequest, type VercelRequestQuery } from "@vercel/node"; 3 | import { testFramework } from "./test/helpers"; 4 | 5 | testFramework("Express", ExpressHandler); 6 | 7 | testFramework("Express (Vercel)", ExpressHandler, { 8 | transformReq: (expressReq, res) => { 9 | const req: Partial = { 10 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 11 | body: expressReq.body, 12 | headers: expressReq.headers, 13 | query: expressReq.query as VercelRequestQuery, 14 | method: expressReq.method, 15 | url: expressReq.url, 16 | }; 17 | 18 | return [req, res]; 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /packages/inngest/src/fastify.test.ts: -------------------------------------------------------------------------------- 1 | import * as FastifyHandler from "@local/fastify"; 2 | import { fromAny } from "@total-typescript/shoehorn"; 3 | import { type Response } from "express"; 4 | import { type FastifyReply, type FastifyRequest } from "fastify"; 5 | import { testFramework } from "./test/helpers"; 6 | 7 | class MockFastifyReply { 8 | constructor(public res: Response) {} 9 | 10 | public header(key: string, value: string) { 11 | this.res.header(key, value); 12 | } 13 | 14 | public code(code: number) { 15 | this.res.statusCode = code; 16 | } 17 | 18 | public send(body: unknown) { 19 | this.res.send(body); 20 | } 21 | } 22 | 23 | testFramework("Fastify", FastifyHandler, { 24 | transformReq: (req, res): [req: FastifyRequest, reply: FastifyReply] => { 25 | return [fromAny(req), fromAny(new MockFastifyReply(res))]; 26 | }, 27 | }); 28 | -------------------------------------------------------------------------------- /packages/inngest/src/h3.test.ts: -------------------------------------------------------------------------------- 1 | import * as h3Handler from "@local/h3"; 2 | import { createEvent } from "h3"; 3 | import { testFramework } from "./test/helpers"; 4 | 5 | testFramework("h3", h3Handler, { 6 | transformReq(req, res) { 7 | return [createEvent(req, res)]; 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /packages/inngest/src/helpers/crypto.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Create a cryptographically secure random value. 3 | * 4 | * @throws {Error} If the crypto module is not available. 5 | */ 6 | export function createEntropy(byteLength: number): Uint8Array { 7 | const bytes = new Uint8Array(byteLength); 8 | 9 | // https://developer.mozilla.org/en-US/docs/Web/API/Crypto#browser_compatibility 10 | const { crypto } = globalThis; 11 | if (!crypto) { 12 | // This should only happen in Node <19. 13 | throw new Error("missing crypto module"); 14 | } 15 | if (!crypto.getRandomValues) { 16 | throw new Error("missing crypto.getRandomValues"); 17 | } 18 | 19 | crypto.getRandomValues(bytes); 20 | return bytes; 21 | } 22 | -------------------------------------------------------------------------------- /packages/inngest/src/helpers/enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns the value of an enum from a string value. 3 | * 4 | * If the value given is not a value from the enum, `undefined` is returned. 5 | */ 6 | export const enumFromValue = >( 7 | enumType: T, 8 | value: unknown 9 | ): T[keyof T] | undefined => { 10 | if (Object.values(enumType).includes(value)) { 11 | return value as T[keyof T]; 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /packages/inngest/src/helpers/validators/index.ts: -------------------------------------------------------------------------------- 1 | import { type IsUnknown } from "../types.js"; 2 | import type * as z from "./zod"; 3 | 4 | /** 5 | * Given an input value, infer the output type. 6 | * 7 | * This is a helper type to infer the output type of schemas, ensuring we can 8 | * support many validation libraries here without having to write custom 9 | * validators for each. 10 | * 11 | * @public 12 | */ 13 | export type ResolveSchema< 14 | TInput, 15 | TFallback = TInput, 16 | TUnknownFallback = TFallback, 17 | > = IsUnknown extends true 18 | ? TUnknownFallback 19 | : TInput extends z.ZodTypeAny 20 | ? z.infer 21 | : TFallback; 22 | 23 | /** 24 | * A valid input schema for an event's `data`. 25 | * 26 | * @public 27 | */ 28 | export type ValidSchemaInput = z.ValidZodValue; 29 | 30 | /** 31 | * A valid output schema. 32 | * 33 | * @public 34 | */ 35 | export type ValidSchemaOutput = z.ZodTypeAny; 36 | -------------------------------------------------------------------------------- /packages/inngest/src/koa.test.ts: -------------------------------------------------------------------------------- 1 | import * as KoaHandler from "@local/koa"; 2 | import { createMockContext } from "@shopify/jest-koa-mocks"; 3 | import { type Dictionary } from "@shopify/jest-koa-mocks/build/ts/create-mock-cookies"; 4 | import { type RequestMethod } from "node-mocks-http"; 5 | import { testFramework } from "./test/helpers"; 6 | 7 | testFramework("Koa", KoaHandler, { 8 | transformReq: (req, _res, _env) => { 9 | const ctx = createMockContext({ 10 | url: `https://${req.headers.host || req.hostname}${req.url}`, 11 | method: req.method as RequestMethod, 12 | statusCode: req.statusCode, 13 | headers: req.headers as Dictionary, 14 | host: req.hostname, 15 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment 16 | requestBody: req.body, 17 | }); 18 | 19 | return [ctx]; 20 | }, 21 | transformRes: (args) => { 22 | const ctx = args[0] as ReturnType; 23 | 24 | return Promise.resolve({ 25 | status: ctx.status, 26 | body: ctx.body as string, 27 | headers: ctx.response.headers as Record, 28 | }); 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /packages/inngest/src/lambda.test.ts: -------------------------------------------------------------------------------- 1 | import * as LambdaHandler from "@local/lambda"; 2 | import { type APIGatewayProxyResult } from "aws-lambda"; 3 | import { testFramework } from "./test/helpers"; 4 | 5 | testFramework("AWS Lambda", LambdaHandler, { 6 | transformReq: (req, _res, _env) => { 7 | return [ 8 | { 9 | path: req.path, 10 | // Intentionally make headers uppercase to ensure we test normalizing 11 | // them for mocked Lambda requests, which do not normalize. 12 | // See https://github.com/inngest/inngest-js/pull/937 13 | headers: Object.fromEntries( 14 | Object.entries(req.headers).map(([key, value]) => [ 15 | key.toUpperCase(), 16 | value, 17 | ]) 18 | ), 19 | httpMethod: req.method, 20 | queryStringParameters: req.query, 21 | body: 22 | typeof req.body === "string" ? req.body : JSON.stringify(req.body), 23 | }, 24 | {}, 25 | ]; 26 | }, 27 | 28 | transformRes: async (_args, retP: Promise) => { 29 | const ret = await retP; 30 | 31 | return { 32 | status: ret.statusCode, 33 | body: ret.body || "", 34 | headers: (ret.headers || {}) as Record, 35 | }; 36 | }, 37 | }); 38 | -------------------------------------------------------------------------------- /packages/inngest/src/middleware/dependencyInjection.test.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "@local/components/Inngest"; 2 | import { dependencyInjectionMiddleware } from "@local/middleware/dependencyInjection"; 3 | import { assertType } from "../test/helpers"; 4 | 5 | describe("Mutates ctx", () => { 6 | test("ctx is injected into the function input", () => { 7 | const inngest = new Inngest({ 8 | id: "test", 9 | middleware: [ 10 | dependencyInjectionMiddleware({ 11 | foo: "bar", 12 | }), 13 | ], 14 | }); 15 | 16 | inngest.createFunction({ id: "test" }, { event: "" }, (ctx) => { 17 | assertType(ctx.foo); 18 | }); 19 | }); 20 | 21 | test("can infer const ctx type", () => { 22 | const inngest = new Inngest({ 23 | id: "test", 24 | middleware: [ 25 | dependencyInjectionMiddleware({ 26 | foo: "bar", 27 | } as const), 28 | ], 29 | }); 30 | 31 | inngest.createFunction({ id: "test" }, { event: "" }, (ctx) => { 32 | assertType<"bar">(ctx.foo); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /packages/inngest/src/middleware/dependencyInjection.ts: -------------------------------------------------------------------------------- 1 | import { InngestMiddleware } from "../components/InngestMiddleware.js"; 2 | 3 | /** 4 | * Adds properties to the function input for every function created using this 5 | * app. 6 | */ 7 | // We can use `const` here yet due to TS constraints. 8 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 9 | export const dependencyInjectionMiddleware = >( 10 | /** 11 | * The context to inject into the function input. 12 | */ 13 | ctx: TCtx 14 | ) => { 15 | return new InngestMiddleware({ 16 | name: "Inngest: Dependency Injection", 17 | init() { 18 | return { 19 | onFunctionRun() { 20 | return { 21 | transformInput() { 22 | return { 23 | ctx, 24 | }; 25 | }, 26 | }; 27 | }, 28 | }; 29 | }, 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/inngest/src/next.test.ts: -------------------------------------------------------------------------------- 1 | import * as NextHandler from "@local/next"; 2 | import { testFramework } from "./test/helpers"; 3 | 4 | testFramework("Next", NextHandler); 5 | -------------------------------------------------------------------------------- /packages/inngest/src/nitro.test.ts: -------------------------------------------------------------------------------- 1 | import * as NitroHandler from "@local/nitro"; 2 | import { createEvent } from "h3"; 3 | import { testFramework } from "./test/helpers"; 4 | 5 | testFramework("Nitro", NitroHandler, { 6 | transformReq(req, res) { 7 | return [createEvent(req, res)]; 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /packages/inngest/src/nitro.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * An adapter for Nitro to serve and register any declared functions with 3 | * Inngest, making them available to be triggered by events. 4 | * 5 | * @module 6 | */ 7 | 8 | import { 9 | type InternalServeHandlerOptions, 10 | type ServeHandlerOptions, 11 | } from "./components/InngestCommHandler.js"; 12 | import { serve as serveH3 } from "./h3.js"; 13 | import { type SupportedFrameworkName } from "./types.js"; 14 | 15 | /** 16 | * The name of the framework, used to identify the framework in Inngest 17 | * dashboards and during testing. 18 | */ 19 | export const frameworkName: SupportedFrameworkName = "nitro"; 20 | 21 | /** 22 | * In Nitro, serve and register any declared functions with Inngest, making them 23 | * available to be triggered by events. 24 | * 25 | * @public 26 | */ 27 | // Has explicit return type to avoid JSR-defined "slow types" 28 | export const serve = ( 29 | options: ServeHandlerOptions 30 | ): ReturnType => { 31 | const optsOverrides: InternalServeHandlerOptions = { 32 | ...options, 33 | frameworkName, 34 | }; 35 | 36 | return serveH3(optsOverrides); 37 | }; 38 | -------------------------------------------------------------------------------- /packages/inngest/src/node.test.ts: -------------------------------------------------------------------------------- 1 | import http from "node:http"; 2 | import { Socket } from "node:net"; 3 | import { Buffer } from "node:buffer"; 4 | import * as NodeHandler from "@local/node"; 5 | import { testFramework } from "./test/helpers"; 6 | 7 | testFramework("Node", NodeHandler, { 8 | transformReq: (req, res) => { 9 | const socket = new Socket(); 10 | const nodeReq = new http.IncomingMessage(socket); 11 | 12 | // Set the method and URL 13 | nodeReq.method = req.method; 14 | nodeReq.url = req.url; 15 | 16 | if (req.protocol === "https") { 17 | nodeReq.headers["x-forwarded-proto"] = req.protocol; 18 | } 19 | 20 | // Set headers 21 | for (const [key, value] of Object.entries(req.headers)) { 22 | nodeReq.headers[key.toLowerCase()] = value; 23 | } 24 | 25 | // Mock the body data 26 | const bodyData = Buffer.from(JSON.stringify(req.body)); 27 | 28 | // Override the read methods to return the body data 29 | nodeReq.push(bodyData); 30 | nodeReq.push(null); // Signals the end of the stream 31 | 32 | return [nodeReq, res]; 33 | }, 34 | }); 35 | -------------------------------------------------------------------------------- /packages/inngest/src/nuxt.test.ts: -------------------------------------------------------------------------------- 1 | import * as NuxtHandler from "@local/nuxt"; 2 | import { createEvent } from "h3"; 3 | import { testFramework } from "./test/helpers"; 4 | 5 | testFramework("Nuxt", NuxtHandler, { 6 | transformReq(req, res) { 7 | return [createEvent(req, res)]; 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /packages/inngest/src/nuxt.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * An adapter for Nuxt to serve and register any declared functions with 3 | * Inngest, making them available to be triggered by events. 4 | * 5 | * @module 6 | */ 7 | 8 | import { 9 | type InternalServeHandlerOptions, 10 | type ServeHandlerOptions, 11 | } from "./components/InngestCommHandler.js"; 12 | import { serve as serveH3 } from "./h3.js"; 13 | import { type SupportedFrameworkName } from "./types.js"; 14 | 15 | /** 16 | * The name of the framework, used to identify the framework in Inngest 17 | * dashboards and during testing. 18 | */ 19 | export const frameworkName: SupportedFrameworkName = "nuxt"; 20 | 21 | /** 22 | * In Nuxt 3, serve and register any declared functions with Inngest, making 23 | * them available to be triggered by events. 24 | * 25 | * @public 26 | */ 27 | // Has explicit return type to avoid JSR-defined "slow types" 28 | export const serve = ( 29 | options: ServeHandlerOptions 30 | ): ReturnType => { 31 | const optsOverrides: InternalServeHandlerOptions = { 32 | ...options, 33 | frameworkName, 34 | }; 35 | 36 | return serveH3(optsOverrides); 37 | }; 38 | -------------------------------------------------------------------------------- /packages/inngest/src/redwood.test.ts: -------------------------------------------------------------------------------- 1 | import * as RedwoodHandler from "@local/redwood"; 2 | import { testFramework } from "./test/helpers"; 3 | 4 | testFramework("Redwood.js", RedwoodHandler, { 5 | transformReq: (req, _res, _env) => { 6 | return [ 7 | { 8 | path: req.path, 9 | headers: req.headers, 10 | httpMethod: req.method, 11 | queryStringParameters: req.query, 12 | body: 13 | typeof req.body === "string" ? req.body : JSON.stringify(req.body), 14 | }, 15 | {}, 16 | ]; 17 | }, 18 | 19 | // eslint-disable-next-line @typescript-eslint/require-await 20 | transformRes: async (_args, ret: RedwoodHandler.RedwoodResponse) => { 21 | return { 22 | status: ret.statusCode, 23 | body: ret.body || "", 24 | headers: ret.headers || {}, 25 | }; 26 | }, 27 | }); 28 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/README.md: -------------------------------------------------------------------------------- 1 | # Inngest SDK Examples 2 | 3 | This directory contains examples of how to use the Inngest SDK. 4 | 5 | They are copied to various example repos to test against when building releases. 6 | 7 | - [**Hello World**](/src/examples/hello-world) - The simplest function 8 | - [**Parallel reduce**](/src/examples/parallel-reduce) - Accumulate values using reduce in parallel 9 | - [**Parallel work**](/src/examples/parallel-work) - Run concurrent chains of work in the same function 10 | - [**Polling**](/src/examples/polling) - Poll an external API for a change, timing out after a given period 11 | - [**Promise.all**](/src/examples/promise-all) - Basic usage of `Promise.all` with step tooling 12 | - [**Promise.race**](/src/examples/promise-race) - Basic usage of `Promise.race` with step tooling 13 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/client.ts: -------------------------------------------------------------------------------- 1 | import { Inngest } from "inngest"; 2 | 3 | export const inngest = new Inngest({ 4 | id: "example-app", 5 | eventKey: "test-key-123", 6 | }); 7 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/handling-step-errors/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "handling-step-errors", retries: 1 }, 5 | { event: "demo/handling.step.errors" }, 6 | async ({ step }) => { 7 | try { 8 | await step.run("a", () => { 9 | throw new Error("Oh no!", { 10 | cause: new Error("This is the cause"), 11 | }); 12 | }); 13 | } catch (err) { 14 | await step.run("b", () => { 15 | return `err was: "${err.message}" and the cause was: "${err.cause.message}"`; 16 | }); 17 | } 18 | 19 | await Promise.all([ 20 | step.run("c succeeds", () => "c succeeds"), 21 | step 22 | .run("d fails", () => { 23 | throw new Error("D failed!"); 24 | }) 25 | .catch((err: Error) => { 26 | return step.run("e succeeds", () => { 27 | return { 28 | errMessage: err.message, 29 | }; 30 | }); 31 | }), 32 | ]); 33 | } 34 | ); 35 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/hello-world/README.md: -------------------------------------------------------------------------------- 1 | # Hello World Example 2 | 3 | This demonstrates the simplest possible function. It's triggered by a `demo/hello.world` event and returns `"Hello, Inngest!"`. 4 | 5 | ```mermaid 6 | graph TD 7 | Inngest -->|demo/hello.world| Function 8 | Function -->|Returns| Hello[Hello, Inngest!] 9 | ``` 10 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/hello-world/index.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unsafe-assignment */ 2 | import { 3 | checkIntrospection, 4 | eventRunWithName, 5 | runHasTimeline, 6 | sendEvent, 7 | } from "@local/test/helpers"; 8 | 9 | checkIntrospection({ 10 | name: "hello-world", 11 | triggers: [{ event: "demo/hello.world" }], 12 | }); 13 | 14 | describe("run", () => { 15 | let eventId: string; 16 | let runId: string; 17 | 18 | beforeAll(async () => { 19 | eventId = await sendEvent("demo/hello.world"); 20 | }); 21 | 22 | test("runs in response to 'demo/hello.world'", async () => { 23 | runId = await eventRunWithName(eventId, "hello-world"); 24 | expect(runId).toEqual(expect.any(String)); 25 | }, 60000); 26 | 27 | test("returns 'Hello, Inngest!'", async () => { 28 | const item = await runHasTimeline(runId, { 29 | type: "StepCompleted", 30 | stepName: "step", 31 | }); 32 | 33 | expect(item).toBeDefined(); 34 | 35 | const output = await item?.getOutput(); 36 | expect(output).toEqual("Hello, Inngest!"); 37 | }, 60000); 38 | }); 39 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/hello-world/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "hello-world" }, 5 | { event: "demo/hello.world" }, 6 | () => "Hello, Inngest!" 7 | ); 8 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/index.ts: -------------------------------------------------------------------------------- 1 | import handlingStepErrors from "./handling-step-errors"; 2 | import helloWorld from "./hello-world"; 3 | import multipleTriggers from "./multiple-triggers"; 4 | import parallelReduce from "./parallel-reduce"; 5 | import parallelWork from "./parallel-work"; 6 | import polling from "./polling"; 7 | import promiseAll from "./promise-all"; 8 | import promiseRace from "./promise-race"; 9 | import sendEvent from "./send-event"; 10 | import sequentialReduce from "./sequential-reduce"; 11 | import stepInvokeFunctions from "./step-invoke"; 12 | import stepInvokeNotFound from "./step-invoke-not-found"; 13 | import undefinedData from "./undefined-data"; 14 | import unhandledStepErrors from "./unhandled-step-errors"; 15 | 16 | export const functions = [ 17 | helloWorld, 18 | promiseAll, 19 | promiseRace, 20 | parallelWork, 21 | parallelReduce, 22 | sequentialReduce, 23 | polling, 24 | sendEvent, 25 | undefinedData, 26 | ...stepInvokeFunctions, 27 | stepInvokeNotFound, 28 | handlingStepErrors, 29 | unhandledStepErrors, 30 | multipleTriggers, 31 | ]; 32 | 33 | export { inngest } from "./client"; 34 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/multiple-triggers/index.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | checkIntrospection, 3 | eventRunWithName, 4 | runHasTimeline, 5 | sendEvent, 6 | } from "@local/test/helpers"; 7 | import { events } from "."; 8 | 9 | checkIntrospection({ 10 | name: "multiple-triggers", 11 | triggers: events.map((event) => ({ event })), 12 | }); 13 | 14 | describe("run", () => { 15 | events.forEach((eventName) => { 16 | let eventId: string; 17 | let runId: string; 18 | 19 | beforeAll(async () => { 20 | eventId = await sendEvent(eventName); 21 | }); 22 | 23 | test(`runs in response to '${eventName}'`, async () => { 24 | runId = await eventRunWithName(eventId, "multiple-triggers"); 25 | expect(runId).toEqual(expect.any(String)); 26 | }, 60000); 27 | 28 | test(`returns 'Hello, ${eventName}!'`, async () => { 29 | const item = await runHasTimeline(runId, { 30 | type: "StepCompleted", 31 | stepName: "step", 32 | }); 33 | 34 | expect(item).toBeDefined(); 35 | 36 | const output = await item?.getOutput(); 37 | expect(output).toEqual(`Hello, ${eventName}!`); 38 | }, 60000); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/multiple-triggers/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | export const events = ["demo/multiple-triggers.1", "demo/multiple-triggers.2"]; 4 | 5 | export default inngest.createFunction( 6 | { id: "multiple-triggers" }, 7 | events.map((event) => ({ event })), 8 | ({ event }) => `Hello, ${event.name}!` 9 | ); 10 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@inngest/example-functions", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@types/jest": "^27.4.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/parallel-reduce/README.md: -------------------------------------------------------------------------------- 1 | # Parallel Reduce Example 2 | 3 | This example demonstrates how to run multiple steps in parallel to accumulate a value using `Array.prototype.reduce`. 4 | 5 | It is triggered by a `demo/parallel.reduce` event, runs three steps in parallel to fetch scores from a database, and accumulates the total of all of the scores. 6 | 7 | ```mermaid 8 | graph TD 9 | Inngest -->|demo/parallel.reduce| Function 10 | Function -->|Run step| blue[Get blue team score] 11 | Function -->|Run step| red[Get red team score] 12 | Function -->|Run step| green[Get green team score] 13 | blue & red & green --> total[Accumulate score] 14 | total -->|Returns| done[150] 15 | ``` 16 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/parallel-reduce/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | const scoresDb: Record = { 4 | blue: 50, 5 | red: 25, 6 | green: 75, 7 | }; 8 | 9 | export default inngest.createFunction( 10 | { id: "parallel-reduce" }, 11 | { event: "demo/parallel.reduce" }, 12 | async ({ step }) => { 13 | const teams = Object.keys(scoresDb); 14 | 15 | // Fetch every team's score in parallel and add them up 16 | const totalScores = await teams.reduce(async (score, team) => { 17 | const teamScore = await step.run( 18 | `Get ${team} team score`, 19 | () => scoresDb[team] 20 | ); 21 | 22 | return (await score) + teamScore; 23 | }, Promise.resolve(0)); 24 | 25 | return totalScores; 26 | } 27 | ); 28 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/parallel-work/README.md: -------------------------------------------------------------------------------- 1 | # Parallel Work Example 2 | 3 | This example demonstrates how to run concurrent chains of work in the same step function, bringing their values together at the end. 4 | 5 | It is triggered by a `demo/parallel.work` event, runs 2 separate chains of work in parallel: `getScore()` and `getFruits()`. 6 | 7 | `getScore()` will run 3 steps sequentially, returning a `number` score. 8 | 9 | `getFruits()` will run 3 steps in parallel, returning an array of fruits. 10 | 11 | Finally, we return the result of these two chains of work at the end of the function. 12 | 13 | ```mermaid 14 | graph TD 15 | Inngest -->|demo/parallel.work| Function 16 | 17 | subgraph getScore["getScore (sequential)"] 18 | score1[First score] 19 | score1 -->|Run step| score2[Second score] 20 | score2 -->|Run step| score3[Third score] 21 | end 22 | 23 | subgraph getFruits["getFruits (parallel)"] 24 | apple[Get apple] 25 | banana[Get banana] 26 | orange[Get orange] 27 | end 28 | 29 | Function -->|Run steps| getScore & getFruits 30 | 31 | getFruits ----> ret[Accumulate results] 32 | score3 --> ret 33 | ret -->|Returns| done["[ 6, 'Apple, Banana, Orange' ]"] 34 | ``` 35 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/parallel-work/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "parallel-work" }, 5 | { event: "demo/parallel.work" }, 6 | async ({ step }) => { 7 | // Run some steps in sequence to add up scores 8 | const getScore = async () => { 9 | let score = await step.run("First score", () => 1); 10 | score += await step.run("Second score", () => 2); 11 | score += await step.run("Third score", () => 3); 12 | 13 | return score; 14 | }; 15 | 16 | // Retrieve some fruits in parallel and return them as an array 17 | const getFruits = async () => { 18 | return Promise.all([ 19 | step.run("Get apple", () => "Apple"), 20 | step.run("Get banana", () => "Banana"), 21 | step.run("Get orange", () => "Orange"), 22 | ]); 23 | }; 24 | 25 | // Run both of the above functions in parallel and return the results 26 | return Promise.all([ 27 | getScore(), 28 | getFruits().then((fruits) => fruits.join(", ")), 29 | ]); 30 | } 31 | ); 32 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/polling/README.md: -------------------------------------------------------------------------------- 1 | # Parallel Work Example 2 | 3 | This example demonstrates how to run concurrent chains of work in the same step function to create a step that polls on a schedule, either returning a result or timing out. 4 | 5 | It is triggered by a `demo/polling` event, and runs 2 separate chains of work in parallel: one for the timeout, and one for the poll. We declare this logic as a `poll()` function within the body of the step function. 6 | 7 | ```mermaid 8 | graph TD 9 | Inngest -->|demo/polling| Function 10 | 11 | subgraph poll 12 | timeout[["step.sleep('30s')"]] 13 | timeout ------>|30s up|timeoutDone[Set timedOut=true] 14 | api[["step.run('Check if external job complete')"]] 15 | api --> check{Job returned data?} 16 | check -->|No| timeoutCheck{timedOut==true?} 17 | timeoutCheck -->|No| iterate["step.sleep('10s')"] 18 | iterate -->|10s up|timeoutCheck2{timedOut==true?} 19 | timeoutCheck2 -->|No|api 20 | end 21 | 22 | Function -->|Runs| poll 23 | 24 | timeoutCheck2 --->|Yes|noJob[jobData = null] 25 | check ------>|Yes| yesJob["jobData = {...}"] 26 | timeoutCheck -->|Yes|noJob 27 | 28 | yesJob -->|Runs|doData["step.run('Do something with data')"] 29 | doData & noJob --> finish([End]) 30 | ``` 31 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/polling/index.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unsafe-assignment */ 2 | import { checkIntrospection } from "@local/test/helpers"; 3 | 4 | checkIntrospection({ 5 | name: "polling", 6 | triggers: [{ event: "demo/polling" }], 7 | }); 8 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/polling/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "polling" }, 5 | { event: "demo/polling" }, 6 | async ({ step }) => { 7 | const poll = async () => { 8 | let timedOut = false; 9 | void step.sleep("polling-time-out", "30s").then(() => (timedOut = true)); 10 | let interval = 0; 11 | 12 | do { 13 | const jobData = await step.run("Check if external job complete", () => { 14 | const jobComplete = Math.random() > 0.5; 15 | 16 | if (jobComplete) { 17 | return { data: { foo: "bar" } }; 18 | } 19 | 20 | return null; 21 | }); 22 | 23 | if (jobData !== null) { 24 | return jobData; 25 | } 26 | 27 | await step.sleep(`interval-${interval++}`, "10s"); 28 | } while (!timedOut); 29 | 30 | return null; 31 | }; 32 | 33 | const jobData = await poll(); 34 | 35 | if (jobData) { 36 | await step.run("Do something with data", () => { 37 | console.log(jobData); 38 | }); 39 | } 40 | } 41 | ); 42 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/promise-all/README.md: -------------------------------------------------------------------------------- 1 | # Promise.all Example 2 | 3 | This example demonstrates using `Promise.all()` to wait for concurrent chains of work to resolve before continuing; all step tooling returns a promise, so any pattern using async JavaScript is supported. 4 | 5 | It is triggered by a `demo/promise.all` event, and runs 2 separate steps in parallel. Once both are complete, Step 3 runs and adds the result of both. 6 | 7 | ```mermaid 8 | graph TD 9 | Inngest -->|demo/promise.all| Function 10 | 11 | Function --> step1["steps.run('Step 1')"] 12 | Function --> step2["steps.run('Step 2')"] 13 | step1 & step2 --> step3["steps.run('Step 3')"] 14 | step3 --> ret["3"] 15 | ``` 16 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/promise-all/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "promise-all" }, 5 | { event: "demo/promise.all" }, 6 | async ({ step }) => { 7 | const [one, two] = await Promise.all([ 8 | step.run("Step 1", () => 1), 9 | step.run("Step 2", () => 2), 10 | ]); 11 | 12 | return step.run("Step 3", () => one + two); 13 | } 14 | ); 15 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/promise-race/README.md: -------------------------------------------------------------------------------- 1 | # Promise.race Example 2 | 3 | This example demonstrates using `Promise.race()` to race concurrent chains of work against each other before continuing; all step tooling returns a promise, so any pattern using async JavaScript is supported. 4 | 5 | It is triggered by a `demo/promise.race` event, and runs 2 separate steps in parallel. The first one to complete wins, and the final step logs the winner. 6 | 7 | ```mermaid 8 | graph TD 9 | Inngest -->|demo/promise.race| Function 10 | 11 | Function --> step1["steps.run('Step A')"] 12 | Function --> step2["steps.run('Step B')"] 13 | step1 -->|A wins| step3["steps.run('Step C')"] 14 | step2 -->|B wins| step3 15 | step3 --> ret["'A is the winner!'
or
'B is the winner!'"] 16 | ``` 17 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/promise-race/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "promise-race" }, 5 | { event: "demo/promise.race" }, 6 | async ({ step }) => { 7 | const winner = await Promise.race([ 8 | step.run("Step A", () => "A"), 9 | step.run("Step B", () => "B"), 10 | ]); 11 | 12 | await step.run("Step C", () => `${winner} is the winner!`); 13 | } 14 | ); 15 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/send-event/README.md: -------------------------------------------------------------------------------- 1 | # Sending an Event Example 2 | 3 | This examples demonstrates sending an event within a step function. 4 | 5 | It is triggered by a `demo/send.event` event, and runs a single step to reliably send an event to Inngest. 6 | 7 | ```mermaid 8 | graph TD 9 | Inngest -->|demo/send.event| Function 10 | Function --> step1["step.sendEvent('app/my.event.happened')"] 11 | step1 --> ret[Complete] 12 | ``` 13 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/send-event/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "send-event" }, 5 | { event: "demo/send.event" }, 6 | async ({ step }) => { 7 | await Promise.all([ 8 | // Send a single event 9 | step.sendEvent("single-event", { 10 | name: "app/my.event.happened", 11 | data: { foo: "bar" }, 12 | }), 13 | 14 | // Send multiple events 15 | step.sendEvent("multiple-events", [ 16 | { 17 | name: "app/my.event.happened.multiple.1", 18 | data: { foo: "bar" }, 19 | }, 20 | { 21 | name: "app/my.event.happened.multiple.2", 22 | data: { foo: "bar" }, 23 | }, 24 | ]), 25 | ]); 26 | } 27 | ); 28 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/sequential-reduce/README.md: -------------------------------------------------------------------------------- 1 | # Sequential Reduce Example 2 | 3 | This example demonstrates how to run multiple steps in sequence to accumulate a value using `Array.prototype.reduce`. 4 | 5 | It is triggered by a `demo/sequential.reduce` event, runs three steps sequentially to fetch scores from a database, and accumulates the total of all of the scores. 6 | 7 | To see a parallel version of this pattern, see the [parallel reduce example](/src/examples/parallel-reduce). 8 | 9 | ```mermaid 10 | graph TD 11 | Inngest -->|demo/sequential.reduce| Function 12 | Function -->|Run step| blue[Get blue team score] 13 | blue -->|Run step| red[Get red team score] 14 | red -->|Run step| green[Get green team score] 15 | green --> total[Accumulate score] 16 | total -->|Returns| done[150] 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/sequential-reduce/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | const scoresDb: Record = { 4 | blue: 50, 5 | red: 25, 6 | green: 75, 7 | }; 8 | 9 | export default inngest.createFunction( 10 | { id: "sequential-reduce" }, 11 | { event: "demo/sequential.reduce" }, 12 | async ({ step }) => { 13 | const teams = Object.keys(scoresDb); 14 | 15 | // Fetch every team's score sequentially and add them up 16 | const totalScores = await teams.reduce(async (score, team) => { 17 | const currentScore = await score; 18 | 19 | const teamScore = await step.run( 20 | `Get ${team} team score`, 21 | () => scoresDb[team] 22 | ); 23 | 24 | return currentScore + teamScore; 25 | }, Promise.resolve(0)); 26 | 27 | return totalScores; 28 | } 29 | ); 30 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/step-invoke-not-found/index.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unsafe-member-access */ 2 | /* eslint-disable @typescript-eslint/no-unsafe-assignment */ 3 | import { 4 | checkIntrospection, 5 | eventRunWithName, 6 | runHasTimeline, 7 | sendEvent, 8 | } from "@local/test/helpers"; 9 | 10 | checkIntrospection({ 11 | name: "step-invoke-not-found", 12 | triggers: [{ event: "demo/step.invoke.not-found" }], 13 | }); 14 | 15 | describe("run", () => { 16 | let eventId: string; 17 | let runId: string; 18 | 19 | beforeAll(async () => { 20 | eventId = await sendEvent("demo/step.invoke.not-found"); 21 | }); 22 | 23 | test("runs in response to 'demo/step.invoke.not-found'", async () => { 24 | runId = await eventRunWithName(eventId, "step-invoke-not-found"); 25 | expect(runId).toEqual(expect.any(String)); 26 | }, 20000); 27 | 28 | test("ran 'invoke-non-existent-fn' step", async () => { 29 | const item = await runHasTimeline(runId, { 30 | type: "StepFailed", 31 | stepName: "step", 32 | }); 33 | expect(item).toBeDefined(); 34 | 35 | const output = await item?.getOutput(); 36 | expect(output?.name).toEqual("Error"); 37 | expect(output?.message).toContain("could not find function"); 38 | }, 20000); 39 | }); 40 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/step-invoke-not-found/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "step-invoke-not-found" }, 5 | { event: "demo/step.invoke.not-found" }, 6 | async ({ step }) => { 7 | await step.invoke("invoke-non-existent-fn", { 8 | function: "non-existant-fn", 9 | }); 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/step-invoke/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | const cronInvokeFn = inngest.createFunction( 4 | { id: "step-invoke-cron" }, 5 | { cron: "59 23 31 12 *" }, 6 | async ({ step }) => { 7 | await step.sleep("wait-a-moment", "1s"); 8 | 9 | return { 10 | cronInvokeDone: true, 11 | }; 12 | } 13 | ); 14 | 15 | const eventInvokeFn = inngest.createFunction( 16 | { id: "step-invoke-event" }, 17 | { event: "demo/step.invoke.other" }, 18 | async ({ step }) => { 19 | await step.sleep("wait-a-moment", "1s"); 20 | 21 | return { 22 | eventInvokeDone: true, 23 | }; 24 | } 25 | ); 26 | 27 | const mainFn = inngest.createFunction( 28 | { id: "step-invoke" }, 29 | { event: "demo/step.invoke" }, 30 | async ({ step }) => { 31 | return Promise.all([ 32 | step.invoke("event-fn", { function: eventInvokeFn }), 33 | step.invoke("cron-fn", { function: cronInvokeFn }), 34 | ]); 35 | } 36 | ); 37 | 38 | export default [mainFn, eventInvokeFn, cronInvokeFn]; 39 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "inngest": ["../../../dist"], 5 | "@local/*": ["../../*"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/undefined-data/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "undefined-data" }, 5 | { event: "demo/undefined.data" }, 6 | async ({ step }) => { 7 | await step.run("step1res", () => "step1res"); 8 | 9 | await step.run("step1", () => { 10 | // no-op 11 | }); 12 | 13 | await Promise.all([ 14 | step.run("step2res", () => "step2res"), 15 | step.run("step2nores", () => { 16 | // no-op 17 | }), 18 | step.run("step2res2", () => "step2res2"), 19 | ]); 20 | 21 | await step.run("step2", async () => { 22 | // no-op 23 | }); 24 | 25 | await step.run("step3", async () => { 26 | // no-op 27 | }); 28 | } 29 | ); 30 | -------------------------------------------------------------------------------- /packages/inngest/src/test/functions/unhandled-step-errors/index.ts: -------------------------------------------------------------------------------- 1 | import { inngest } from "../client"; 2 | 3 | export default inngest.createFunction( 4 | { id: "unhandled-step-errors", retries: 1 }, 5 | { event: "demo/unhandled.step.errors" }, 6 | async ({ step }) => { 7 | await step.run("a fails", () => { 8 | throw new Error("A failed!"); 9 | }); 10 | 11 | await step.run("b never runs", () => "b"); 12 | } 13 | ); 14 | -------------------------------------------------------------------------------- /packages/inngest/test/benchmark/execution/index.ts: -------------------------------------------------------------------------------- 1 | import { group } from "mitata"; 2 | import { loadBenchmarks } from "../util"; 3 | 4 | // Give me Bun 5 | export const register = async () => { 6 | const benchmarks = await loadBenchmarks(["memoized-steps"]); 7 | 8 | group("execution", () => { 9 | benchmarks.register(); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/inngest/test/benchmark/execution/memoized-steps.ts: -------------------------------------------------------------------------------- 1 | import { createExecutionWithMemoizedSteps } from "./util"; 2 | 3 | const stepCounts = [0, 1, 10, 100, 500, 1000, 2000, 5000, 10000]; 4 | 5 | export default stepCounts.reduce((acc, stepCount) => { 6 | const { run } = createExecutionWithMemoizedSteps({ stepCount }); 7 | 8 | return { 9 | ...acc, 10 | [stepCount]: run, 11 | }; 12 | }, {}); 13 | -------------------------------------------------------------------------------- /packages/inngest/test/benchmark/main.ts: -------------------------------------------------------------------------------- 1 | import { run } from "mitata"; 2 | import { register } from "./execution"; 3 | 4 | register().then(() => { 5 | return run(); 6 | }); 7 | -------------------------------------------------------------------------------- /packages/inngest/test/composite_project/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | tsconfig.tsbuildinfo 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /packages/inngest/test/composite_project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "t_composite_test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "tsc --build --force" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "typescript": "^5.3.3" 14 | }, 15 | "dependencies": { 16 | "inngest": "file:../../inngest.tgz" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/inngest/test/composite_project/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "target": "es5", 5 | "forceConsistentCasingInFileNames": true, 6 | "composite": true, 7 | "lib": ["dom", "dom.iterable", "esnext"], 8 | "allowJs": true, 9 | "skipLibCheck": false, 10 | "strict": true, 11 | "noEmit": false, 12 | "outDir": "dist", 13 | "esModuleInterop": true, 14 | "module": "esnext", 15 | "moduleResolution": "bundler", 16 | "resolveJsonModule": true, 17 | "isolatedModules": true, 18 | "jsx": "preserve", 19 | "incremental": true, 20 | "typeRoots": ["./types"], 21 | "plugins": [ 22 | { 23 | "name": "next", 24 | }, 25 | ], 26 | "paths": { 27 | "~/*": ["./src/*"], 28 | }, 29 | }, 30 | "include": [ 31 | "next-env.d.ts", 32 | "src/**/*.ts", 33 | "**/*.tsx", 34 | ".next/types/**/*.ts", 35 | ], 36 | "exclude": ["node_modules"], 37 | } 38 | -------------------------------------------------------------------------------- /packages/inngest/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": [ 4 | "src/**/*.spec.ts", 5 | "src/**/*.test.ts", 6 | "src/test/**/*", 7 | "scripts/**/*" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /packages/inngest/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["./**/*.test.ts"], 4 | "exclude": ["src/test/functions/**/*"], 5 | "compilerOptions": { 6 | "paths": { 7 | "@local": ["./dist"], 8 | "@local/*": ["./dist/*"] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/middleware-encryption/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /packages/middleware-encryption/eslint.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import eslint from "@eslint/js"; 4 | import tseslint from "typescript-eslint"; 5 | 6 | export default tseslint.config( 7 | eslint.configs.recommended, 8 | ...tseslint.configs.recommended 9 | ); 10 | -------------------------------------------------------------------------------- /packages/middleware-encryption/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} **/ 2 | module.exports = { 3 | testEnvironment: "node", 4 | transform: { 5 | "^.+.tsx?$": ["ts-jest", {}], 6 | }, 7 | roots: ["/src"], 8 | }; 9 | -------------------------------------------------------------------------------- /packages/middleware-encryption/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://jsr.io/schema/config-file.v1.json", 3 | "name": "@inngest/middleware-encryption", 4 | "description": "E2E encryption middleware for Inngest.", 5 | "version": "1.0.1", 6 | "include": [ 7 | "./src/**/*.ts" 8 | ], 9 | "exclude": [], 10 | "exports": { 11 | ".": "./src/index.ts", 12 | "./manual": "./src/manual.ts", 13 | "./strategies/aes": "./src/strategies/aes.ts", 14 | "./strategies/libsodium": "./src/strategies/libSodium.ts" 15 | } 16 | } -------------------------------------------------------------------------------- /packages/middleware-encryption/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./middleware"; 2 | -------------------------------------------------------------------------------- /packages/middleware-encryption/src/manual.ts: -------------------------------------------------------------------------------- 1 | import { InngestMiddleware, type MiddlewareOptions } from "inngest"; 2 | import { type EncryptionMiddlewareOptions } from "./middleware"; 3 | import { 4 | getEncryptionStages, 5 | } from "./stages"; 6 | 7 | /** 8 | * Encrypts and decrypts data sent to and from Inngest. 9 | * 10 | * Returns two separate middlewares: one for encrypting data, and one for 11 | * decrypting data, used in special circumstances pre-v4. 12 | */ 13 | export const manualEncryptionMiddleware = ( 14 | /** 15 | * Options used to configure the encryption middleware. If a custom 16 | * `encryptionService` is not provided, the `key` option is required. 17 | */ 18 | opts: EncryptionMiddlewareOptions 19 | ): { 20 | encryptionMiddleware: InngestMiddleware; 21 | decryptionMiddleware: InngestMiddleware; 22 | } => { 23 | const { encrypt, decrypt } = getEncryptionStages(opts); 24 | 25 | return { 26 | encryptionMiddleware: new InngestMiddleware({ 27 | name: "@inngest/middleware-encryption/manual/encrypt", 28 | init: () => encrypt, 29 | }), 30 | 31 | decryptionMiddleware: new InngestMiddleware({ 32 | name: "@inngest/middleware-encryption/manual/decrypt", 33 | init: () => decrypt, 34 | }), 35 | }; 36 | }; 37 | -------------------------------------------------------------------------------- /packages/middleware-encryption/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/middleware-encryption/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "commonjs", 5 | "rootDir": "./src", 6 | "declaration": true, 7 | "outDir": "./dist", 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "strict": true, 11 | "skipLibCheck": true 12 | }, 13 | "include": ["./src/**/*"] 14 | } 15 | -------------------------------------------------------------------------------- /packages/middleware-sentry/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /packages/middleware-sentry/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @inngest/middleware-sentry 2 | 3 | ## 0.1.2 4 | 5 | ### Patch Changes 6 | 7 | - [#810](https://github.com/inngest/inngest-js/pull/810) [`47b08dd`](https://github.com/inngest/inngest-js/commit/47b08dd8e5d1a47c28be528e8df9f44244578ac8) Thanks [@djfarrelly](https://github.com/djfarrelly)! - Updated to use Sentry's withIsolationScope 8 | 9 | ## 0.1.1 10 | 11 | ### Patch Changes 12 | 13 | - [#673](https://github.com/inngest/inngest-js/pull/673) [`42f0e71`](https://github.com/inngest/inngest-js/commit/42f0e71e55186941378159e57c752c177bf79b42) Thanks [@mattddean](https://github.com/mattddean)! - Add event ID as a Sentry tag 14 | 15 | - [#672](https://github.com/inngest/inngest-js/pull/672) [`b637d3a`](https://github.com/inngest/inngest-js/commit/b637d3a5cee9bd4792912185077ab9184ba6d364) Thanks [@mattddean](https://github.com/mattddean)! - Set sentry transaction name according to Inngest function 16 | 17 | ## 0.1.0 18 | 19 | ### Minor Changes 20 | 21 | - [#598](https://github.com/inngest/inngest-js/pull/598) [`cb4fdfd`](https://github.com/inngest/inngest-js/commit/cb4fdfdcd39b5051b87e736d3c18948dec9c2b30) Thanks [@jpwilliams](https://github.com/jpwilliams)! - Initial release! 22 | -------------------------------------------------------------------------------- /packages/middleware-sentry/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import pluginJs from "@eslint/js"; 2 | import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"; 3 | import globals from "globals"; 4 | import tseslint from "typescript-eslint"; 5 | 6 | /** @type {import('eslint').Linter.Config[]} */ 7 | export default [ 8 | { files: ["**/src/*.{js,mjs,cjs,ts}"] }, 9 | { languageOptions: { globals: globals.browser } }, 10 | { ignores: ["**/node_modules/**", "**/dist/**"] }, 11 | pluginJs.configs.recommended, 12 | ...tseslint.configs.recommended, 13 | eslintPluginPrettierRecommended, 14 | ]; 15 | -------------------------------------------------------------------------------- /packages/middleware-sentry/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://jsr.io/schema/config-file.v1.json", 3 | "name": "@inngest/middleware-sentry", 4 | "description": "Sentry middleware for Inngest.", 5 | "version": "0.1.2", 6 | "include": [ 7 | "./src/**/*.ts" 8 | ], 9 | "exclude": [], 10 | "exports": { 11 | ".": "./src/index.ts" 12 | } 13 | } -------------------------------------------------------------------------------- /packages/middleware-sentry/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./middleware"; 2 | -------------------------------------------------------------------------------- /packages/middleware-validation/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /packages/middleware-validation/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @inngest/middleware-validation 2 | 3 | ## 0.0.2 4 | 5 | ### Patch Changes 6 | 7 | - [#953](https://github.com/inngest/inngest-js/pull/953) [`6ac90b5`](https://github.com/inngest/inngest-js/commit/6ac90b5680c8f4f7dbe9fcdc3c6fda3a5d4e284c) Thanks [@jpwilliams](https://github.com/jpwilliams)! - Fix possibility of silently failing when multiple versions of Zod are installed 8 | 9 | - Updated dependencies [[`a641cc2`](https://github.com/inngest/inngest-js/commit/a641cc219846a2c6ef66ad62fb371725555e7caa)]: 10 | - inngest@3.35.0 11 | 12 | ## 0.0.1 13 | 14 | ### Patch Changes 15 | 16 | - [#744](https://github.com/inngest/inngest-js/pull/744) [`0c2bb8e`](https://github.com/inngest/inngest-js/commit/0c2bb8e048f39500e25ed0b521db210bbc4a757d) Thanks [@jpwilliams](https://github.com/jpwilliams)! - Initial release of `@inngest/middleware-validation` 17 | 18 | - Updated dependencies [[`255416c`](https://github.com/inngest/inngest-js/commit/255416c4478ac367381da0c166b6762056d94e1d), [`efc6c79`](https://github.com/inngest/inngest-js/commit/efc6c79d5a1baf7a011396b8406aea4982f03778)]: 19 | - inngest@3.27.0 20 | -------------------------------------------------------------------------------- /packages/middleware-validation/eslint.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import eslint from "@eslint/js"; 4 | import tseslint from "typescript-eslint"; 5 | 6 | export default tseslint.config( 7 | eslint.configs.recommended, 8 | ...tseslint.configs.recommended 9 | ); 10 | -------------------------------------------------------------------------------- /packages/middleware-validation/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} **/ 2 | module.exports = { 3 | testEnvironment: "node", 4 | transform: { 5 | "^.+.tsx?$": ["ts-jest", {}], 6 | }, 7 | roots: ["/src"], 8 | }; 9 | -------------------------------------------------------------------------------- /packages/middleware-validation/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://jsr.io/schema/config-file.v1.json", 3 | "name": "@inngest/middleware-validation", 4 | "description": "Schema validation middleware for Inngest.", 5 | "version": "0.0.2", 6 | "include": [ 7 | "./src/**/*.ts" 8 | ], 9 | "exclude": [ 10 | "**/*.test.*", 11 | "*.js", 12 | "**/tsconfig.*" 13 | ], 14 | "exports": { 15 | ".": "./src/index.ts" 16 | } 17 | } -------------------------------------------------------------------------------- /packages/middleware-validation/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./middleware"; 2 | -------------------------------------------------------------------------------- /packages/middleware-validation/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/middleware-validation/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2016", 4 | "module": "commonjs", 5 | "rootDir": "./src", 6 | "declaration": true, 7 | "outDir": "./dist", 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "strict": true, 11 | "skipLibCheck": true 12 | }, 13 | "include": ["./src/**/*"] 14 | } 15 | -------------------------------------------------------------------------------- /packages/realtime/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | *.tgz 4 | -------------------------------------------------------------------------------- /packages/realtime/README.md: -------------------------------------------------------------------------------- 1 | # @inngest/realtime 2 | -------------------------------------------------------------------------------- /packages/realtime/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import pluginJs from "@eslint/js"; 2 | import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"; 3 | import globals from "globals"; 4 | import tseslint from "typescript-eslint"; 5 | 6 | /** @type {import('eslint').Linter.Config[]} */ 7 | export default [ 8 | { files: ["**/*.{js,mjs,cjs,ts}"] }, 9 | { languageOptions: { globals: globals.browser } }, 10 | pluginJs.configs.recommended, 11 | ...tseslint.configs.recommended, 12 | eslintPluginPrettierRecommended, 13 | { 14 | rules: { 15 | "@typescript-eslint/no-namespace": "off", 16 | "@typescript-eslint/ban-types": "off", 17 | }, 18 | }, 19 | ]; 20 | -------------------------------------------------------------------------------- /packages/realtime/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} **/ 2 | module.exports = { 3 | testEnvironment: "node", 4 | transform: { 5 | "^.+.tsx?$": ["ts-jest", {}], 6 | }, 7 | roots: ["/src"], 8 | }; 9 | -------------------------------------------------------------------------------- /packages/realtime/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://jsr.io/schema/config-file.v1.json", 3 | "name": "@inngest/realtime", 4 | "description": "", 5 | "version": "0.3.1", 6 | "include": [ 7 | "./src/**/*.ts" 8 | ], 9 | "exports": { 10 | ".": "./src/index.ts", 11 | "./hooks": "./src/hooks.ts" 12 | } 13 | } -------------------------------------------------------------------------------- /packages/realtime/src/env.d.ts: -------------------------------------------------------------------------------- 1 | // For Vite 2 | interface ImportMeta { 3 | env: { 4 | INNGEST_DEV?: string; 5 | VITE_INNGEST_DEV?: string; 6 | MODE: "development" | "production"; 7 | VITE_MODE: "development" | "production"; 8 | INNGEST_BASE_URL?: string; 9 | VITE_INNGEST_BASE_URL?: string; 10 | INNGEST_API_BASE_URL?: string; 11 | VITE_INNGEST_API_BASE_URL?: string; 12 | INNGEST_SIGNING_KEY?: string; 13 | INNGEST_SIGNING_KEY_FALLBACK?: string; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /packages/realtime/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./channel"; 2 | export * from "./middleware"; 3 | export * from "./subscribe"; 4 | export * from "./topic"; 5 | export * from "./types"; 6 | -------------------------------------------------------------------------------- /packages/realtime/src/subscribe/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./helpers"; 2 | -------------------------------------------------------------------------------- /packages/test/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | inngest-test.tgz 4 | -------------------------------------------------------------------------------- /packages/test/eslint.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import eslint from "@eslint/js"; 4 | import tseslint from "typescript-eslint"; 5 | 6 | export default tseslint.config( 7 | eslint.configs.recommended, 8 | ...tseslint.configs.recommended 9 | ); 10 | -------------------------------------------------------------------------------- /packages/test/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} **/ 2 | module.exports = { 3 | testEnvironment: "node", 4 | transform: { 5 | "^.+.tsx?$": ["ts-jest", {}], 6 | }, 7 | roots: ["/src"], 8 | }; 9 | -------------------------------------------------------------------------------- /packages/test/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://jsr.io/schema/config-file.v1.json", 3 | "name": "@inngest/test", 4 | "description": "Tooling for testing Inngest functions.", 5 | "version": "0.1.6", 6 | "include": [ 7 | "./src/**/*.ts" 8 | ], 9 | "exclude": [], 10 | "exports": { 11 | ".": "./src/index.ts" 12 | } 13 | } -------------------------------------------------------------------------------- /packages/test/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./InngestTestEngine"; 2 | export * from "./InngestTestRun"; 3 | export * from "./util"; 4 | -------------------------------------------------------------------------------- /packages/test/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "commonjs", 5 | "rootDir": "./src", 6 | "declaration": true, 7 | "sourceMap": true, 8 | "outDir": "./dist", 9 | "esModuleInterop": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "strict": true, 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "strictNullChecks": true, 15 | "moduleResolution": "node" 16 | }, 17 | "include": ["./src/**/*"] 18 | } 19 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | -------------------------------------------------------------------------------- /scripts/generateReleaseConfig.js: -------------------------------------------------------------------------------- 1 | const fs = require("node:fs"); 2 | const path = require("node:path"); 3 | 4 | const config = { 5 | $schema: "https://unpkg.com/@changesets/config@2.3.0/schema.json", 6 | changelog: "@changesets/cli/changelog", 7 | commit: false, 8 | fixed: [], 9 | linked: [], 10 | access: "public", 11 | baseBranch: process.env.BRANCH || "main", 12 | updateInternalDependencies: "patch", 13 | ignore: [], 14 | }; 15 | 16 | console.log("Writing release config:", config); 17 | 18 | const rootDir = path.join(__dirname, ".."); 19 | process.chdir(rootDir); 20 | 21 | const changesetDir = path.join(rootDir, ".changeset"); 22 | const configName = "config.json"; 23 | const configPath = path.join(changesetDir, configName); 24 | 25 | const serializedConfig = JSON.stringify(config, null, 2); 26 | 27 | fs.writeFileSync(configPath, serializedConfig); 28 | -------------------------------------------------------------------------------- /scripts/release/jsrVersion.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const fs = require("fs"); 3 | const { exec: rawExec, getExecOutput } = require("@actions/exec"); 4 | 5 | const packageRootDir = process.cwd(); 6 | const version = process.env.npm_package_version; 7 | 8 | const exec = async (...args) => { 9 | const exitCode = await rawExec(...args); 10 | if (exitCode !== 0) { 11 | throw new Error(`Command exited with ${exitCode}`); 12 | } 13 | }; 14 | 15 | (async () => { 16 | // If this package has a `jsr.json` file, also update the version there 17 | const jsrFilePath = path.join(packageRootDir, "jsr.json"); 18 | if (!fs.existsSync(jsrFilePath)) { 19 | return; 20 | } 21 | 22 | const packageJson = JSON.parse( 23 | fs.readFileSync(path.join(packageRootDir, "package.json"), "utf8") 24 | ); 25 | 26 | const version = packageJson.version; 27 | console.log({ version }); 28 | 29 | const jsr = JSON.parse(fs.readFileSync(jsrFilePath, "utf8")); 30 | jsr.version = version; 31 | fs.writeFileSync(jsrFilePath, JSON.stringify(jsr, null, 2)); 32 | })(); 33 | -------------------------------------------------------------------------------- /scripts/release/tag.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { exec: rawExec, getExecOutput } = require("@actions/exec"); 3 | 4 | const branch = process.env.BRANCH; 5 | if (branch !== "main" && !branch.endsWith(".x")) { 6 | throw new Error( 7 | `Stopping release from branch ${branch}; only "main" and "v*.x" branches are allowed to release` 8 | ); 9 | } 10 | console.log("branch:", branch); 11 | 12 | const exec = async (...args) => { 13 | const exitCode = await rawExec(...args); 14 | if (exitCode !== 0) { 15 | throw new Error(`Command exited with ${exitCode}`); 16 | } 17 | }; 18 | 19 | const repoRootDir = path.join(__dirname, "..", ".."); 20 | 21 | (async () => { 22 | // Tag and push the release commit 23 | console.log('running "changeset tag" to tag the release commit'); 24 | await exec("changeset", ["tag"], { cwd: repoRootDir }); 25 | 26 | console.log(`pushing git tags to origin/${branch}`); 27 | await exec("git", ["push", "--follow-tags", "origin", branch]); 28 | })(); 29 | --------------------------------------------------------------------------------