diff --git a/bun.lockb b/bun.lockb index 8a06aa9..1359c29 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/examples/astro/.env.example b/examples/astro/.env.example new file mode 100644 index 0000000..0996685 --- /dev/null +++ b/examples/astro/.env.example @@ -0,0 +1 @@ +QSTASH_TOKEN="" \ No newline at end of file diff --git a/examples/astro/.gitignore b/examples/astro/.gitignore new file mode 100644 index 0000000..3736f9a --- /dev/null +++ b/examples/astro/.gitignore @@ -0,0 +1,25 @@ +# build output +dist/ + +# generated types +.astro/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store + +# jetbrains setting folder +.idea/ +.vercel diff --git a/examples/astro/.vscode/extensions.json b/examples/astro/.vscode/extensions.json new file mode 100644 index 0000000..22a1505 --- /dev/null +++ b/examples/astro/.vscode/extensions.json @@ -0,0 +1,4 @@ +{ + "recommendations": ["astro-build.astro-vscode"], + "unwantedRecommendations": [] +} diff --git a/examples/astro/.vscode/launch.json b/examples/astro/.vscode/launch.json new file mode 100644 index 0000000..d642209 --- /dev/null +++ b/examples/astro/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "command": "./node_modules/.bin/astro dev", + "name": "Development server", + "request": "launch", + "type": "node-terminal" + } + ] +} diff --git a/examples/astro/README.md b/examples/astro/README.md new file mode 100644 index 0000000..ff8b211 --- /dev/null +++ b/examples/astro/README.md @@ -0,0 +1,49 @@ +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fupstash%2Fqstash-js%2Ftree%2Fmain%2Fexamples%2Fworkflow%2Fastro&env=QSTASH_TOKEN&envDescription=You%20can%20access%20this%20variable%20from%20Upstash%20Console%2C%20under%20QStash%20page.%20&project-name=qstash-workflow-astro&repository-name=qstash-workflow-astro&demo-title=Upstash%20QStash%20Workflow%20Example&demo-description=A%20Astro%20application%20utilizing%20QStash%20Workflows) + +# Upstash Workflow Astro Example + +This is an example of how to use Upstash Workflow with Astro. You can learn more in [Upstash Workflow quickstart documentation](https://upstash.com/docs/workflow/quickstarts/platforms). + + +## Development + +> [!TIP] +> You can use [the `bootstrap.sh` script](https://github.com/upstash/qstash-js/tree/main/examples/workflow) to run this example with a local tunnel. +> +> Simply set the environment variables as explained below and run the following command in the `qstash-js/examples/workflow` directory: +> +> ``` +> bash bootstrap.sh astro +> ``` + +1. Install the dependencies + +```bash +npm install +``` + +1. Get the credentials from the [Upstash Console](https://console.upstash.com/qstash) and add them to the `.env` file. + +```bash +QSTASH_TOKEN= +``` + +3. Open a local tunnel to port of the development server + +```bash +ngrok http 3001 +``` + +Also, set the `UPSTASH_WORKLFOW_URL` environment variable to the public url provided by ngrok. + +4. Run the development server + +```bash +npm run dev +``` + +5. Send a `POST` request to the endpoint. + +```bash +curl -X POST "http://localhost:3001/api/demo-workflow" -d '{"url": "test.com"}' +``` \ No newline at end of file diff --git a/examples/astro/astro.config.mjs b/examples/astro/astro.config.mjs new file mode 100644 index 0000000..0448651 --- /dev/null +++ b/examples/astro/astro.config.mjs @@ -0,0 +1,10 @@ +// @ts-check +import { defineConfig } from 'astro/config'; +import vercel from '@astrojs/vercel/serverless'; + +// https://astro.build/config +export default defineConfig({ + output: "server", + adapter: vercel(), + server: { port: 3001 } +}); diff --git a/examples/astro/package.json b/examples/astro/package.json new file mode 100644 index 0000000..30df0c5 --- /dev/null +++ b/examples/astro/package.json @@ -0,0 +1,22 @@ +{ + "name": "workflow-astro", + "type": "module", + "version": "0.0.1", + "scripts": { + "dev": "astro dev", + "start": "astro dev", + "build": "astro check && astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "@astrojs/check": "^0.9.4", + "@astrojs/vercel": "^7.8.2", + "@upstash/workflow": "0.1.2-canary-astro", + "astro": "^4.16.7", + "typescript": "^5.6.3" + }, + "devDependencies": { + "@types/node": "^22.8.7" + } +} diff --git a/examples/astro/public/favicon.svg b/examples/astro/public/favicon.svg new file mode 100644 index 0000000..f157bd1 --- /dev/null +++ b/examples/astro/public/favicon.svg @@ -0,0 +1,9 @@ + + + + diff --git a/examples/astro/src/components/Card.astro b/examples/astro/src/components/Card.astro new file mode 100644 index 0000000..bd6d597 --- /dev/null +++ b/examples/astro/src/components/Card.astro @@ -0,0 +1,61 @@ +--- +interface Props { + title: string; + body: string; + href: string; +} + +const { href, title, body } = Astro.props; +--- + + + diff --git a/examples/astro/src/env.d.ts b/examples/astro/src/env.d.ts new file mode 100644 index 0000000..3eeda9d --- /dev/null +++ b/examples/astro/src/env.d.ts @@ -0,0 +1,8 @@ +/// +interface ImportMetaEnv { + readonly QSTASH_TOKEN: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/examples/astro/src/layouts/Layout.astro b/examples/astro/src/layouts/Layout.astro new file mode 100644 index 0000000..1810971 --- /dev/null +++ b/examples/astro/src/layouts/Layout.astro @@ -0,0 +1,50 @@ +--- +interface Props { + title: string; +} + +const { title } = Astro.props; +--- + + + + + + + + + + {title} + + + + + + diff --git a/examples/astro/src/pages/api/demo-workflow.ts b/examples/astro/src/pages/api/demo-workflow.ts new file mode 100644 index 0000000..9810c2a --- /dev/null +++ b/examples/astro/src/pages/api/demo-workflow.ts @@ -0,0 +1,27 @@ +import { serve } from "@upstash/workflow/astro"; + +const someWork = (input: string) => { + return `processed '${JSON.stringify(input)}'` +} + +export const { POST } = serve<{ url: string }>(async (context) => { + const input = context.requestPayload.url + const result1 = await context.run('step1', async () => { + const output = someWork(input) + console.log('step 1 input', input, 'output', output) + return output + }) + + await context.run('step2', async () => { + const output = someWork(result1) + console.log('step 2 input', result1, 'output', output) + }) +}, { + // env must be passed in astro. + // for local dev, we need import.meta.env. + // For deployment, we need process.env: + env: { + ...process.env, + ...import.meta.env + } +}) \ No newline at end of file diff --git a/examples/astro/src/pages/index.astro b/examples/astro/src/pages/index.astro new file mode 100644 index 0000000..fb62628 --- /dev/null +++ b/examples/astro/src/pages/index.astro @@ -0,0 +1,123 @@ +--- +import Layout from '../layouts/Layout.astro'; +import Card from '../components/Card.astro'; +--- + + +
+ +

