diff --git a/examples/sveltekit-pages/.env.example b/examples/sveltekit-pages/.env.example
new file mode 100644
index 0000000..06348fd
--- /dev/null
+++ b/examples/sveltekit-pages/.env.example
@@ -0,0 +1 @@
+DATABASE_URL=file:.wrangler/state/v3/d1/miniflare-D1DatabaseObject/your-d1.sqlite
diff --git a/examples/sveltekit-pages/.gitignore b/examples/sveltekit-pages/.gitignore
new file mode 100644
index 0000000..f28151d
--- /dev/null
+++ b/examples/sveltekit-pages/.gitignore
@@ -0,0 +1,28 @@
+node_modules
+
+# Output
+.output
+.vercel
+.netlify
+.wrangler
+/.svelte-kit
+/build
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Env
+.env
+.env.*
+!.env.example
+!.env.test
+
+# Vite
+vite.config.js.timestamp-*
+vite.config.ts.timestamp-*
+
+# SQLite
+*.db
+
+.dev.vars*
diff --git a/examples/sveltekit-pages/.npmrc b/examples/sveltekit-pages/.npmrc
new file mode 100644
index 0000000..b6f27f1
--- /dev/null
+++ b/examples/sveltekit-pages/.npmrc
@@ -0,0 +1 @@
+engine-strict=true
diff --git a/examples/sveltekit-pages/.prettierignore b/examples/sveltekit-pages/.prettierignore
new file mode 100644
index 0000000..6562bcb
--- /dev/null
+++ b/examples/sveltekit-pages/.prettierignore
@@ -0,0 +1,6 @@
+# Package Managers
+package-lock.json
+pnpm-lock.yaml
+yarn.lock
+bun.lock
+bun.lockb
diff --git a/examples/sveltekit-pages/.prettierrc b/examples/sveltekit-pages/.prettierrc
new file mode 100644
index 0000000..7ebb855
--- /dev/null
+++ b/examples/sveltekit-pages/.prettierrc
@@ -0,0 +1,15 @@
+{
+ "useTabs": true,
+ "singleQuote": true,
+ "trailingComma": "none",
+ "printWidth": 100,
+ "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
+ "overrides": [
+ {
+ "files": "*.svelte",
+ "options": {
+ "parser": "svelte"
+ }
+ }
+ ]
+}
diff --git a/examples/sveltekit-pages/.vscode/settings.json b/examples/sveltekit-pages/.vscode/settings.json
new file mode 100644
index 0000000..4110aab
--- /dev/null
+++ b/examples/sveltekit-pages/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "files.associations": {
+ "wrangler.json": "jsonc"
+ }
+}
diff --git a/examples/sveltekit-pages/README.md b/examples/sveltekit-pages/README.md
new file mode 100644
index 0000000..9312c05
--- /dev/null
+++ b/examples/sveltekit-pages/README.md
@@ -0,0 +1,106 @@
+# Better Auth Cloudflare SvelteKit Example (deploy on Cloudflare Pages)
+
+This example demonstrates how to integrate [Better Auth](https://github.com/better-auth/better-auth) with [SvelteKit](https://svelte.dev/docs/kit/) on Cloudflare Pages using the `better-auth-cloudflare` plugin.
+
+## Features
+
+- **User Authentication**: Secure sign-in options including email/password and passwordless logins.
+- **Session Management**: Leverages Cloudflare KV for efficient session storage.
+- **File Management**: Upload, download, and manage files securely using Cloudflare R2.
+- **Data Persistence**: Utilizes Cloudflare D1 for database storage.
+- **Geolocation**: Fetches and displays user's location data via Cloudflare headers.
+- **Protected Routes**: Example of a dashboard page accessible only to authenticated users.
+
+## Getting Started
+
+### Prerequisites
+
+- You will need a [Cloudflare account](https://dash.cloudflare.com/sign-up).
+- You will need [Node.js](https://nodejs.org/en/) installed, preferably the latest LTS version.
+- This project uses `pnpm` as a package manager, but you can use `npm` or `bun`.
+
+### Installation
+
+#### 1. Navigate to this directory
+
+```shell
+cd examples/sveltekit-pages && pnpm install
+```
+
+This directory initialized with `bun create cloudflare@latest sveltekit-pages --framework=svelte --platform=pages`. You can create with `npm` or `bun`
+
+#### 2. Create Cloudflare Storages (D1, KV and R2)
+
+To run the demo project, create a D1 Database and KV Storage in your Cloudflare account using the following CLI commands. (KV is optional and used for secondary session storage).
+
+```shell
+pnpm wrangler d1 create your-sveltekit-pages-d1
+pnpm wrangler kv namespace create "SVELTEKIT_PAGES_AUTH_SESSION_KV"
+pnpm wrangler kv namespace create "SVELTEKIT_PAGES_AUTH_SESSION_KV" --preview #This is for `wrangler pages dev`
+pnpm wrangler r2 bucket create "your-sveltekit-pages-assets"
+```
+
+#### 3. Configure your Cloudflare bindings in `wrangler.jsonc`
+
+Update the information in `wrangler.jsonc` based on the resources created in step 2.
+
+```wrangler.jsonc
+"d1_databases": [
+ {
+ "binding": "DB",
+ "database_name": "your-sveltekit-pages-d1",
+ "database_id": "your-sveltekit-pages-d1-id",
+ "migrations_dir": "drizzle"
+ }
+],
+"kv_namespaces": [
+ {
+ "binding": "SVELTEKIT_PAGES_AUTH_SESSION_KV",
+ "id": "your-sveltekit-pages-auth-session-kv-id",
+ "preview_id": "your-sveltekit-pages-auth-session-kv-preview-id"
+ }
+],
+"r2_buckets": [
+ {
+ "binding": "SVELTEKIT_PAGES_ASSETS",
+ "bucket_name": "your-sveltekit-pages-assets",
+ "preview_bucket_name": "your-sveltekit-pages-assets-preview"
+ }
+]
+```
+
+If you used a different name when creating the resources with the Wrangler CLI, you must also change the name in the `binding:` section. Additionally, run `pnpm run cf-typegen` to update the `worker-configuration.d.ts` file.
+
+In the D1 configuration, add `"migrations_dir": "drizzle"`. This is the migration path for the Drizzle ORM.
+
+> Support for `wrangler.jsonc` requires wrangler version v3.91.0 or higher.[^1]
+
+#### 4. Apply Database Migrations
+
+After configuring your bindings, apply the database schema to your D1 database.
+
+```shell
+# For production environment
+pnpm wrangler d1 migrations apply sveltekit-pages-d1
+
+# For local development
+pnpm wrangler d1 migrations apply sveltekit-pages-d1 --local
+```
+
+### Local Development
+
+To start the local development server, run the following command:
+
+```shell
+pnpm run dev
+```
+
+This command starts the SvelteKit development server and uses `wrangler` to simulate the Cloudflare environment locally. This includes access to your local D1 database and KV namespaces.
+
+### Deploy
+
+```shell
+pnpm run deploy
+```
+
+[^1]: [Configuration - Wrangler · Cloudflare Workers docs](https://developers.cloudflare.com/workers/wrangler/configuration/)
diff --git a/examples/sveltekit-pages/components.json b/examples/sveltekit-pages/components.json
new file mode 100644
index 0000000..c5d91b4
--- /dev/null
+++ b/examples/sveltekit-pages/components.json
@@ -0,0 +1,16 @@
+{
+ "$schema": "https://shadcn-svelte.com/schema.json",
+ "tailwind": {
+ "css": "src/app.css",
+ "baseColor": "slate"
+ },
+ "aliases": {
+ "components": "$lib/components",
+ "utils": "$lib/utils",
+ "ui": "$lib/components/ui",
+ "hooks": "$lib/hooks",
+ "lib": "$lib"
+ },
+ "typescript": true,
+ "registry": "https://shadcn-svelte.com/registry"
+}
diff --git a/examples/sveltekit-pages/drizzle.config.ts b/examples/sveltekit-pages/drizzle.config.ts
new file mode 100644
index 0000000..317f310
--- /dev/null
+++ b/examples/sveltekit-pages/drizzle.config.ts
@@ -0,0 +1,11 @@
+import { defineConfig } from 'drizzle-kit';
+
+if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is not set');
+
+export default defineConfig({
+ schema: './src/lib/server/db/schema.ts',
+ dialect: 'sqlite',
+ dbCredentials: { url: process.env.DATABASE_URL },
+ verbose: true,
+ strict: true
+});
diff --git a/examples/sveltekit-pages/drizzle/0000_parched_glorian.sql b/examples/sveltekit-pages/drizzle/0000_parched_glorian.sql
new file mode 100644
index 0000000..2f7ce0f
--- /dev/null
+++ b/examples/sveltekit-pages/drizzle/0000_parched_glorian.sql
@@ -0,0 +1,73 @@
+CREATE TABLE `accounts` (
+ `id` text PRIMARY KEY NOT NULL,
+ `account_id` text NOT NULL,
+ `provider_id` text NOT NULL,
+ `user_id` text NOT NULL,
+ `access_token` text,
+ `refresh_token` text,
+ `id_token` text,
+ `access_token_expires_at` integer,
+ `refresh_token_expires_at` integer,
+ `scope` text,
+ `password` text,
+ `created_at` integer NOT NULL,
+ `updated_at` integer NOT NULL,
+ FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE TABLE `sessions` (
+ `id` text PRIMARY KEY NOT NULL,
+ `expires_at` integer NOT NULL,
+ `token` text NOT NULL,
+ `created_at` integer NOT NULL,
+ `updated_at` integer NOT NULL,
+ `ip_address` text,
+ `user_agent` text,
+ `user_id` text NOT NULL,
+ `timezone` text,
+ `city` text,
+ `country` text,
+ `region` text,
+ `region_code` text,
+ `colo` text,
+ `latitude` text,
+ `longitude` text,
+ FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `sessions_token_unique` ON `sessions` (`token`);--> statement-breakpoint
+CREATE TABLE `user_files` (
+ `id` text PRIMARY KEY NOT NULL,
+ `user_id` text NOT NULL,
+ `filename` text NOT NULL,
+ `original_name` text NOT NULL,
+ `content_type` text NOT NULL,
+ `size` integer NOT NULL,
+ `r2_key` text NOT NULL,
+ `uploaded_at` integer NOT NULL,
+ `category` text,
+ `is_public` integer,
+ `description` text,
+ FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
+);
+--> statement-breakpoint
+CREATE TABLE `users` (
+ `id` text PRIMARY KEY NOT NULL,
+ `name` text NOT NULL,
+ `email` text NOT NULL,
+ `email_verified` integer NOT NULL,
+ `image` text,
+ `created_at` integer NOT NULL,
+ `updated_at` integer NOT NULL,
+ `is_anonymous` integer
+);
+--> statement-breakpoint
+CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);--> statement-breakpoint
+CREATE TABLE `verifications` (
+ `id` text PRIMARY KEY NOT NULL,
+ `identifier` text NOT NULL,
+ `value` text NOT NULL,
+ `expires_at` integer NOT NULL,
+ `created_at` integer,
+ `updated_at` integer
+);
diff --git a/examples/sveltekit-pages/drizzle/meta/0000_snapshot.json b/examples/sveltekit-pages/drizzle/meta/0000_snapshot.json
new file mode 100644
index 0000000..7bc8efd
--- /dev/null
+++ b/examples/sveltekit-pages/drizzle/meta/0000_snapshot.json
@@ -0,0 +1,488 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "315afb53-fd27-4d2e-9012-f01df830c9d9",
+ "prevId": "00000000-0000-0000-0000-000000000000",
+ "tables": {
+ "accounts": {
+ "name": "accounts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "provider_id": {
+ "name": "provider_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "id_token": {
+ "name": "id_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "access_token_expires_at": {
+ "name": "access_token_expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "refresh_token_expires_at": {
+ "name": "refresh_token_expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "scope": {
+ "name": "scope",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "password": {
+ "name": "password",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "accounts_user_id_users_id_fk": {
+ "name": "accounts_user_id_users_id_fk",
+ "tableFrom": "accounts",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "sessions": {
+ "name": "sessions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "ip_address": {
+ "name": "ip_address",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "user_agent": {
+ "name": "user_agent",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "timezone": {
+ "name": "timezone",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "city": {
+ "name": "city",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "country": {
+ "name": "country",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "region_code": {
+ "name": "region_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "colo": {
+ "name": "colo",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "latitude": {
+ "name": "latitude",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "longitude": {
+ "name": "longitude",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "sessions_token_unique": {
+ "name": "sessions_token_unique",
+ "columns": ["token"],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "sessions_user_id_users_id_fk": {
+ "name": "sessions_user_id_users_id_fk",
+ "tableFrom": "sessions",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "user_files": {
+ "name": "user_files",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "filename": {
+ "name": "filename",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "original_name": {
+ "name": "original_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "content_type": {
+ "name": "content_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "size": {
+ "name": "size",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "r2_key": {
+ "name": "r2_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "uploaded_at": {
+ "name": "uploaded_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "category": {
+ "name": "category",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "is_public": {
+ "name": "is_public",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "user_files_user_id_users_id_fk": {
+ "name": "user_files_user_id_users_id_fk",
+ "tableFrom": "user_files",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "users": {
+ "name": "users",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email_verified": {
+ "name": "email_verified",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "is_anonymous": {
+ "name": "is_anonymous",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "users_email_unique": {
+ "name": "users_email_unique",
+ "columns": ["email"],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "verifications": {
+ "name": "verifications",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "identifier": {
+ "name": "identifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
diff --git a/examples/sveltekit-pages/drizzle/meta/_journal.json b/examples/sveltekit-pages/drizzle/meta/_journal.json
new file mode 100644
index 0000000..79d064b
--- /dev/null
+++ b/examples/sveltekit-pages/drizzle/meta/_journal.json
@@ -0,0 +1,13 @@
+{
+ "version": "7",
+ "dialect": "sqlite",
+ "entries": [
+ {
+ "idx": 0,
+ "version": "6",
+ "when": 1750676711714,
+ "tag": "0000_parched_glorian",
+ "breakpoints": true
+ }
+ ]
+}
diff --git a/examples/sveltekit-pages/eslint.config.js b/examples/sveltekit-pages/eslint.config.js
new file mode 100644
index 0000000..ef07d32
--- /dev/null
+++ b/examples/sveltekit-pages/eslint.config.js
@@ -0,0 +1,36 @@
+import prettier from 'eslint-config-prettier';
+import js from '@eslint/js';
+import { includeIgnoreFile } from '@eslint/compat';
+import svelte from 'eslint-plugin-svelte';
+import globals from 'globals';
+import { fileURLToPath } from 'node:url';
+import ts from 'typescript-eslint';
+import svelteConfig from './svelte.config.js';
+
+const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
+
+export default ts.config(
+ includeIgnoreFile(gitignorePath),
+ js.configs.recommended,
+ ...ts.configs.recommended,
+ ...svelte.configs.recommended,
+ prettier,
+ ...svelte.configs.prettier,
+ {
+ languageOptions: {
+ globals: { ...globals.browser, ...globals.node }
+ },
+ rules: { 'no-undef': 'off' }
+ },
+ {
+ files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
+ languageOptions: {
+ parserOptions: {
+ projectService: true,
+ extraFileExtensions: ['.svelte'],
+ parser: ts.parser,
+ svelteConfig
+ }
+ }
+ }
+);
diff --git a/examples/sveltekit-pages/package.json b/examples/sveltekit-pages/package.json
new file mode 100644
index 0000000..2205c93
--- /dev/null
+++ b/examples/sveltekit-pages/package.json
@@ -0,0 +1,64 @@
+{
+ "name": "sveltekit-pages",
+ "private": true,
+ "version": "0.0.1",
+ "type": "module",
+ "scripts": {
+ "dev": "vite dev",
+ "build": "vite build",
+ "preview": "pnpm run build && wrangler pages dev",
+ "prepare": "svelte-kit sync || echo ''",
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
+ "format": "prettier --write .",
+ "lint": "prettier --check . && eslint .",
+ "clean": "rm -rf .svelte-kit .vite && rm -rf node_modules",
+ "deploy": "pnpm run build && wrangler pages deploy",
+ "cf-typegen": "pnpm wrangler types src/worker-configuration.d.ts",
+ "db:push": "drizzle-kit push",
+ "db:generate": "drizzle-kit generate",
+ "db:migrate:dev": "pnpm wrangler d1 migrations apply your-sveltekit-pages-d1 --local",
+ "db:migrate:prod": "pnpm wrangler d1 migrations apply your-sveltekit-pages-d1 --remote",
+ "db:studio": "drizzle-kit studio"
+ },
+ "devDependencies": {
+ "@cloudflare/workers-types": "^4.20250620.0",
+ "@eslint/compat": "^1.2.5",
+ "@eslint/js": "^9.18.0",
+ "@iconify-json/lucide": "^1.2.49",
+ "@internationalized/date": "^3.8.1",
+ "@libsql/client": "^0.15.9",
+ "@lucide/svelte": "^0.515.0",
+ "@sveltejs/adapter-cloudflare": "^7.0.4",
+ "@sveltejs/kit": "^2.16.0",
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
+ "@tailwindcss/vite": "^4.0.0",
+ "@types/node": "^22",
+ "bits-ui": "^2.8.6",
+ "clsx": "^2.1.1",
+ "drizzle-kit": "^0.30.2",
+ "eslint": "^9.18.0",
+ "eslint-config-prettier": "^10.0.1",
+ "eslint-plugin-svelte": "^3.0.0",
+ "globals": "^16.0.0",
+ "prettier": "^3.4.2",
+ "prettier-plugin-svelte": "^3.3.3",
+ "prettier-plugin-tailwindcss": "^0.6.11",
+ "svelte": "^5.0.0",
+ "svelte-check": "^4.0.0",
+ "tailwind-merge": "^3.3.1",
+ "tailwind-variants": "^1.0.0",
+ "tailwindcss": "^4.0.0",
+ "tw-animate-css": "^1.3.4",
+ "typescript": "^5.0.0",
+ "typescript-eslint": "^8.20.0",
+ "unplugin-icons": "^22.1.0",
+ "vite": "^6.2.6",
+ "wrangler": "^4.20.5"
+ },
+ "dependencies": {
+ "better-auth": "^1.2.9",
+ "better-auth-cloudflare": "file:../../",
+ "drizzle-orm": "^0.44.2"
+ }
+}
diff --git a/examples/sveltekit-pages/src/app.css b/examples/sveltekit-pages/src/app.css
new file mode 100644
index 0000000..7e9bf26
--- /dev/null
+++ b/examples/sveltekit-pages/src/app.css
@@ -0,0 +1,134 @@
+@import 'tailwindcss';
+
+@import 'tw-animate-css';
+
+@custom-variant dark (&:is(.dark *));
+
+:root {
+ --radius: 0.625rem;
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.129 0.042 264.695);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.129 0.042 264.695);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.129 0.042 264.695);
+ --primary: oklch(0.208 0.042 265.755);
+ --primary-foreground: oklch(0.984 0.003 247.858);
+ --secondary: oklch(0.968 0.007 247.896);
+ --secondary-foreground: oklch(0.208 0.042 265.755);
+ --muted: oklch(0.968 0.007 247.896);
+ --muted-foreground: oklch(0.554 0.046 257.417);
+ --accent: oklch(0.968 0.007 247.896);
+ --accent-foreground: oklch(0.208 0.042 265.755);
+ --destructive: oklch(0.577 0.245 27.325);
+ --border: oklch(0.929 0.013 255.508);
+ --input: oklch(0.929 0.013 255.508);
+ --ring: oklch(0.704 0.04 256.788);
+ --chart-1: oklch(0.646 0.222 41.116);
+ --chart-2: oklch(0.6 0.118 184.704);
+ --chart-3: oklch(0.398 0.07 227.392);
+ --chart-4: oklch(0.828 0.189 84.429);
+ --chart-5: oklch(0.769 0.188 70.08);
+ --sidebar: oklch(0.984 0.003 247.858);
+ --sidebar-foreground: oklch(0.129 0.042 264.695);
+ --sidebar-primary: oklch(0.208 0.042 265.755);
+ --sidebar-primary-foreground: oklch(0.984 0.003 247.858);
+ --sidebar-accent: oklch(0.968 0.007 247.896);
+ --sidebar-accent-foreground: oklch(0.208 0.042 265.755);
+ --sidebar-border: oklch(0.929 0.013 255.508);
+ --sidebar-ring: oklch(0.704 0.04 256.788);
+}
+
+.dark {
+ --background: oklch(0.129 0.042 264.695);
+ --foreground: oklch(0.984 0.003 247.858);
+ --card: oklch(0.208 0.042 265.755);
+ --card-foreground: oklch(0.984 0.003 247.858);
+ --popover: oklch(0.208 0.042 265.755);
+ --popover-foreground: oklch(0.984 0.003 247.858);
+ --primary: oklch(0.929 0.013 255.508);
+ --primary-foreground: oklch(0.208 0.042 265.755);
+ --secondary: oklch(0.279 0.041 260.031);
+ --secondary-foreground: oklch(0.984 0.003 247.858);
+ --muted: oklch(0.279 0.041 260.031);
+ --muted-foreground: oklch(0.704 0.04 256.788);
+ --accent: oklch(0.279 0.041 260.031);
+ --accent-foreground: oklch(0.984 0.003 247.858);
+ --destructive: oklch(0.704 0.191 22.216);
+ --border: oklch(1 0 0 / 10%);
+ --input: oklch(1 0 0 / 15%);
+ --ring: oklch(0.551 0.027 264.364);
+ --chart-1: oklch(0.488 0.243 264.376);
+ --chart-2: oklch(0.696 0.17 162.48);
+ --chart-3: oklch(0.769 0.188 70.08);
+ --chart-4: oklch(0.627 0.265 303.9);
+ --chart-5: oklch(0.645 0.246 16.439);
+ --sidebar: oklch(0.208 0.042 265.755);
+ --sidebar-foreground: oklch(0.984 0.003 247.858);
+ --sidebar-primary: oklch(0.488 0.243 264.376);
+ --sidebar-primary-foreground: oklch(0.984 0.003 247.858);
+ --sidebar-accent: oklch(0.279 0.041 260.031);
+ --sidebar-accent-foreground: oklch(0.984 0.003 247.858);
+ --sidebar-border: oklch(1 0 0 / 10%);
+ --sidebar-ring: oklch(0.551 0.027 264.364);
+}
+
+@theme inline {
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-card: var(--card);
+ --color-card-foreground: var(--card-foreground);
+ --color-popover: var(--popover);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-primary: var(--primary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-secondary: var(--secondary);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-muted: var(--muted);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-accent: var(--accent);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-destructive: var(--destructive);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+ --color-chart-1: var(--chart-1);
+ --color-chart-2: var(--chart-2);
+ --color-chart-3: var(--chart-3);
+ --color-chart-4: var(--chart-4);
+ --color-chart-5: var(--chart-5);
+ --color-sidebar: var(--sidebar);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-ring: var(--sidebar-ring);
+}
+
+@layer base {
+ * {
+ @apply border-border outline-ring/50;
+ }
+
+ body {
+ @apply bg-background text-foreground;
+ }
+}
+
+@layer base {
+ button,
+ [role='button'] {
+ cursor: pointer;
+ }
+
+ button:disabled,
+ [role='button']:disabled {
+ cursor: default;
+ }
+}
diff --git a/examples/sveltekit-pages/src/app.d.ts b/examples/sveltekit-pages/src/app.d.ts
new file mode 100644
index 0000000..a6200d1
--- /dev/null
+++ b/examples/sveltekit-pages/src/app.d.ts
@@ -0,0 +1,21 @@
+///
+import type { DrizzleClient } from '$lib/server/db';
+import type { Auth } from '$lib/server/auth';
+import 'unplugin-icons/types/svelte';
+// See https://svelte.dev/docs/kit/types#app.d.ts
+// for information about these interfaces
+declare global {
+ namespace App {
+ interface Platform {
+ env: Env;
+ cf: CfProperties;
+ ctx: ExecutionContext;
+ }
+ interface Locals {
+ auth: Auth;
+ db: DrizzleClient;
+ }
+ }
+}
+
+export {};
diff --git a/examples/sveltekit-pages/src/app.html b/examples/sveltekit-pages/src/app.html
new file mode 100644
index 0000000..06fe453
--- /dev/null
+++ b/examples/sveltekit-pages/src/app.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ %sveltekit.head%
+
+
+
+ %sveltekit.body%
+
+
diff --git a/examples/sveltekit-pages/src/hooks.server.ts b/examples/sveltekit-pages/src/hooks.server.ts
new file mode 100644
index 0000000..d437ded
--- /dev/null
+++ b/examples/sveltekit-pages/src/hooks.server.ts
@@ -0,0 +1,22 @@
+import { createAuth } from '$lib/server/auth'; // path to your auth file
+import { createClient } from '$lib/server/db';
+import type { Handle } from '@sveltejs/kit';
+import { svelteKitHandler } from 'better-auth/svelte-kit';
+
+export const handle: Handle = async ({ event, resolve }) => {
+ try {
+ const db = event.platform?.env.DB;
+ if (!db) {
+ throw new Error('Database instance (DB) is not available in event.platform.env.');
+ }
+ event.locals.db = createClient(db);
+
+ const auth = createAuth(event.locals.db, event);
+ event.locals.auth = auth;
+
+ return await svelteKitHandler({ auth, event, resolve });
+ } catch (error) {
+ console.error('Database connection failed:', error);
+ throw error;
+ }
+};
diff --git a/examples/sveltekit-pages/src/lib/auth/client.ts b/examples/sveltekit-pages/src/lib/auth/client.ts
new file mode 100644
index 0000000..be42326
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/auth/client.ts
@@ -0,0 +1,7 @@
+import { cloudflareClient } from 'better-auth-cloudflare/client';
+import { anonymousClient } from 'better-auth/client/plugins';
+import { createAuthClient } from 'better-auth/svelte';
+
+export const authClient = createAuthClient({
+ plugins: [cloudflareClient(), anonymousClient()]
+});
diff --git a/examples/sveltekit-pages/src/lib/auth/index.ts b/examples/sveltekit-pages/src/lib/auth/index.ts
new file mode 100644
index 0000000..4f1cce4
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/auth/index.ts
@@ -0,0 +1 @@
+export * from './client';
diff --git a/examples/sveltekit-pages/src/lib/components/file-upload-demo.svelte b/examples/sveltekit-pages/src/lib/components/file-upload-demo.svelte
new file mode 100644
index 0000000..7eccbce
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/file-upload-demo.svelte
@@ -0,0 +1,315 @@
+
+
+
+
+
+
+
+ File Upload
+
+
+
+
+
+
(file = e.currentTarget.files?.[0] || null)}
+ />
+ {#if file}
+
+ Selected: {file.name} ({formatFileSize(file.size)})
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {#if fileOperationResult}
+
+ {#if fileOperationResult.error}
+
+
❌
+
{fileOperationResult.error}
+
+ {:else}
+
+
+
+
File uploaded successfully!
+
+ Your file has been stored securely and is now available in your file list.
+
+
+
+ {/if}
+
+ {/if}
+
+
+
+
+
+
+ Your Files
+
+
+
+ {#if userFiles.length === 0}
+
+
+
+
+
No files uploaded yet
+
Upload your first file using the form above
+
+ {:else}
+
+ {#each userFiles as file (file.id)}
+
+
+
{file.originalName}
+
+ {#if file.category}
+
+ {file.category}
+
+ {/if}
+ {formatFileSize(file.size)}
+ •
+ {formatRelativeTime(file.uploadedAt)}
+ {#if file.isPublic}
+ •
+
+ Public
+
+ {/if}
+
+ {#if file.description}
+
{file.description}
+ {/if}
+
+
+
+
+
+
+ {/each}
+
+ {/if}
+
+
+
diff --git a/examples/sveltekit-pages/src/lib/components/login-form.svelte b/examples/sveltekit-pages/src/lib/components/login-form.svelte
new file mode 100644
index 0000000..70f8446
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/login-form.svelte
@@ -0,0 +1,52 @@
+
+
+
+
+ Login
+ Powered by better-auth-cloudflare.
+
+
+
+
No personal information required.
+
+
+
+
+
+
diff --git a/examples/sveltekit-pages/src/lib/components/sign-out-button.svelte b/examples/sveltekit-pages/src/lib/components/sign-out-button.svelte
new file mode 100644
index 0000000..8579317
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/sign-out-button.svelte
@@ -0,0 +1,69 @@
+
+
+
+
+
+ {#if error}
+
{error}
+ {/if}
+
diff --git a/examples/sveltekit-pages/src/lib/components/ui/button/button.svelte b/examples/sveltekit-pages/src/lib/components/ui/button/button.svelte
new file mode 100644
index 0000000..16f1a3c
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/button/button.svelte
@@ -0,0 +1,80 @@
+
+
+
+
+{#if href}
+
+ {@render children?.()}
+
+{:else}
+
+{/if}
diff --git a/examples/sveltekit-pages/src/lib/components/ui/button/index.ts b/examples/sveltekit-pages/src/lib/components/ui/button/index.ts
new file mode 100644
index 0000000..5414d9d
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/button/index.ts
@@ -0,0 +1,17 @@
+import Root, {
+ type ButtonProps,
+ type ButtonSize,
+ type ButtonVariant,
+ buttonVariants
+} from './button.svelte';
+
+export {
+ Root,
+ type ButtonProps as Props,
+ //
+ Root as Button,
+ buttonVariants,
+ type ButtonProps,
+ type ButtonSize,
+ type ButtonVariant
+};
diff --git a/examples/sveltekit-pages/src/lib/components/ui/card/card-action.svelte b/examples/sveltekit-pages/src/lib/components/ui/card/card-action.svelte
new file mode 100644
index 0000000..bbaafd2
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/card/card-action.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/examples/sveltekit-pages/src/lib/components/ui/card/card-content.svelte b/examples/sveltekit-pages/src/lib/components/ui/card/card-content.svelte
new file mode 100644
index 0000000..1d60124
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/card/card-content.svelte
@@ -0,0 +1,15 @@
+
+
+
+ {@render children?.()}
+
diff --git a/examples/sveltekit-pages/src/lib/components/ui/card/card-description.svelte b/examples/sveltekit-pages/src/lib/components/ui/card/card-description.svelte
new file mode 100644
index 0000000..bfb0725
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/card/card-description.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/examples/sveltekit-pages/src/lib/components/ui/card/card-footer.svelte b/examples/sveltekit-pages/src/lib/components/ui/card/card-footer.svelte
new file mode 100644
index 0000000..4e390bf
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/card/card-footer.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/examples/sveltekit-pages/src/lib/components/ui/card/card-header.svelte b/examples/sveltekit-pages/src/lib/components/ui/card/card-header.svelte
new file mode 100644
index 0000000..9cdc602
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/card/card-header.svelte
@@ -0,0 +1,23 @@
+
+
+
+ {@render children?.()}
+
diff --git a/examples/sveltekit-pages/src/lib/components/ui/card/card-title.svelte b/examples/sveltekit-pages/src/lib/components/ui/card/card-title.svelte
new file mode 100644
index 0000000..0eae8ec
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/card/card-title.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/examples/sveltekit-pages/src/lib/components/ui/card/card.svelte b/examples/sveltekit-pages/src/lib/components/ui/card/card.svelte
new file mode 100644
index 0000000..4112332
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/card/card.svelte
@@ -0,0 +1,23 @@
+
+
+
+ {@render children?.()}
+
diff --git a/examples/sveltekit-pages/src/lib/components/ui/card/index.ts b/examples/sveltekit-pages/src/lib/components/ui/card/index.ts
new file mode 100644
index 0000000..77d3674
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/card/index.ts
@@ -0,0 +1,25 @@
+import Root from './card.svelte';
+import Content from './card-content.svelte';
+import Description from './card-description.svelte';
+import Footer from './card-footer.svelte';
+import Header from './card-header.svelte';
+import Title from './card-title.svelte';
+import Action from './card-action.svelte';
+
+export {
+ Root,
+ Content,
+ Description,
+ Footer,
+ Header,
+ Title,
+ Action,
+ //
+ Root as Card,
+ Content as CardContent,
+ Description as CardDescription,
+ Footer as CardFooter,
+ Header as CardHeader,
+ Title as CardTitle,
+ Action as CardAction
+};
diff --git a/examples/sveltekit-pages/src/lib/components/ui/input/index.ts b/examples/sveltekit-pages/src/lib/components/ui/input/index.ts
new file mode 100644
index 0000000..15c0933
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/input/index.ts
@@ -0,0 +1,7 @@
+import Root from './input.svelte';
+
+export {
+ Root,
+ //
+ Root as Input
+};
diff --git a/examples/sveltekit-pages/src/lib/components/ui/input/input.svelte b/examples/sveltekit-pages/src/lib/components/ui/input/input.svelte
new file mode 100644
index 0000000..7598a86
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/input/input.svelte
@@ -0,0 +1,51 @@
+
+
+{#if type === 'file'}
+
+{:else}
+
+{/if}
diff --git a/examples/sveltekit-pages/src/lib/components/ui/label/index.ts b/examples/sveltekit-pages/src/lib/components/ui/label/index.ts
new file mode 100644
index 0000000..808d141
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/label/index.ts
@@ -0,0 +1,7 @@
+import Root from './label.svelte';
+
+export {
+ Root,
+ //
+ Root as Label
+};
diff --git a/examples/sveltekit-pages/src/lib/components/ui/label/label.svelte b/examples/sveltekit-pages/src/lib/components/ui/label/label.svelte
new file mode 100644
index 0000000..7fef72e
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/label/label.svelte
@@ -0,0 +1,20 @@
+
+
+
diff --git a/examples/sveltekit-pages/src/lib/components/ui/tabs/index.ts b/examples/sveltekit-pages/src/lib/components/ui/tabs/index.ts
new file mode 100644
index 0000000..d2a7939
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/tabs/index.ts
@@ -0,0 +1,16 @@
+import Root from './tabs.svelte';
+import Content from './tabs-content.svelte';
+import List from './tabs-list.svelte';
+import Trigger from './tabs-trigger.svelte';
+
+export {
+ Root,
+ Content,
+ List,
+ Trigger,
+ //
+ Root as Tabs,
+ Content as TabsContent,
+ List as TabsList,
+ Trigger as TabsTrigger
+};
diff --git a/examples/sveltekit-pages/src/lib/components/ui/tabs/tabs-content.svelte b/examples/sveltekit-pages/src/lib/components/ui/tabs/tabs-content.svelte
new file mode 100644
index 0000000..92044c8
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/tabs/tabs-content.svelte
@@ -0,0 +1,17 @@
+
+
+
diff --git a/examples/sveltekit-pages/src/lib/components/ui/tabs/tabs-list.svelte b/examples/sveltekit-pages/src/lib/components/ui/tabs/tabs-list.svelte
new file mode 100644
index 0000000..e875fe4
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/tabs/tabs-list.svelte
@@ -0,0 +1,16 @@
+
+
+
diff --git a/examples/sveltekit-pages/src/lib/components/ui/tabs/tabs-trigger.svelte b/examples/sveltekit-pages/src/lib/components/ui/tabs/tabs-trigger.svelte
new file mode 100644
index 0000000..8dac6c5
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/tabs/tabs-trigger.svelte
@@ -0,0 +1,20 @@
+
+
+
diff --git a/examples/sveltekit-pages/src/lib/components/ui/tabs/tabs.svelte b/examples/sveltekit-pages/src/lib/components/ui/tabs/tabs.svelte
new file mode 100644
index 0000000..b275bda
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/components/ui/tabs/tabs.svelte
@@ -0,0 +1,19 @@
+
+
+
diff --git a/examples/sveltekit-pages/src/lib/index.ts b/examples/sveltekit-pages/src/lib/index.ts
new file mode 100644
index 0000000..856f2b6
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/index.ts
@@ -0,0 +1 @@
+// place files you want to import through the `$lib` alias in this folder.
diff --git a/examples/sveltekit-pages/src/lib/server/auth.ts b/examples/sveltekit-pages/src/lib/server/auth.ts
new file mode 100644
index 0000000..629a573
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/server/auth.ts
@@ -0,0 +1,83 @@
+import type { RequestEvent } from '@sveltejs/kit';
+import { betterAuth } from 'better-auth';
+import { anonymous } from 'better-auth/plugins';
+import { type DrizzleClient } from '$lib/server/db';
+import { withCloudflare } from 'better-auth-cloudflare';
+
+function createAuth(db: DrizzleClient, event?: RequestEvent) {
+ return betterAuth(
+ withCloudflare(
+ {
+ autoDetectIpAddress: true,
+ geolocationTracking: true,
+ cf: event?.platform?.cf || {},
+ d1: {
+ db,
+ options: {
+ usePlural: true,
+ debugLogs: true
+ }
+ },
+ // @ts-expect-error FIX: `@cloudflare/workers-types` is not compatible
+ kv: event?.platform?.env?.SVELTEKIT_PAGES_AUTH_SESSION_KV as KVNamespace,
+ r2: {
+ bucket: event?.platform?.env?.SVELTEKIT_PAGES_ASSETS as R2Bucket,
+ maxFileSize: 2 * 1024 * 1024, // 2MB
+ allowedTypes: ['.jpg', '.jpeg', '.png', '.gif'],
+ additionalFields: {
+ category: { type: 'string', required: false },
+ isPublic: { type: 'boolean', required: false },
+ description: { type: 'string', required: false }
+ },
+ hooks: {
+ upload: {
+ before: async (file, ctx) => {
+ // Only allow authenticated users to upload files
+ if (ctx.session === null) {
+ return null; // Blocks upload
+ }
+
+ // Only allow paid users to upload files (for example)
+ const isPaidUser = (userId: string) => true; // example
+ if (isPaidUser(ctx.session.user.id) === false) {
+ return null; // Blocks upload
+ }
+
+ // Allow upload
+ },
+ after: async (file, ctx) => {
+ // Track your analytics (for example)
+ console.log('File uploaded:', file);
+ }
+ },
+ download: {
+ before: async (file, ctx) => {
+ // Only allow user to access their own files (by default all files are public)
+ if (file.isPublic === false && file.userId !== ctx.session?.user.id) {
+ return null; // Blocks download
+ }
+ // Allow download
+ }
+ }
+ }
+ }
+ },
+ {
+ emailAndPassword: {
+ enabled: true
+ },
+ plugins: [anonymous()],
+ rateLimit: {
+ enabled: true
+ }
+ }
+ )
+ );
+}
+
+export type Auth = ReturnType;
+
+// Export for CLI schema generation
+// export const auth = createAuth(event.locals.db);
+
+export { createAuth };
diff --git a/examples/sveltekit-pages/src/lib/server/db/auth.schema.ts b/examples/sveltekit-pages/src/lib/server/db/auth.schema.ts
new file mode 100644
index 0000000..460a5c1
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/server/db/auth.schema.ts
@@ -0,0 +1,86 @@
+import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
+
+export const users = sqliteTable('users', {
+ id: text('id').primaryKey(),
+ name: text('name').notNull(),
+ email: text('email').notNull().unique(),
+ emailVerified: integer('email_verified', { mode: 'boolean' })
+ .$defaultFn(() => false)
+ .notNull(),
+ image: text('image'),
+ createdAt: integer('created_at', { mode: 'timestamp' })
+ .$defaultFn(() => /* @__PURE__ */ new Date())
+ .notNull(),
+ updatedAt: integer('updated_at', { mode: 'timestamp' })
+ .$defaultFn(() => /* @__PURE__ */ new Date())
+ .notNull(),
+ isAnonymous: integer('is_anonymous', { mode: 'boolean' })
+});
+
+export const sessions = sqliteTable('sessions', {
+ id: text('id').primaryKey(),
+ expiresAt: integer('expires_at', { mode: 'timestamp' }).notNull(),
+ token: text('token').notNull().unique(),
+ createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
+ updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(),
+ ipAddress: text('ip_address'),
+ userAgent: text('user_agent'),
+ userId: text('user_id')
+ .notNull()
+ .references(() => users.id, { onDelete: 'cascade' }),
+ timezone: text('timezone'),
+ city: text('city'),
+ country: text('country'),
+ region: text('region'),
+ regionCode: text('region_code'),
+ colo: text('colo'),
+ latitude: text('latitude'),
+ longitude: text('longitude')
+});
+
+export const accounts = sqliteTable('accounts', {
+ id: text('id').primaryKey(),
+ accountId: text('account_id').notNull(),
+ providerId: text('provider_id').notNull(),
+ userId: text('user_id')
+ .notNull()
+ .references(() => users.id, { onDelete: 'cascade' }),
+ accessToken: text('access_token'),
+ refreshToken: text('refresh_token'),
+ idToken: text('id_token'),
+ accessTokenExpiresAt: integer('access_token_expires_at', { mode: 'timestamp' }),
+ refreshTokenExpiresAt: integer('refresh_token_expires_at', { mode: 'timestamp' }),
+ scope: text('scope'),
+ password: text('password'),
+ createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
+ updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull()
+});
+
+export const verifications = sqliteTable('verifications', {
+ id: text('id').primaryKey(),
+ identifier: text('identifier').notNull(),
+ value: text('value').notNull(),
+ expiresAt: integer('expires_at', { mode: 'timestamp' }).notNull(),
+ createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(
+ () => /* @__PURE__ */ new Date()
+ ),
+ updatedAt: integer('updated_at', { mode: 'timestamp' }).$defaultFn(
+ () => /* @__PURE__ */ new Date()
+ )
+});
+
+export const userFiles = sqliteTable('user_files', {
+ id: text('id').primaryKey(),
+ userId: text('user_id')
+ .notNull()
+ .references(() => users.id, { onDelete: 'cascade' }),
+ filename: text('filename').notNull(),
+ originalName: text('original_name').notNull(),
+ contentType: text('content_type').notNull(),
+ size: integer('size').notNull(),
+ r2Key: text('r2_key').notNull(),
+ uploadedAt: integer('uploaded_at', { mode: 'timestamp' }).notNull(),
+ category: text('category'),
+ isPublic: integer('is_public', { mode: 'boolean' }),
+ description: text('description')
+});
diff --git a/examples/sveltekit-pages/src/lib/server/db/index.ts b/examples/sveltekit-pages/src/lib/server/db/index.ts
new file mode 100644
index 0000000..bb36513
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/server/db/index.ts
@@ -0,0 +1,12 @@
+import { drizzle, type DrizzleD1Database } from 'drizzle-orm/d1';
+import * as schema from './schema';
+
+export function createClient(db: D1Database): DrizzleD1Database {
+ return drizzle(db, {
+ schema
+ });
+}
+
+export type DrizzleClient = ReturnType;
+
+export * from './schema';
diff --git a/examples/sveltekit-pages/src/lib/server/db/schema.ts b/examples/sveltekit-pages/src/lib/server/db/schema.ts
new file mode 100644
index 0000000..1b3d10f
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/server/db/schema.ts
@@ -0,0 +1,14 @@
+import * as authSchema from './auth.schema';
+
+// Export all schemas individually so that Drizzle Kit can discover the tables.
+export * from './auth.schema';
+
+// If you have other schema files, you can export them here.
+// import * as otherSchema from "./other.schema";
+// export * from "./other.schema";
+
+// Combine all schemas into a single object for the Drizzle client to use at runtime.
+export const schema = {
+ ...authSchema
+ // ...otherSchema,
+} as const;
diff --git a/examples/sveltekit-pages/src/lib/utils.ts b/examples/sveltekit-pages/src/lib/utils.ts
new file mode 100644
index 0000000..f92bfcb
--- /dev/null
+++ b/examples/sveltekit-pages/src/lib/utils.ts
@@ -0,0 +1,13 @@
+import { clsx, type ClassValue } from 'clsx';
+import { twMerge } from 'tailwind-merge';
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export type WithoutChild = T extends { child?: any } ? Omit : T;
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export type WithoutChildren = T extends { children?: any } ? Omit : T;
+export type WithoutChildrenOrChild = WithoutChildren>;
+export type WithElementRef = T & { ref?: U | null };
diff --git a/examples/sveltekit-pages/src/routes/+layout.svelte b/examples/sveltekit-pages/src/routes/+layout.svelte
new file mode 100644
index 0000000..ad5c6f1
--- /dev/null
+++ b/examples/sveltekit-pages/src/routes/+layout.svelte
@@ -0,0 +1,37 @@
+
+
+
+ {@render children()}
+
+
+
diff --git a/examples/sveltekit-pages/src/routes/+page.server.ts b/examples/sveltekit-pages/src/routes/+page.server.ts
new file mode 100644
index 0000000..359e36d
--- /dev/null
+++ b/examples/sveltekit-pages/src/routes/+page.server.ts
@@ -0,0 +1,9 @@
+import { redirect } from '@sveltejs/kit';
+
+export const load = async ({ request, locals }) => {
+ const session = await locals.auth.api.getSession(request);
+ if (session) {
+ throw redirect(302, '/dashboard');
+ }
+ return {};
+};
diff --git a/examples/sveltekit-pages/src/routes/+page.svelte b/examples/sveltekit-pages/src/routes/+page.svelte
new file mode 100644
index 0000000..5807421
--- /dev/null
+++ b/examples/sveltekit-pages/src/routes/+page.svelte
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/examples/sveltekit-pages/src/routes/dashboard/+page.server.ts b/examples/sveltekit-pages/src/routes/dashboard/+page.server.ts
new file mode 100644
index 0000000..f2f54af
--- /dev/null
+++ b/examples/sveltekit-pages/src/routes/dashboard/+page.server.ts
@@ -0,0 +1,15 @@
+import { redirect } from '@sveltejs/kit';
+
+export const load = async ({ request, locals }) => {
+ const session = await locals.auth.api.getSession(request);
+ if (!session) {
+ throw redirect(302, '/');
+ }
+
+ return {
+ user: session.user,
+ cloudflareGeolocationData: await locals.auth.api.getGeolocation({
+ headers: request.headers
+ })
+ };
+};
diff --git a/examples/sveltekit-pages/src/routes/dashboard/+page.svelte b/examples/sveltekit-pages/src/routes/dashboard/+page.svelte
new file mode 100644
index 0000000..9bb15a3
--- /dev/null
+++ b/examples/sveltekit-pages/src/routes/dashboard/+page.svelte
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
Dashboard
+
Powered by better-auth-cloudflare
+
+
+
+
+ User Info
+ Geolocation
+ File Upload
+
+
+
+
+
+ User Information
+
+
+
+ Welcome,{' '}
+
+ {data.user?.name || data.user?.email || 'Anonymous User'}
+
+ !
+
+ {#if data.user?.email}
+
+ Email:{' '}
+ {data.user.email}
+
+ {/if}
+ {#if !data.user?.email}
+
+ Account Type: Anonymous
+
+ {/if}
+ {#if data.user?.id}
+
+ User ID:
+ {data.user.id}
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+ Your Location
+
+
+ Automatically detected using Cloudflare's global network
+
+
+
+ {#if data.cloudflareGeolocationData && 'error' in data.cloudflareGeolocationData}
+
+
⚠️
+
+ Error:
+ {data.cloudflareGeolocationData.error}
+
+
+ {/if}
+ {#if data.cloudflareGeolocationData && !('error' in data.cloudflareGeolocationData)}
+
+
+
+
+
Timezone
+
+ {data.cloudflareGeolocationData.timezone || 'Unknown'}
+
+
+
+
+
+
+
+
City
+
+ {data.cloudflareGeolocationData.city || 'Unknown'}
+
+
+
+
+
+
+
+
Country
+
+ {data.cloudflareGeolocationData.country || 'Unknown'}
+
+
+
+
+
+
+
+
Region
+
+ {data.cloudflareGeolocationData.region || 'Unknown'}
+ {data.cloudflareGeolocationData.regionCode &&
+ ` (${data.cloudflareGeolocationData.regionCode})`}
+
+
+
+
+
+
+
+
Data Center
+
+ {data.cloudflareGeolocationData.colo || 'Unknown'}
+
+
+
+
+ {#if data.cloudflareGeolocationData.latitude || data.cloudflareGeolocationData.longitude}
+
+
+
+
Coordinates
+
+ {data.cloudflareGeolocationData.latitude &&
+ data.cloudflareGeolocationData.longitude
+ ? `${data.cloudflareGeolocationData.latitude}, ${data.cloudflareGeolocationData.longitude}`
+ : 'Partially available'}
+
+
+
+ {/if}
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/sveltekit-pages/src/worker-configuration.d.ts b/examples/sveltekit-pages/src/worker-configuration.d.ts
new file mode 100644
index 0000000..0700584
--- /dev/null
+++ b/examples/sveltekit-pages/src/worker-configuration.d.ts
@@ -0,0 +1,8208 @@
+/* eslint-disable */
+// Generated by Wrangler by running `wrangler types src/worker-configuration.d.ts` (hash: 761ef398fac8ef6f8c89132d7bbb465c)
+// Runtime types generated with workerd@1.20250617.0 2025-06-14 nodejs_compat
+declare namespace Cloudflare {
+ interface Env {
+ SVELTEKIT_PAGES_AUTH_SESSION_KV: KVNamespace;
+ SVELTEKIT_PAGES_ASSETS: R2Bucket;
+ DB: D1Database;
+ }
+}
+interface Env extends Cloudflare.Env {}
+
+// Begin runtime types
+/*! *****************************************************************************
+Copyright (c) Cloudflare. All rights reserved.
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at http://www.apache.org/licenses/LICENSE-2.0
+THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
+WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
+MERCHANTABLITY OR NON-INFRINGEMENT.
+See the Apache Version 2.0 License for specific language governing permissions
+and limitations under the License.
+***************************************************************************** */
+/* eslint-disable */
+// noinspection JSUnusedGlobalSymbols
+declare var onmessage: never;
+/**
+ * An abnormal event (called an exception) which occurs as a result of calling a method or accessing a property of a web API.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException)
+ */
+declare class DOMException extends Error {
+ constructor(message?: string, name?: string);
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/message) */
+ readonly message: string;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/name) */
+ readonly name: string;
+ /**
+ * @deprecated
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/code)
+ */
+ readonly code: number;
+ static readonly INDEX_SIZE_ERR: number;
+ static readonly DOMSTRING_SIZE_ERR: number;
+ static readonly HIERARCHY_REQUEST_ERR: number;
+ static readonly WRONG_DOCUMENT_ERR: number;
+ static readonly INVALID_CHARACTER_ERR: number;
+ static readonly NO_DATA_ALLOWED_ERR: number;
+ static readonly NO_MODIFICATION_ALLOWED_ERR: number;
+ static readonly NOT_FOUND_ERR: number;
+ static readonly NOT_SUPPORTED_ERR: number;
+ static readonly INUSE_ATTRIBUTE_ERR: number;
+ static readonly INVALID_STATE_ERR: number;
+ static readonly SYNTAX_ERR: number;
+ static readonly INVALID_MODIFICATION_ERR: number;
+ static readonly NAMESPACE_ERR: number;
+ static readonly INVALID_ACCESS_ERR: number;
+ static readonly VALIDATION_ERR: number;
+ static readonly TYPE_MISMATCH_ERR: number;
+ static readonly SECURITY_ERR: number;
+ static readonly NETWORK_ERR: number;
+ static readonly ABORT_ERR: number;
+ static readonly URL_MISMATCH_ERR: number;
+ static readonly QUOTA_EXCEEDED_ERR: number;
+ static readonly TIMEOUT_ERR: number;
+ static readonly INVALID_NODE_TYPE_ERR: number;
+ static readonly DATA_CLONE_ERR: number;
+ get stack(): any;
+ set stack(value: any);
+}
+type WorkerGlobalScopeEventMap = {
+ fetch: FetchEvent;
+ scheduled: ScheduledEvent;
+ queue: QueueEvent;
+ unhandledrejection: PromiseRejectionEvent;
+ rejectionhandled: PromiseRejectionEvent;
+};
+declare abstract class WorkerGlobalScope extends EventTarget {
+ EventTarget: typeof EventTarget;
+}
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console) */
+interface Console {
+ 'assert'(condition?: boolean, ...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/clear_static) */
+ clear(): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/count_static) */
+ count(label?: string): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/countReset_static) */
+ countReset(label?: string): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/debug_static) */
+ debug(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dir_static) */
+ dir(item?: any, options?: any): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dirxml_static) */
+ dirxml(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/error_static) */
+ error(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/group_static) */
+ group(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupCollapsed_static) */
+ groupCollapsed(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupEnd_static) */
+ groupEnd(): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/info_static) */
+ info(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static) */
+ log(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/table_static) */
+ table(tabularData?: any, properties?: string[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/time_static) */
+ time(label?: string): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeEnd_static) */
+ timeEnd(label?: string): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeLog_static) */
+ timeLog(label?: string, ...data: any[]): void;
+ timeStamp(label?: string): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/trace_static) */
+ trace(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static) */
+ warn(...data: any[]): void;
+}
+declare const console: Console;
+type BufferSource = ArrayBufferView | ArrayBuffer;
+type TypedArray =
+ | Int8Array
+ | Uint8Array
+ | Uint8ClampedArray
+ | Int16Array
+ | Uint16Array
+ | Int32Array
+ | Uint32Array
+ | Float32Array
+ | Float64Array
+ | BigInt64Array
+ | BigUint64Array;
+declare namespace WebAssembly {
+ class CompileError extends Error {
+ constructor(message?: string);
+ }
+ class RuntimeError extends Error {
+ constructor(message?: string);
+ }
+ type ValueType = 'anyfunc' | 'externref' | 'f32' | 'f64' | 'i32' | 'i64' | 'v128';
+ interface GlobalDescriptor {
+ value: ValueType;
+ mutable?: boolean;
+ }
+ class Global {
+ constructor(descriptor: GlobalDescriptor, value?: any);
+ value: any;
+ valueOf(): any;
+ }
+ type ImportValue = ExportValue | number;
+ type ModuleImports = Record;
+ type Imports = Record;
+ type ExportValue = Function | Global | Memory | Table;
+ type Exports = Record;
+ class Instance {
+ constructor(module: Module, imports?: Imports);
+ readonly exports: Exports;
+ }
+ interface MemoryDescriptor {
+ initial: number;
+ maximum?: number;
+ shared?: boolean;
+ }
+ class Memory {
+ constructor(descriptor: MemoryDescriptor);
+ readonly buffer: ArrayBuffer;
+ grow(delta: number): number;
+ }
+ type ImportExportKind = 'function' | 'global' | 'memory' | 'table';
+ interface ModuleExportDescriptor {
+ kind: ImportExportKind;
+ name: string;
+ }
+ interface ModuleImportDescriptor {
+ kind: ImportExportKind;
+ module: string;
+ name: string;
+ }
+ abstract class Module {
+ static customSections(module: Module, sectionName: string): ArrayBuffer[];
+ static exports(module: Module): ModuleExportDescriptor[];
+ static imports(module: Module): ModuleImportDescriptor[];
+ }
+ type TableKind = 'anyfunc' | 'externref';
+ interface TableDescriptor {
+ element: TableKind;
+ initial: number;
+ maximum?: number;
+ }
+ class Table {
+ constructor(descriptor: TableDescriptor, value?: any);
+ readonly length: number;
+ get(index: number): any;
+ grow(delta: number, value?: any): number;
+ set(index: number, value?: any): void;
+ }
+ function instantiate(module: Module, imports?: Imports): Promise;
+ function validate(bytes: BufferSource): boolean;
+}
+/**
+ * This ServiceWorker API interface represents the global execution context of a service worker.
+ * Available only in secure contexts.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ServiceWorkerGlobalScope)
+ */
+interface ServiceWorkerGlobalScope extends WorkerGlobalScope {
+ DOMException: typeof DOMException;
+ WorkerGlobalScope: typeof WorkerGlobalScope;
+ btoa(data: string): string;
+ atob(data: string): string;
+ setTimeout(callback: (...args: any[]) => void, msDelay?: number): number;
+ setTimeout(
+ callback: (...args: Args) => void,
+ msDelay?: number,
+ ...args: Args
+ ): number;
+ clearTimeout(timeoutId: number | null): void;
+ setInterval(callback: (...args: any[]) => void, msDelay?: number): number;
+ setInterval(
+ callback: (...args: Args) => void,
+ msDelay?: number,
+ ...args: Args
+ ): number;
+ clearInterval(timeoutId: number | null): void;
+ queueMicrotask(task: Function): void;
+ structuredClone(value: T, options?: StructuredSerializeOptions): T;
+ reportError(error: any): void;
+ fetch(input: RequestInfo | URL, init?: RequestInit): Promise;
+ self: ServiceWorkerGlobalScope;
+ crypto: Crypto;
+ caches: CacheStorage;
+ scheduler: Scheduler;
+ performance: Performance;
+ Cloudflare: Cloudflare;
+ readonly origin: string;
+ Event: typeof Event;
+ ExtendableEvent: typeof ExtendableEvent;
+ CustomEvent: typeof CustomEvent;
+ PromiseRejectionEvent: typeof PromiseRejectionEvent;
+ FetchEvent: typeof FetchEvent;
+ TailEvent: typeof TailEvent;
+ TraceEvent: typeof TailEvent;
+ ScheduledEvent: typeof ScheduledEvent;
+ MessageEvent: typeof MessageEvent;
+ CloseEvent: typeof CloseEvent;
+ ReadableStreamDefaultReader: typeof ReadableStreamDefaultReader;
+ ReadableStreamBYOBReader: typeof ReadableStreamBYOBReader;
+ ReadableStream: typeof ReadableStream;
+ WritableStream: typeof WritableStream;
+ WritableStreamDefaultWriter: typeof WritableStreamDefaultWriter;
+ TransformStream: typeof TransformStream;
+ ByteLengthQueuingStrategy: typeof ByteLengthQueuingStrategy;
+ CountQueuingStrategy: typeof CountQueuingStrategy;
+ ErrorEvent: typeof ErrorEvent;
+ EventSource: typeof EventSource;
+ ReadableStreamBYOBRequest: typeof ReadableStreamBYOBRequest;
+ ReadableStreamDefaultController: typeof ReadableStreamDefaultController;
+ ReadableByteStreamController: typeof ReadableByteStreamController;
+ WritableStreamDefaultController: typeof WritableStreamDefaultController;
+ TransformStreamDefaultController: typeof TransformStreamDefaultController;
+ CompressionStream: typeof CompressionStream;
+ DecompressionStream: typeof DecompressionStream;
+ TextEncoderStream: typeof TextEncoderStream;
+ TextDecoderStream: typeof TextDecoderStream;
+ Headers: typeof Headers;
+ Body: typeof Body;
+ Request: typeof Request;
+ Response: typeof Response;
+ WebSocket: typeof WebSocket;
+ WebSocketPair: typeof WebSocketPair;
+ WebSocketRequestResponsePair: typeof WebSocketRequestResponsePair;
+ AbortController: typeof AbortController;
+ AbortSignal: typeof AbortSignal;
+ TextDecoder: typeof TextDecoder;
+ TextEncoder: typeof TextEncoder;
+ navigator: Navigator;
+ Navigator: typeof Navigator;
+ URL: typeof URL;
+ URLSearchParams: typeof URLSearchParams;
+ URLPattern: typeof URLPattern;
+ Blob: typeof Blob;
+ File: typeof File;
+ FormData: typeof FormData;
+ Crypto: typeof Crypto;
+ SubtleCrypto: typeof SubtleCrypto;
+ CryptoKey: typeof CryptoKey;
+ CacheStorage: typeof CacheStorage;
+ Cache: typeof Cache;
+ FixedLengthStream: typeof FixedLengthStream;
+ IdentityTransformStream: typeof IdentityTransformStream;
+ HTMLRewriter: typeof HTMLRewriter;
+}
+declare function addEventListener(
+ type: Type,
+ handler: EventListenerOrEventListenerObject,
+ options?: EventTargetAddEventListenerOptions | boolean
+): void;
+declare function removeEventListener(
+ type: Type,
+ handler: EventListenerOrEventListenerObject,
+ options?: EventTargetEventListenerOptions | boolean
+): void;
+/**
+ * Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent)
+ */
+declare function dispatchEvent(
+ event: WorkerGlobalScopeEventMap[keyof WorkerGlobalScopeEventMap]
+): boolean;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/btoa) */
+declare function btoa(data: string): string;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/atob) */
+declare function atob(data: string): string;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/setTimeout) */
+declare function setTimeout(callback: (...args: any[]) => void, msDelay?: number): number;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/setTimeout) */
+declare function setTimeout(
+ callback: (...args: Args) => void,
+ msDelay?: number,
+ ...args: Args
+): number;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/clearTimeout) */
+declare function clearTimeout(timeoutId: number | null): void;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/setInterval) */
+declare function setInterval(callback: (...args: any[]) => void, msDelay?: number): number;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/setInterval) */
+declare function setInterval(
+ callback: (...args: Args) => void,
+ msDelay?: number,
+ ...args: Args
+): number;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/clearInterval) */
+declare function clearInterval(timeoutId: number | null): void;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/queueMicrotask) */
+declare function queueMicrotask(task: Function): void;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/structuredClone) */
+declare function structuredClone(value: T, options?: StructuredSerializeOptions): T;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/reportError) */
+declare function reportError(error: any): void;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/fetch) */
+declare function fetch(
+ input: RequestInfo | URL,
+ init?: RequestInit
+): Promise;
+declare const self: ServiceWorkerGlobalScope;
+/**
+ * The Web Crypto API provides a set of low-level functions for common cryptographic tasks.
+ * The Workers runtime implements the full surface of this API, but with some differences in
+ * the [supported algorithms](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/#supported-algorithms)
+ * compared to those implemented in most browsers.
+ *
+ * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/)
+ */
+declare const crypto: Crypto;
+/**
+ * The Cache API allows fine grained control of reading and writing from the Cloudflare global network cache.
+ *
+ * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/)
+ */
+declare const caches: CacheStorage;
+declare const scheduler: Scheduler;
+/**
+ * The Workers runtime supports a subset of the Performance API, used to measure timing and performance,
+ * as well as timing of subrequests and other operations.
+ *
+ * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/)
+ */
+declare const performance: Performance;
+declare const Cloudflare: Cloudflare;
+declare const origin: string;
+declare const navigator: Navigator;
+interface TestController {}
+interface ExecutionContext {
+ waitUntil(promise: Promise): void;
+ passThroughOnException(): void;
+ props: any;
+}
+type ExportedHandlerFetchHandler = (
+ request: Request>,
+ env: Env,
+ ctx: ExecutionContext
+) => Response | Promise;
+type ExportedHandlerTailHandler = (
+ events: TraceItem[],
+ env: Env,
+ ctx: ExecutionContext
+) => void | Promise;
+type ExportedHandlerTraceHandler = (
+ traces: TraceItem[],
+ env: Env,
+ ctx: ExecutionContext
+) => void | Promise;
+type ExportedHandlerTailStreamHandler = (
+ event: TailStream.TailEvent,
+ env: Env,
+ ctx: ExecutionContext
+) => TailStream.TailEventHandlerType | Promise;
+type ExportedHandlerScheduledHandler = (
+ controller: ScheduledController,
+ env: Env,
+ ctx: ExecutionContext
+) => void | Promise;
+type ExportedHandlerQueueHandler = (
+ batch: MessageBatch,
+ env: Env,
+ ctx: ExecutionContext
+) => void | Promise;
+type ExportedHandlerTestHandler = (
+ controller: TestController,
+ env: Env,
+ ctx: ExecutionContext
+) => void | Promise;
+interface ExportedHandler {
+ fetch?: ExportedHandlerFetchHandler;
+ tail?: ExportedHandlerTailHandler;
+ trace?: ExportedHandlerTraceHandler;
+ tailStream?: ExportedHandlerTailStreamHandler;
+ scheduled?: ExportedHandlerScheduledHandler;
+ test?: ExportedHandlerTestHandler;
+ email?: EmailExportedHandler;
+ queue?: ExportedHandlerQueueHandler;
+}
+interface StructuredSerializeOptions {
+ transfer?: any[];
+}
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent) */
+declare abstract class PromiseRejectionEvent extends Event {
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/promise) */
+ readonly promise: Promise;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/reason) */
+ readonly reason: any;
+}
+declare abstract class Navigator {
+ sendBeacon(
+ url: string,
+ body?:
+ | ReadableStream
+ | string
+ | (ArrayBuffer | ArrayBufferView)
+ | Blob
+ | FormData
+ | URLSearchParams
+ | URLSearchParams
+ ): boolean;
+ readonly userAgent: string;
+ readonly hardwareConcurrency: number;
+ readonly language: string;
+ readonly languages: string[];
+}
+/**
+ * The Workers runtime supports a subset of the Performance API, used to measure timing and performance,
+ * as well as timing of subrequests and other operations.
+ *
+ * [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/)
+ */
+interface Performance {
+ /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/#performancetimeorigin) */
+ readonly timeOrigin: number;
+ /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/#performancenow) */
+ now(): number;
+}
+interface AlarmInvocationInfo {
+ readonly isRetry: boolean;
+ readonly retryCount: number;
+}
+interface Cloudflare {
+ readonly compatibilityFlags: Record;
+}
+interface DurableObject {
+ fetch(request: Request): Response | Promise;
+ alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise;
+ webSocketMessage?(ws: WebSocket, message: string | ArrayBuffer): void | Promise;
+ webSocketClose?(
+ ws: WebSocket,
+ code: number,
+ reason: string,
+ wasClean: boolean
+ ): void | Promise;
+ webSocketError?(ws: WebSocket, error: unknown): void | Promise;
+}
+type DurableObjectStub = Fetcher<
+ T,
+ 'alarm' | 'webSocketMessage' | 'webSocketClose' | 'webSocketError'
+> & {
+ readonly id: DurableObjectId;
+ readonly name?: string;
+};
+interface DurableObjectId {
+ toString(): string;
+ equals(other: DurableObjectId): boolean;
+ readonly name?: string;
+}
+interface DurableObjectNamespace {
+ newUniqueId(options?: DurableObjectNamespaceNewUniqueIdOptions): DurableObjectId;
+ idFromName(name: string): DurableObjectId;
+ idFromString(id: string): DurableObjectId;
+ get(
+ id: DurableObjectId,
+ options?: DurableObjectNamespaceGetDurableObjectOptions
+ ): DurableObjectStub;
+ jurisdiction(jurisdiction: DurableObjectJurisdiction): DurableObjectNamespace;
+}
+type DurableObjectJurisdiction = 'eu' | 'fedramp' | 'fedramp-high';
+interface DurableObjectNamespaceNewUniqueIdOptions {
+ jurisdiction?: DurableObjectJurisdiction;
+}
+type DurableObjectLocationHint =
+ | 'wnam'
+ | 'enam'
+ | 'sam'
+ | 'weur'
+ | 'eeur'
+ | 'apac'
+ | 'oc'
+ | 'afr'
+ | 'me';
+interface DurableObjectNamespaceGetDurableObjectOptions {
+ locationHint?: DurableObjectLocationHint;
+}
+interface DurableObjectState {
+ waitUntil(promise: Promise): void;
+ readonly id: DurableObjectId;
+ readonly storage: DurableObjectStorage;
+ container?: Container;
+ blockConcurrencyWhile(callback: () => Promise): Promise;
+ acceptWebSocket(ws: WebSocket, tags?: string[]): void;
+ getWebSockets(tag?: string): WebSocket[];
+ setWebSocketAutoResponse(maybeReqResp?: WebSocketRequestResponsePair): void;
+ getWebSocketAutoResponse(): WebSocketRequestResponsePair | null;
+ getWebSocketAutoResponseTimestamp(ws: WebSocket): Date | null;
+ setHibernatableWebSocketEventTimeout(timeoutMs?: number): void;
+ getHibernatableWebSocketEventTimeout(): number | null;
+ getTags(ws: WebSocket): string[];
+ abort(reason?: string): void;
+}
+interface DurableObjectTransaction {
+ get(key: string, options?: DurableObjectGetOptions): Promise;
+ get(keys: string[], options?: DurableObjectGetOptions): Promise