Adapter for building SvelteKit applications on Cloudflare Pages with Workers integration
—
Cloudflare-specific platform context and runtime environment integration for SvelteKit applications running on Cloudflare Workers and Pages.
Global platform interface providing access to Cloudflare runtime environment within SvelteKit applications.
import {
CacheStorage,
IncomingRequestCfProperties,
ExecutionContext
} from '@cloudflare/workers-types';
declare global {
namespace App {
interface Platform {
/**
* Environment variables and bindings from Wrangler configuration
* Includes KV stores, Durable Objects, R2 buckets, etc.
*/
env: unknown;
/**
* Cloudflare execution context for request handling
* Used for waitUntil() and passThroughOnException()
*/
ctx: ExecutionContext;
/**
* @deprecated Use ctx instead
* Legacy alias for execution context
*/
context: ExecutionContext;
/**
* Cloudflare cache storage interface
* Provides access to Cloudflare's edge caching
*/
caches: CacheStorage;
/**
* Cloudflare-specific request properties
* Includes country, IP geolocation, bot detection, etc.
*/
cf?: IncomingRequestCfProperties;
}
}
}Usage in SvelteKit Routes:
// src/routes/api/data/+server.ts
import type { RequestHandler } from './$types';
export const GET: RequestHandler = async ({ platform }) => {
// Access environment variables/bindings
const db = platform?.env?.DB; // KV or D1 database
const bucket = platform?.env?.MY_BUCKET; // R2 storage
// Use execution context
platform?.ctx.waitUntil(
fetch('https://api.example.com/webhook', {
method: 'POST',
body: JSON.stringify({ event: 'processed' })
})
);
// Access Cloudflare request properties
const country = platform?.cf?.country;
const isBot = platform?.cf?.botManagement?.score;
return new Response(JSON.stringify({
country,
isBot: isBot < 30
}));
};Access to Cloudflare environment variables and bindings configured in your Wrangler configuration.
import {
KVNamespace,
D1Database,
R2Bucket,
DurableObjectNamespace
} from '@cloudflare/workers-types';
// Environment bindings are accessed via platform.env
interface CloudflareEnv {
// KV Namespace
MY_KV?: KVNamespace;
// D1 Database
DB?: D1Database;
// R2 Storage
MY_BUCKET?: R2Bucket;
// Durable Objects
MY_DURABLE_OBJECT?: DurableObjectNamespace;
// Environment Variables
API_KEY?: string;
SECRET?: string;
// And any other bindings from wrangler.toml
[key: string]: unknown;
}Usage Examples:
// Accessing KV storage
const value = await platform.env.MY_KV.get('cache-key');
await platform.env.MY_KV.put('cache-key', 'value', { expirationTtl: 3600 });
// Using D1 database
const result = await platform.env.DB
.prepare('SELECT * FROM users WHERE id = ?')
.bind(userId)
.first();
// R2 storage operations
const file = await platform.env.MY_BUCKET.get('uploads/image.jpg');
await platform.env.MY_BUCKET.put('uploads/new-file.txt', 'content');Control over request lifecycle and background task scheduling.
interface ExecutionContext {
/**
* Extend the lifetime of the request handler
* Allows background tasks to complete
*/
waitUntil(promise: Promise<any>): void;
/**
* Prevent the runtime from cancelling the request
* when an uncaught exception occurs
*/
passThroughOnException(): void;
}Usage Examples:
// Background logging without blocking response
platform.ctx.waitUntil(
fetch('https://analytics.example.com/track', {
method: 'POST',
body: JSON.stringify({
event: 'page_view',
timestamp: Date.now()
})
})
);
// Graceful error handling
try {
// Request processing logic
const data = await processRequest();
return new Response(JSON.stringify(data));
} catch (error) {
platform.ctx.passThroughOnException();
throw error; // Will be handled by Cloudflare's error page
}Access to Cloudflare's edge caching system for optimized performance.
import { CacheStorage, Cache, CacheQueryOptions } from '@cloudflare/workers-types';
interface CacheStorage {
/**
* Default cache for the current zone
*/
default: Cache;
/**
* Open a named cache
*/
open(cacheName: string): Promise<Cache>;
}
interface Cache {
match(request: RequestInfo, options?: CacheQueryOptions): Promise<Response | undefined>;
put(request: RequestInfo, response: Response): Promise<void>;
delete(request: RequestInfo, options?: CacheQueryOptions): Promise<boolean>;
}Usage Examples:
// Cache API responses
const cacheKey = new URL(request.url);
const cachedResponse = await platform.caches.default.match(cacheKey);
if (cachedResponse) {
return cachedResponse;
}
const apiResponse = await fetch('https://api.example.com/data');
const responseClone = apiResponse.clone();
// Cache for 1 hour
responseClone.headers.set('Cache-Control', 'public, max-age=3600');
await platform.caches.default.put(cacheKey, responseClone);
return apiResponse;Access to Cloudflare-specific request metadata and geolocation information.
interface IncomingRequestCfProperties {
/**
* Two-letter country code (ISO 3166-1 alpha-2)
*/
country?: string;
/**
* Cloudflare data center processing the request
*/
colo?: string;
/**
* Bot management information
*/
botManagement?: {
score: number; // 1-99, lower = more likely to be bot
staticResource: boolean;
verifiedBot: boolean;
};
/**
* Request geolocation data
*/
city?: string;
region?: string;
regionCode?: string;
postalCode?: string;
timezone?: string;
latitude?: string;
longitude?: string;
/**
* Additional metadata
*/
asn?: number;
asOrganization?: string;
tlsVersion?: string;
tlsCipher?: string;
}Usage Examples:
// Geolocation-based responses
const userCountry = platform.cf?.country;
const userCity = platform.cf?.city;
if (userCountry === 'US') {
// Serve US-specific content
} else if (userCountry === 'GB') {
// Serve UK-specific content
}
// Bot detection
const botScore = platform.cf?.botManagement?.score || 100;
if (botScore < 30) {
return new Response('Access denied', { status: 403 });
}
// Regional content delivery
const timezone = platform.cf?.timezone || 'UTC';
const localizedTime = new Date().toLocaleString('en-US', {
timeZone: timezone
});Install with Tessl CLI
npx tessl i tessl/npm-sveltejs--adapter-cloudflare