Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
4153e42
add workbench sveltekit
adriandlam Oct 29, 2025
ff11f59
add sveltekit package
adriandlam Oct 29, 2025
49d696c
fix: use js for generated server routes in svelte
adriandlam Oct 29, 2025
d90e965
add test routes for sveltekit workbench
adriandlam Oct 29, 2025
777db32
updates from debugging
ijjk Oct 29, 2025
aa53572
feat: add sveltekit build target
adriandlam Oct 30, 2025
99a03c3
update user sign up workflow workbench sveltekit
adriandlam Oct 30, 2025
f436c92
fix: base builder missing GET route handler for sveltekit
adriandlam Oct 30, 2025
5d844a6
feat: add vercel builder and check for vercel env
adriandlam Oct 30, 2025
1438ac6
refactor: workflowPlugin for sveltekit
adriandlam Oct 30, 2025
cd161c6
ci: add tests to workbench sveltekit
adriandlam Oct 30, 2025
919ce3b
fix: no start command and vercel builder outputs
adriandlam Oct 30, 2025
3f6b249
fix: base builder conditions
adriandlam Oct 30, 2025
d4ca09f
.
adriandlam Oct 30, 2025
8c0cad1
add auto adapter sveltekit
adriandlam Oct 30, 2025
3da001e
fix: disable checking origin for cross site ci stuff
adriandlam Oct 30, 2025
3ac85f2
allow all trusted origins in svelte config
adriandlam Oct 30, 2025
03997dd
fix: add catch for error thrown when waiting for ops
adriandlam Oct 30, 2025
00d487d
fix: sveltekit workbench adapter
adriandlam Oct 30, 2025
92787ef
test
adriandlam Oct 30, 2025
7febb8c
test
adriandlam Oct 30, 2025
2243e0c
refactor: move vercel builder on config resolved
adriandlam Oct 30, 2025
ac4000e
update package json
adriandlam Oct 30, 2025
b0ecab6
add demo workflow trigger
adriandlam Oct 30, 2025
4f1fc09
test letting sveltekit handle route generation
adriandlam Oct 30, 2025
289bc3e
fix: exclude git ignore for local builder outputs
adriandlam Oct 30, 2025
ec35feb
update config
ijjk Oct 30, 2025
4bd162b
add debug logs
ijjk Oct 30, 2025
9b10ed4
update debug
ijjk Oct 30, 2025
f3a71ce
update turbo.json
ijjk Oct 30, 2025
e45e258
fix env check
ijjk Oct 30, 2025
d935d87
another output
ijjk Oct 30, 2025
9003f84
use top-level await
ijjk Oct 30, 2025
c8915d9
ensure vercel functions are patched
ijjk Oct 30, 2025
10a564b
change hook
ijjk Oct 30, 2025
7fa2da9
update
ijjk Oct 30, 2025
26e1ac5
fix spread
ijjk Oct 30, 2025
35ee459
debug
ijjk Oct 30, 2025
d0a38b2
update
ijjk Oct 31, 2025
22ed0ca
chore: remove vercel builder
adriandlam Oct 31, 2025
65c9cb5
chore: update comments in sveltekit workflow package
adriandlam Oct 31, 2025
85b2e12
chore: remove console comment
adriandlam Oct 31, 2025
ca5a5d2
refactor: workflow svelte plugin
adriandlam Oct 31, 2025
e54ec44
refactor: simplify local builder config
adriandlam Oct 31, 2025
a75e298
chore: remove unused deps
adriandlam Oct 31, 2025
4b808af
chore: add comment for workbench svelte app
adriandlam Oct 31, 2025
5c23668
chore: add sveltekit export to workflow
adriandlam Oct 31, 2025
fe82169
export sveltekit from workflow
adriandlam Oct 31, 2025
0c9471f
lockfile
adriandlam Oct 31, 2025
ae6c230
chore: remove unused deps svelte workbench
adriandlam Oct 31, 2025
38a2b7c
update styling
adriandlam Oct 31, 2025
c49cac1
add sveltekit getting started docs
adriandlam Oct 31, 2025
53ef3f9
update sveltekit docs getting started
adriandlam Oct 31, 2025
479ce93
changeset
adriandlam Oct 31, 2025
1729fe5
Apply suggestion from @vercel[bot]
adriandlam Oct 31, 2025
2e8c7f5
use proper env var
adriandlam Oct 31, 2025
604db69
Update packages/sveltekit/src/index.ts
adriandlam Oct 31, 2025
c073b97
Update docs/content/docs/getting-started/sveltekit.mdx
adriandlam Oct 31, 2025
6fff1b7
Document CSRF protection bypass in SvelteKit workbench config (#157)
Copilot Oct 31, 2025
c894384
refactor: deduplicate SvelteKit request conversion logic (#156)
Copilot Oct 31, 2025
1e0297d
Update packages/core/e2e/local-build.test.ts
adriandlam Oct 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@workflow/example-hono",
"@workflow/example-nitro-v3",
"@workflow/example-nitro-v2",
"@workflow/example-nuxt"
"@workflow/example-nuxt",
"@workflow/example-sveltekit"
]
}
3 changes: 2 additions & 1 deletion .changeset/pre.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"nextjs-webpack": "0.0.2-alpha.5",
"@workflow/example-nitro-v3": "0.0.0",
"@workflow/example-nitro-v2": "0.0.0",
"@workflow/example-nuxt": "0.0.0"
"@workflow/example-nuxt": "0.0.0",
"@workflow/example-sveltekit": "0.0.0"
},
"changesets": [
"angry-owls-beg",
Expand Down
9 changes: 9 additions & 0 deletions .changeset/purple-regions-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@workflow/world-local": patch
"@workflow/sveltekit": patch
"workflow": patch
"@workflow/core": patch
"@workflow/cli": patch
---

Add sveltekit workflow integration
10 changes: 9 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ jobs:
project-id: "prj_avRPBF3eWjh6iDNQgmhH4VOg27h0"
- name: "nitro"
project-id: "prj_e7DZirYdLrQKXNrlxg7KmA6ABx8r"
- name: "sveltekit"
project-id: "prj_MqnBLm71ceXGSnm3Fs8i8gBnI23G"
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
Expand Down Expand Up @@ -170,7 +172,7 @@ jobs:
run: cd workbench/${{ matrix.app.name }} && ./resolve-symlinks.sh

- name: Run E2E Tests (Next.js)
if: matrix.app.name != 'nitro'
if: matrix.app.name != 'nitro' && matrix.app.name != 'sveltekit'
run: cd workbench/${{ matrix.app.name }} && pnpm dev & echo "starting tests in 10 seconds" && sleep 10 && pnpm vitest run packages/core/e2e/next-dev.test.ts && pnpm run test:e2e
env:
APP_NAME: ${{ matrix.app.name }}
Expand All @@ -182,6 +184,12 @@ jobs:
env:
APP_NAME: ${{ matrix.app.name }}
DEPLOYMENT_URL: "http://localhost:3000"
- name: Run E2E Tests (SvelteKit)
if: matrix.app.name == 'sveltekit'
run: cd workbench/${{ matrix.app.name }} && pnpm dev & echo "starting tests in 10 seconds" && sleep 10 && pnpm vitest run packages/core/e2e/e2e.test.ts
env:
APP_NAME: ${{ matrix.app.name }}
DEPLOYMENT_URL: "http://localhost:3000"

e2e-local-prod:
name: E2E Local Prod Tests (${{ matrix.app.name }} - ${{ matrix.app.canary && 'canary' || 'stable' }})
Expand Down
20 changes: 10 additions & 10 deletions docs/app/(home)/components/frameworks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -485,11 +485,18 @@ export const Frameworks = () => {
</Badge>
</div>

<Link href="/docs/getting-started/next">
<Next className="size-[56px]" />
<Link href="/docs/getting-started/next" className="relative">
<Next className="size-[56px] relative" />
<Next className="size-[64px] absolute top-0 opacity-15 blur-lg -z-10" />
</Link>
<Link href="/docs/getting-started/nitro">
<Link href="/docs/getting-started/nitro" className="relative">
<Nitro className="size-[56px]" />
<Nitro className="size-[64px] absolute top-0 opacity-15 blur-lg -z-10" />
</Link>

<Link href="/docs/getting-started/sveltekit" className="relative">
<SvelteKit className="size-[56px]" />
<SvelteKit className="size-[64px] absolute top-0 opacity-15 blur-lg -z-10" />
</Link>

<div className="col-span-4 w-full pt-6">
Expand All @@ -508,13 +515,6 @@ export const Frameworks = () => {
</span>
</div>
</div>
<div
className="group relative cursor-pointer size-[48px]"
onClick={() => handleRequest('SvelteKit')}
>
<SvelteKitGray className="size-[48px] opacity-70 transition-all duration-200 group-hover:opacity-0 group-hover:scale-95" />
<SvelteKit className="size-[48px] absolute inset-0 opacity-0 scale-95 transition-all duration-200 group-hover:opacity-100 group-hover:scale-100" />
</div>
<div
className="group relative cursor-pointer size-[60px]"
onClick={() => handleRequest('Nuxt')}
Expand Down
2 changes: 1 addition & 1 deletion docs/app/docs/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function Card({ title, href, className, children, disabled }: CardProps) {
<a
href={href}
className={cn(
'block rounded-lg border border-border p-6 transition hover:border-primary/25 hover:bg-accent no-underline duration-200',
'block rounded-lg border border-border p-6 transition hover:border-primary/25 hover:bg-accent no-underline duration-150 ease-out',
className
)}
>
Expand Down
3 changes: 1 addition & 2 deletions docs/content/docs/getting-started/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ Start by choosing your framework. Each guide will walk you through the steps to
<Nitro className="size-16" />
<span className="font-medium">Nitro</span>
</Card>
<Card href="/docs/getting-started/sveltekit" disabled className="flex flex-col items-center justify-center text-center gap-2">
<Card href="/docs/getting-started/sveltekit" className="flex flex-col items-center justify-center text-center gap-2">
<SvelteKit className="size-16" />
<span className="font-medium">SvelteKit</span>
<Badge variant="secondary">Coming soon</Badge>
</Card>
<Card href="/docs/getting-started/nuxt" disabled className="flex flex-col items-center justify-center text-center gap-2">
<Nuxt className="size-16" />
Expand Down
258 changes: 258 additions & 0 deletions docs/content/docs/getting-started/sveltekit.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
---
title: SvelteKit
---

# SvelteKit

This guide will walk through setting up your first workflow in a SvelteKit app. Along the way, you'll learn more about the concepts that are fundamental to using the development kit in your own projects.

---

<Steps>

<Step>
## Create Your SvelteKit Project

Start by creating a new SvelteKit project. This command will create a new directory named `my-workflow-app` with a minimal setup and setup a SvelteKit project inside it.

```bash
npx sv create my-workflow-app --template=minimal --types=ts --no-add-ons
```

Enter the newly made directory:

```bash
cd my-workflow-app
```

### Install `workflow`

<Tabs items={['npm', 'pnpm', 'yarn']}>
<Tab value="npm">
<CodeBlock>
npm i workflow
</CodeBlock>
</Tab>
<Tab value="pnpm">
<CodeBlock>
pnpm i workflow
</CodeBlock>
</Tab>
<Tab value="yarn">
<CodeBlock>
yarn add workflow
</CodeBlock>
</Tab>
</Tabs>

### Configure Vite

Add `workflowPlugin()` to your Vite config. This enables usage of the `"use workflow"` and `"use step"` directives.

```typescript title="vite.config.ts" lineNumbers
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
import { workflowPlugin } from "workflow/sveltekit"; // [!code highlight]

export default defineConfig({
plugins: [sveltekit(), workflowPlugin()], // [!code highlight]
});
```

### Update `package.json`

Update your `package.json` to include port `3000` for the development server:

```json title="package.json" lineNumbers
{
// ...
"scripts": {
"dev": "vite dev --port 3000"
// ...
},
}
```

<Accordion type="single" collapsible>
<AccordionItem value="typescript-intellisense" className="[&_h3]:my-0">
<AccordionTrigger className="text-sm">
### Setup IntelliSense for TypeScript (Optional)
</AccordionTrigger>
<AccordionContent className="[&_p]:my-2">

To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json`:

```json title="tsconfig.json" lineNumbers
{
"compilerOptions": {
// ... rest of your TypeScript config
"plugins": [
{
"name": "workflow" // [!code highlight]
}
]
}
}
```

</AccordionContent>
</AccordionItem>
</Accordion>

</Step>

<Step>

## Create Your First Workflow

Create a new file for our first workflow:

```typescript title="workflows/user-signup.ts" lineNumbers
import { sleep } from "workflow";

export async function handleUserSignup(email: string) {
"use workflow"; // [!code highlight]

const user = await createUser(email);
await sendWelcomeEmail(user);

await sleep("5s"); // Pause for 5s - doesn't consume any resources
await sendOnboardingEmail(user);

return { userId: user.id, status: "onboarded" };
}

```

We'll fill in those functions next, but let's take a look at this code:

* We define a **workflow** function with the directive `"use workflow"`. Think of the workflow function as the _orchestrator_ of individual **steps**.
* The Workflow DevKit's `sleep` function allows us to suspend execution of the workflow without using up any resources. A sleep can be a few seconds, hours, days, or even months long.

## Create Your Workflow Steps

Let's now define those missing functions.

```typescript title="workflows/user-signup.ts" lineNumbers
import { FatalError } from "workflow"

// Our workflow function defined earlier

async function createUser(email: string) {
"use step"; // [!code highlight]

console.log(`Creating user with email: ${email}`);

// Full Node.js access - database calls, APIs, etc.
return { id: crypto.randomUUID(), email };
}

async function sendWelcomeEmail(user: { id: string; email: string; }) {
"use step"; // [!code highlight]

console.log(`Sending welcome email to user: ${user.id}`);

if (Math.random() < 0.3) {
// By default, steps will be retried for unhandled errors
throw new Error("Retryable!");
}
}

async function sendOnboardingEmail(user: { id: string; email: string}) {
"use step"; // [!code highlight]

if (!user.email.includes("@")) {
// To skip retrying, throw a FatalError instead
throw new FatalError("Invalid Email");
}

console.log(`Sending onboarding email to user: ${user.id}`);
}
```

Taking a look at this code:

* Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
* If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
* Steps can throw a `FatalError` if an error is intentional and should not be retried.

<Callout>
We'll dive deeper into workflows, steps, and other ways to suspend or handle events in [Foundations](/docs/foundations).
</Callout>

</Step>

<Step>

## Create Your Route Handler

To invoke your new workflow, we'll have to add your workflow to a `POST` API route handler, `src/routes/api/signup/+server.ts` with the following code:

```typescript title="src/routes/api/+server.ts"
import { start } from "workflow/api";
import { handleUserSignup } from "../../../../workflows/user-signup";
import { json, type RequestHandler } from "@sveltejs/kit";

export const POST: RequestHandler = async ({
request,
}: {
request: Request;
}) => {
const { email } = await request.json();

// Executes asynchronously and doesn't block your app
await start(handleUserSignup, [email]);

return json({ message: "User signup workflow started" });
};

```

This route handler creates a `POST` request endpoint at `/api/signup` that will trigger your workflow.

<Callout>
Workflows can be triggered from API routes or any server-side code.
</Callout>

</Step>

</Steps>

## Run in development

To start your development server, run the following command in your terminal in the SvelteKit root directory:

```bash
npm run dev
```

Once your development server is running, you can trigger your workflow by running this command in the terminal:

```bash
curl -X POST --json '{"email":"hello@example.com"}' http://localhost:3000/api/signup
```

Check the SvelteKit development server logs to see your workflow execute as well as the steps that are being processed.

Additionally, you can use the [Workflow DevKit CLI or Web UI](/docs/observability) to inspect your workflow runs and steps in detail.

```bash
npx workflow inspect runs
# or add '--web' for an interactive Web based UI
```

<img src="/o11y-ui.png" alt="Workflow DevKit Web UI" />

---

## Deploying to production

Workflow DevKit apps currently work best when deployed to [Vercel](https://vercel.com/home) and needs no special configuration.

Check the [Deploying](/docs/deploying) section to learn how your workflows can be deployed elsewhere.

## Next Steps

* Learn more about the [Foundations](/docs/foundations).
* Check [Errors](/docs/errors) if you encounter issues.
* Explore the [API Reference](/docs/api-reference).
Loading