update skills

This commit is contained in:
2026-03-17 16:53:22 -07:00
parent 0b0783ef8e
commit f9a530667e
389 changed files with 54512 additions and 1 deletions

View File

@@ -0,0 +1,108 @@
# Cloudflare Workers
Expert guidance for building, deploying, and optimizing Cloudflare Workers applications.
## Overview
Cloudflare Workers run on V8 isolates (NOT containers/VMs):
- Extremely fast cold starts (< 1ms)
- Global deployment across 300+ locations
- Web standards compliant (fetch, URL, Headers, Request, Response)
- Support JS/TS, Python, Rust, and WebAssembly
**Key principle**: Workers use web platform APIs wherever possible for portability.
## Module Worker Pattern (Recommended)
```typescript
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
return new Response('Hello World!');
},
};
```
**Handler parameters**:
- `request`: Incoming HTTP request (standard Request object)
- `env`: Environment bindings (KV, D1, R2, secrets, vars)
- `ctx`: Execution context (`waitUntil`, `passThroughOnException`)
## Essential Commands
```bash
npx wrangler dev # Local dev
npx wrangler dev --remote # Remote dev (actual resources)
npx wrangler deploy # Production
npx wrangler deploy --env staging # Specific environment
npx wrangler tail # Stream logs
npx wrangler secret put API_KEY # Set secret
```
## When to Use Workers
- API endpoints at the edge
- Request/response transformation
- Authentication/authorization layers
- Static asset optimization
- A/B testing and feature flags
- Rate limiting and security
- Proxy/routing logic
- WebSocket applications
## Quick Start
```bash
npm create cloudflare@latest my-worker -- --type hello-world
cd my-worker
npx wrangler dev
```
## Handler Signatures
```typescript
// HTTP requests
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response>
// Cron triggers
async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext): Promise<void>
// Queue consumer
async queue(batch: MessageBatch, env: Env, ctx: ExecutionContext): Promise<void>
// Tail consumer
async tail(events: TraceItem[], env: Env, ctx: ExecutionContext): Promise<void>
```
## Resources
**Docs**: https://developers.cloudflare.com/workers/
**Examples**: https://developers.cloudflare.com/workers/examples/
**Runtime APIs**: https://developers.cloudflare.com/workers/runtime-apis/
## In This Reference
- [Configuration](./configuration.md) - wrangler.jsonc setup, bindings, environments
- [API](./api.md) - Runtime APIs, bindings, execution context
- [Patterns](./patterns.md) - Common workflows, testing, optimization
- [Frameworks](./frameworks.md) - Hono, routing, validation
- [Gotchas](./gotchas.md) - Common issues, limits, troubleshooting
## Reading Order
| Task | Start With | Then Read |
|------|------------|-----------|
| First Worker | README → Configuration → API | Patterns |
| Add framework | Frameworks | Configuration (bindings) |
| Add storage/bindings | Configuration → API (binding usage) | See Also links |
| Debug issues | Gotchas | API (specific binding docs) |
| Production optimization | Patterns | API (caching, streaming) |
| Type safety | Configuration (TypeScript) | Frameworks (Hono typing) |
## See Also
- [KV](../kv/README.md) - Key-value storage
- [D1](../d1/README.md) - SQL database
- [R2](../r2/README.md) - Object storage
- [Durable Objects](../durable-objects/README.md) - Stateful coordination
- [Queues](../queues/README.md) - Message queues
- [Wrangler](../wrangler/README.md) - CLI tool reference

View File