Welcome to Astro

+

+ To get started, open the directory src/pages in your project.
+ Code Challenge: Tweak the "Welcome to Astro" message above. +

+ +
+
+ + diff --git a/examples/astro/tsconfig.json b/examples/astro/tsconfig.json new file mode 100644 index 0000000..bcbf8b5 --- /dev/null +++ b/examples/astro/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "astro/tsconfigs/strict" +} diff --git a/package.json b/package.json index a20f604..5067380 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,10 @@ "./cloudflare": { "import": "./cloudflare.mjs", "require": "./cloudflare.js" + }, + "./astro": { + "import": "./astro.mjs", + "require": "./astro.js" } }, "scripts": { @@ -77,6 +81,7 @@ "@solidjs/start": "^1.0.8", "@sveltejs/kit": "^2.6.1", "@types/bun": "^1.1.10", + "astro": "^4.16.7", "eslint": "^9.11.1", "eslint-plugin-unicorn": "^55.0.0", "globals": "^15.10.0", diff --git a/platforms/astro.ts b/platforms/astro.ts new file mode 100644 index 0000000..8951d5f --- /dev/null +++ b/platforms/astro.ts @@ -0,0 +1,23 @@ +import type { APIContext, APIRoute } from "astro"; + +import type { WorkflowServeOptions, WorkflowContext } from "../src"; +import { serve as serveBase } from "../src"; + +export function serve( + routeFunction: ( + workflowContext: WorkflowContext, + apiContext: APIContext + ) => Promise, + options?: Omit, "onStepFinish"> +) { + const POST: APIRoute = (apiContext) => { + const { handler } = serveBase( + (workflowContext) => routeFunction(workflowContext, apiContext), + options + ); + + return handler(apiContext.request); + }; + + return { POST }; +} diff --git a/tsup.config.ts b/tsup.config.ts index 5db56aa..e67fecd 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -9,6 +9,7 @@ export default defineConfig({ solidjs: "./platforms/solidjs.ts", hono: "./platforms/hono.ts", cloudflare: "./platforms/cloudflare.ts", + astro: "./platforms/astro.ts", }, format: ["cjs", "esm"], clean: true,