├── .gitmodules ├── .husky ├── pre-push ├── pre-commit └── commit-msg ├── examples ├── astro │ ├── .env.example │ ├── tsconfig.json │ ├── .vscode │ │ ├── extensions.json │ │ └── launch.json │ ├── src │ │ ├── env.d.ts │ │ ├── pages │ │ │ └── api │ │ │ │ └── demo-workflow.ts │ │ └── layouts │ │ │ └── Layout.astro │ ├── astro.config.mjs │ ├── .gitignore │ ├── package.json │ └── public │ │ └── favicon.svg ├── express │ ├── .gitignore │ ├── .env.local.example │ ├── vercel.json │ ├── vitest.config.ts │ ├── package.json │ └── tsconfig.json ├── hono │ ├── .env.example │ ├── .vscode │ │ └── settings.json │ ├── .gitignore │ ├── tsconfig.json │ ├── package.json │ └── README.md ├── sveltekit │ ├── .npmrc │ ├── src │ │ ├── app.css │ │ ├── types.ts │ │ ├── routes │ │ │ ├── +layout.svelte │ │ │ ├── path │ │ │ │ └── +server.ts │ │ │ ├── -call-qstash │ │ │ │ └── +server.ts │ │ │ ├── sleep │ │ │ │ └── +server.ts │ │ │ └── ci │ │ │ │ └── +server.ts │ │ ├── lib │ │ │ └── index.ts │ │ ├── app.d.ts │ │ └── app.html │ ├── static │ │ ├── ss.png │ │ └── favicon.png │ ├── postcss.config.js │ ├── tailwind.config.js │ ├── vite.config.ts │ ├── .gitignore │ ├── svelte.config.js │ ├── tsconfig.json │ └── package.json ├── cloudflare-workers-hono │ ├── .gitignore │ ├── .dev.vars.example │ ├── wrangler.toml │ ├── src │ │ └── index.ts │ ├── .github │ │ └── workflows │ │ │ └── deploy.yaml │ └── package.json ├── ci │ ├── .eslintrc.json │ ├── app │ │ ├── globals.css │ │ ├── favicon-32x32.png │ │ ├── test-routes │ │ │ ├── trigger-non-workflow │ │ │ │ ├── constants.ts │ │ │ │ └── non-workflow │ │ │ │ │ └── route.ts │ │ │ ├── failureUrl │ │ │ │ ├── constants.ts │ │ │ │ ├── workflow │ │ │ │ │ └── route.ts │ │ │ │ └── third-party │ │ │ │ │ └── route.ts │ │ │ ├── auth │ │ │ │ ├── README.md │ │ │ │ └── custom │ │ │ │ │ └── target │ │ │ │ │ └── route.ts │ │ │ ├── large-payload │ │ │ │ ├── utils.ts │ │ │ │ ├── call-result │ │ │ │ │ └── third-party │ │ │ │ │ │ └── route.ts │ │ │ │ └── README.md │ │ │ ├── invoke │ │ │ │ └── called-endpoint │ │ │ │ │ └── route.ts │ │ │ ├── webhook │ │ │ │ ├── constants.ts │ │ │ │ └── caller │ │ │ │ │ └── route.ts │ │ │ ├── call │ │ │ │ └── constants.ts │ │ │ └── wait-for-event │ │ │ │ ├── constants.ts │ │ │ │ ├── README.md │ │ │ │ └── notifier │ │ │ │ └── route.ts │ │ ├── ci │ │ │ ├── ci.test.ts │ │ │ └── types.ts │ │ └── layout.tsx │ ├── next.config.mjs │ ├── postcss.config.mjs │ ├── .env.local.example │ ├── tailwind.config.ts │ ├── .gitignore │ ├── tsconfig.json │ └── package.json ├── cloudflare-workers │ ├── .dev.vars.example │ ├── .prettierrc │ ├── worker-configuration.d.ts │ ├── wrangler.toml │ ├── .editorconfig │ ├── test │ │ └── tsconfig.json │ ├── vitest.config.mts │ ├── .github │ │ └── workflows │ │ │ └── deploy.yaml │ ├── package.json │ └── src │ │ ├── index.ts │ │ └── serve-many.ts ├── nextjs-pages │ ├── .env.local.example │ ├── .eslintrc.json │ ├── src │ │ ├── styles │ │ │ └── globals.css │ │ ├── utils │ │ │ ├── types.ts │ │ │ └── cx.ts │ │ └── pages │ │ │ ├── fonts │ │ │ ├── GeistVF.woff │ │ │ └── GeistMonoVF.woff │ │ │ ├── _app.tsx │ │ │ ├── _document.tsx │ │ │ └── api │ │ │ └── path.ts │ ├── public │ │ └── ss.png │ ├── next.config.mjs │ ├── postcss.config.mjs │ ├── tailwind.config.ts │ ├── .gitignore │ ├── tsconfig.json │ └── package.json ├── nextjs │ ├── .eslintrc.json │ ├── app │ │ ├── globals.css │ │ ├── favicon-32x32.png │ │ ├── auth │ │ │ └── route.ts │ │ ├── path │ │ │ └── route.ts │ │ ├── sleep │ │ │ └── route.ts │ │ ├── layout.tsx │ │ ├── -call-qstash │ │ │ └── route.ts │ │ └── serve-many │ │ │ └── [...any] │ │ │ └── route.ts │ ├── public │ │ └── ss.png │ ├── .env.local.example │ ├── next.config.mjs │ ├── postcss.config.mjs │ ├── utils │ │ └── cx.ts │ ├── tailwind.config.ts │ ├── .gitignore │ ├── tsconfig.json │ ├── ci.test.ts │ └── package.json ├── solidjs │ ├── src │ │ ├── global.d.ts │ │ ├── app.css │ │ ├── entry-client.tsx │ │ ├── utils │ │ │ └── cx.ts │ │ ├── app.tsx │ │ ├── entry-server.tsx │ │ └── routes │ │ │ ├── path.ts │ │ │ ├── -call-qstash.ts │ │ │ └── sleep.ts │ ├── public │ │ └── ss.png │ ├── app.config.ts │ ├── .env.example │ ├── postcss.config.cjs │ ├── tailwind.config.cjs │ ├── .gitignore │ ├── tsconfig.json │ └── package.json ├── nextjs-12 │ ├── .eslintrc.json │ ├── public │ │ ├── favicon.ico │ │ └── vercel.svg │ ├── next.config.js │ ├── pages │ │ ├── _app.js │ │ └── api │ │ │ └── workflow.js │ ├── styles │ │ └── globals.css │ ├── .gitignore │ └── package.json ├── email-analyzer-o1 │ ├── .env.example │ ├── img │ │ ├── flow.png │ │ └── webhook-config.png │ ├── app │ │ ├── favicon.ico │ │ ├── globals.css │ │ └── layout.tsx │ ├── public │ │ ├── vercel.svg │ │ ├── file.svg │ │ ├── window.svg │ │ └── globe.svg │ ├── postcss.config.mjs │ ├── next.config.ts │ ├── next-env.d.ts │ ├── eslint.config.mjs │ ├── tailwind.config.ts │ ├── .gitignore │ ├── tsconfig.json │ └── package.json ├── nestjs │ ├── .prettierrc │ ├── tsconfig.build.json │ ├── src │ │ ├── app.service.ts │ │ ├── main.ts │ │ └── app.module.ts │ ├── app.module.ts │ ├── nest-cli.json │ ├── test │ │ ├── jest-e2e.json │ │ └── app.e2e-spec.ts │ ├── tsconfig.json │ ├── .gitignore │ └── eslint.config.mjs ├── tanstack-start │ ├── .prettierignore │ ├── public │ │ ├── robots.txt │ │ ├── favicon.ico │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── tanstack-circle-logo.png │ │ └── manifest.json │ ├── eslint.config.js │ ├── .gitignore │ ├── prettier.config.js │ ├── .vscode │ │ └── settings.json │ ├── .cta.json │ ├── src │ │ ├── router.tsx │ │ ├── routes │ │ │ └── demo │ │ │ │ ├── api.names.ts │ │ │ │ └── api │ │ │ │ └── single-workflow.ts │ │ ├── styles.css │ │ └── data │ │ │ └── demo.punk-songs.ts │ ├── vite.config.ts │ └── tsconfig.json ├── nuxt │ ├── assets │ │ └── css │ │ │ └── main.css │ ├── public │ │ └── ss.png │ ├── postcss.config.js │ ├── tsconfig.json │ ├── .gitignore │ ├── tailwind.config.js │ ├── nuxt.config.ts │ ├── server │ │ └── api │ │ │ ├── path.ts │ │ │ ├── sleep.ts │ │ │ ├── callQstash.ts │ │ │ └── serve-many │ │ │ └── [...].ts │ └── package.json ├── agents-researcher │ ├── app │ │ ├── globals.css │ │ ├── favicon-32x32.png │ │ ├── utils │ │ │ └── cx.ts │ │ ├── page.tsx │ │ ├── [session] │ │ │ └── page.tsx │ │ ├── icons │ │ │ ├── workflow-icon.tsx │ │ │ └── caret-dropdown.tsx │ │ ├── types.ts │ │ ├── components │ │ │ ├── code-block.tsx │ │ │ ├── agent-block.tsx │ │ │ └── deploy-button.tsx │ │ └── layout.tsx │ ├── prettier.config.js │ ├── public │ │ ├── icons │ │ │ ├── exa.jpg │ │ │ ├── wikipedia.png │ │ │ └── wolfram-alpha.png │ │ └── screenshot.png │ ├── next.config.ts │ ├── postcss.config.mjs │ ├── eslint.config.mjs │ ├── tailwind.config.ts │ ├── .env.local.example │ ├── .gitignore │ ├── tsconfig.json │ └── package.json ├── agents │ ├── app │ │ ├── favicon.ico │ │ ├── globals.css │ │ └── layout.tsx │ ├── .env.example │ ├── public │ │ ├── vercel.svg │ │ ├── window.svg │ │ ├── file.svg │ │ └── globe.svg │ ├── next.config.ts │ ├── postcss.config.mjs │ ├── eslint.config.mjs │ ├── tailwind.config.ts │ ├── .gitignore │ ├── tsconfig.json │ └── package.json ├── imgs │ ├── flow-diagram.png │ └── flow-diagram-nuxt.png ├── nextjs-webhook-stripe │ ├── .eslintrc.json │ ├── app │ │ ├── favicon.ico │ │ ├── fonts │ │ │ ├── GeistVF.woff │ │ │ └── GeistMonoVF.woff │ │ ├── globals.css │ │ └── layout.tsx │ ├── public │ │ ├── vercel.svg │ │ ├── window.svg │ │ ├── file.svg │ │ └── globe.svg │ ├── next.config.ts │ ├── postcss.config.mjs │ ├── tailwind.config.ts │ ├── .gitignore │ ├── tsconfig.json │ ├── package.json │ └── sh │ │ └── create-user.sh ├── upstash-realtime-ai-sdk │ ├── src │ │ ├── lib │ │ │ ├── redis.ts │ │ │ ├── utils.ts │ │ │ └── realtime.ts │ │ ├── app │ │ │ ├── favicon.ico │ │ │ ├── page.tsx │ │ │ └── layout.tsx │ │ └── components │ │ │ ├── providers.tsx │ │ │ └── ui │ │ │ └── collapsible.tsx │ ├── postcss.config.cjs │ ├── public │ │ ├── vercel.svg │ │ ├── window.svg │ │ ├── file.svg │ │ └── globe.svg │ ├── next.config.ts │ ├── components.json │ ├── .gitignore │ └── tsconfig.json ├── upstash-realtime │ ├── postcss.config.mjs │ ├── src │ │ ├── app │ │ │ ├── favicon.ico │ │ │ ├── api │ │ │ │ ├── realtime │ │ │ │ │ └── route.ts │ │ │ │ └── notify │ │ │ │ │ └── route.ts │ │ │ ├── globals.css │ │ │ └── layout.tsx │ │ └── lib │ │ │ ├── workflow.ts │ │ │ ├── redis.ts │ │ │ ├── realtime-client.ts │ │ │ ├── test.ts │ │ │ └── realtime.ts │ ├── .env.example │ ├── public │ │ ├── vercel.svg │ │ ├── window.svg │ │ ├── file.svg │ │ └── globe.svg │ ├── next.config.ts │ ├── eslint.config.mjs │ ├── .gitignore │ ├── tsconfig.json │ └── package.json ├── image-gen-with-workflow │ ├── public │ │ ├── train.png │ │ ├── landing.png │ │ ├── astronauts.png │ │ ├── futuristic-city.png │ │ ├── supersonic-jet.png │ │ └── mountain-village.png │ ├── next.config.mjs │ ├── app │ │ ├── favicon-32x32.png │ │ ├── fonts │ │ │ ├── GeistVF.woff │ │ │ └── GeistMonoVF.woff │ │ ├── globals.css │ │ ├── api │ │ │ ├── mock-image-gen-endpoint │ │ │ │ └── route.ts │ │ │ ├── check-workflow │ │ │ │ └── route.ts │ │ │ └── regular-simple │ │ │ │ └── route.ts │ │ └── layout.tsx │ ├── postcss.config.mjs │ ├── utils │ │ ├── cx.ts │ │ ├── helper.ts │ │ └── types.ts │ ├── .env.local.example │ ├── tailwind.config.ts │ ├── .gitignore │ ├── tsconfig.json │ ├── components │ │ ├── codeblock.tsx │ │ ├── button.tsx │ │ ├── header.tsx │ │ └── tooltip.tsx │ └── package.json ├── agents-instagram-post-generator │ ├── app │ │ ├── favicon.ico │ │ ├── globals.css │ │ ├── types.ts │ │ ├── layout.tsx │ │ └── api │ │ │ └── check-workflow │ │ │ └── route.ts │ ├── public │ │ ├── vercel.svg │ │ ├── window.svg │ │ ├── file.svg │ │ └── globe.svg │ ├── .env.example │ ├── next.config.ts │ ├── postcss.config.mjs │ ├── utils │ │ └── cx.ts │ ├── .prettierrc │ ├── eslint.config.mjs │ ├── tailwind.config.ts │ ├── .gitignore │ ├── tsconfig.json │ └── package.json ├── README.md └── fastify │ ├── tsconfig.json │ ├── src │ └── index.ts │ └── package.json ├── .prettierignore ├── src ├── context │ ├── index.ts │ └── api │ │ └── index.ts ├── integration.yml ├── serve │ ├── utils.ts │ └── utils.test.ts ├── index.ts └── agents │ └── constants.ts ├── bun.lockb ├── .gitignore ├── prettier.config.mjs ├── eslint.config.mjs ├── tsconfig.json ├── tsup.config.ts └── LICENSE /.gitmodules: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | bun run build 2 | -------------------------------------------------------------------------------- /examples/astro/.env.example: -------------------------------------------------------------------------------- 1 | QSTASH_TOKEN="" -------------------------------------------------------------------------------- /examples/express/.gitignore: -------------------------------------------------------------------------------- 1 | .vercel 2 | -------------------------------------------------------------------------------- /examples/hono/.env.example: -------------------------------------------------------------------------------- 1 | QSTASH_TOKEN="" -------------------------------------------------------------------------------- /examples/hono/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /examples/sveltekit/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | bun run lint && bun run fmt 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | examples 3 | node_modules -------------------------------------------------------------------------------- /examples/hono/.gitignore: -------------------------------------------------------------------------------- 1 | # deps 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /src/context/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./context"; 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | bun --no -- commitlint --edit "" 2 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/bun.lockb -------------------------------------------------------------------------------- /examples/cloudflare-workers-hono/.gitignore: -------------------------------------------------------------------------------- 1 | /.dev.vars 2 | /.wrangler/ -------------------------------------------------------------------------------- /examples/ci/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /examples/cloudflare-workers/.dev.vars.example: -------------------------------------------------------------------------------- 1 | QSTASH_URL= 2 | QSTASH_TOKEN= -------------------------------------------------------------------------------- /examples/astro/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strict" 3 | } 4 | -------------------------------------------------------------------------------- /examples/cloudflare-workers-hono/.dev.vars.example: -------------------------------------------------------------------------------- 1 | QSTASH_URL= 2 | QSTASH_TOKEN= -------------------------------------------------------------------------------- /examples/nextjs-pages/.env.local.example: -------------------------------------------------------------------------------- 1 | QSTASH_URL="*****" 2 | QSTASH_TOKEN="*****" -------------------------------------------------------------------------------- /examples/nextjs/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /examples/solidjs/src/global.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/nextjs-12/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /examples/email-analyzer-o1/.env.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= 2 | QSTASH_TOKEN= 3 | RESEND_API_KEY= -------------------------------------------------------------------------------- /examples/nestjs/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /examples/tanstack-start/.prettierignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | pnpm-lock.yaml 3 | yarn.lock -------------------------------------------------------------------------------- /examples/ci/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /examples/sveltekit/src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /examples/nextjs/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /examples/nuxt/assets/css/main.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /examples/solidjs/src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /examples/sveltekit/src/types.ts: -------------------------------------------------------------------------------- 1 | export type RedisEntry = { 2 | secret: string, 3 | result: unknown 4 | } -------------------------------------------------------------------------------- /examples/agents-researcher/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /examples/nextjs-pages/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/core-web-vitals", "next/typescript"] 3 | } 4 | -------------------------------------------------------------------------------- /examples/nextjs/public/ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/nextjs/public/ss.png -------------------------------------------------------------------------------- /examples/nuxt/public/ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/nuxt/public/ss.png -------------------------------------------------------------------------------- /examples/sveltekit/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /examples/agents/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/agents/app/favicon.ico -------------------------------------------------------------------------------- /examples/express/.env.local.example: -------------------------------------------------------------------------------- 1 | QSTASH_TOKEN="***" 2 | 3 | # for local development 4 | UPSTASH_WORKFLOW_URL="" -------------------------------------------------------------------------------- /examples/imgs/flow-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/imgs/flow-diagram.png -------------------------------------------------------------------------------- /examples/nextjs-webhook-stripe/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/core-web-vitals", "next/typescript"] 3 | } 4 | -------------------------------------------------------------------------------- /examples/solidjs/public/ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/solidjs/public/ss.png -------------------------------------------------------------------------------- /examples/sveltekit/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /examples/ci/app/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/ci/app/favicon-32x32.png -------------------------------------------------------------------------------- /examples/nextjs-pages/src/styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | -------------------------------------------------------------------------------- /examples/sveltekit/static/ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/sveltekit/static/ss.png -------------------------------------------------------------------------------- /examples/tanstack-start/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /examples/agents/.env.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= 2 | FIRECRAWL_API_KEY= 3 | SERPAPI_API_KEY= 4 | QSTASH_TOKEN= 5 | RESEND_API_KEY= -------------------------------------------------------------------------------- /examples/imgs/flow-diagram-nuxt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/imgs/flow-diagram-nuxt.png -------------------------------------------------------------------------------- /examples/nextjs-pages/public/ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/nextjs-pages/public/ss.png -------------------------------------------------------------------------------- /examples/nextjs-pages/src/utils/types.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export type RedisEntry = { 4 | secret: string, 5 | result: unknown 6 | } -------------------------------------------------------------------------------- /examples/ci/app/test-routes/trigger-non-workflow/constants.ts: -------------------------------------------------------------------------------- 1 | export const NON_WORKFLOW_ROUTE_RESPONSE = "super-secret-response-foo"; -------------------------------------------------------------------------------- /examples/email-analyzer-o1/img/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/email-analyzer-o1/img/flow.png -------------------------------------------------------------------------------- /examples/nextjs-12/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/nextjs-12/public/favicon.ico -------------------------------------------------------------------------------- /examples/nextjs/app/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/nextjs/app/favicon-32x32.png -------------------------------------------------------------------------------- /examples/solidjs/app.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "@solidjs/start/config"; 2 | 3 | export default defineConfig({}); 4 | -------------------------------------------------------------------------------- /examples/sveltekit/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/sveltekit/static/favicon.png -------------------------------------------------------------------------------- /examples/ci/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /examples/nextjs/.env.local.example: -------------------------------------------------------------------------------- 1 | QSTASH_URL="***" 2 | QSTASH_TOKEN="***" 3 | 4 | # for local development 5 | UPSTASH_WORKFLOW_URL="" -------------------------------------------------------------------------------- /examples/nuxt/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /examples/nuxt/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/src/lib/redis.ts: -------------------------------------------------------------------------------- 1 | import { Redis } from "@upstash/redis" 2 | 3 | export const redis = Redis.fromEnv() 4 | -------------------------------------------------------------------------------- /examples/astro/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["astro-build.astro-vscode"], 3 | "unwantedRecommendations": [] 4 | } 5 | -------------------------------------------------------------------------------- /examples/email-analyzer-o1/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/email-analyzer-o1/app/favicon.ico -------------------------------------------------------------------------------- /examples/nextjs/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /examples/solidjs/.env.example: -------------------------------------------------------------------------------- 1 | QSTASH_TOKEN="***" 2 | QSTASH_URL="***" 3 | QSTASH_CURRENT_SIGNING_KEY="***" 4 | QSTASH_NEXT_SIGNING_KEY="***" -------------------------------------------------------------------------------- /examples/solidjs/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /examples/sveltekit/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /examples/tanstack-start/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/tanstack-start/public/favicon.ico -------------------------------------------------------------------------------- /examples/tanstack-start/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/tanstack-start/public/logo192.png -------------------------------------------------------------------------------- /examples/tanstack-start/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/tanstack-start/public/logo512.png -------------------------------------------------------------------------------- /examples/agents-researcher/prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | singleQuote: true, 3 | semi: true, 4 | trailingComma: 'none' 5 | }; 6 | -------------------------------------------------------------------------------- /examples/cloudflare-workers/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 140, 3 | "singleQuote": true, 4 | "semi": true, 5 | "useTabs": true 6 | } 7 | -------------------------------------------------------------------------------- /examples/nestjs/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /examples/nextjs-webhook-stripe/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/nextjs-webhook-stripe/app/favicon.ico -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | "@tailwindcss/postcss": {}, 4 | }, 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /examples/upstash-realtime/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: ["@tailwindcss/postcss"], 3 | }; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /examples/upstash-realtime/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/upstash-realtime/src/app/favicon.ico -------------------------------------------------------------------------------- /examples/agents-researcher/app/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/agents-researcher/app/favicon-32x32.png -------------------------------------------------------------------------------- /examples/agents-researcher/public/icons/exa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/agents-researcher/public/icons/exa.jpg -------------------------------------------------------------------------------- /examples/agents-researcher/public/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/agents-researcher/public/screenshot.png -------------------------------------------------------------------------------- /examples/email-analyzer-o1/img/webhook-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/email-analyzer-o1/img/webhook-config.png -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/public/train.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/image-gen-with-workflow/public/train.png -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | export default nextConfig 5 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/public/landing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/image-gen-with-workflow/public/landing.png -------------------------------------------------------------------------------- /examples/nextjs-pages/src/pages/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/nextjs-pages/src/pages/fonts/GeistVF.woff -------------------------------------------------------------------------------- /examples/agents-researcher/public/icons/wikipedia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/agents-researcher/public/icons/wikipedia.png -------------------------------------------------------------------------------- /examples/agents/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/app/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/image-gen-with-workflow/app/favicon-32x32.png -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/public/astronauts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/image-gen-with-workflow/public/astronauts.png -------------------------------------------------------------------------------- /examples/nextjs-pages/src/pages/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/nextjs-pages/src/pages/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /examples/nextjs-webhook-stripe/app/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/nextjs-webhook-stripe/app/fonts/GeistVF.woff -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/upstash-realtime-ai-sdk/src/app/favicon.ico -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/agents-instagram-post-generator/app/favicon.ico -------------------------------------------------------------------------------- /examples/express/vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "rewrites": [ 4 | { 5 | "source": "/(.*)", 6 | "destination": "/api" 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /examples/hono/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "hono/jsx" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/app/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/image-gen-with-workflow/app/fonts/GeistVF.woff -------------------------------------------------------------------------------- /examples/tanstack-start/eslint.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import { tanstackConfig } from '@tanstack/eslint-config' 4 | 5 | export default [...tanstackConfig] 6 | -------------------------------------------------------------------------------- /examples/tanstack-start/public/tanstack-circle-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/tanstack-start/public/tanstack-circle-logo.png -------------------------------------------------------------------------------- /examples/upstash-realtime/.env.example: -------------------------------------------------------------------------------- 1 | # Upstash Redis 2 | UPSTASH_REDIS_REST_URL= 3 | UPSTASH_REDIS_REST_TOKEN= 4 | 5 | # QStash (for Workflow) 6 | QSTASH_TOKEN= 7 | -------------------------------------------------------------------------------- /examples/agents-researcher/public/icons/wolfram-alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/agents-researcher/public/icons/wolfram-alpha.png -------------------------------------------------------------------------------- /examples/email-analyzer-o1/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/app/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/image-gen-with-workflow/app/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/public/futuristic-city.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/image-gen-with-workflow/public/futuristic-city.png -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/public/supersonic-jet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/image-gen-with-workflow/public/supersonic-jet.png -------------------------------------------------------------------------------- /examples/nextjs-webhook-stripe/app/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/nextjs-webhook-stripe/app/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /examples/upstash-realtime/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/public/mountain-village.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upstash/workflow-js/HEAD/examples/image-gen-with-workflow/public/mountain-village.png -------------------------------------------------------------------------------- /examples/nextjs-webhook-stripe/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/nextjs-pages/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | }; 5 | 6 | export default nextConfig; 7 | -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/integration.yml: -------------------------------------------------------------------------------- 1 | authtoken: 2 | version: 2 3 | tunnels: 4 | first: 5 | addr: 3000 6 | proto: http 7 | second: 8 | addr: 3001 9 | proto: http 10 | -------------------------------------------------------------------------------- /examples/ci/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-12/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | swcMinify: true, 5 | } 6 | 7 | module.exports = nextConfig 8 | -------------------------------------------------------------------------------- /examples/nextjs-12/pages/_app.js: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | 3 | function MyApp({ Component, pageProps }) { 4 | return 5 | } 6 | 7 | export default MyApp 8 | -------------------------------------------------------------------------------- /examples/solidjs/src/entry-client.tsx: -------------------------------------------------------------------------------- 1 | // @refresh reload 2 | import { mount, StartClient } from "@solidjs/start/client"; 3 | 4 | mount(() => , document.getElementById("app")!); 5 | -------------------------------------------------------------------------------- /examples/upstash-realtime/src/lib/workflow.ts: -------------------------------------------------------------------------------- 1 | import { Client } from "@upstash/workflow"; 2 | 3 | export const workflowClient = new Client({ 4 | token: process.env.QSTASH_TOKEN!, 5 | }); 6 | -------------------------------------------------------------------------------- /examples/agents-researcher/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/agents/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | serverExternalPackages: ["pdf-parse"] 5 | }; 6 | 7 | export default nextConfig; 8 | -------------------------------------------------------------------------------- /examples/agents/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/cloudflare-workers/worker-configuration.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by Wrangler 2 | // After adding bindings to `wrangler.toml`, regenerate this interface via `npm run cf-typegen` 3 | interface Env {} 4 | -------------------------------------------------------------------------------- /examples/nextjs/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/upstash-realtime/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/nestjs/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/nextjs-pages/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-webhook-stripe/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/agents-instagram-post-generator/.env.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= 2 | FIRECRAWL_API_KEY= 3 | SERPAPI_API_KEY= 4 | QSTASH_TOKEN= 5 | RESEND_API_KEY= 6 | 7 | UPSTASH_REDIS_REST_URL= 8 | UPSTASH_REDIS_REST_TOKEN= -------------------------------------------------------------------------------- /examples/agents-researcher/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/email-analyzer-o1/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/agents-instagram-post-generator/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/email-analyzer-o1/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | serverExternalPackages: ["pdf-parse"] 5 | }; 6 | 7 | export default nextConfig; 8 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/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-webhook-stripe/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/utils/cx.ts: -------------------------------------------------------------------------------- 1 | import { ClassValue, clsx } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export default function cx(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } -------------------------------------------------------------------------------- /examples/astro/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | interface ImportMetaEnv { 3 | readonly QSTASH_TOKEN: string; 4 | } 5 | 6 | interface ImportMeta { 7 | readonly env: ImportMetaEnv; 8 | } 9 | -------------------------------------------------------------------------------- /examples/nestjs/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigModule } from '@nestjs/config'; 3 | 4 | @Module({ 5 | imports: [ConfigModule.forRoot()], 6 | }) 7 | export class AppModule {} 8 | -------------------------------------------------------------------------------- /examples/solidjs/src/utils/cx.ts: -------------------------------------------------------------------------------- 1 | import { ClassValue, clsx } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export default function cx(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/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-pages/src/utils/cx.ts: -------------------------------------------------------------------------------- 1 | import { ClassValue, clsx } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export default function cx(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } -------------------------------------------------------------------------------- /examples/tanstack-start/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | count.txt 7 | .env 8 | .nitro 9 | .tanstack 10 | .output 11 | .vinxi 12 | todos.json 13 | .nvmrc 14 | restart.sh 15 | -------------------------------------------------------------------------------- /examples/cloudflare-workers/wrangler.toml: -------------------------------------------------------------------------------- 1 | #:schema node_modules/wrangler/config-schema.json 2 | name = "upstash-workflow-cf" 3 | main = "src/index.ts" 4 | compatibility_date = "2024-08-15" 5 | compatibility_flags = ["nodejs_compat"] -------------------------------------------------------------------------------- /examples/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/solidjs/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{html,js,jsx,ts,tsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /examples/agents-researcher/app/utils/cx.ts: -------------------------------------------------------------------------------- 1 | import { ClassValue, clsx } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | export default function cx(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/utils/cx.ts: -------------------------------------------------------------------------------- 1 | import { ClassValue, clsx } from 'clsx' 2 | import { twMerge } from 'tailwind-merge' 3 | 4 | export default function cx(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /examples/upstash-realtime/src/lib/redis.ts: -------------------------------------------------------------------------------- 1 | import { Redis } from "@upstash/redis"; 2 | 3 | export const redis = new Redis({ 4 | url: process.env.UPSTASH_REDIS_REST_URL!, 5 | token: process.env.UPSTASH_REDIS_REST_TOKEN!, 6 | }); 7 | -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/utils/cx.ts: -------------------------------------------------------------------------------- 1 | import { ClassValue, clsx } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export default function cx(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } -------------------------------------------------------------------------------- /examples/ci/app/test-routes/failureUrl/constants.ts: -------------------------------------------------------------------------------- 1 | 2 | export const PAYLOAD = "my-payload-zed" 3 | 4 | export const HEADER = `Test-Header-Foo` 5 | export const HEADER_VALUE = `header-bar` 6 | 7 | export const ERROR_MESSAGE = "my-error-zed" -------------------------------------------------------------------------------- /examples/express/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config" 2 | 3 | export default defineConfig({ 4 | test: { 5 | globals: true, 6 | environment: "node", 7 | testTimeout: 30000, 8 | }, 9 | }) 10 | -------------------------------------------------------------------------------- /examples/sveltekit/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ['./src/**/*.{html,js,svelte,ts}'], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | } 9 | 10 | -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /examples/upstash-realtime/src/app/api/realtime/route.ts: -------------------------------------------------------------------------------- 1 | import { handle } from "@upstash/realtime"; 2 | import { realtime } from "@/lib/realtime"; 3 | 4 | export const maxDuration = 300; 5 | 6 | export const GET = handle({ realtime }); 7 | -------------------------------------------------------------------------------- /examples/cloudflare-workers-hono/wrangler.toml: -------------------------------------------------------------------------------- 1 | #:schema node_modules/wrangler/config-schema.json 2 | name = "upstash-workflow-cf-hono" 3 | main = "src/index.ts" 4 | compatibility_date = "2024-08-15" 5 | compatibility_flags = ["nodejs_compat"] 6 | -------------------------------------------------------------------------------- /examples/nextjs-pages/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/tanstack-start/prettier.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | /** @type {import('prettier').Config} */ 4 | const config = { 5 | semi: false, 6 | singleQuote: true, 7 | trailingComma: "all", 8 | }; 9 | 10 | export default config; 11 | -------------------------------------------------------------------------------- /examples/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/upstash-realtime/src/lib/realtime-client.ts: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { createRealtime } from "@upstash/realtime/client"; 4 | import type { RealtimeEvents } from "./realtime"; 5 | 6 | export const { useRealtime } = createRealtime(); -------------------------------------------------------------------------------- /examples/ci/app/test-routes/auth/README.md: -------------------------------------------------------------------------------- 1 | this directory has three tests 2 | - success: checking auth correctly 3 | - fail: auth failing 4 | - custom: define an workflow endpoint secured with custom auth (instead of receiver) and try to call it as if failure callback -------------------------------------------------------------------------------- /examples/ci/app/test-routes/large-payload/utils.ts: -------------------------------------------------------------------------------- 1 | export const largeObjectLength = 5 * 1024 * 1024 2 | export const largeObject = "x".repeat(largeObjectLength); 3 | 4 | export const GET_HEADER = "Get-Header" 5 | export const GET_HEADER_VALUE = "get-header-value-FOO" -------------------------------------------------------------------------------- /examples/ci/app/test-routes/trigger-non-workflow/non-workflow/route.ts: -------------------------------------------------------------------------------- 1 | import { NON_WORKFLOW_ROUTE_RESPONSE } from "../constants"; 2 | 3 | export const POST = async (request: Request) => { 4 | return new Response(NON_WORKFLOW_ROUTE_RESPONSE, { status: 200 }); 5 | } -------------------------------------------------------------------------------- /examples/sveltekit/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()], 6 | server: { 7 | port: 3001, 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .turbo 2 | node_modules 3 | dist 4 | .next 5 | .env 6 | .dev.vars 7 | .vercel 8 | .DS_Store 9 | .idea 10 | 11 | # examples 12 | examples/*/package-lock.json 13 | examples/*/pnpm-lock.yaml 14 | examples/ngrok.log 15 | restart.sh 16 | 17 | bootstrap.sh -------------------------------------------------------------------------------- /examples/ci/.env.local.example: -------------------------------------------------------------------------------- 1 | QSTASH_URL="" 2 | QSTASH_TOKEN="" 3 | 4 | UPSTASH_REDIS_REST_URL="" 5 | UPSTASH_REDIS_REST_TOKEN="" 6 | 7 | QSTASH_CURRENT_SIGNING_KEY="" 8 | QSTASH_NEXT_SIGNING_KEY="" 9 | 10 | # for local development 11 | UPSTASH_WORKFLOW_URL="" -------------------------------------------------------------------------------- /examples/email-analyzer-o1/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next" 2 | 3 | const nextConfig: NextConfig = { 4 | /* config options here */ 5 | typescript: { 6 | ignoreBuildErrors: true, 7 | }, 8 | } 9 | 10 | export default nextConfig 11 | -------------------------------------------------------------------------------- /src/serve/utils.ts: -------------------------------------------------------------------------------- 1 | import { WorkflowContext } from "../context"; 2 | import { DisabledWorkflowContext } from "./authorization"; 3 | 4 | export const isDisabledWorkflowContext = (context: WorkflowContext | DisabledWorkflowContext) => { 5 | return "disabled" in context; 6 | }; 7 | -------------------------------------------------------------------------------- /examples/cloudflare-workers-hono/src/index.ts: -------------------------------------------------------------------------------- 1 | import app from "./app"; 2 | 3 | export type Env = { 4 | QSTASH_URL: string; 5 | QSTASH_TOKEN: string; 6 | QSTASH_CURRENT_SIGNING_KEY: string; 7 | QSTASH_NEXT_SIGNING_KEY: string; 8 | }; 9 | 10 | export default app; 11 | -------------------------------------------------------------------------------- /examples/cloudflare-workers/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.yml] 12 | indent_style = space 13 | -------------------------------------------------------------------------------- /examples/nestjs/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './app.module'; 3 | 4 | async function bootstrap() { 5 | const app = await NestFactory.create(AppModule); 6 | await app.listen(process.env.PORT ?? 3001); 7 | } 8 | bootstrap(); 9 | -------------------------------------------------------------------------------- /examples/astro/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "./node_modules/.bin/astro dev", 6 | "name": "Development server", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /examples/ci/app/test-routes/invoke/called-endpoint/route.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "app/ci/utils"; 2 | 3 | export const GET = async (request: Request) => { 4 | expect(request.headers.get("upstash-workflow-invoke-count"), "2") 5 | return new Response(JSON.stringify({}), { status: 200 }); 6 | } -------------------------------------------------------------------------------- /examples/cloudflare-workers/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["@cloudflare/workers-types/experimental", "@cloudflare/vitest-pool-workers"] 5 | }, 6 | "include": ["./**/*.ts", "../src/env.d.ts"], 7 | "exclude": [] 8 | } 9 | -------------------------------------------------------------------------------- /examples/tanstack-start/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.watcherExclude": { 3 | "**/routeTree.gen.ts": true 4 | }, 5 | "search.exclude": { 6 | "**/routeTree.gen.ts": true 7 | }, 8 | "files.readonlyInclude": { 9 | "**/routeTree.gen.ts": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Workflow Examples 2 | 3 | This directory has example projects for Upstash Workflow with different frameworks. 4 | 5 | Each project has an interface where you can enter the deployment URL, pick a workflow endpoint, enter a payload and finally call the picked workflow endpoint. 6 | -------------------------------------------------------------------------------- /examples/ci/app/test-routes/webhook/constants.ts: -------------------------------------------------------------------------------- 1 | export const WEBHOOK_TEST_METHOD = "POST" 2 | export const WEBHOOK_TEST_BODY = { test: "webhook-body", timestamp: 1764768991643 } 3 | export const WEBHOOK_TEST_HEADER = "X-Test-Header" 4 | export const WEBHOOK_TEST_HEADER_VALUE = "webhook-test-value" 5 | -------------------------------------------------------------------------------- /examples/agents-researcher/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from "react"; 2 | import { AgentUI } from "./components/agent-ui"; 3 | 4 | export default function HomePage() { 5 | return ( 6 | Loading...}> 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /examples/astro/astro.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import { defineConfig } from 'astro/config'; 3 | import vercel from '@astrojs/vercel/serverless'; 4 | 5 | // https://astro.build/config 6 | export default defineConfig({ 7 | output: "server", 8 | adapter: vercel(), 9 | server: { port: 3001 } 10 | }); 11 | -------------------------------------------------------------------------------- /prettier.config.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('prettier').Config} 3 | */ 4 | const config = { 5 | endOfLine: "lf", 6 | singleQuote: false, 7 | tabWidth: 2, 8 | trailingComma: "es5", 9 | printWidth: 100, 10 | arrowParens: "always", 11 | useTabs: false, 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /examples/sveltekit/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | # Output 4 | .output 5 | .vercel 6 | /.svelte-kit 7 | /build 8 | 9 | # OS 10 | .DS_Store 11 | Thumbs.db 12 | 13 | # Env 14 | .env 15 | .env.* 16 | !.env.example 17 | !.env.test 18 | 19 | # Vite 20 | vite.config.js.timestamp-* 21 | vite.config.ts.timestamp-* 22 | -------------------------------------------------------------------------------- /examples/nuxt/.gitignore: -------------------------------------------------------------------------------- 1 | # Nuxt dev/build outputs 2 | .output 3 | .data 4 | .nuxt 5 | .nitro 6 | .cache 7 | dist 8 | 9 | # Node dependencies 10 | node_modules 11 | 12 | # Logs 13 | logs 14 | *.log 15 | 16 | # Misc 17 | .DS_Store 18 | .fleet 19 | .idea 20 | 21 | # Local env files 22 | .env 23 | .env.* 24 | !.env.example 25 | -------------------------------------------------------------------------------- /examples/cloudflare-workers/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config'; 2 | 3 | export default defineWorkersConfig({ 4 | test: { 5 | poolOptions: { 6 | workers: { 7 | wrangler: { configPath: './wrangler.toml' }, 8 | }, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /examples/ci/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss' 2 | 3 | const config: Config = { 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 | plugins: [], 11 | } 12 | export default config 13 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import globals from "globals"; 2 | import pluginJs from "@eslint/js"; 3 | import tseslint from "typescript-eslint"; 4 | 5 | export default [ 6 | { files: ["**/*.{js,mjs,cjs,ts}"] }, 7 | { languageOptions: { globals: globals.browser } }, 8 | pluginJs.configs.recommended, 9 | ...tseslint.configs.recommended, 10 | ]; 11 | -------------------------------------------------------------------------------- /examples/hono/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hono", 3 | "scripts": { 4 | "dev": "bun run --hot -p 3001 src/index.ts" 5 | }, 6 | "dependencies": { 7 | "@upstash/qstash": "latest", 8 | "@upstash/workflow": "latest", 9 | "hono": "^4.6.20" 10 | }, 11 | "devDependencies": { 12 | "@types/bun": "latest" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/nextjs/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss' 2 | 3 | const config: Config = { 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 | plugins: [], 11 | } 12 | export default config 13 | -------------------------------------------------------------------------------- /examples/nextjs-pages/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/tanstack-start/.cta.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "tanstack-start", 3 | "mode": "file-router", 4 | "typescript": true, 5 | "tailwind": true, 6 | "packageManager": "pnpm", 7 | "addOnOptions": {}, 8 | "git": true, 9 | "version": 1, 10 | "framework": "react-cra", 11 | "chosenAddOns": [ 12 | "eslint", 13 | "start" 14 | ] 15 | } -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/utils/helper.ts: -------------------------------------------------------------------------------- 1 | import { REDIS_PREFIX } from './constants' 2 | 3 | export const costCalc = (time = 0, isWorkflow = false) => { 4 | return 0.00_005 * (time / 1000) + (isWorkflow ? 0.00004 : 0) 5 | } 6 | 7 | export const generateCallKey = () => { 8 | return `${REDIS_PREFIX}-${Math.ceil(Math.random() * 1000000)}` 9 | } 10 | -------------------------------------------------------------------------------- /examples/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 PageState {} 9 | // interface Platform {} 10 | } 11 | } 12 | 13 | export {}; 14 | -------------------------------------------------------------------------------- /examples/ci/app/test-routes/large-payload/call-result/third-party/route.ts: -------------------------------------------------------------------------------- 1 | import { GET_HEADER, GET_HEADER_VALUE, largeObject } from "../../utils" 2 | 3 | export const GET = async () => { 4 | return new Response( 5 | largeObject, 6 | { 7 | status: 201, 8 | headers: { 9 | [ GET_HEADER ]: GET_HEADER_VALUE 10 | } 11 | } 12 | ) 13 | } -------------------------------------------------------------------------------- /examples/nuxt/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./components/**/*.{js,vue,ts}", 5 | "./layouts/**/*.vue", 6 | "./pages/**/*.vue", 7 | "./plugins/**/*.{js,ts}", 8 | "./app.vue", 9 | "./error.vue", 10 | ], 11 | theme: { 12 | extend: {}, 13 | }, 14 | plugins: [], 15 | } 16 | -------------------------------------------------------------------------------- /examples/solidjs/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | dist 3 | .solid 4 | .output 5 | .vercel 6 | .netlify 7 | .vinxi 8 | 9 | # Environment 10 | .env 11 | .env*.local 12 | 13 | # dependencies 14 | /node_modules 15 | 16 | # IDEs and editors 17 | /.idea 18 | .project 19 | .classpath 20 | *.launch 21 | .settings/ 22 | 23 | # Temp 24 | gitignore 25 | 26 | # System Files 27 | .DS_Store 28 | Thumbs.db 29 | -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "printWidth": 80, 4 | "editor.formatOnSave": true, 5 | "proseWrap": "always", 6 | "tabWidth": 4, 7 | "requireConfig": false, 8 | "useTabs": false, 9 | "trailingComma": "none", 10 | "bracketSpacing": true, 11 | "jsxBracketSameLine": false, 12 | "semi": true 13 | } -------------------------------------------------------------------------------- /examples/nestjs/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | import { ConfigModule } from '@nestjs/config'; 5 | 6 | @Module({ 7 | imports: [ConfigModule.forRoot()], 8 | controllers: [AppController], 9 | providers: [AppService], 10 | }) 11 | export class AppModule {} 12 | -------------------------------------------------------------------------------- /examples/tanstack-start/src/router.tsx: -------------------------------------------------------------------------------- 1 | import { createRouter } from '@tanstack/react-router' 2 | 3 | // Import the generated route tree 4 | import { routeTree } from './routeTree.gen' 5 | 6 | // Create a new router instance 7 | export const getRouter = () => { 8 | return createRouter({ 9 | routeTree, 10 | scrollRestoration: true, 11 | defaultPreloadStaleTime: 0, 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /examples/agents/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/agents/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/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 | 23 | # jetbrains setting folder 24 | .idea/ 25 | .vercel 26 | -------------------------------------------------------------------------------- /examples/upstash-realtime/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/email-analyzer-o1/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/email-analyzer-o1/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/nextjs-webhook-stripe/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/upstash-realtime/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/nextjs-webhook-stripe/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { serve } from "./serve"; // exclude serveBase 2 | export * from "./context"; 3 | export * from "./types"; 4 | export * from "./client/types"; 5 | export * from "./logger"; 6 | export * from "./client"; 7 | export { 8 | WorkflowError, 9 | WorkflowAbort, 10 | WorkflowNonRetryableError, 11 | WorkflowRetryAfterError, 12 | } from "./error"; 13 | export { WorkflowTool } from "./agents/adapters"; 14 | -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/fastify/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "esModuleInterop": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "outDir": "dist", 11 | "rootDir": "src" 12 | }, 13 | "include": ["src/**/*"], 14 | "exclude": ["node_modules"] 15 | } 16 | -------------------------------------------------------------------------------- /examples/sveltekit/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/agents-researcher/app/[session]/page.tsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from 'react'; 2 | import { AgentUI } from '../components/agent-ui'; 3 | 4 | export default async function Page({ 5 | params, 6 | }: { 7 | params: Promise<{ session: string }> 8 | }) { 9 | const { session } = await params 10 | return ( 11 | Loading...}> 12 | 13 | 14 | ); 15 | } -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/src/lib/realtime.ts: -------------------------------------------------------------------------------- 1 | import { InferRealtimeEvents, Realtime } from "@upstash/realtime" 2 | import { UIMessageChunk } from "ai" 3 | import z from "zod/v4" 4 | import { redis } from "./redis" 5 | 6 | export const schema = { 7 | ai: { chunk: z.any() as z.ZodType }, 8 | } 9 | 10 | export const realtime = new Realtime({ schema, redis }) 11 | export type RealtimeEvents = InferRealtimeEvents 12 | -------------------------------------------------------------------------------- /examples/agents/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/ci/app/ci/ci.test.ts: -------------------------------------------------------------------------------- 1 | import { test, describe } from "vitest" 2 | import { TEST_ROUTES, TEST_TIMEOUT_DURATION } from "./constants"; 3 | import { initiateTest } from "./utils"; 4 | 5 | describe("workflow integration tests", () => { 6 | TEST_ROUTES.forEach(testConfig => { 7 | test( 8 | testConfig.route, 9 | async () => { 10 | await initiateTest(testConfig.route) 11 | }, 12 | TEST_TIMEOUT_DURATION 13 | ) 14 | }); 15 | }) -------------------------------------------------------------------------------- /examples/tanstack-start/src/routes/demo/api.names.ts: -------------------------------------------------------------------------------- 1 | import { createFileRoute } from '@tanstack/react-router' 2 | 3 | export const Route = createFileRoute('/demo/api/names')({ 4 | server: { 5 | handlers: { 6 | GET: () => { 7 | return new Response(JSON.stringify(['Alice', 'Bob', 'Charlie']), { 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | }, 11 | }) 12 | }, 13 | }, 14 | }, 15 | }) 16 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/.env.local.example: -------------------------------------------------------------------------------- 1 | # Upstash redis for ratelimit and saving workflow result 2 | UPSTASH_REDIS_REST_URL= 3 | UPSTASH_REDIS_REST_TOKEN= 4 | 5 | # QSTash token for workflow 6 | QSTASH_TOKEN= 7 | 8 | # Environment variables for local development 9 | UPSTASH_WORKFLOW_URL= 10 | 11 | # one of openai or ideogram key for image generation 12 | # leave both of them empty for dev with placeholder image 13 | IDEOGRAM_API_KEY= 14 | OPENAI_API_KEY= 15 | -------------------------------------------------------------------------------- /examples/solidjs/src/app.tsx: -------------------------------------------------------------------------------- 1 | import { Router } from "@solidjs/router"; 2 | import { FileRoutes } from "@solidjs/start/router"; 3 | import { Suspense } from "solid-js"; 4 | 5 | import "./app.css"; 6 | 7 | export default function App() { 8 | return ( 9 | ( 11 | <> 12 | {props.children} 13 | 14 | )} 15 | > 16 | 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /examples/email-analyzer-o1/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/ci/app/test-routes/call/constants.ts: -------------------------------------------------------------------------------- 1 | 2 | export const FAILING_HEADER = "Fail-Header-Foo" 3 | export const FAILING_HEADER_VALUE = "fail-header-value-BAR" 4 | 5 | export const GET_HEADER = "Get-Header" 6 | export const GET_HEADER_VALUE = "get-header-value-FOO" 7 | 8 | export const PATCH_RESULT = 99999999 9 | 10 | export const DELETE_RESULT = { foo: "bar", zed: 2, unicode: "`“X” - 𐐷𐐶𐐹`" } 11 | 12 | export const CUSTOM_CONTENT_TYPE = "application/x-www-form-urlencoded" -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss' 2 | 3 | const config: Config = { 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 | fontFamily: { 12 | sans: ['var(--font-default)'], 13 | }, 14 | }, 15 | }, 16 | plugins: [], 17 | } 18 | export default config 19 | -------------------------------------------------------------------------------- /examples/nextjs-webhook-stripe/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/sveltekit/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 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: adapter() 12 | } 13 | }; 14 | 15 | export default config; 16 | -------------------------------------------------------------------------------- /examples/nextjs/app/auth/route.ts: -------------------------------------------------------------------------------- 1 | import { serve } from '@upstash/workflow/nextjs' 2 | 3 | export const { POST } = serve(async (context) => { 4 | if (context.headers.get('authentication') !== 'Bearer secretPassword') { 5 | console.error('Authentication failed.') 6 | return 7 | } 8 | 9 | await context.run('step1', async () => { 10 | return 'output 1' 11 | }) 12 | 13 | await context.run('step2', async () => { 14 | return 'output 2' 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/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/agents/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/agents/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/tanstack-start/src/styles.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | 3 | body { 4 | @apply m-0; 5 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 6 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 7 | sans-serif; 8 | -webkit-font-smoothing: antialiased; 9 | -moz-osx-font-smoothing: grayscale; 10 | } 11 | 12 | code { 13 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 14 | monospace; 15 | } 16 | -------------------------------------------------------------------------------- /examples/agents-researcher/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/agents-researcher/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/email-analyzer-o1/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/email-analyzer-o1/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/agents-researcher/.env.local.example: -------------------------------------------------------------------------------- 1 | # Upstash redis for saving the workflow results 2 | UPSTASH_REDIS_REST_URL= 3 | UPSTASH_REDIS_REST_TOKEN= 4 | 5 | # QSTash token for workflow 6 | QSTASH_TOKEN= 7 | 8 | # Environment variables for local development 9 | UPSTASH_WORKFLOW_URL= 10 | 11 | # OpenAI API key to power agents 12 | OPENAI_API_KEY= 13 | 14 | # Wolfram Alpha App ID for Wolfram Alpha queries 15 | WOLFRAM_ALPHA_APP_ID= 16 | 17 | # Exa API key for Exa Search queries 18 | EXASEARCH_API_KEY= -------------------------------------------------------------------------------- /examples/nextjs-webhook-stripe/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/ci/app/test-routes/large-payload/README.md: -------------------------------------------------------------------------------- 1 | This directory has a endpoints testing the lazy fetch functionality: 2 | - `call-result`: endpoint called with context.call returns a large payload 3 | - `error`: a large error is thrown. failureFunction is called with the initial body. 4 | - `initial`: workflow is started with a large object 5 | - `step-result`: a step returns a large result 6 | - `step-result-parallel`: a parallel step returns a large result 7 | 8 | In `utils.ts`, you can find the large object used. -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/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/agents-instagram-post-generator/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-pages/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | const config: Config = { 4 | content: [ 5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/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 | }; 19 | export default config; 20 | -------------------------------------------------------------------------------- /examples/solidjs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "allowSyntheticDefaultImports": true, 7 | "esModuleInterop": true, 8 | "jsx": "preserve", 9 | "jsxImportSource": "solid-js", 10 | "allowJs": true, 11 | "noEmit": true, 12 | "strict": true, 13 | "types": ["vinxi/types/client"], 14 | "isolatedModules": true, 15 | "paths": { 16 | "~/*": ["./src/*"] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/nuxt/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | // https://nuxt.com/docs/api/configuration/nuxt-config 2 | export default defineNuxtConfig({ 3 | compatibilityDate: '2024-04-03', 4 | devtools: { enabled: true }, 5 | runtimeConfig: { 6 | QSTASH_URL: process.env.QSTASH_URL, 7 | QSTASH_TOKEN: process.env.QSTASH_TOKEN, 8 | }, 9 | css: ['~/assets/css/main.css'], 10 | postcss: { 11 | plugins: { 12 | tailwindcss: {}, 13 | autoprefixer: {}, 14 | }, 15 | }, 16 | devServer: { 17 | port: 3001 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /examples/upstash-realtime/src/lib/test.ts: -------------------------------------------------------------------------------- 1 | import { Realtime, InferRealtimeEvents } from "@upstash/realtime" 2 | import { redis } from "./redis" 3 | import z from "zod/v4" 4 | 5 | const schema = { 6 | notification: { 7 | alert: z.string(), 8 | }, 9 | } 10 | 11 | export const realtime = new Realtime({ schema, redis }) 12 | export type RealtimeEvents = InferRealtimeEvents 13 | 14 | export const POST = async () => { 15 | await realtime.emit("notification.alert", "hello world!") 16 | 17 | return new Response("OK") 18 | } -------------------------------------------------------------------------------- /examples/ci/app/test-routes/auth/custom/target/route.ts: -------------------------------------------------------------------------------- 1 | import { WorkflowContext } from "@upstash/workflow"; 2 | import { serve } from "@upstash/workflow/nextjs"; 3 | import { fail } from "app/ci/upstash/redis"; 4 | import { nanoid } from "app/ci/utils"; 5 | 6 | 7 | export const { POST } = serve(async (context) => { 8 | if (context.headers.get("authorization") !== nanoid()) { 9 | return; 10 | }; 11 | }, { 12 | receiver: undefined, 13 | async failureFunction({ context }) { 14 | await fail(context as WorkflowContext) 15 | }, 16 | }) -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { redis } from "@/lib/redis"; 2 | import { UIMessage } from "ai"; 3 | import { Chat } from "@/components/chat"; 4 | 5 | type Params = Promise<{ chatId?: string }>; 6 | 7 | const Page = async ({ searchParams }: { searchParams: Params }) => { 8 | const { chatId } = await searchParams; 9 | 10 | const history = await redis.get(`history:${chatId}`) || []; 11 | 12 | return ; 13 | }; 14 | 15 | export default Page; 16 | -------------------------------------------------------------------------------- /examples/nextjs-12/styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | 18 | @media (prefers-color-scheme: dark) { 19 | html { 20 | color-scheme: dark; 21 | } 22 | body { 23 | color: white; 24 | background: black; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["ESNext"], 4 | "module": "esnext", 5 | "target": "esnext", 6 | "moduleResolution": "bundler", 7 | "moduleDetection": "force", 8 | "allowImportingTsExtensions": true, 9 | "noEmit": true, 10 | "strict": true, 11 | "downlevelIteration": true, 12 | "skipLibCheck": true, 13 | "allowSyntheticDefaultImports": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "allowJs": true, 16 | "types": ["bun-types"] 17 | }, 18 | "exclude": ["examples"] 19 | } 20 | -------------------------------------------------------------------------------- /examples/nextjs-12/.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 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /examples/ci/.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | ngrok.log -------------------------------------------------------------------------------- /examples/nextjs-pages/.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /examples/nextjs/.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | ngrok.log -------------------------------------------------------------------------------- /examples/astro/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workflow-astro", 3 | "type": "module", 4 | "version": "0.0.1", 5 | "scripts": { 6 | "dev": "astro dev", 7 | "start": "astro dev", 8 | "build": "astro check && astro build", 9 | "preview": "astro preview", 10 | "astro": "astro" 11 | }, 12 | "dependencies": { 13 | "@astrojs/check": "^0.9.4", 14 | "@astrojs/vercel": "^7.8.2", 15 | "@upstash/workflow": "latest", 16 | "astro": "^4.16.7", 17 | "typescript": "^5.6.3" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "^22.8.7" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/ci/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next' 2 | import './globals.css' 3 | 4 | export const metadata: Metadata = { 5 | title: 'Upstash Workflow', 6 | description: 'Generated by create next app', 7 | icons: { 8 | icon: '/favicon-32x32.png', 9 | }, 10 | } 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: Readonly<{ 15 | children: React.ReactNode 16 | }>) { 17 | return ( 18 | 19 | {children} 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | scripts -------------------------------------------------------------------------------- /examples/nextjs-pages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "paths": { 16 | "@/*": ["./src/*"] 17 | } 18 | }, 19 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /examples/tanstack-start/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import { tanstackStart } from '@tanstack/react-start/plugin/vite' 3 | import viteReact from '@vitejs/plugin-react' 4 | import viteTsConfigPaths from 'vite-tsconfig-paths' 5 | import tailwindcss from '@tailwindcss/vite' 6 | 7 | const config = defineConfig({ 8 | plugins: [ 9 | // this is the plugin that enables path aliases 10 | viteTsConfigPaths({ 11 | projects: ['./tsconfig.json'], 12 | }), 13 | tailwindcss(), 14 | tanstackStart(), 15 | viteReact(), 16 | ], 17 | }) 18 | 19 | export default config 20 | -------------------------------------------------------------------------------- /examples/nextjs-12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs-12", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev -p 3001", 7 | "build": "next build", 8 | "start": "next start -p 3001", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@upstash/redis": "^1.34.3", 13 | "@upstash/qstash": "latest", 14 | "@upstash/workflow": "latest", 15 | "next": "12.3.4", 16 | "react": "18.3.1", 17 | "react-dom": "18.3.1" 18 | }, 19 | "devDependencies": { 20 | "eslint": "9.14.0", 21 | "eslint-config-next": "15.0.3" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/cloudflare-workers/.github/workflows/deploy.yaml: -------------------------------------------------------------------------------- 1 | name: Deploy Worker 2 | on: 3 | push: 4 | pull_request: 5 | repository_dispatch: 6 | jobs: 7 | deploy: 8 | runs-on: ubuntu-latest 9 | timeout-minutes: 60 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Build & Deploy Worker 13 | uses: cloudflare/wrangler-action@v3 14 | with: 15 | apiToken: ${{ secrets.CF_API_TOKEN }} 16 | accountId: ${{ secrets.CF_ACCOUNT_ID }} 17 | env: 18 | QSTASH_URL: ${{ secrets.QSTASH_URL }} 19 | QSTASH_TOKEN: ${{ secrets.QSTASH_TOKEN }} 20 | -------------------------------------------------------------------------------- /examples/fastify/src/index.ts: -------------------------------------------------------------------------------- 1 | // src/index.ts 2 | import server from './server.js'; 3 | 4 | // Run the server! 5 | const start = async (): Promise => { 6 | try { 7 | await server.listen({ port: 3001, host: '0.0.0.0' }); 8 | const address = server.server.address(); 9 | const port = typeof address === 'string' ? address : address?.port; 10 | server.log.info(`Server is running on http://localhost:${port}`); 11 | } catch (err) { 12 | server.log.error(err); 13 | console.log(err); 14 | console.error('Server failed to start'); 15 | process.exit(1); 16 | } 17 | }; 18 | 19 | start(); 20 | -------------------------------------------------------------------------------- /examples/cloudflare-workers-hono/.github/workflows/deploy.yaml: -------------------------------------------------------------------------------- 1 | name: Deploy Worker 2 | on: 3 | push: 4 | pull_request: 5 | repository_dispatch: 6 | jobs: 7 | deploy: 8 | runs-on: ubuntu-latest 9 | timeout-minutes: 60 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Build & Deploy Worker 13 | uses: cloudflare/wrangler-action@v3 14 | with: 15 | apiToken: ${{ secrets.CF_API_TOKEN }} 16 | accountId: ${{ secrets.CF_ACCOUNT_ID }} 17 | env: 18 | QSTASH_URL: ${{ secrets.QSTASH_URL }} 19 | QSTASH_TOKEN: ${{ secrets.QSTASH_TOKEN }} 20 | -------------------------------------------------------------------------------- /src/context/api/index.ts: -------------------------------------------------------------------------------- 1 | import { AnthropicAPI } from "./anthropic"; 2 | import { BaseWorkflowApi } from "./base"; 3 | import { OpenAIAPI } from "./openai"; 4 | import { ResendAPI } from "./resend"; 5 | 6 | export class WorkflowApi extends BaseWorkflowApi { 7 | public get openai() { 8 | return new OpenAIAPI({ 9 | context: this.context, 10 | }); 11 | } 12 | 13 | public get resend() { 14 | return new ResendAPI({ 15 | context: this.context, 16 | }); 17 | } 18 | 19 | public get anthropic() { 20 | return new AnthropicAPI({ 21 | context: this.context, 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/tanstack-start/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "TanStack App", 3 | "name": "Create TanStack App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /examples/tanstack-start/src/data/demo.punk-songs.ts: -------------------------------------------------------------------------------- 1 | import { createServerFn } from '@tanstack/react-start' 2 | 3 | export const getPunkSongs = createServerFn({ 4 | method: 'GET', 5 | }).handler(async () => [ 6 | { id: 1, name: 'Teenage Dirtbag', artist: 'Wheatus' }, 7 | { id: 2, name: 'Smells Like Teen Spirit', artist: 'Nirvana' }, 8 | { id: 3, name: 'The Middle', artist: 'Jimmy Eat World' }, 9 | { id: 4, name: 'My Own Worst Enemy', artist: 'Lit' }, 10 | { id: 5, name: 'Fat Lip', artist: 'Sum 41' }, 11 | { id: 6, name: 'All the Small Things', artist: 'blink-182' }, 12 | { id: 7, name: 'Beverly Hills', artist: 'Weezer' }, 13 | ]) 14 | -------------------------------------------------------------------------------- /examples/upstash-realtime/src/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/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": "ES2023", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "noImplicitAny": false, 18 | "strictBindCallApply": false, 19 | "noFallthroughCasesInSwitch": false 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/agents-researcher/app/icons/workflow-icon.tsx: -------------------------------------------------------------------------------- 1 | const DEFAULT_ICON_SIZE = 32; 2 | 3 | export const WorkflowIcon = ({ size = DEFAULT_ICON_SIZE, ...props }) => { 4 | return ( 5 | 13 | 14 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | *:focus { 6 | @apply outline-dotted outline-2 outline-offset-2 outline-emerald-500; 7 | } 8 | 9 | @layer utilities { 10 | .shadow { 11 | @apply shadow-[4px_4px_0_#00000030]; 12 | } 13 | 14 | .shadow-0 { 15 | @apply shadow-[0_0_0_#00000000]; 16 | } 17 | } 18 | 19 | a { 20 | @apply font-bold text-emerald-800 underline decoration-emerald-800 hover:bg-emerald-200; 21 | } 22 | 23 | fieldset { 24 | @apply border-2 border-emerald-800 p-4 shadow; 25 | } 26 | 27 | legend { 28 | @apply px-2 font-bold text-emerald-800; 29 | } 30 | -------------------------------------------------------------------------------- /examples/nextjs/app/path/route.ts: -------------------------------------------------------------------------------- 1 | import { serve } from '@upstash/workflow/nextjs' 2 | 3 | const someWork = (input: string) => { 4 | return `processed '${JSON.stringify(input)}'` 5 | } 6 | 7 | export const { POST } = serve(async (context) => { 8 | const input = context.requestPayload 9 | const result1 = await context.run('step1', async () => { 10 | const output = someWork(input) 11 | console.log('step 1 input', input, 'output', output) 12 | return output 13 | }) 14 | 15 | await context.run('step2', async () => { 16 | const output = someWork(result1) 17 | console.log('step 2 input', result1, 'output', output) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "src/app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "iconLibrary": "lucide", 14 | "aliases": { 15 | "components": "@/components", 16 | "utils": "@/lib/utils", 17 | "ui": "@/components/ui", 18 | "lib": "@/lib", 19 | "hooks": "@/hooks" 20 | }, 21 | "registries": { 22 | "@ai-elements": "https://registry.ai-sdk.dev/{name}.json" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/app/types.ts: -------------------------------------------------------------------------------- 1 | export interface Image { 2 | /** 3 | * The base64-encoded JSON of the generated image, if `response_format` is 4 | * `b64_json`. 5 | */ 6 | b64_json?: string; 7 | 8 | /** 9 | * The prompt that was used to generate the image, if there was any revision to the 10 | * prompt. 11 | */ 12 | revised_prompt?: string; 13 | 14 | /** 15 | * The URL of the generated image, if `response_format` is `url` (default). 16 | */ 17 | url?: string; 18 | } 19 | 20 | export type ImageModel = 'dall-e-2' | 'dall-e-3'; 21 | 22 | export interface ImagesResponse { 23 | created: number; 24 | 25 | data: Array; 26 | } -------------------------------------------------------------------------------- /examples/upstash-realtime/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 | ignores: [ 16 | "node_modules/**", 17 | ".next/**", 18 | "out/**", 19 | "build/**", 20 | "next-env.d.ts", 21 | ], 22 | }, 23 | ]; 24 | 25 | export default eslintConfig; 26 | -------------------------------------------------------------------------------- /examples/ci/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "baseUrl": ".", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | }, 22 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 23 | "exclude": ["node_modules"] 24 | } 25 | -------------------------------------------------------------------------------- /examples/solidjs/src/entry-server.tsx: -------------------------------------------------------------------------------- 1 | // @refresh reload 2 | import { createHandler, StartServer } from "@solidjs/start/server"; 3 | 4 | export default createHandler(() => ( 5 | ( 7 | 8 | 9 | 10 | 11 | 12 | {assets} 13 | 14 | 15 |
{children}
16 | {scripts} 17 | 18 | 19 | )} 20 | /> 21 | )); 22 | -------------------------------------------------------------------------------- /examples/nextjs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "baseUrl": ".", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | }, 22 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 23 | "exclude": ["node_modules"] 24 | } 25 | -------------------------------------------------------------------------------- /examples/nextjs-webhook-stripe/.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 | 32 | # env files (can opt-in for committing if needed) 33 | .env* 34 | 35 | # vercel 36 | .vercel 37 | 38 | # typescript 39 | *.tsbuildinfo 40 | next-env.d.ts 41 | -------------------------------------------------------------------------------- /examples/agents/.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/image-gen-with-workflow/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "baseUrl": ".", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ] 21 | }, 22 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 23 | "exclude": ["node_modules"] 24 | } 25 | -------------------------------------------------------------------------------- /examples/email-analyzer-o1/.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/upstash-realtime/.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/fastify/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fastify", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "build": "tsc", 10 | "start": "bun src/index.ts", 11 | "start:prod": "bun dist/index.js" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "@fastify/env": "^5.0.2", 18 | "@upstash/workflow": "latest", 19 | "fastify": "^5.3.3", 20 | "fastify-cli": "^7.4.0" 21 | }, 22 | "devDependencies": { 23 | "@types/node": "^22.15.23", 24 | "typescript": "^5.8.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/nuxt/server/api/path.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "@upstash/workflow/h3"; 2 | 3 | const someWork = (input: string) => { 4 | return `processed '${JSON.stringify(input)}'`; 5 | }; 6 | 7 | const { handler } = serve(async (context) => { 8 | const input = context.requestPayload; 9 | const result1 = await context.run("step1", async () => { 10 | const output = someWork(input); 11 | console.log("step 1 input", input, "output", output); 12 | return output; 13 | }); 14 | 15 | await context.run("step2", async () => { 16 | const output = someWork(result1); 17 | console.log("step 2 input", result1, "output", output); 18 | }); 19 | }); 20 | 21 | export default handler 22 | -------------------------------------------------------------------------------- /examples/solidjs/src/routes/path.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "@upstash/workflow/solidjs" 2 | 3 | const someWork = (input: string) => { 4 | return `processed '${JSON.stringify(input)}'` 5 | } 6 | 7 | export const { POST } = serve( 8 | async context => { 9 | const input = context.requestPayload 10 | const result1 = await context.run("step1", async () => { 11 | const output = someWork(input) 12 | console.log("step 1 input", input, "output", output) 13 | return output 14 | }); 15 | 16 | await context.run("step2", async () => { 17 | const output = someWork(result1) 18 | console.log("step 2 input", result1, "output", output) 19 | }); 20 | }, 21 | ) 22 | -------------------------------------------------------------------------------- /examples/upstash-realtime/src/lib/realtime.ts: -------------------------------------------------------------------------------- 1 | import { Realtime, InferRealtimeEvents } from "@upstash/realtime"; 2 | import { redis } from "./redis"; 3 | import z from "zod/v4"; 4 | 5 | const schema = { 6 | workflow: { 7 | runFinish: z.object({}), 8 | stepFinish: z.object({ 9 | stepName: z.string(), 10 | result: z.unknown().optional() 11 | }), 12 | waitingForInput: z.object({ 13 | eventId: z.string(), 14 | message: z.string() 15 | }), 16 | inputResolved: z.object({ 17 | eventId: z.string() 18 | }), 19 | } 20 | } 21 | 22 | export const realtime = new Realtime({ schema, redis }) 23 | export type RealtimeEvents = InferRealtimeEvents -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/app/api/mock-image-gen-endpoint/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest } from "next/server" 2 | import { IMAGES, MOCK_WAIT_MS } from "utils/constants" 3 | import { ImageResponse, Prompt } from "utils/types" 4 | 5 | 6 | export const POST = async (request: NextRequest) => { 7 | const params = (await request.json()) as { prompt: Prompt } 8 | 9 | const prompt = params.prompt 10 | 11 | await new Promise((r) => setTimeout(r, MOCK_WAIT_MS)) 12 | const response: ImageResponse = { 13 | created: "mock", 14 | data: [ 15 | { 16 | prompt, 17 | url: IMAGES[prompt] 18 | } 19 | ] 20 | } 21 | return new Response(JSON.stringify(response)) 22 | } 23 | -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/.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/agents-instagram-post-generator/.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/nuxt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt-app", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "build": "nuxt build", 7 | "dev": "nuxt dev", 8 | "generate": "nuxt generate", 9 | "preview": "nuxt preview", 10 | "postinstall": "nuxt prepare" 11 | }, 12 | "dependencies": { 13 | "@upstash/qstash": "latest", 14 | "@upstash/workflow": "latest", 15 | "nuxt": "^3.12.4", 16 | "vue": "latest" 17 | }, 18 | "devDependencies": { 19 | "@nuxt/types": "^2.18.1", 20 | "@nuxt/typescript-build": "^3.0.2", 21 | "autoprefixer": "^10.4.19", 22 | "postcss": "^8.4.39", 23 | "tailwindcss": "^3.4.6", 24 | "typescript": "^5.5.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/agents/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/image-gen-with-workflow/components/codeblock.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import React, { useEffect } from 'react' 4 | import Prism from 'prismjs' 5 | 6 | export default function CodeBlock({ 7 | children, 8 | ...props 9 | }: React.ComponentProps<'pre'>) { 10 | const ref = React.useRef(null) 11 | 12 | useEffect(() => { 13 | if (!ref.current) return 14 | Prism.highlightElement(ref.current) 15 | }, []) 16 | 17 | return ( 18 |
22 |       
23 |         {children}
24 |       
25 |     
26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /examples/cloudflare-workers-hono/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudflare-workers", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "@upstash/qstash": "latest", 6 | "@upstash/redis": "^1.34.3", 7 | "@upstash/workflow": "latest", 8 | "hono": "^4.5.8" 9 | }, 10 | "devDependencies": { 11 | "@cloudflare/workers-types": "^4.20240815.0", 12 | "@vitest/ui": "^2.1.8", 13 | "typescript": "^5.5.2", 14 | "vitest": "^2.1.8", 15 | "wrangler": "^3.60.3" 16 | }, 17 | "private": true, 18 | "scripts": { 19 | "dev": "wrangler dev --port 3001 --var UPSTASH_WORKFLOW_URL:$UPSTASH_WORKFLOW_URL", 20 | "deploy": "wrangler publish", 21 | "test": "vitest run", 22 | "test:watch": "vitest" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig({ 4 | entry: { 5 | index: "./src/index.ts", 6 | nextjs: "./platforms/nextjs.ts", 7 | h3: "./platforms/h3.ts", 8 | svelte: "./platforms/svelte.ts", 9 | solidjs: "./platforms/solidjs.ts", 10 | hono: "./platforms/hono.ts", 11 | cloudflare: "./platforms/cloudflare.ts", 12 | astro: "./platforms/astro.ts", 13 | express: "./platforms/express.ts", 14 | tanstack: "./platforms/tanstack.ts", 15 | }, 16 | format: ["cjs", "esm"], 17 | clean: true, 18 | dts: true, 19 | // This should optimally be an optional peer dependency, 20 | // we can change it in a future release 21 | external: ["next", "express"], 22 | }); 23 | -------------------------------------------------------------------------------- /examples/agents-researcher/.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*.local 36 | 37 | # vercel 38 | .vercel 39 | 40 | # typescript 41 | *.tsbuildinfo 42 | next-env.d.ts 43 | 44 | bootstrap.sh 45 | ngrok.log -------------------------------------------------------------------------------- /examples/agents-researcher/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/email-analyzer-o1/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/nextjs-webhook-stripe/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/upstash-realtime/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 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /examples/agents-researcher/app/types.ts: -------------------------------------------------------------------------------- 1 | export type AgentName = 2 | | "Wikipedia" 3 | | "WolframAlpha" 4 | | "Exa" 5 | | "Cross Reference"; 6 | 7 | export type StepRecord = { 8 | stepName: string; 9 | stepOut: string; 10 | }; 11 | 12 | export type StepStatus = "init" | "loading" | "done"; 13 | 14 | export type WorkflowStatus = { 15 | query: string; 16 | progress: string; 17 | agentStates: { 18 | [key in AgentName]: StepStatus; 19 | }; 20 | }; 21 | 22 | export type PollResult = { 23 | query: string | null; 24 | progress: string | null; 25 | wikipediaOutput: StepRecord[] | null; 26 | wolframAlphaOutput: StepRecord[] | null; 27 | searchOutput: StepRecord[] | null; 28 | crossReferenceOutput: StepRecord[] | null; 29 | }; 30 | -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/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/upstash-realtime-ai-sdk/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 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules", "_old"] 27 | } 28 | -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/src/components/providers.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { QueryClient, QueryClientProvider } from "@tanstack/react-query" 4 | import { NuqsAdapter } from "nuqs/adapters/next/app" 5 | import { useState } from "react" 6 | 7 | export function Providers({ children }: { children: React.ReactNode }) { 8 | const [queryClient] = useState( 9 | () => 10 | new QueryClient({ 11 | defaultOptions: { 12 | queries: { 13 | staleTime: 60 * 1000, 14 | refetchOnWindowFocus: false, 15 | }, 16 | }, 17 | }) 18 | ) 19 | 20 | return ( 21 | 22 | {children} 23 | 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/components/button.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import cx from 'utils/cx' 3 | 4 | const Button = ({ 5 | variant = 'primary', 6 | className, 7 | ...props 8 | }: React.ComponentProps<'button'> & { 9 | variant?: 'primary' | 'secondary' 10 | }) => { 11 | return ( 12 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/utils/types.ts: -------------------------------------------------------------------------------- 1 | import { PROMPTS } from "./constants" 2 | 3 | export type CallInfo = { 4 | duration: number 5 | result: string 6 | functionTime: number 7 | } 8 | 9 | export type RedisEntry = { 10 | time: number 11 | url: string 12 | } 13 | 14 | export type FetchParameters = { 15 | url: string 16 | method: 'POST' 17 | body: object 18 | headers: Record 19 | } 20 | 21 | export type IdeogramResponse = { 22 | created: string 23 | data: Array<{ 24 | prompt: string 25 | url: string 26 | }> 27 | } 28 | 29 | export type OpenAIResponse = { 30 | created: number 31 | data: Array<{ 32 | revised_prompt: string 33 | url: string 34 | }> 35 | } 36 | 37 | export type ImageResponse = IdeogramResponse | OpenAIResponse 38 | 39 | export type CallPayload = { 40 | promptIndex: number 41 | } 42 | 43 | export type Prompt = typeof PROMPTS[number] -------------------------------------------------------------------------------- /examples/nextjs-webhook-stripe/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import localFont from "next/font/local"; 3 | import "./globals.css"; 4 | 5 | const geistSans = localFont({ 6 | src: "./fonts/GeistVF.woff", 7 | variable: "--font-geist-sans", 8 | weight: "100 900", 9 | }); 10 | const geistMono = localFont({ 11 | src: "./fonts/GeistMonoVF.woff", 12 | variable: "--font-geist-mono", 13 | weight: "100 900", 14 | }); 15 | 16 | export const metadata: Metadata = { 17 | title: "Create Next App", 18 | description: "Generated by create next app", 19 | }; 20 | 21 | export default function RootLayout({ 22 | children, 23 | }: Readonly<{ 24 | children: React.ReactNode; 25 | }>) { 26 | return ( 27 | 28 | 31 | {children} 32 | 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /examples/sveltekit/src/routes/-call-qstash/+server.ts: -------------------------------------------------------------------------------- 1 | import { Client } from "@upstash/qstash"; 2 | import type { RequestHandler } from "@sveltejs/kit"; 3 | import { json } from "@sveltejs/kit"; 4 | import { env } from '$env/dynamic/private' 5 | 6 | const client = new Client({ 7 | baseUrl: env.QSTASH_URL!, 8 | token: env.QSTASH_TOKEN! 9 | }); 10 | 11 | export const POST: RequestHandler = async ({ request }) => { 12 | const { route, payload } = await request.json() as { route: string, payload: unknown }; 13 | 14 | try { 15 | const baseUrl = env.UPSTASH_WORKFLOW_URL ?? request.url.replace("/-call-qstash", "") 16 | const { messageId } = await client.publishJSON({ 17 | url: `${baseUrl}/${route}`, 18 | body: payload 19 | }); 20 | 21 | return json({ messageId }, { status: 200 }); 22 | } catch (error) { 23 | return json({ error: `Error when publishing to QStash: ${error}` }, { status: 500 }); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /examples/agents-researcher/app/icons/caret-dropdown.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const IconCaretDownFilled = ({ 4 | className 5 | }: { 6 | className?: React.HTMLProps['className']; 7 | }) => { 8 | return ( 9 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /examples/nestjs/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | /build 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | pnpm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | lerna-debug.log* 14 | 15 | # OS 16 | .DS_Store 17 | 18 | # Tests 19 | /coverage 20 | /.nyc_output 21 | 22 | # IDEs and editors 23 | /.idea 24 | .project 25 | .classpath 26 | .c9/ 27 | *.launch 28 | .settings/ 29 | *.sublime-workspace 30 | 31 | # IDE - VSCode 32 | .vscode/* 33 | !.vscode/settings.json 34 | !.vscode/tasks.json 35 | !.vscode/launch.json 36 | !.vscode/extensions.json 37 | 38 | # dotenv environment variable files 39 | .env 40 | .env.development.local 41 | .env.test.local 42 | .env.production.local 43 | .env.local 44 | 45 | # temp directory 46 | .temp 47 | .tmp 48 | 49 | # Runtime data 50 | pids 51 | *.pid 52 | *.seed 53 | *.pid.lock 54 | 55 | # Diagnostic reports (https://nodejs.org/api/report.html) 56 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 57 | -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Geist, Geist_Mono } from "next/font/google"; 3 | import "./globals.css"; 4 | import { Providers } from "@/components/providers"; 5 | 6 | const geistSans = Geist({ 7 | variable: "--font-geist-sans", 8 | subsets: ["latin"], 9 | }); 10 | 11 | const geistMono = Geist_Mono({ 12 | variable: "--font-geist-mono", 13 | subsets: ["latin"], 14 | }); 15 | 16 | export const metadata: Metadata = { 17 | title: "Realtime Chat", 18 | description: "Real-time chat powered by Upstash", 19 | }; 20 | 21 | export default function RootLayout({ 22 | children, 23 | }: Readonly<{ 24 | children: React.ReactNode; 25 | }>) { 26 | return ( 27 | 28 | 31 | {children} 32 | 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /examples/email-analyzer-o1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "email-analyzer-o1", 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 | "@upstash/workflow": "^0.2.4", 13 | "next": "15.1.11", 14 | "nodemailer": "^6.9.16", 15 | "openai": "^4.79.1", 16 | "pdf-parse": "^1.1.1", 17 | "react": "^19.0.0", 18 | "react-dom": "^19.0.0", 19 | "resend": "^4.1.1" 20 | }, 21 | "devDependencies": { 22 | "@eslint/eslintrc": "^3", 23 | "@types/node": "^20", 24 | "@types/nodemailer": "^6.4.17", 25 | "@types/pdf-parse": "^1.1.4", 26 | "@types/react": "^19", 27 | "@types/react-dom": "^19", 28 | "eslint": "^9", 29 | "eslint-config-next": "15.1.5", 30 | "postcss": "^8", 31 | "tailwindcss": "^3.4.1", 32 | "typescript": "^5" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/ci/app/test-routes/wait-for-event/constants.ts: -------------------------------------------------------------------------------- 1 | export const NOTIFIER_WORKFLOW_ROUTE = "wait-for-event/notifier-workflow" 2 | export const NOTIFIER_RESULT = "super-secret-foo" 3 | export const NOTIFIER_CALL_COUNT_OVERRIDE = -1 4 | 5 | export const SDK_EVENT_DATA = "notifying-with-sdk" 6 | export const TEXT_EVENT_DATA = "notifying-with-text-foo" 7 | export const OBJECT_EVENT_DATA = {"notifying": "object", "with": 1} 8 | 9 | export const NOTIFIER_SECRET = process.env.UPSTASH_REDIS_REST_TOKEN!.slice(0, 10) 10 | 11 | export type NotifierWorkflowConfig = { 12 | /** 13 | * event id used in /notifier 14 | */ 15 | sdkEventId: string, 16 | /** 17 | * event id used in /notifier-workflow for text 18 | */ 19 | textEventId: string, 20 | /** 21 | * event id used in /notifier-workflow for object 22 | */ 23 | objectEventId: string, 24 | /** 25 | * random id used to save result to redis in /notifier-workflow 26 | */ 27 | redisEntryId: string 28 | } 29 | -------------------------------------------------------------------------------- /examples/nextjs-pages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs-pages", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev -p 3001", 7 | "build": "next build", 8 | "start": "next start -p 3001", 9 | "lint": "next lint", 10 | "test": "vitest run", 11 | "test:watch": "vitest" 12 | }, 13 | "dependencies": { 14 | "@upstash/qstash": "^2.7.16", 15 | "@upstash/redis": "^1.34.3", 16 | "@upstash/workflow": "latest", 17 | "clsx": "^2.1.1", 18 | "next": "14.2.35", 19 | "react": "^18", 20 | "react-dom": "^18", 21 | "tailwind-merge": "^2.5.2" 22 | }, 23 | "devDependencies": { 24 | "@types/node": "^20", 25 | "@types/react": "^18", 26 | "@types/react-dom": "^18", 27 | "@vitest/ui": "^2.1.8", 28 | "eslint": "^8", 29 | "eslint-config-next": "14.2.8", 30 | "postcss": "^8", 31 | "tailwindcss": "^3.4.1", 32 | "typescript": "^5", 33 | "vitest": "^2.1.8" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/src/components/ui/collapsible.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" 4 | 5 | function Collapsible({ 6 | ...props 7 | }: React.ComponentProps) { 8 | return 9 | } 10 | 11 | function CollapsibleTrigger({ 12 | ...props 13 | }: React.ComponentProps) { 14 | return ( 15 | 19 | ) 20 | } 21 | 22 | function CollapsibleContent({ 23 | ...props 24 | }: React.ComponentProps) { 25 | return ( 26 | 30 | ) 31 | } 32 | 33 | export { Collapsible, CollapsibleTrigger, CollapsibleContent } 34 | -------------------------------------------------------------------------------- /examples/nestjs/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import eslint from '@eslint/js'; 3 | import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; 4 | import globals from 'globals'; 5 | import tseslint from 'typescript-eslint'; 6 | 7 | export default tseslint.config( 8 | { 9 | ignores: ['eslint.config.mjs'], 10 | }, 11 | eslint.configs.recommended, 12 | ...tseslint.configs.recommendedTypeChecked, 13 | eslintPluginPrettierRecommended, 14 | { 15 | languageOptions: { 16 | globals: { 17 | ...globals.node, 18 | ...globals.jest, 19 | }, 20 | sourceType: 'commonjs', 21 | parserOptions: { 22 | projectService: true, 23 | tsconfigRootDir: import.meta.dirname, 24 | }, 25 | }, 26 | }, 27 | { 28 | rules: { 29 | '@typescript-eslint/no-explicit-any': 'off', 30 | '@typescript-eslint/no-floating-promises': 'warn', 31 | '@typescript-eslint/no-unsafe-argument': 'warn' 32 | }, 33 | }, 34 | ); -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/app/api/check-workflow/route.ts: -------------------------------------------------------------------------------- 1 | import { Post } from '@/app/page'; 2 | import { Redis } from '@upstash/redis'; 3 | import { NextRequest, NextResponse } from 'next/server'; 4 | 5 | const redis = Redis.fromEnv(); 6 | 7 | export async function POST(request: NextRequest) { 8 | try { 9 | const { callKey } = await request.json(); 10 | 11 | if (!callKey) { 12 | return NextResponse.json( 13 | { error: 'No callKey provided' }, 14 | { status: 400 } 15 | ); 16 | } 17 | 18 | const posts = await redis.lrange(`${callKey}-posts`, 0, -1); 19 | 20 | if (!posts || posts.length === 0) { 21 | return NextResponse.json(null); 22 | } 23 | 24 | return NextResponse.json({ 25 | posts 26 | }); 27 | } catch (error) { 28 | console.error('Error checking workflow:', error); 29 | return NextResponse.json( 30 | { error: 'Failed to check workflow status' }, 31 | { status: 500 } 32 | ); 33 | } 34 | } -------------------------------------------------------------------------------- /examples/solidjs/src/routes/sleep.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "@upstash/workflow/solidjs" 2 | 3 | const someWork = (input: string) => { 4 | return `processed '${JSON.stringify(input)}'` 5 | } 6 | 7 | export const { POST } = serve( 8 | async context => { 9 | const input = context.requestPayload 10 | const result1 = await context.run("step1", async () => { 11 | const output = someWork(input) 12 | console.log("step 1 input", input, "output", output) 13 | return output 14 | }); 15 | 16 | await context.sleepUntil("sleep1", (Date.now()/1000) + 3) 17 | 18 | const result2 = await context.run("step2", async () => { 19 | const output = someWork(result1) 20 | console.log("step 2 input", result1, "output", output) 21 | return output 22 | }); 23 | 24 | await context.sleep("sleep2", 2) 25 | 26 | await context.run("step3", async () => { 27 | const output = someWork(result2) 28 | console.log("step 3 input", result2, "output", output) 29 | }); 30 | } 31 | ) -------------------------------------------------------------------------------- /examples/agents/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/components/header.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | export default function Header({}: {}) { 4 | return ( 5 |
6 | upstash logo 11 | 12 |

Optimizing Vercel Functions With Upstash Workflow

13 | 14 |

15 | This demo shows the cost-saving benefits of using Upstash Workflow for Vercel functions. It compares two methods of calling an image generation API: 16 |

17 | 18 |
    19 |
  • - Method 1: Calling the API in a standard Vercel function
  • 20 |
  • - Method 2: Calling the API using Upstash Workflow
  • 21 |
22 | 23 |

Both methods start at the same time and take about the same time to finish. The key difference is the estimated cost per 1M requests (hover for details).

24 | 25 |
26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /examples/ci/app/test-routes/webhook/caller/route.ts: -------------------------------------------------------------------------------- 1 | import { 2 | WEBHOOK_TEST_METHOD, 3 | WEBHOOK_TEST_BODY, 4 | WEBHOOK_TEST_HEADER, 5 | WEBHOOK_TEST_HEADER_VALUE 6 | } from "../constants"; 7 | 8 | export const POST = async (request: Request) => { 9 | const { webhookUrl } = await request.json() as { webhookUrl: string }; 10 | 11 | if (!webhookUrl) { 12 | return new Response("webhook URL not provided", { status: 400 }); 13 | } 14 | 15 | // Call the webhook URL with specific method, body, and headers 16 | const response = await fetch(webhookUrl, { 17 | method: WEBHOOK_TEST_METHOD, 18 | headers: { 19 | "Content-Type": "application/json", 20 | [WEBHOOK_TEST_HEADER]: WEBHOOK_TEST_HEADER_VALUE, 21 | }, 22 | body: JSON.stringify(WEBHOOK_TEST_BODY), 23 | }); 24 | 25 | if (!response.ok) { 26 | return new Response(`webhook call failed with status ${response.status}`, { 27 | status: 500 28 | }); 29 | } 30 | 31 | return new Response("webhook called", { status: 200 }); 32 | }; 33 | -------------------------------------------------------------------------------- /examples/email-analyzer-o1/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/upstash-realtime/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/nextjs-webhook-stripe/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/app/api/regular-simple/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from 'next/server' 2 | import { ImageResponse } from 'utils/types' 3 | 4 | export const POST = async (request: NextRequest) => { 5 | // get prompt from request 6 | const params = await request.json() 7 | const prompt = params.prompt as string 8 | 9 | // make the fetch request 10 | const response = await fetch('https://api.ideogram.ai/generate', { 11 | method: 'POST', 12 | body: JSON.stringify({ 13 | image_request: { 14 | model: 'V_2', 15 | prompt, 16 | aspect_ratio: 'ASPECT_1_1', 17 | magic_prompt_option: 'AUTO', 18 | }, 19 | }), 20 | headers: { 21 | 'Content-Type': 'application/json', 22 | 'Api-Key': process.env.IDEOGRAM_API_KEY!, 23 | }, 24 | }) 25 | 26 | // get the image url 27 | const payload = (await response.json()) as ImageResponse 28 | const url = payload.data[0].url 29 | 30 | return new NextResponse(JSON.stringify({ url }), { status: 200 }) 31 | } 32 | -------------------------------------------------------------------------------- /examples/nextjs-12/pages/api/workflow.js: -------------------------------------------------------------------------------- 1 | import { servePagesRouter } from "@upstash/workflow/nextjs"; 2 | 3 | const someWork = (input) => { 4 | return `processed '${JSON.stringify(input)}'` 5 | } 6 | 7 | const baseUrl = process.env.VERCEL_URL 8 | ? `https://${process.env.VERCEL_URL}` 9 | : process.env.UPSTASH_WORKFLOW_URL 10 | ? process.env.UPSTASH_WORKFLOW_URL 11 | : "http://localhost:3001" 12 | 13 | const endpointUrl = `${baseUrl}/api/workflow` 14 | 15 | const { handler } = servePagesRouter( 16 | async (context) => { 17 | const input = context.requestPayload 18 | const result1 = await context.run("step1", async () => { 19 | const output = someWork(input) 20 | console.log("step 1 input", input, "output", output) 21 | return output 22 | }); 23 | 24 | await context.run("step2", async () => { 25 | const output = someWork(result1) 26 | console.log("step 2 input", result1, "output", output) 27 | }); 28 | }, 29 | { 30 | url: endpointUrl 31 | } 32 | ) 33 | 34 | export default handler 35 | -------------------------------------------------------------------------------- /examples/upstash-realtime-ai-sdk/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/nuxt/server/api/sleep.ts: -------------------------------------------------------------------------------- 1 | 2 | import { serve } from "@upstash/workflow/h3"; 3 | 4 | const someWork = (input: string) => { 5 | return `processed '${JSON.stringify(input)}'` 6 | } 7 | 8 | const { handler } = serve( 9 | async context => { 10 | const input = context.requestPayload 11 | const result1 = await context.run("step1", async () => { 12 | const output = someWork(input) 13 | console.log("step 1 input", input, "output", output) 14 | return output 15 | }); 16 | 17 | await context.sleepUntil("sleep1", (Date.now()/1000) + 3) 18 | 19 | const result2 = await context.run("step2", async () => { 20 | const output = someWork(result1) 21 | console.log("step 2 input", result1, "output", output) 22 | return output 23 | }); 24 | 25 | await context.sleep("sleep2", 2) 26 | 27 | await context.run("step3", async () => { 28 | const output = someWork(result2) 29 | console.log("step 3 input", result2, "output", output) 30 | }); 31 | } 32 | ) 33 | 34 | export default handler 35 | -------------------------------------------------------------------------------- /examples/ci/app/test-routes/wait-for-event/README.md: -------------------------------------------------------------------------------- 1 | Under the `wait-for-event` directory, there are three routes: 2 | - `/workflow`: the workflow we run in the tests to do the following in order: 3 | 1. wait for a random event which should timeout 4 | 2. sequentially, call `/notifier` and wait to get notified. `/notifier` uses `waitUntil` to sleep for 2 secs and call notify 5 | 3. in parallel, call `/notifier-workflow` and wait to get notified with text data 6 | 4. wait to get notified with object data by `/notifier-workflow` 7 | - `/notifier`: an endpoint which notifies the workflow using the SDK 8 | - `/notifier-workflow`: a workflow which notifies the original workflow two times: 9 | 1. with a text event data 10 | 2. with an object event data 11 | 12 | `/notifier` workflow will keep retrying until it has successfully notified the original worklfow two times (one with text one with object). 13 | 14 | once the `/notifier-workflow` finishes execution, it will save it's state to Redis. `/workflow` will check if `/notifier-workflow` has finished in its last step. -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/components/tooltip.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import type { TooltipProps } from '@radix-ui/react-tooltip' 3 | import * as RadixTooltip from '@radix-ui/react-tooltip' 4 | 5 | const Tooltip = ({ 6 | children, 7 | title, 8 | }: TooltipProps & { 9 | title: React.ReactNode 10 | }) => { 11 | return ( 12 | 13 | 14 | 15 | {children} 16 | 17 | 18 | 24 | {title} 25 | 26 | 27 | 28 | 29 | 30 | ) 31 | } 32 | 33 | export default Tooltip 34 | -------------------------------------------------------------------------------- /examples/agents-researcher/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata, Viewport } from "next"; 2 | import { Inter } from "next/font/google"; 3 | import "./globals.css"; 4 | import cx from "./utils/cx"; 5 | import "prismjs/themes/prism-tomorrow.css"; 6 | 7 | export const metadata: Metadata = { 8 | title: "Cross Referencer", 9 | description: "Generated by create next app", 10 | icons: { 11 | icon: "/favicon-32x32.png", 12 | }, 13 | }; 14 | 15 | export const viewport: Viewport = { 16 | width: "device-width", 17 | initialScale: 1, 18 | maximumScale: 1, 19 | userScalable: false, 20 | }; 21 | 22 | const defaultFont = Inter({ 23 | variable: "--font-inter", 24 | display: "swap", 25 | style: "normal", 26 | subsets: ["latin-ext"], 27 | }); 28 | 29 | export default function RootLayout({ 30 | children, 31 | }: Readonly<{ 32 | children: React.ReactNode; 33 | }>) { 34 | return ( 35 | 36 | {children} 37 | 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /examples/ci/app/ci/types.ts: -------------------------------------------------------------------------------- 1 | export type TestConfig = { 2 | /** 3 | * path of the workflow endpoint 4 | * 5 | * will also be part of the redis key 6 | */ 7 | route: string, 8 | /** 9 | * payload to send in the initial request 10 | */ 11 | payload: TPayload, 12 | /** 13 | * headers of the request 14 | */ 15 | headers?: Record, 16 | /** 17 | * number of times the endpoint is to be called in this test 18 | */ 19 | expectedCallCount: number 20 | /** 21 | * expected result in the Redis 22 | */ 23 | expectedResult: string 24 | /** 25 | * whether the workflow should start 26 | * 27 | * @default true 28 | */ 29 | shouldWorkflowStart?: boolean 30 | } 31 | 32 | export type RedisResult = { 33 | /** 34 | * observed call count 35 | */ 36 | callCount: number 37 | /** 38 | * result written to redis 39 | */ 40 | result: string 41 | /** 42 | * a randomly generated string which is generated 43 | * in each test and sent as a header. 44 | */ 45 | randomTestId: string 46 | } 47 | -------------------------------------------------------------------------------- /examples/agents-instagram-post-generator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agents-instagram-post-generator", 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 | "@agentic/firecrawl": "^7.2.0", 13 | "@agentic/serpapi": "^7.2.0", 14 | "@upstash/redis": "^1.34.3", 15 | "@upstash/workflow": "^0.2.5-agents-3", 16 | "ai": "^4.1.0", 17 | "clsx": "^2.1.1", 18 | "lucide-react": "^0.473.0", 19 | "next": "15.1.11", 20 | "openai": "^4.79.4", 21 | "react": "^19.0.0", 22 | "react-dom": "^19.0.0", 23 | "tailwind-merge": "^2.6.0", 24 | "zod": "^3.24.1" 25 | }, 26 | "devDependencies": { 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 | "postcss": "^8", 34 | "tailwindcss": "^3.4.1", 35 | "typescript": "^5" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/agents-researcher/app/components/deploy-button.tsx: -------------------------------------------------------------------------------- 1 | export default function DeployButton() { 2 | return ( 3 | 4 | Deploy with Vercel 5 | 6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /examples/ci/app/test-routes/failureUrl/workflow/route.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "@upstash/workflow/nextjs"; 2 | import { BASE_URL, TEST_ROUTE_PREFIX } from "app/ci/constants"; 3 | import { testServe, expect, ANY_STRING } from "app/ci/utils"; 4 | import { ERROR_MESSAGE, PAYLOAD, HEADER, HEADER_VALUE } from "../constants"; 5 | 6 | const thirdPartyEndpoint = `${TEST_ROUTE_PREFIX}/failureUrl/third-party` 7 | 8 | export const { POST, GET } = testServe( 9 | serve( 10 | async (context) => { 11 | const input = context.requestPayload; 12 | 13 | expect(input, PAYLOAD); 14 | expect(context.headers.get(HEADER)!, HEADER_VALUE) 15 | 16 | await context.run("step1", () => { 17 | throw new Error(ERROR_MESSAGE); 18 | }); 19 | }, { 20 | baseUrl: BASE_URL, 21 | retries: 0, 22 | failureUrl: thirdPartyEndpoint 23 | } 24 | ), { 25 | expectedCallCount: 2, 26 | expectedResult: `{"error":"Error","message":"${ERROR_MESSAGE}","stack":${ANY_STRING}}`, 27 | payload: PAYLOAD, 28 | headers: { 29 | [ HEADER ]: HEADER_VALUE, 30 | } 31 | } 32 | ) -------------------------------------------------------------------------------- /examples/nextjs-12/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /examples/nextjs/ci.test.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Client } from "@upstash/qstash" 3 | import { serve } from "@upstash/workflow/nextjs" 4 | import { describe, test, expect } from "vitest" 5 | 6 | const qstashClient = new Client({ 7 | baseUrl: "https://workflow-tests.requestcatcher.com/", 8 | token: "mock" 9 | }) 10 | 11 | // mocking batch 12 | qstashClient.batch = async () => { 13 | return [{ messageId: "msgId" }] 14 | } 15 | 16 | const { POST: serveHandler } = serve( 17 | async (context) => { 18 | await context.sleep("sleeping", 10) 19 | }, { 20 | qstashClient, 21 | receiver: undefined 22 | } 23 | ) 24 | 25 | describe("nextjs tests", () => { 26 | test("should send first invocation", async () => { 27 | const request = new Request("https://workflow-tests.requestcatcher.com/") 28 | const response = await serveHandler(request) 29 | 30 | // it should send a request, but get failed to parse error because 31 | // request catcher returns string 32 | expect(response.status).toBe(200) 33 | const result = await response.json() 34 | expect(result.workflowRunId).toBeTruthy() 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /examples/sveltekit/src/routes/sleep/+server.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "@upstash/workflow/svelte"; 2 | import { env } from '$env/dynamic/private' 3 | 4 | const someWork = (input: string) => { 5 | return `processed '${JSON.stringify(input)}'` 6 | } 7 | 8 | export const { POST } = serve( 9 | async context => { 10 | const input = context.requestPayload 11 | const result1 = await context.run("step1", async () => { 12 | const output = someWork(input) 13 | console.log("step 1 input", input, "output", output) 14 | return output 15 | }); 16 | 17 | await context.sleepUntil("sleep1", (Date.now()/1000) + 3) 18 | 19 | const result2 = await context.run("step2", async () => { 20 | const output = someWork(result1) 21 | console.log("step 2 input", result1, "output", output) 22 | return output 23 | }); 24 | 25 | await context.sleep("sleep2", 2) 26 | 27 | await context.run("step3", async () => { 28 | const output = someWork(result2) 29 | console.log("step 3 input", result2, "output", output) 30 | }); 31 | }, 32 | { 33 | env 34 | } 35 | ) 36 | -------------------------------------------------------------------------------- /examples/nextjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workflow", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev -p 3001", 7 | "build": "next build", 8 | "start": "next start -p 3001", 9 | "lint": "next lint", 10 | "test": "vitest run", 11 | "test:watch": "vitest" 12 | }, 13 | "dependencies": { 14 | "@ai-sdk/openai": "^1.0.8", 15 | "@upstash/qstash": "^2.7.12", 16 | "@upstash/workflow": "latest", 17 | "ai": "^4.0.16", 18 | "clsx": "^2.1.1", 19 | "next": "14.2.35", 20 | "react": "^18.3.1", 21 | "react-dom": "^18.3.1", 22 | "tailwind-merge": "^2.5.2", 23 | "zod": "^3.25.76" 24 | }, 25 | "devDependencies": { 26 | "@types/node": "^20.16.5", 27 | "@types/react": "^18.3.5", 28 | "@types/react-dom": "^18.3.0", 29 | "@vitest/ui": "^2.1.8", 30 | "eslint": "^8.0.0", 31 | "eslint-config-next": "14.2.9", 32 | "postcss": "^8.4.45", 33 | "prettier": "^3.3.3", 34 | "prettier-plugin-tailwindcss": "^0.6.6", 35 | "tailwindcss": "^3.4.1", 36 | "typescript": "^5.6.2", 37 | "vitest": "^2.1.8" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/ci/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workflow", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev -p 3001", 7 | "build": "next build", 8 | "start": "next start -p 3001", 9 | "lint": "next lint", 10 | "test": "vitest run", 11 | "test:watch": "vitest" 12 | }, 13 | "dependencies": { 14 | "@upstash/qstash": "^2.7.12", 15 | "@upstash/redis": "^1.34.2", 16 | "@upstash/workflow": "latest", 17 | "@vercel/functions": "^1.5.0", 18 | "clsx": "^2.1.1", 19 | "next": "14.2.35", 20 | "react": "^18.3.1", 21 | "react-dom": "^18.3.1", 22 | "tailwind-merge": "^2.5.2", 23 | "zod": "^3.24.2" 24 | }, 25 | "devDependencies": { 26 | "@types/node": "^20.16.5", 27 | "@types/react": "^18.3.5", 28 | "@types/react-dom": "^18.3.0", 29 | "@vitest/ui": "^2.1.8", 30 | "eslint": "^8.0.0", 31 | "eslint-config-next": "14.2.9", 32 | "postcss": "^8.4.45", 33 | "prettier": "^3.3.3", 34 | "prettier-plugin-tailwindcss": "^0.6.6", 35 | "tailwindcss": "^3.4.1", 36 | "typescript": "^5.6.2", 37 | "vitest": "^2.1.8" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 Upstash, Inc. 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. -------------------------------------------------------------------------------- /examples/sveltekit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sveltekit", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite dev", 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 run", 12 | "test:watch": "vitest" 13 | }, 14 | "devDependencies": { 15 | "@sveltejs/adapter-vercel": "4", 16 | "@sveltejs/kit": "^2.0.0", 17 | "@sveltejs/vite-plugin-svelte": "^3.0.0", 18 | "@vitest/ui": "^2.1.8", 19 | "autoprefixer": "^10.4.19", 20 | "postcss": "^8.4.39", 21 | "svelte": "^5.0.0", 22 | "svelte-check": "^4.0.0", 23 | "tailwindcss": "^3.4.6", 24 | "tslib": "^2.4.1", 25 | "typescript": "^5.0.0", 26 | "vite": "^5.0.3", 27 | "vitest": "^2.1.8" 28 | }, 29 | "type": "module", 30 | "dependencies": { 31 | "@sveltejs/adapter-auto": "^3.3.1", 32 | "@upstash/qstash": "latest", 33 | "@upstash/redis": "^1.34.3", 34 | "@upstash/workflow": "latest" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/serve/utils.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "bun:test"; 2 | import { WorkflowContext } from "../context"; 3 | import { Client } from "@upstash/qstash"; 4 | import { isDisabledWorkflowContext } from "./utils"; 5 | import { DisabledWorkflowContext } from "./authorization"; 6 | 7 | describe("isDisabledWorkflowContext", () => { 8 | test("should return false for context", () => { 9 | const context = new WorkflowContext({ 10 | qstashClient: new Client({ token: "mock" }), 11 | headers: new Headers({}) as Headers, 12 | initialPayload: "", 13 | steps: [], 14 | url: "", 15 | workflowRunId: "", 16 | }); 17 | 18 | expect(isDisabledWorkflowContext(context)).toBeFalse(); 19 | }); 20 | 21 | test("should return true for disabled context", () => { 22 | const context = new DisabledWorkflowContext({ 23 | qstashClient: new Client({ token: "mock" }), 24 | headers: new Headers({}) as Headers, 25 | initialPayload: "", 26 | steps: [], 27 | url: "", 28 | workflowRunId: "", 29 | }); 30 | 31 | expect(isDisabledWorkflowContext(context)).toBeTrue(); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /examples/nextjs/app/-call-qstash/route.ts: -------------------------------------------------------------------------------- 1 | import { Client as WorkflowClient } from '@upstash/workflow' 2 | import { NextRequest } from 'next/server' 3 | 4 | const client = new WorkflowClient({ 5 | baseUrl: process.env.QSTASH_URL!, 6 | token: process.env.QSTASH_TOKEN!, 7 | }) 8 | 9 | export const POST = async (request: NextRequest) => { 10 | const { route, payload } = (await request.json()) as { 11 | route: string 12 | payload: unknown 13 | } 14 | 15 | console.log('Route:', route) 16 | console.log('Payload:', payload) 17 | 18 | try { 19 | const baseUrl = 20 | process.env.UPSTASH_WORKFLOW_URL ?? 21 | request.url.replace('/-call-qstash', '') 22 | 23 | const { workflowRunId } = await client.trigger({ 24 | url: `${baseUrl}/${route}`, 25 | body: payload, 26 | headers: { 27 | "test": "value" 28 | } 29 | }) 30 | 31 | return new Response(JSON.stringify({ workflowRunId }), { status: 200 }) 32 | } catch (error) { 33 | return new Response( 34 | JSON.stringify({ error: `Error when publishing to QStash: ${error}` }), 35 | { 36 | status: 500, 37 | }, 38 | ) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/agents-researcher/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agents-researcher", 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 | "@langchain/community": "^0.3.28", 13 | "@langchain/core": "^0.3.40", 14 | "@langchain/exa": "^0.1.0", 15 | "@tabler/icons-react": "^3.31.0", 16 | "@upstash/redis": "^1.34.4", 17 | "@upstash/workflow": "^0.2.11", 18 | "clsx": "^2.1.1", 19 | "exa-js": "^1.4.10", 20 | "markdown-to-jsx": "^7.7.4", 21 | "next": "15.1.11", 22 | "prismjs": "^1.29.0", 23 | "react": "^19.0.0", 24 | "react-dom": "^19.0.0", 25 | "tailwind-merge": "^3.0.1" 26 | }, 27 | "devDependencies": { 28 | "@eslint/eslintrc": "^3", 29 | "@types/node": "^20", 30 | "@types/prismjs": "^1.26.5", 31 | "@types/react": "^19", 32 | "@types/react-dom": "^19", 33 | "eslint": "^9", 34 | "eslint-config-next": "15.1.6", 35 | "postcss": "^8", 36 | "prettier": "^3.5.3", 37 | "tailwindcss": "^3.4.1", 38 | "typescript": "^5" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/nuxt/server/api/callQstash.ts: -------------------------------------------------------------------------------- 1 | import { Client } from "@upstash/qstash"; 2 | import type { H3Event } from "h3"; 3 | import { defineEventHandler, readBody } from "h3"; 4 | 5 | const client = new Client({ baseUrl: process.env.QSTASH_URL!, token: process.env.QSTASH_TOKEN! }); 6 | 7 | export default defineEventHandler(async (event: H3Event) => { 8 | const { route, payload } = await readBody(event) as { route: string, payload: unknown }; 9 | 10 | try { 11 | const request_ = event.node.req; 12 | const protocol = request_.headers["x-forwarded-proto"]; 13 | const host = request_.headers.host; 14 | const url = `${protocol}://${host}${event.path}`; 15 | 16 | const baseUrl = process.env.UPSTASH_WORKFLOW_URL ?? url?.replace("/api/callQstash", "") 17 | 18 | const { messageId } = await client.publishJSON({ 19 | url: `${baseUrl}/api/${route}`, 20 | body: payload, 21 | }); 22 | 23 | return { 24 | statusCode: 200, 25 | body: JSON.stringify({ messageId }), 26 | }; 27 | } catch (error) { 28 | return { 29 | statusCode: 500, 30 | body: `Error when publishing to QStash: ${error}`, 31 | }; 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "image-gen-with-workflow", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev -p 3001", 7 | "build": "next build", 8 | "start": "next start -p 3001", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@radix-ui/react-tooltip": "^1.1.2", 13 | "@tabler/icons-react": "^3.17.0", 14 | "@upstash/qstash": "^2.7.8", 15 | "@upstash/ratelimit": "^2.0.3", 16 | "@upstash/redis": "^1.34.0", 17 | "@upstash/workflow": "^0.2.2", 18 | "@vercel/functions": "^1.4.1", 19 | "clsx": "^2.1.1", 20 | "next": "14.2.35", 21 | "pretty-ms": "^9.1.0", 22 | "prismjs": "^1.29.0", 23 | "react": "^18.3.1", 24 | "react-dom": "^18.3.1" 25 | }, 26 | "devDependencies": { 27 | "@types/node": "^20.16.5", 28 | "@types/prismjs": "^1.26.4", 29 | "@types/react": "^18.3.8", 30 | "@types/react-dom": "^18.3.0", 31 | "postcss": "^8.4.47", 32 | "prettier": "^3.3.3", 33 | "prettier-plugin-tailwindcss": "^0.6.6", 34 | "tailwind-merge": "^2.5.2", 35 | "tailwindcss": "^3.4.12", 36 | "typescript": "^5.6.2" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/image-gen-with-workflow/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next' 2 | import { Reddit_Mono } from 'next/font/google' 3 | import cx from 'utils/cx' 4 | import './globals.css' 5 | import 'prismjs/themes/prism-tomorrow.css' 6 | 7 | export const metadata: Metadata = { 8 | title: 'Image Generation with Workflow', 9 | description: 'Optimizing Vercel Functions With Upstash Workflow', 10 | icons: { 11 | icon: '/upstash-logo.svg', 12 | }, 13 | } 14 | 15 | const defaultFont = Reddit_Mono({ 16 | variable: '--font-default', 17 | display: 'swap', 18 | style: ['normal'], 19 | weight: ['400', '700'], 20 | subsets: ['latin-ext'], 21 | }) 22 | 23 | export default function RootLayout({ 24 | children, 25 | }: Readonly<{ 26 | children: React.ReactNode 27 | }>) { 28 | return ( 29 | 30 | 36 | {children} 37 | 38 | 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /examples/ci/app/test-routes/wait-for-event/notifier/route.ts: -------------------------------------------------------------------------------- 1 | import { Client } from "@upstash/workflow" 2 | import { NOTIFIER_SECRET, NotifierWorkflowConfig, SDK_EVENT_DATA } from "../constants" 3 | import { waitUntil } from '@vercel/functions'; 4 | 5 | const client = new Client({ baseUrl: process.env.QSTASH_URL, token: process.env.QSTASH_TOKEN! }) 6 | 7 | export const POST = async (request: Request) => { 8 | if (!NOTIFIER_SECRET) { 9 | return new Response("secret not set", { status: 500 }) 10 | } 11 | if (request.headers.get("authorization") !== `Bearer ${NOTIFIER_SECRET}`) { 12 | return new Response("unauthorized.", { status: 401 } ) 13 | } 14 | 15 | const { sdkEventId } = await request.json() as Pick 16 | 17 | const sleepAndNotify = async () => { 18 | 19 | await new Promise(r => setTimeout(r, 1000)); 20 | 21 | const result = await client.notify({ 22 | eventId: sdkEventId, 23 | eventData: SDK_EVENT_DATA 24 | }) 25 | 26 | if (!result.length) { 27 | console.error("failed to notify workflow.") 28 | } 29 | } 30 | 31 | waitUntil(sleepAndNotify()) 32 | return new Response("notifying...", { status: 200 }) 33 | } 34 | -------------------------------------------------------------------------------- /examples/cloudflare-workers/src/serve-many.ts: -------------------------------------------------------------------------------- 1 | import { WorkflowContext } from "@upstash/workflow"; 2 | import { createWorkflow, serveMany } from "@upstash/workflow/cloudflare"; 3 | 4 | const workflowOne = createWorkflow(async (context) => { 5 | await context.run("step 1", async () => { 6 | console.log("workflow one says hi") 7 | }) 8 | 9 | const { body, isCanceled, isFailed } = await context.invoke("invoking other", { 10 | workflow: workflowTwo, 11 | body: "hello from workflow one", 12 | }) 13 | 14 | await context.run("checking invoke results", () => { 15 | console.log("invoke results", { body, isCanceled, isFailed }) 16 | }) 17 | 18 | await context.run("step 2", async () => { 19 | console.log("workflow one says bye") 20 | }) 21 | }) 22 | 23 | const workflowTwo = createWorkflow(async (context: WorkflowContext) => { 24 | await context.run("step 1", async () => { 25 | console.log("workflow two says hi") 26 | }) 27 | 28 | await context.run("step 2", async () => { 29 | console.log("workflow two says bye") 30 | }) 31 | 32 | return "workflow two done" 33 | }, { 34 | retries: 0 35 | }) 36 | 37 | export default serveMany({ 38 | workflowOne, 39 | workflowTwo 40 | }) 41 | -------------------------------------------------------------------------------- /examples/hono/README.md: -------------------------------------------------------------------------------- 1 | # Upstash Workflow Hono Example 2 | 3 | This is an example of how to use Upstash Workflow in a Hono project. You can learn more in [Workflow documentation for Hono](https://upstash.com/docs/qstash/workflow/quickstarts/hono). 4 | 5 | ## Development 6 | 7 | 1. Install the dependencies 8 | 9 | ```bash 10 | npm install 11 | ``` 12 | 13 | 2. [Start the QStash development server](https://upstash.com/docs/workflow/howto/local-development): 14 | 15 | ```bash 16 | npx @upstash/qstash-cli dev 17 | ``` 18 | 19 | 3. Once you run the development server, you will see `QSTASH_URL` and `QSTASH_TOKEN` environment variables for the local development server. Add these to the `.env` file: 20 | 21 | ```bash 22 | QSTASH_URL="***" 23 | QSTASH_TOKEN="***" 24 | ``` 25 | 26 | When you are deploying your app to production, you don't need to set `QSTASH_URL`. You should only set the `QSTASH_TOKEN` environment variable to the token you get from [Upstash Console](https://console.upstash.com/qstash). 27 | 28 | 4. Run your app: 29 | 30 | ```bash 31 | npm run dev 32 | ``` 33 | 34 | 5. Send a `POST` request to the `/workflow` endpoint. 35 | 36 | ```bash 37 | curl -X POST "http://localhost:3001/workflow" -d '{"text": "hello world!"}' 38 | ``` 39 | -------------------------------------------------------------------------------- /examples/ci/app/test-routes/failureUrl/third-party/route.ts: -------------------------------------------------------------------------------- 1 | import { CI_RANDOM_ID_HEADER, CI_ROUTE_HEADER } from "app/ci/constants" 2 | import { saveResultsWithoutContext } from "app/ci/upstash/redis" 3 | import { ANY_STRING, expect } from "app/ci/utils" 4 | import { ERROR_MESSAGE, HEADER, HEADER_VALUE } from "../constants" 5 | 6 | export const POST = async (request: Request) => { 7 | const result = await request.json() as { 8 | body: string, 9 | header: Record, 10 | workflowRunId: string 11 | } 12 | 13 | const errorMessage = atob(result.body) 14 | expect(errorMessage, `{"error":"Error","message":"${ERROR_MESSAGE}","stack":${ANY_STRING}}`) 15 | expect(request.headers.get(HEADER), HEADER_VALUE) 16 | 17 | // get id and route 18 | const randomTestId = request.headers.get(CI_RANDOM_ID_HEADER) 19 | const route = request.headers.get(CI_ROUTE_HEADER) 20 | 21 | if (!route || !randomTestId || !errorMessage) { 22 | throw new Error(`failed to get route, randomTestId or errorMessage. route: ${route}, randomTestId: ${randomTestId}, errorMessage: ${errorMessage}`) 23 | } 24 | 25 | await saveResultsWithoutContext( 26 | route, randomTestId, errorMessage 27 | ) 28 | 29 | return new Response("", { status: 200 }) 30 | } -------------------------------------------------------------------------------- /examples/nextjs/app/serve-many/[...any]/route.ts: -------------------------------------------------------------------------------- 1 | import { WorkflowContext } from "@upstash/workflow"; 2 | import { createWorkflow, serveMany } from "@upstash/workflow/nextjs"; 3 | 4 | const workflowOne = createWorkflow(async (context) => { 5 | await context.run("step 1", async () => { 6 | console.log("workflow one says hi") 7 | }) 8 | 9 | const { body, isCanceled, isFailed } = await context.invoke("invoking other", { 10 | workflow: workflowTwo, 11 | body: "hello from workflow one", 12 | }) 13 | 14 | await context.run("checking invoke results", () => { 15 | console.log("invoke results", { body, isCanceled, isFailed }) 16 | }) 17 | 18 | await context.run("step 2", async () => { 19 | console.log("workflow one says bye") 20 | }) 21 | }) 22 | 23 | const workflowTwo = createWorkflow(async (context: WorkflowContext) => { 24 | await context.run("step 1", async () => { 25 | console.log("workflow two says hi") 26 | }) 27 | 28 | await context.run("step 2", async () => { 29 | console.log("workflow two says bye") 30 | }) 31 | 32 | return "workflow two done" 33 | }, { 34 | retries: 0 35 | }) 36 | 37 | export const { POST } = serveMany( 38 | { 39 | workflowOne, 40 | workflowTwo, 41 | } 42 | ) 43 | -------------------------------------------------------------------------------- /examples/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 | 51 | -------------------------------------------------------------------------------- /examples/nuxt/server/api/serve-many/[...].ts: -------------------------------------------------------------------------------- 1 | import type { WorkflowContext } from "@upstash/workflow"; 2 | import { serveMany, createWorkflow } from "@upstash/workflow/h3"; 3 | 4 | 5 | const workflowOne = createWorkflow(async (context) => { 6 | await context.run("step 1", async () => { 7 | console.log("workflow one says hi") 8 | }) 9 | 10 | const { body, isCanceled, isFailed } = await context.invoke("invoking other", { 11 | workflow: workflowTwo, 12 | body: "hello from workflow one", 13 | }) 14 | 15 | await context.run("checking invoke results", () => { 16 | console.log("invoke results", { body, isCanceled, isFailed }) 17 | }) 18 | 19 | await context.run("step 2", async () => { 20 | console.log("workflow one says bye") 21 | }) 22 | }) 23 | 24 | const workflowTwo = createWorkflow(async (context: WorkflowContext) => { 25 | await context.run("step 1", async () => { 26 | console.log("workflow two says hi") 27 | }) 28 | 29 | await context.run("step 2", async () => { 30 | console.log("workflow two says bye") 31 | }) 32 | 33 | return "workflow two done" 34 | }, { 35 | retries: 0 36 | }) 37 | 38 | const { handler } = serveMany({ 39 | workflowOne, 40 | workflowTwo 41 | }); 42 | 43 | export default handler -------------------------------------------------------------------------------- /examples/sveltekit/src/routes/ci/+server.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "@upstash/workflow/svelte"; 2 | import { env } from '$env/dynamic/private' 3 | import type { RedisEntry } from "../../types"; 4 | import { Redis } from "@upstash/redis" 5 | 6 | export const { POST } = serve( 7 | async (context) => { 8 | const input = context.requestPayload 9 | const result1 = await context.run("step1", async () => { 10 | const output = `step 1 input: '${input}', type: '${typeof input}', stringified input: '${JSON.stringify(input)}'` 11 | return output 12 | }); 13 | 14 | await context.sleep("sleep", 1); 15 | 16 | const secret = context.headers.get("secret-header") 17 | if (!secret) { 18 | console.error("secret not found"); 19 | throw new Error("secret not found. can't end the CI workflow") 20 | } else { 21 | const redis = new Redis({ 22 | url: context.env["UPSTASH_REDIS_REST_URL"], 23 | token: context.env["UPSTASH_REDIS_REST_TOKEN"] 24 | }) 25 | await redis.set( 26 | `ci-cf-ran-${secret}`, 27 | { 28 | secret, 29 | result: result1 30 | }, 31 | { ex: 30 } 32 | ) 33 | } 34 | }, 35 | { 36 | env, 37 | retries: 0, 38 | } 39 | ) 40 | -------------------------------------------------------------------------------- /examples/agents/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agents", 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 | "@agentic/firecrawl": "^7.2.0", 13 | "@agentic/serpapi": "^7.2.0", 14 | "@browserbasehq/sdk": "^2.0.0", 15 | "@langchain/community": "^0.3.26", 16 | "@mozilla/readability": "^0.5.0", 17 | "@upstash/workflow": "0.2.5-agents-2", 18 | "ai": "^4.1.0", 19 | "html-to-text": "^9.0.5", 20 | "jsdom": "^26.0.0", 21 | "next": "15.1.11", 22 | "pdf-parse": "^1.1.1", 23 | "playwright-core": "^1.49.1", 24 | "react": "^19.0.0", 25 | "react-dom": "^19.0.0", 26 | "resend": "^4.1.1", 27 | "zod": "^3.24.1" 28 | }, 29 | "devDependencies": { 30 | "@eslint/eslintrc": "^3", 31 | "@types/html-to-text": "^9.0.4", 32 | "@types/jsdom": "^21.1.7", 33 | "@types/node": "^20", 34 | "@types/pdf-parse": "^1.1.4", 35 | "@types/react": "^19", 36 | "@types/react-dom": "^19", 37 | "eslint": "^9", 38 | "eslint-config-next": "15.1.5", 39 | "postcss": "^8", 40 | "tailwindcss": "^3.4.1", 41 | "typescript": "^5" 42 | } 43 | } 44 | --------------------------------------------------------------------------------