@@ -0,0 +1,195 @@
# Workers Runtime APIs
## Fetch Handler
```typescript
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
if (request.method === 'POST' && url.pathname === '/api') {
const body = await request.json();
return new Response(JSON.stringify({ id: 1 }), {
headers: { 'Content-Type': 'application/json' }
});
}
return fetch(request); // Subrequest to origin
},
};
```
## Execution Context
```typescript
ctx.waitUntil(logAnalytics(request)); // Background work, don't block response
ctx.passThroughOnException(); // Failover to origin on error
```
**Never** `await` background operations - use `ctx.waitUntil()`.
## Bindings
```typescript
// KV
await env.MY_KV.get('key');
await env.MY_KV.put('key', 'value', { expirationTtl: 3600 });
// R2
const obj = await env.MY_BUCKET.get('file.txt');
await env.MY_BUCKET.put('file.txt', 'content');
// D1
const result = await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(1).first();
// D1 Sessions (2024+) - read-after-write consistency
const session = env.DB.withSession();
await session.prepare('INSERT INTO users (name) VALUES (?)').bind('Alice').run();
const user = await session.prepare('SELECT * FROM users WHERE name = ?').bind('Alice').first(); // Guaranteed fresh
// Queues
await env.MY_QUEUE.send({ timestamp: Date.now() });
// Secrets/vars
const key = env.API_KEY;
```
## Cache API
```typescript
const cache = caches.default;
let response = await cache.match(request);
if (!response) {
response = await fetch(request);
response = new Response(response.body, response);
response.headers.set('Cache-Control', 'max-age=3600');
ctx.waitUntil(cache.put(request, response.clone())); // Clone before caching
}
```
## HTMLRewriter
```typescript
return new HTMLRewriter()
.on('a[href]', {
element(el) {
const href = el.getAttribute('href');
if (href?.startsWith('http://')) {
el.setAttribute('href', href.replace('http://', 'https://'));
}
}
})
.transform(response);
```
**Use cases**: A/B testing, analytics injection, link rewriting
## WebSockets
### Standard WebSocket
```typescript
const [client, server] = Object.values(new WebSocketPair());
server.accept();
server.addEventListener('message', event => {
server.send(`Echo: ${event.data}`);
});
return new Response(null, { status: 101, webSocket: client });
```
### WebSocket Hibernation (Recommended for idle connections)
```typescript
// In Durable Object
export class WebSocketDO {
async webSocketMessage(ws: WebSocket, message: string) {
ws.send(`Echo: ${message}`);
}
async webSocketClose(ws: WebSocket, code: number, reason: string) {
// Cleanup on close
}
async webSocketError(ws: WebSocket, error: Error) {
console.error('WebSocket error:', error);
}
}
```
Hibernation automatically suspends inactive connections (no CPU cost), wakes on events
## Durable Objects
### RPC Pattern (Recommended 2024+)
```typescript
export class Counter {
private value = 0;
constructor(private state: DurableObjectState) {
state.blockConcurrencyWhile(async () => {
this.value = (await state.storage.get('value')) || 0;
});
}
// Export methods directly - called via RPC (type-safe, zero serialization)
async increment(): Promise<number> {
this.value++;
await this.state.storage.put('value', this.value);
return this.value;
}
async getValue(): Promise<number> {
return this.value;
}
}
// Worker usage:
const stub = env.COUNTER.get(env.COUNTER.idFromName('global'));
const count = await stub.increment(); // Direct method call, full type safety
```
### Legacy Fetch Pattern (Pre-2024)
```typescript
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === '/increment') {
await this.state.storage.put('value', ++this.value);
}
return new Response(String(this.value));
}
// Usage: await stub.fetch('http://x/increment')
```
**When to use DOs**: Real-time collaboration, rate limiting, strongly consistent state
## Other Handlers
```typescript
// Cron: async scheduled(event, env, ctx) { ctx.waitUntil(doCleanup(env)); }
// Queue: async queue(batch) { for (const msg of batch.messages) { await process(msg.body); msg.ack(); } }
// Tail: async tail(events, env) { for (const e of events) if (e.outcome === 'exception') await log(e); }
```
## Service Bindings
```typescript
// Worker-to-worker RPC (zero latency, no internet round-trip)
return env.SERVICE_B.fetch(request);
// With RPC (2024+) - same as Durable Objects RPC
export class ServiceWorker {
async getData() { return { data: 'value' }; }
}
// Usage: const data = await env.SERVICE_B.getData();
```
**Benefits**: Type-safe method calls, no HTTP overhead, share code between Workers
## See Also
- [Configuration](./configuration.md) - Binding setup
- [Patterns](./patterns.md) - Common workflows
- [KV](../kv/README.md), [D1](../d1/README.md), [R2](../r2/README.md), [Durable Objects](../durable-objects/README.md), [Queues](../queues/README.md)

