npm package: @sveltext/adapter-cloudflare-platform
Description: SvelteKit adapter for Cloudflare Platform: cron, queues, bindings, wrangler validation, and typegen.
Latest version: 0.1.0

# @sveltext/adapter-cloudflare-platform

SvelteKit adapter focused on **Cloudflare Workers** deployments. It mirrors the official `@sveltejs/adapter-cloudflare` ergonomics, adds first-class support for Cloudflare cron/queue jobs, and generates Wrangler-aware typings so you can adopt Workers without glue code.

> **Paired runtime** – install and use [`@sveltext/cloudflare-platform-runtime`](../cloudflare-platform-runtime/README.md) in your app to declare cron and queue jobs with a remote-functions style API.

---

## Table of contents

1. [Why another adapter?](#why-another-adapter)  
2. [Installation](#installation)  
3. [Quick start](#quick-start)  
4. [Configuration reference](#configuration-reference)  
5. [Guided migration from `@sveltejs/adapter-cloudflare`](#migration-guide)  
6. [Cron & queue workflow](#cron--queue-workflow)  
7. [Manual triggers](#manual-triggers)  
8. [Wrangler validation & hints](#wrangler-validation--hints)  
9. [Environment typing](#environment-typing)  
10. [Developer experience](#developer-experience)  
11. [CLI utilities](#cli-utilities)  
12. [FAQ](#faq)

---

## Why another adapter?

- **Workers-only** focus – assumes you target Workers (not Pages) so the generated worker, validation, and messages can rely on Workers features and nudge you toward best practices.
- **Jobs-first** ergonomics – remote-style cron/queue helpers ship in the runtime, and the adapter serialises job metadata into the worker bundle so cron/queue registration has zero runtime overhead.
- **Wrangler-aware** typing – the adapter reads your `wrangler.toml` during build and generates `.svelte-kit/types/cf-platform.d.ts` with bindings (`kv_namespaces`, queues, services, workflows, Hyperdrive, Browser Rendering, etc.).
- **Actionable validation** – missing queue producers, cron schedules, or workflow compatibility dates surface as build errors with copy/paste TOML snippets.

---

## Installation

```bash
pnpm add -D @sveltext/adapter-cloudflare-platform @sveltext/cloudflare-platform-runtime
# or: npm install --save-dev …
```

In your `svelte.config.js`:

```js
import cloudflarePlatform from '@sveltext/adapter-cloudflare-platform';

export default {
  kit: {
    adapter: cloudflarePlatform({
      config: 'wrangler.toml',          // optional – autodetected by default
      fallback: 'plaintext',            // or 'spa'
      manual: { base: '/__jobs', enabled: false },
      validate: { wrangler: 'error' }   // 'warn' | 'off'
    })
  }
};
```

Ensure `wrangler.toml` targets Workers (not Pages):

```toml
main = "./.cloudflare/_worker.js"
assets = { directory = ".cloudflare", binding = "ASSETS", not_found_handling = "single-page-application" }

compatibility_date = "2024-10-22" # or newer, required for Workflows support
```

---

## Quick start

1. **Declare jobs**

   ```ts
   // src/routes/+page.server.ts
   import { cron, queue } from '@sveltext/cloudflare-platform-runtime';

   export const nightly = cron({ schedule: '0 4 * * *' }, async ({ log }) => {
     log.info('Nightly job');
   });

   export const emails = queue(
     { binding: 'MAILS', consume: true, deadLetter: 'MAILS_DLQ' },
     async (message) => {
       await sendEmail(message.body);
     }
   );
   ```

2. **Describe bindings**

   ```toml
   [[queues.producers]]
   binding = "MAILS"
   queue = "project-mails"

   [[queues.consumers]]
   queue = "project-mails"
   dead_letter_queue = "project-mails-dlq"

   [[queues.producers]]
   binding = "MAILS_DLQ"
   queue = "project-mails-dlq"
   ```

3. **Build**

   ```bash
   pnpm run build
   ```

   - Generates `.cloudflare/_worker.js` and static assets.
   - Serialises your job metadata into the worker file (no manifest scanning at runtime).
   - Creates `.svelte-kit/types/cf-platform.d.ts` with typed bindings + warnings if wrangler config is incomplete.

4. **Deploy**

   ```bash
   pnpm exec wrangler deploy
   ```

---

## Configuration reference

| Option        | Type / Default                             | Description |
| ------------- | ------------------------------------------ | ----------- |
| `config`      | `string?`                                  | Path to `wrangler.toml`/JSON. Auto-detected if omitted. |
| `assetsOut`   | `string` (default: `'.cloudflare'`)        | Output folder for static assets when `assets.directory` isn’t set. |
| `fallback`    | `'plaintext' | 'spa'` (default: `'plaintext'`) | Whether to generate an SPA fallback. When `'spa'`, `index.html` is created regardless of Wrangler config (you’ll see a warning if `not_found_handling` isn’t `"single-page-application"`). |
| `manual`      | `{ base?: string \| null; enabled?: boolean; headers?: Record<string,string> }` | Configure manual cron triggers. `base = null` disables HTTP endpoints entirely. |
| `validate`    | `{ wrangler?: 'error' | 'warn' | 'off' }` (default: `'error'`) | Severity for Wrangler validation. |
| `platformProxy` | `Parameters<typeof wrangler.getPlatformProxy>[0]` | Forwarded to Wrangler for local emulation. |

---

## Migration guide

Coming from `@sveltejs/adapter-cloudflare`:

| Area | What changed | How to adapt |
| ---- | ------------ | ------------ |
| Workers vs Pages | This adapter targets Workers only. | Remove Pages-specific config (`pages_build_output_dir`, `site`). Keep `assets.directory` + `main`. |
| Cron/queue jobs | Jobs live in `.remote.ts` (or other server modules) using runtime helpers. | Replace manual `export const onCron` / queue handlers with `cron()` / `queue()` helpers. |
| Manual triggers | Automatic HTTP endpoints available at `/__jobs/cron/:name`. | Configure `manual.base` / `enabled` / headers. |
| Typings | Adapter generates `.svelte-kit/types/cf-platform.d.ts` automatically; optional CLI mirrors Wrangler’s `types`. | Remove old `wrangler types` outputs from your repo, or keep them if needed—our generated file lives under `.svelte-kit/`. |
| Validation | Missing queue producers, cron schedules, workflow compatibility, SPA fallback etc. throw early. | Update `wrangler.toml` according to hints (copy & paste the suggested TOML slices). |
| Worker boot | Job inventory is embedded; there’s no runtime manifest walk. | No changes needed—just enjoy faster cold starts. |

---

## Cron & queue workflow

1. Declare jobs with the runtime helper (any `.server.ts`, `.remote.ts`, or server module).  
2. Build: the adapter scans the generated SvelteKit manifest, collects job metadata, and serialises it into `files/worker.js`.  
3. Runtime: the worker lazily `import()`s only the modules needed for cron/queue execution, so cold starts stay lean.  
4. Manual triggers: available at `/<manual.base>/cron/:route`, respecting global + per-job headers.  
5. Queue producers get stubbed during local dev if bindings are missing, with `console.info` logs so you see payloads.

Example manual trigger for local testing:

```bash
curl -X POST "http://127.0.0.1:8787/__jobs/cron/nightly" \
  -H "x-secret: dev-token"
```

---

## Manual triggers

- Configure `manual` in the adapter options:

  ```js
  manual: {
    base: '/__jobs',
    enabled: process.env.NODE_ENV !== 'production',
    headers: { 'x-secret': process.env.JOBS_SECRET ?? '' }
  }
  ```

- For each `cron()` job with `manual: true` or an explicit `manual.route`, the worker exposes `/{base}/cron/{route}`.
- Required headers merge in the following order (lowest precedence first):
  1. Adapter-level `manual.headers`
  2. Deprecated `cron({ manualHeaders })`
  3. Per-job `cron({ manual: { headers } })`

If manual triggers are disabled (`base: null` or `enabled: false`), endpoints return `404`.

---

## Wrangler validation & hints

- **Cron schedules** – cross-checked with `triggers.crons[]`. Missing schedules produce an error with the JSON snippet you can paste.
- **Queue producers/consumers** – validates `queues.producers` bindings, queue names, and `dead_letter_queue`. Missing items return a nicely formatted TOML block.
- **Workflows** – warns if `compatibility_date` is older than `2024-10-22`.
- **Remote-only bindings** – surfaces a warning telling you to run `wrangler dev --remote` (for mTLS certificates, Vectorize, Browser Rendering, Hyperdrive, AI).
- **Legacy exports** – if any job still exports raw `cron`/`queue` handlers (without runtime metadata), the build fails with a clear migration message.

You can demote validation with `validate: { wrangler: 'warn' }`, but errors ensure you don’t ship a broken worker.

---

## Environment typing

During `adapt` we read `wrangler.toml` and generate `.svelte-kit/types/cf-platform.d.ts` with entries such as:

```ts
declare global {
  namespace App {
    interface Platform {
      env: {
        ASSETS: Fetcher;
        DB: D1Database;
        MAILS: Queue;
        MAILS_DLQ: Queue;
        MAIL_SERVICE: Fetcher;
        WORKFLOW: Workflow;
        VECTOR: VectorizeIndex;
        // …
        [key: string]: unknown;
      };
    }
  }
}
```

We import both `@cloudflare/workers-types` and `@cloudflare/workers-types/experimental`, so bleeding-edge bindings resolve without manual augmentation.

> Need standalone typings? Use the CLI below or run `wrangler types --experimental-typings`. Either way, keep `.svelte-kit/types/` out of version control.

---

## Developer experience

### `adapter.emulate()`

When using Vite preview or the SvelteKit dev server:

```ts
const adapter = cloudflarePlatform();
const { platform, jobs } = adapter.emulate();

const { env } = await platform();
jobs.log();        // pretty-prints cron + queue definitions
jobs.definitions() // returns JSON metadata
```

### Local queues / cron

- `queue()` producers stub `env[binding].send()` if the binding doesn’t exist during dev, logging payloads so you can verify messages.
- Cron jobs are invokable via the manual HTTP endpoints described earlier.

### Remote development hints

Bindings that Cloudflare can’t simulate locally (mTLS certs, Hyperdrive, Vectorize, Browser Rendering, Workers AI) trigger a warning suggesting `wrangler dev --remote` / `--remote-binds`.

---

## CLI utilities

The packaged binary mirrors Wrangler’s output but stays inside your project:

```bash
pnpm exec sveltext-cf-typegen --config wrangler.toml
```

Outputs `.svelte-kit/types/cf-platform.d.ts` using the same generator the adapter calls during `adapt`. Useful when you want the types without a full SvelteKit build.

CLI flags:

| Flag        | Description                              |
| ----------- | ---------------------------------------- |
| `--config`  | Path to `wrangler.toml` / JSON.          |

---

## FAQ

### Do I need to check in `.cloudflare` assets?

No. Treat the build output the same way you do with other SvelteKit adapters: run `pnpm build`, then let Wrangler deploy from `.cloudflare/`. Ignore the directory in git if you prefer.

### How do I deploy to Cloudflare Pages?

The adapter assumes Workers deployments. For Pages, stick with `@sveltejs/adapter-cloudflare` – it handles `_routes.json`, assets routing, and other Pages specifics.

### Can I combine this with other adapters?

Not directly. SvelteKit loads exactly one adapter per configuration file. If you deploy to multiple platforms, manage separate `svelte.config.*` files or use project-specific scripts.

---

Questions or feedback? Open an issue or start a discussion – we want to make Cloudflare Workers feel completely native in SvelteKit.