View File

@@ -0,0 +1,185 @@
# Workers Configuration
## wrangler.jsonc (Recommended)
```jsonc
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2025-01-01", // Use current date for new projects
// Bindings (non-inheritable)
"vars": { "ENVIRONMENT": "production" },
"kv_namespaces": [{ "binding": "MY_KV", "id": "abc123" }],
"r2_buckets": [{ "binding": "MY_BUCKET", "bucket_name": "my-bucket" }],
"d1_databases": [{ "binding": "DB", "database_name": "my-db", "database_id": "xyz789" }],
// Environments
"env": {
"staging": {
"vars": { "ENVIRONMENT": "staging" },
"kv_namespaces": [{ "binding": "MY_KV", "id": "staging-id" }]
}
}
}
```
## Configuration Rules
**Inheritable**: `name`, `main`, `compatibility_date`, `routes`, `workers_dev`
**Non-inheritable**: All bindings (`vars`, `kv_namespaces`, `r2_buckets`, etc.)
**Top-level only**: `migrations`, `keep_vars`, `send_metrics`
**ALWAYS set `compatibility_date` to current date for new projects**
## Bindings
```jsonc
{
// Environment variables - access via env.VAR_NAME
"vars": { "ENVIRONMENT": "production" },
// KV (key-value storage)
"kv_namespaces": [{ "binding": "MY_KV", "id": "abc123" }],
// R2 (object storage)
"r2_buckets": [{ "binding": "MY_BUCKET", "bucket_name": "my-bucket" }],
// D1 (SQL database)
"d1_databases": [{ "binding": "DB", "database_name": "my-db", "database_id": "xyz789" }],
// Durable Objects (stateful coordination)
"durable_objects": {
"bindings": [{ "name": "COUNTER", "class_name": "Counter" }]
},
// Queues (message queues)
"queues": {
"producers": [{ "binding": "MY_QUEUE", "queue": "my-queue" }],
"consumers": [{ "queue": "my-queue", "max_batch_size": 10 }]
},
// Service bindings (worker-to-worker RPC)
"services": [{ "binding": "SERVICE_B", "service": "service-b" }],
// Analytics Engine
"analytics_engine_datasets": [{ "binding": "ANALYTICS" }]
}
```
### Secrets
Set via CLI (never in config):
```bash
npx wrangler secret put API_KEY
```
Access: `env.API_KEY`
### Automatic Provisioning (Beta)
Bindings without IDs are auto-created:
```jsonc
{ "kv_namespaces": [{ "binding": "MY_KV" }] } // ID added on deploy
```
## Routes & Triggers
```jsonc
{
"routes": [
{ "pattern": "example.com/*", "zone_name": "example.com" }
],
"triggers": {
"crons": ["0 */6 * * *"] // Every 6 hours
}
}
```
## TypeScript Setup
### Automatic Type Generation (Recommended)
```bash
npm install -D @cloudflare/workers-types
npx wrangler types # Generates .wrangler/types/runtime.d.ts from wrangler.jsonc
```
`tsconfig.json`:
```jsonc
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"types": ["@cloudflare/workers-types"]
},
"include": [".wrangler/types/**/*.ts", "src/**/*"]
}
```
Import generated types:
```typescript
import type { Env } from './.wrangler/types/runtime';
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
await env.MY_KV.get('key'); // Fully typed, autocomplete works
return new Response('OK');
},
};
```
Re-run `npx wrangler types` after changing bindings in wrangler.jsonc
### Manual Type Definition (Legacy)
```typescript
interface Env {
MY_KV: KVNamespace;
DB: D1Database;
API_KEY: string;
}
```
## Advanced Options
```jsonc
{
// Auto-locate compute near data sources
"placement": { "mode": "smart" },
// Enable Node.js built-ins (Buffer, process, path, etc.)
"compatibility_flags": ["nodejs_compat_v2"],
// Observability (10% sampling)
"observability": { "enabled": true, "head_sampling_rate": 0.1 }
}
```
### Node.js Compatibility
`nodejs_compat_v2` enables:
- `Buffer`, `process.env`, `path`, `stream`
- CommonJS `require()` for Node modules
- `node:` imports (e.g., `import { Buffer } from 'node:buffer'`)
**Note:** Adds ~1-2ms cold start overhead. Use Workers APIs (R2, KV) when possible
## Deployment Commands
```bash
npx wrangler deploy # Production
npx wrangler deploy --env staging
npx wrangler deploy --dry-run # Validate only
```
## See Also
- [API](./api.md) - Runtime APIs and bindings usage
- [Patterns](./patterns.md) - Deployment strategies
- [Wrangler](../wrangler/README.md) - CLI reference

View File

@@ -0,0 +1,197 @@
# Workers Frameworks
## Hono (Recommended)
Workers-native web framework with excellent TypeScript support and middleware ecosystem.
```bash
npm install hono
```
### Basic Setup
```typescript
import { Hono } from 'hono';
const app = new Hono();
app.get('/', (c) => c.text('Hello World!'));
app.post('/api/users', async (c) => {
const body = await c.req.json();
return c.json({ id: 1, ...body }, 201);
});
export default app;
```
### Typed Environment
```typescript
import type { Env } from './.wrangler/types/runtime';
const app = new Hono<{ Bindings: Env }>();
app.get('/data', async (c) => {
const value = await c.env.MY_KV.get('key'); // Fully typed
return c.text(value || 'Not found');
});
```
### Middleware
```typescript
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
app.use('*', logger());
app.use('/api/*', cors({ origin: '*' }));
// Custom middleware
app.use('/protected/*', async (c, next) => {
const auth = c.req.header('Authorization');
if (!auth?.startsWith('Bearer ')) return c.text('Unauthorized', 401);
await next();
});
```
### Request Validation (Zod)
```typescript
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
const schema = z.object({
name: z.string().min(1),
email: z.string().email(),
});
app.post('/users', zValidator('json', schema), async (c) => {
const validated = c.req.valid('json'); // Type-safe, validated data
return c.json({ id: 1, ...validated });
});
```
**Error handling**: Automatic 400 response with validation errors
### Route Groups
```typescript
const api = new Hono().basePath('/api');
api.get('/users', (c) => c.json([]));
api.post('/users', (c) => c.json({ id: 1 }));
app.route('/', api); // Mounts at /api/*
```
### Error Handling
```typescript
app.onError((err, c) => {
console.error(err);
return c.json({ error: err.message }, 500);
});
app.notFound((c) => c.json({ error: 'Not Found' }, 404));
```
### Accessing ExecutionContext
```typescript
export default {
fetch(request: Request, env: Env, ctx: ExecutionContext) {
return app.fetch(request, env, ctx);
},
};
// In route handlers:
app.get('/log', (c) => {
c.executionCtx.waitUntil(logRequest(c.req));
return c.text('OK');
});
```
### OpenAPI/Swagger (Hono OpenAPI)
```typescript
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi';
const app = new OpenAPIHono();
const route = createRoute({
method: 'get',
path: '/users/{id}',
request: { params: z.object({ id: z.string() }) },
responses: {
200: { description: 'User found', content: { 'application/json': { schema: z.object({ id: z.string() }) } } },
},
});
app.openapi(route, (c) => {
const { id } = c.req.valid('param');
return c.json({ id });
});
app.doc('/openapi.json', { openapi: '3.0.0', info: { version: '1.0.0', title: 'API' } });
```
### Testing with Hono
```typescript
import { describe, it, expect } from 'vitest';
import app from '../src/index';
describe('API', () => {
it('GET /', async () => {
const res = await app.request('/');
expect(res.status).toBe(200);
expect(await res.text()).toBe('Hello World!');
});
});
```
## Other Frameworks
### itty-router (Minimalist)
```typescript
import { Router } from 'itty-router';
const router = Router();
router.get('/users/:id', ({ params }) => new Response(params.id));
export default { fetch: router.handle };
```
**Use case**: Tiny bundle size (~500 bytes), simple routing needs
### Worktop (Advanced)
```typescript
import { Router } from 'worktop';
const router = new Router();
router.add('GET', '/users/:id', (req, res) => {
res.send(200, { id: req.params.id });
});
router.listen();
```
**Use case**: Advanced routing, built-in CORS/cache utilities
## Framework Comparison
| Framework | Bundle Size | TypeScript | Middleware | Validation | Best For |
|-----------|-------------|------------|------------|------------|----------|
| Hono | ~12KB | Excellent | Rich | Zod | Production apps |
| itty-router | ~500B | Good | Basic | Manual | Minimal APIs |
| Worktop | ~8KB | Good | Advanced | Manual | Complex routing |
## See Also
- [Patterns](./patterns.md) - Common workflows
- [API](./api.md) - Runtime APIs
- [Gotchas](./gotchas.md) - Framework-specific issues

View File

@@ -0,0 +1,136 @@
# Workers Gotchas
## Common Errors
### "Too much CPU time used"
**Cause:** Worker exceeded CPU time limit (10ms standard, 30ms unbound)
**Solution:** Use `ctx.waitUntil()` for background work, offload heavy compute to Durable Objects, or consider Workers AI for ML workloads
### "Module-Level State Lost"
**Cause:** Workers are stateless between requests; module-level variables reset unpredictably
**Solution:** Use KV, D1, or Durable Objects for persistent state; don't rely on module-level variables
### "Body has already been used"
**Cause:** Attempting to read response body twice (bodies are streams)
**Solution:** Clone response before reading: `response.clone()` or read once and create new Response with the text
### "Node.js module not found"
**Cause:** Node.js built-ins not available by default
**Solution:** Use Workers APIs (e.g., R2 for file storage) or enable Node.js compat with `"compatibility_flags": ["nodejs_compat_v2"]`
### "Cannot fetch in global scope"
**Cause:** Attempting to use fetch during module initialization
**Solution:** Move fetch calls inside handler functions (fetch, scheduled, etc.) where they're allowed
### "Subrequest depth limit exceeded"
**Cause:** Too many nested subrequests creating deep call chain
**Solution:** Flatten request chain or use service bindings for direct Worker-to-Worker communication
### "D1 read-after-write inconsistency"
**Cause:** D1 is eventually consistent; reads may not reflect recent writes
**Solution:** Use D1 Sessions (2024+) to guarantee read-after-write consistency within a session:
```typescript
const session = env.DB.withSession();
await session.prepare('INSERT INTO users (name) VALUES (?)').bind('Alice').run();
const user = await session.prepare('SELECT * FROM users WHERE name = ?').bind('Alice').first(); // Guaranteed to see Alice
```
**When to use sessions:** Write → Read patterns, transactions requiring consistency
### "wrangler types not generating TypeScript definitions"
**Cause:** Type generation not configured or outdated
**Solution:** Run `npx wrangler types` after changing bindings in wrangler.jsonc:
```bash
npx wrangler types # Generates .wrangler/types/runtime.d.ts
```
Add to `tsconfig.json`: `"include": [".wrangler/types/**/*.ts"]`
Then import: `import type { Env } from './.wrangler/types/runtime';`
### "Durable Object RPC errors with deprecated fetch pattern"
**Cause:** Using old `stub.fetch()` pattern instead of RPC (2024+)
**Solution:** Export methods directly, call via RPC:
```typescript
// ❌ Old fetch pattern
export class MyDO {
async fetch(request: Request) {
const { method } = await request.json();
if (method === 'increment') return new Response(String(await this.increment()));
}
async increment() { return ++this.value; }
}
const stub = env.DO.get(id);
const res = await stub.fetch('http://x', { method: 'POST', body: JSON.stringify({ method: 'increment' }) });
// ✅ RPC pattern (type-safe, no serialization overhead)
export class MyDO {
async increment() { return ++this.value; }
}
const stub = env.DO.get(id);
const count = await stub.increment(); // Direct method call
```
### "WebSocket connection closes unexpectedly"
**Cause:** Worker reaches CPU limit while maintaining WebSocket connection
**Solution:** Use WebSocket hibernation (2024+) to offload idle connections:
```typescript
export class WebSocketDO {
async webSocketMessage(ws: WebSocket, message: string) {
// Handle message
}
async webSocketClose(ws: WebSocket, code: number) {
// Cleanup
}
}
```
Hibernation automatically suspends inactive connections, wakes on events
### "Framework middleware not working with Workers"
**Cause:** Framework expects Node.js primitives (e.g., Express uses Node streams)
**Solution:** Use Workers-native frameworks (Hono, itty-router, Worktop) or adapt middleware:
```typescript
// ✅ Hono (Workers-native)
import { Hono } from 'hono';
const app = new Hono();
app.use('*', async (c, next) => { /* middleware */ await next(); });
```
See [frameworks.md](./frameworks.md) for full patterns
## Limits
| Limit | Value | Notes |
|-------|-------|-------|
| Request size | 100 MB | Maximum incoming request size |
| Response size | Unlimited | Supports streaming |
| CPU time (standard) | 10ms | Standard Workers |
| CPU time (unbound) | 30ms | Unbound Workers |
| Subrequests | 1000 | Per request |
| KV reads | 1000 | Per request |
| KV write size | 25 MB | Maximum per write |
| Environment size | 5 MB | Total size of env bindings |
## See Also
- [Patterns](./patterns.md) - Best practices
- [API](./api.md) - Runtime APIs
- [Configuration](./configuration.md) - Setup
- [Frameworks](./frameworks.md) - Hono, routing, validation

View File

@@ -0,0 +1,198 @@
# Workers Patterns
## Error Handling
```typescript
class HTTPError extends Error {
constructor(public status: number, message: string) { super(message); }
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
try {
return await handleRequest(request, env);
} catch (error) {
if (error instanceof HTTPError) {
return new Response(JSON.stringify({ error: error.message }), {
status: error.status, headers: { 'Content-Type': 'application/json' }
});
}
return new Response('Internal Server Error', { status: 500 });
}
},
};
```
## CORS
```typescript
const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS' };
if (request.method === 'OPTIONS') return new Response(null, { headers: corsHeaders });
```
## Routing
```typescript
const router = { 'GET /api/users': handleGetUsers, 'POST /api/users': handleCreateUser };
const handler = router[`${request.method} ${url.pathname}`];
return handler ? handler(request, env) : new Response('Not Found', { status: 404 });
```
**Production**: Use Hono, itty-router, or Worktop (see [frameworks.md](./frameworks.md))
## Request Validation (Zod)
```typescript
import { z } from 'zod';
const userSchema = z.object({
name: z.string().min(1).max(100),
email: z.string().email(),
age: z.number().int().positive().optional(),
});
async function handleCreateUser(request: Request) {
try {
const body = await request.json();
const validated = userSchema.parse(body); // Throws on invalid data
return new Response(JSON.stringify({ id: 1, ...validated }), {
status: 201,
headers: { 'Content-Type': 'application/json' },
});
} catch (err) {
if (err instanceof z.ZodError) {
return new Response(JSON.stringify({ errors: err.errors }), { status: 400 });
}
throw err;
}
}
```
**With Hono**: Use `@hono/zod-validator` for automatic validation (see [frameworks.md](./frameworks.md))
## Performance
```typescript
// ❌ Sequential
const user = await fetch('/api/user/1');
const posts = await fetch('/api/posts?user=1');
// ✅ Parallel
const [user, posts] = await Promise.all([fetch('/api/user/1'), fetch('/api/posts?user=1')]);
```
## Streaming
```typescript
const stream = new ReadableStream({
async start(controller) {
for (let i = 0; i < 1000; i++) {
controller.enqueue(new TextEncoder().encode(`Item ${i}\n`));
if (i % 100 === 0) await new Promise(r => setTimeout(r, 0));
}
controller.close();
}
});
```
## Transform Streams
```typescript
response.body.pipeThrough(new TextDecoderStream()).pipeThrough(
new TransformStream({ transform(chunk, c) { c.enqueue(chunk.toUpperCase()); } })
).pipeThrough(new TextEncoderStream());
```
## Testing
```typescript
import { describe, it, expect } from 'vitest';
import worker from '../src/index';
describe('Worker', () => {
it('returns 200', async () => {
const req = new Request('http://localhost/');
const env = { MY_VAR: 'test' };
const ctx = { waitUntil: () => {}, passThroughOnException: () => {} };
expect((await worker.fetch(req, env, ctx)).status).toBe(200);
});
});
```
## Deployment
```bash
npx wrangler deploy # production
npx wrangler deploy --env staging
npx wrangler versions upload --message "Add feature"
npx wrangler rollback
```
## Monitoring
```typescript
const start = Date.now();
const response = await handleRequest(request, env);
ctx.waitUntil(env.ANALYTICS.writeDataPoint({
doubles: [Date.now() - start], blobs: [request.url, String(response.status)]
}));
```
## Security & Rate Limiting
```typescript
// Security headers
const security = { 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'DENY' };
// Auth
const auth = request.headers.get('Authorization');
if (!auth?.startsWith('Bearer ')) return new Response('Unauthorized', { status: 401 });
// Gradual rollouts (deterministic user bucketing)
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(userId));
if (new Uint8Array(hash)[0] % 100 < rolloutPercent) return newFeature(request);
```
Rate limiting: See [Durable Objects](../durable-objects/README.md)
## R2 Multipart Upload
```typescript
// For files > 100MB
const upload = await env.MY_BUCKET.createMultipartUpload('large-file.bin');
try {
const parts = [];
for (let i = 0; i < chunks.length; i++) {
parts.push(await upload.uploadPart(i + 1, chunks[i]));
}
await upload.complete(parts);
} catch (err) { await upload.abort(); throw err; }
```
Parallel uploads, resume on failure, handle files > 5GB
## Workflows (Step Orchestration)
```typescript
import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from 'cloudflare:workers';
export class MyWorkflow extends WorkflowEntrypoint {
async run(event: WorkflowEvent<{ userId: string }>, step: WorkflowStep) {
const user = await step.do('fetch-user', async () =>
fetch(`/api/users/${event.payload.userId}`).then(r => r.json())
);
await step.sleep('wait', '1 hour');
await step.do('notify', async () => sendEmail(user.email));
}
}
```
Multi-step jobs with automatic retries, state persistence, resume from failure
## See Also
- [API](./api.md) - Runtime APIs
- [Gotchas](./gotchas.md) - Common issues
- [Configuration](./configuration.md) - Setup
- [Frameworks](./frameworks.md) - Hono, routing, validation