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,141 @@
# Cloudflare Wrangler
Official CLI for Cloudflare Workers - develop, manage, and deploy Workers from the command line.
## What is Wrangler?
Wrangler is the Cloudflare Developer Platform CLI that allows you to:
- Create, develop, and deploy Workers
- Manage bindings (KV, D1, R2, Durable Objects, etc.)
- Configure routing and environments
- Run local development servers
- Execute migrations and manage resources
- Perform integration testing
## Installation
```bash
npm install wrangler --save-dev
# or globally
npm install -g wrangler
```
Run commands: `npx wrangler <command>` (or `pnpm`/`yarn wrangler`)
## Reading Order
| If you want to... | Start here |
|-------------------|------------|
| Create/deploy Worker quickly | Essential Commands below → [patterns.md](./patterns.md) §New Worker |
| Configure bindings (KV, D1, R2) | [configuration.md](./configuration.md) §Bindings |
| Write integration tests | [api.md](./api.md) §startWorker |
| Debug production issues | [gotchas.md](./gotchas.md) + Essential Commands §Monitoring |
| Set up multi-environment workflow | [configuration.md](./configuration.md) §Environments |
## Essential Commands
### Project & Development
```bash
wrangler init [name] # Create new project
wrangler dev # Local dev server (fast, simulated)
wrangler dev --remote # Dev with remote resources (production-like)
wrangler deploy # Deploy to production
wrangler deploy --env staging # Deploy to environment
wrangler versions list # List versions
wrangler rollback [id] # Rollback deployment
wrangler login # OAuth login
wrangler whoami # Check auth status
```
## Resource Management
### KV
```bash
wrangler kv namespace create NAME
wrangler kv key put "key" "value" --namespace-id=<id>
wrangler kv key get "key" --namespace-id=<id>
```
### D1
```bash
wrangler d1 create NAME
wrangler d1 execute NAME --command "SQL"
wrangler d1 migrations create NAME "description"
wrangler d1 migrations apply NAME
```
### R2
```bash
wrangler r2 bucket create NAME
wrangler r2 object put BUCKET/key --file path
wrangler r2 object get BUCKET/key
```
### Other Resources
```bash
wrangler queues create NAME
wrangler vectorize create NAME --dimensions N --metric cosine
wrangler hyperdrive create NAME --connection-string "..."
wrangler workflows create NAME
wrangler constellation create NAME
wrangler pages project create NAME
wrangler pages deployment create --project NAME --branch main
```
### Secrets
```bash
wrangler secret put NAME # Set Worker secret
wrangler secret list # List Worker secrets
wrangler secret delete NAME # Delete Worker secret
wrangler secret bulk FILE.json # Bulk upload from JSON
# Secrets Store (centralized, reusable across Workers)
wrangler secret-store:secret put STORE_NAME SECRET_NAME
wrangler secret-store:secret list STORE_NAME
```
### Monitoring
```bash
wrangler tail # Real-time logs
wrangler tail --env production # Tail specific env
wrangler tail --status error # Filter by status
```
## In This Reference
- [auth.md](./auth.md) - Authentication setup (`wrangler login`, API tokens)
- [configuration.md](./configuration.md) - wrangler.jsonc setup, environments, bindings
- [api.md](./api.md) - Programmatic API (`startWorker`, `getPlatformProxy`, events)
- [patterns.md](./patterns.md) - Common workflows and development patterns
- [gotchas.md](./gotchas.md) - Common pitfalls, limits, and troubleshooting
## Quick Decision Tree
```
Need to test your Worker?
├─ Testing full Worker with bindings → api.md §startWorker
├─ Testing individual functions → api.md §getPlatformProxy
└─ Testing with Vitest → patterns.md §Testing with Vitest
Need to configure something?
├─ Bindings (KV, D1, R2, etc.) → configuration.md §Bindings
├─ Multiple environments → configuration.md §Environments
├─ Static files → configuration.md §Workers Assets
└─ Routing → configuration.md §Routing
Development not working?
├─ Local differs from production → Use `wrangler dev --remote`
├─ Bindings not available → gotchas.md §Binding Not Available
└─ Auth issues → auth.md
Authentication issues?
├─ "Not logged in" / "Unauthorized" → auth.md
├─ First time deploying → `wrangler login` (one-time OAuth)
└─ CI/CD setup → auth.md §API Token
```
## See Also
- [workers](../workers/) - Workers runtime API reference
- [miniflare](../miniflare/) - Local testing with Miniflare
- [workerd](../workerd/) - Runtime that powers `wrangler dev`

View File

@@ -0,0 +1,188 @@
# Wrangler Programmatic API
Node.js APIs for testing and development.
## startWorker (Testing)
Starts Worker with real local bindings for integration tests. Stable API (replaces `unstable_startWorker`).
```typescript
import { startWorker } from "wrangler";
import { describe, it, before, after } from "node:test";
import assert from "node:assert";
describe("worker", () => {
let worker;
before(async () => {
worker = await startWorker({
config: "wrangler.jsonc",
environment: "development"
});
});
after(async () => {
await worker.dispose();
});
it("responds with 200", async () => {
const response = await worker.fetch("http://example.com");
assert.strictEqual(response.status, 200);
});
});
```
### Options
| Option | Type | Description |
|--------|------|-------------|
| `config` | `string` | Path to wrangler.jsonc |
| `environment` | `string` | Environment name from config |
| `persist` | `boolean \| { path: string }` | Enable persistent state |
| `bundle` | `boolean` | Enable bundling (default: true) |
| `remote` | `false \| true \| "minimal"` | Remote mode: `false` (local), `true` (full remote), `"minimal"` (remote bindings only) |
### Remote Mode
```typescript
// Local mode (default) - fast, simulated
const worker = await startWorker({ config: "wrangler.jsonc" });
// Full remote mode - production-like, slower
const worker = await startWorker({
config: "wrangler.jsonc",
remote: true
});
// Minimal remote mode - remote bindings, local Worker
const worker = await startWorker({
config: "wrangler.jsonc",
remote: "minimal"
});
```
## getPlatformProxy
Emulate bindings in Node.js without starting Worker.
```typescript
import { getPlatformProxy } from "wrangler";
const { env, dispose, caches } = await getPlatformProxy<Env>({
configPath: "wrangler.jsonc",
environment: "production",
persist: { path: ".wrangler/state" }
});
// Use bindings
const value = await env.MY_KV.get("key");
await env.DB.prepare("SELECT * FROM users").all();
await env.ASSETS.put("file.txt", "content");
// Platform APIs
await caches.default.put("https://example.com", new Response("cached"));
await dispose();
```
Use for unit tests (test functions, not full Worker) or scripts that need bindings.
## Type Generation
Generate types from config: `wrangler types` → creates `worker-configuration.d.ts`
## Event System
Listen to Worker lifecycle events for advanced workflows.
```typescript
import { startWorker } from "wrangler";
const worker = await startWorker({
config: "wrangler.jsonc",
bundle: true
});
// Bundle events
worker.on("bundleStart", (details) => {
console.log("Bundling started:", details.config);
});
worker.on("bundleComplete", (details) => {
console.log("Bundle ready:", details.duration);
});
// Reconfiguration events
worker.on("reloadStart", () => {
console.log("Worker reloading...");
});
worker.on("reloadComplete", () => {
console.log("Worker reloaded");
});
await worker.dispose();
```
### Dynamic Reconfiguration
```typescript
import { startWorker } from "wrangler";
const worker = await startWorker({ config: "wrangler.jsonc" });
// Replace entire config
await worker.setConfig({
config: "wrangler.staging.jsonc",
environment: "staging"
});
// Patch specific fields
await worker.patchConfig({
vars: { DEBUG: "true" }
});
await worker.dispose();
```
## unstable_dev (Deprecated)
Use `startWorker` instead.
## Multi-Worker Registry
Test multiple Workers with service bindings.
```typescript
import { startWorker } from "wrangler";
const auth = await startWorker({ config: "./auth/wrangler.jsonc" });
const api = await startWorker({
config: "./api/wrangler.jsonc",
bindings: { AUTH: auth } // Service binding
});
const response = await api.fetch("http://example.com/api/login");
// API Worker calls AUTH Worker via env.AUTH.fetch()
await api.dispose();
await auth.dispose();
```
## Best Practices
- Use `startWorker` for integration tests (tests full Worker)
- Use `getPlatformProxy` for unit tests (tests individual functions)
- Use `remote: true` when debugging production-specific issues
- Use `remote: "minimal"` for faster tests with real bindings
- Enable `persist: true` for debugging (state survives runs)
- Run `wrangler types` after config changes
- Always `dispose()` to prevent resource leaks
- Listen to bundle events for build monitoring
- Use multi-worker registry for testing service bindings
## See Also
- [README.md](./README.md) - CLI commands
- [configuration.md](./configuration.md) - Config
- [patterns.md](./patterns.md) - Testing patterns

View File

@@ -0,0 +1,73 @@
# Authentication
Authenticate with Cloudflare before deploying Workers or Pages.
## Quick Decision Tree
```
Need to authenticate?
├─ Interactive/local dev → wrangler login (recommended)
├─ CI/CD or headless → CLOUDFLARE_API_TOKEN env var
└─ Terraform/Pulumi → See respective references
```
## wrangler login (Recommended)
One-time OAuth flow for local development:
```bash
npx wrangler login # Opens browser, completes OAuth
npx wrangler whoami # Verify: shows email + account ID
```
Credentials stored locally. Works for all subsequent commands.
## API Token (CI/CD)
For automated pipelines or environments without browser access:
1. Go to: **https://dash.cloudflare.com/profile/api-tokens**
2. Click **Create Token**
3. Use template: **"Edit Cloudflare Workers"** (covers Workers, Pages, KV, D1, R2)
4. Copy the token (shown only once)
5. Set environment variable:
```bash
export CLOUDFLARE_API_TOKEN="your-token-here"
```
### Minimal Permissions by Task
| Task | Template / Permissions |
|------|------------------------|
| Deploy Workers/Pages | "Edit Cloudflare Workers" template |
| Read-only access | "Read All Resources" template |
| Custom scope | Account:Read + Workers Scripts:Edit + specific resources |
## Troubleshooting
| Error | Cause | Fix |
|-------|-------|-----|
| "Not logged in" | No credentials | `wrangler login` or set `CLOUDFLARE_API_TOKEN` |
| "Authentication error" | Invalid/expired token | Regenerate token in dashboard |
| "Missing account" | Wrong account selected | `wrangler whoami` to check, add `account_id` to wrangler.jsonc |
| Token works locally, fails CI | Token scoped to wrong account | Verify account ID matches in both places |
| "Insufficient permissions" | Token lacks required scope | Create new token with correct permissions |
## Verifying Authentication
```bash
npx wrangler whoami
```
Output shows:
- Email (if OAuth login)
- Account ID and name
- Token scopes (if API token)
Non-zero exit code means not authenticated.
## See Also
- [terraform/README.md](../terraform/README.md) - Terraform provider auth
- [pulumi/README.md](../pulumi/README.md) - Pulumi provider auth

View File

@@ -0,0 +1,197 @@
# Wrangler Configuration
Configuration reference for wrangler.jsonc (recommended).
## Config Format
**wrangler.jsonc recommended** (v3.91.0+) - provides schema validation.
```jsonc
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2025-01-01", // Use current date
"vars": { "API_KEY": "dev-key" },
"kv_namespaces": [{ "binding": "MY_KV", "id": "abc123" }]
}
```
## Field Inheritance
Inheritable: `name`, `main`, `compatibility_date`, `routes`, `triggers`
Non-inheritable (define per env): `vars`, bindings (KV, D1, R2, etc.)
## Environments
```jsonc
{
"name": "my-worker",
"vars": { "ENV": "dev" },
"env": {
"production": {
"name": "my-worker-prod",
"vars": { "ENV": "prod" },
"route": { "pattern": "example.com/*", "zone_name": "example.com" }
}
}
}
```
Deploy: `wrangler deploy --env production`
## Routing
```jsonc
// Custom domain (recommended)
{ "routes": [{ "pattern": "api.example.com", "custom_domain": true }] }
// Zone-based
{ "routes": [{ "pattern": "api.example.com/*", "zone_name": "example.com" }] }
// workers.dev
{ "workers_dev": true }
```
## Bindings
```jsonc
// Variables
{ "vars": { "API_URL": "https://api.example.com" } }
// KV
{ "kv_namespaces": [{ "binding": "CACHE", "id": "abc123" }] }
// D1
{ "d1_databases": [{ "binding": "DB", "database_id": "abc-123" }] }
// R2
{ "r2_buckets": [{ "binding": "ASSETS", "bucket_name": "my-assets" }] }
// Durable Objects
{ "durable_objects": {
"bindings": [{
"name": "COUNTER",
"class_name": "Counter",
"script_name": "my-worker" // Required for external DOs
}]
} }
{ "migrations": [{ "tag": "v1", "new_sqlite_classes": ["Counter"] }] }
// Service Bindings
{ "services": [{ "binding": "AUTH", "service": "auth-worker" }] }
// Queues
{ "queues": {
"producers": [{ "binding": "TASKS", "queue": "task-queue" }],
"consumers": [{ "queue": "task-queue", "max_batch_size": 10 }]
} }
// Vectorize
{ "vectorize": [{ "binding": "VECTORS", "index_name": "embeddings" }] }
// Hyperdrive (requires nodejs_compat_v2 for pg/postgres)
{ "hyperdrive": [{ "binding": "HYPERDRIVE", "id": "hyper-id" }] }
{ "compatibility_flags": ["nodejs_compat_v2"] } // For pg/postgres
// Workers AI
{ "ai": { "binding": "AI" } }
// Workflows
{ "workflows": [{ "binding": "WORKFLOW", "name": "my-workflow", "class_name": "MyWorkflow" }] }
// Secrets Store (centralized secrets)
{ "secrets_store": [{ "binding": "SECRETS", "id": "store-id" }] }
// Constellation (AI inference)
{ "constellation": [{ "binding": "MODEL", "project_id": "proj-id" }] }
```
## Workers Assets (Static Files)
Recommended for serving static files (replaces old `site` config).
```jsonc
{
"assets": {
"directory": "./public",
"binding": "ASSETS",
"html_handling": "auto-trailing-slash", // or "none", "force-trailing-slash"
"not_found_handling": "single-page-application" // or "404-page", "none"
}
}
```
Access in Worker:
```typescript
export default {
async fetch(request, env) {
// Try serving static asset first
const asset = await env.ASSETS.fetch(request);
if (asset.status !== 404) return asset;
// Custom logic for non-assets
return new Response("API response");
}
}
```
## Placement
Control where Workers run geographically.
```jsonc
{
"placement": {
"mode": "smart" // or "off"
}
}
```
- `"smart"`: Run Worker near data sources (D1, Durable Objects) to reduce latency
- `"off"`: Default distribution (run everywhere)
## Auto-Provisioning (Beta)
Omit resource IDs - Wrangler creates them and writes back to config on deploy.
```jsonc
{ "kv_namespaces": [{ "binding": "MY_KV" }] } // No id - auto-provisioned
```
After deploy, ID is added to config automatically.
## Advanced
```jsonc
// Cron Triggers
{ "triggers": { "crons": ["0 0 * * *"] } }
// Observability (tracing)
{ "observability": { "enabled": true, "head_sampling_rate": 0.1 } }
// Runtime Limits
{ "limits": { "cpu_ms": 100 } }
// Browser Rendering
{ "browser": { "binding": "BROWSER" } }
// mTLS Certificates
{ "mtls_certificates": [{ "binding": "CERT", "certificate_id": "cert-uuid" }] }
// Logpush (stream logs to R2/S3)
{ "logpush": true }
// Tail Consumers (process logs with another Worker)
{ "tail_consumers": [{ "service": "log-worker" }] }
// Unsafe bindings (access to arbitrary bindings)
{ "unsafe": { "bindings": [{ "name": "MY_BINDING", "type": "plain_text", "text": "value" }] } }
```
## See Also
- [README.md](./README.md) - Overview and commands
- [api.md](./api.md) - Programmatic API
- [patterns.md](./patterns.md) - Workflows
- [gotchas.md](./gotchas.md) - Common issues

View File

@@ -0,0 +1,197 @@
# Wrangler Common Issues
## Common Errors
### "Binding ID vs name mismatch"
**Cause:** Confusion between binding name (code) and resource ID
**Solution:** Bindings use `binding` (code name) and `id`/`database_id`/`bucket_name` (resource ID). Preview bindings need separate IDs: `preview_id`, `preview_database_id`
### "Environment not inheriting config"
**Cause:** Non-inheritable keys not redefined per environment
**Solution:** Non-inheritable keys (bindings, vars) must be redefined per environment. Inheritable keys (routes, compatibility_date) can be overridden
### "Local dev behavior differs from production"
**Cause:** Using local simulation instead of remote execution
**Solution:** Choose appropriate remote mode:
- `wrangler dev` (default): Local simulation, fast, limited accuracy
- `wrangler dev --remote`: Full remote execution, production-accurate, slower
- Use `remote: "minimal"` in tests for fast tests with real remote bindings
### "startWorker doesn't match production"
**Cause:** Using local mode when remote resources needed
**Solution:** Use `remote` option:
```typescript
const worker = await startWorker({
config: "wrangler.jsonc",
remote: true // or "minimal" for faster tests
});
```
### "Unexpected runtime changes"
**Cause:** Missing compatibility_date
**Solution:** Always set `compatibility_date`:
```jsonc
{ "compatibility_date": "2025-01-01" }
```
### "Durable Object binding not working"
**Cause:** Missing script_name for external DOs
**Solution:** Always specify `script_name` for external Durable Objects:
```jsonc
{
"durable_objects": {
"bindings": [
{ "name": "MY_DO", "class_name": "MyDO", "script_name": "my-worker" }
]
}
}
```
For local DOs in same Worker, `script_name` is optional.
### "Auto-provisioned resources not appearing"
**Cause:** IDs written back to config on first deploy, but config not reloaded
**Solution:** After first deploy with auto-provisioning, config file is updated with IDs. Commit the updated config. On subsequent deploys, existing resources are reused.
### "Secrets not available in local dev"
**Cause:** Secrets set with `wrangler secret put` only work in deployed Workers
**Solution:** For local dev, use `.dev.vars`
### "Node.js compatibility error"
**Cause:** Missing Node.js compatibility flag
**Solution:** Some bindings (Hyperdrive with `pg`) require:
```jsonc
{ "compatibility_flags": ["nodejs_compat_v2"] }
```
### "Workers Assets 404 errors"
**Cause:** Asset path mismatch or incorrect `html_handling`
**Solution:**
- Check `assets.directory` points to correct build output
- Set `html_handling: "auto-trailing-slash"` for SPAs
- Use `not_found_handling: "single-page-application"` to serve index.html for 404s
```jsonc
{
"assets": {
"directory": "./dist",
"html_handling": "auto-trailing-slash",
"not_found_handling": "single-page-application"
}
}
```
### "Placement not reducing latency"
**Cause:** Misunderstanding of Smart Placement
**Solution:** Smart Placement only helps when Worker accesses D1 or Durable Objects. It doesn't affect KV, R2, or external API latency.
```jsonc
{ "placement": { "mode": "smart" } } // Only beneficial with D1/DOs
```
### "unstable_startWorker not found"
**Cause:** Using outdated API
**Solution:** Use stable `startWorker` instead:
```typescript
import { startWorker } from "wrangler"; // Not unstable_startWorker
```
### "outboundService not mocking fetch"
**Cause:** Mock function not returning Response
**Solution:** Always return Response, use `fetch(req)` for passthrough:
```typescript
const worker = await startWorker({
outboundService: (req) => {
if (shouldMock(req)) {
return new Response("mocked");
}
return fetch(req); // Required for non-mocked requests
}
});
```
## Limits
| Resource/Limit | Value | Notes |
|----------------|-------|-------|
| Bindings per Worker | 64 | Total across all types |
| Environments | Unlimited | Named envs in config |
| Config file size | ~1MB | Keep reasonable |
| Workers Assets size | 25 MB | Per deployment |
| Workers Assets files | 20,000 | Max number of files |
| Script size (compressed) | 1 MB | Free, 10 MB paid |
| CPU time | 10-50ms | Free, 50-500ms paid |
| Subrequest limit | 50 | Free, 1000 paid |
## Troubleshooting
### Authentication Issues
```bash
wrangler logout
wrangler login
wrangler whoami
```
### Configuration Errors
```bash
wrangler check # Validate config
```
Use wrangler.jsonc with `$schema` for validation.
### Binding Not Available
- Check binding exists in config
- For environments, ensure binding defined for that env
- Local dev: some bindings need `--remote`
### Deployment Failures
```bash
wrangler tail # Check logs
wrangler deploy --dry-run # Validate
wrangler whoami # Check account limits
```
### Local Development Issues
```bash
rm -rf .wrangler/state # Clear local state
wrangler dev --remote # Use remote bindings
wrangler dev --persist-to ./local-state # Custom persist location
wrangler dev --inspector-port 9229 # Enable debugging
```
### Testing Issues
```bash
# If tests hang, ensure dispose() is called
worker.dispose() // Always cleanup
# If bindings don't work in tests
const worker = await startWorker({
config: "wrangler.jsonc",
remote: "minimal" // Use remote bindings
});
```
## Resources
- Docs: https://developers.cloudflare.com/workers/wrangler/
- Config: https://developers.cloudflare.com/workers/wrangler/configuration/
- Commands: https://developers.cloudflare.com/workers/wrangler/commands/
- Examples: https://github.com/cloudflare/workers-sdk/tree/main/templates
- Discord: https://discord.gg/cloudflaredev
## See Also
- [README.md](./README.md) - Commands
- [configuration.md](./configuration.md) - Config
- [api.md](./api.md) - Programmatic API
- [patterns.md](./patterns.md) - Workflows

View File

@@ -0,0 +1,209 @@
# Wrangler Development Patterns
Common workflows and best practices.
## New Worker Project
```bash
wrangler init my-worker && cd my-worker
wrangler dev # Develop locally
wrangler deploy # Deploy
```
## Local Development
```bash
wrangler dev # Local mode (fast, simulated)
wrangler dev --remote # Remote mode (production-accurate)
wrangler dev --env staging --port 8787
wrangler dev --inspector-port 9229 # Enable debugging
```
Debug: chrome://inspect → Configure → localhost:9229
## Secrets
```bash
# Production
echo "secret-value" | wrangler secret put SECRET_KEY
# Local: use .dev.vars (gitignored)
# SECRET_KEY=local-dev-key
```
## Adding KV
```bash
wrangler kv namespace create MY_KV
wrangler kv namespace create MY_KV --preview
# Add to wrangler.jsonc: { "binding": "MY_KV", "id": "abc123" }
wrangler deploy
```
## Adding D1
```bash
wrangler d1 create my-db
wrangler d1 migrations create my-db "initial_schema"
# Edit migration file in migrations/, then:
wrangler d1 migrations apply my-db --local
wrangler deploy
wrangler d1 migrations apply my-db --remote
# Time Travel (restore to point in time)
wrangler d1 time-travel restore my-db --timestamp 2025-01-01T12:00:00Z
```
## Multi-Environment
```bash
wrangler deploy --env staging
wrangler deploy --env production
```
```jsonc
{ "env": { "staging": { "vars": { "ENV": "staging" } } } }
```
## Testing
### Integration Tests with Node.js Test Runner
```typescript
import { startWorker } from "wrangler";
import { describe, it, before, after } from "node:test";
import assert from "node:assert";
describe("API", () => {
let worker;
before(async () => {
worker = await startWorker({
config: "wrangler.jsonc",
remote: "minimal" // Fast tests with real bindings
});
});
after(async () => await worker.dispose());
it("creates user", async () => {
const response = await worker.fetch("http://example.com/api/users", {
method: "POST",
body: JSON.stringify({ name: "Alice" })
});
assert.strictEqual(response.status, 201);
});
});
```
### Testing with Vitest
Install: `npm install -D vitest @cloudflare/vitest-pool-workers`
**vitest.config.ts:**
```typescript
import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";
export default defineWorkersConfig({
test: { poolOptions: { workers: { wrangler: { configPath: "./wrangler.jsonc" } } } }
});
```
**tests/api.test.ts:**
```typescript
import { env, SELF } from "cloudflare:test";
import { describe, it, expect } from "vitest";
it("fetches users", async () => {
const response = await SELF.fetch("https://example.com/api/users");
expect(response.status).toBe(200);
});
it("uses bindings", async () => {
await env.MY_KV.put("key", "value");
expect(await env.MY_KV.get("key")).toBe("value");
});
```
### Multi-Worker Development (Service Bindings)
```typescript
const authWorker = await startWorker({ config: "./auth/wrangler.jsonc" });
const apiWorker = await startWorker({
config: "./api/wrangler.jsonc",
bindings: { AUTH: authWorker } // Service binding
});
// Test API calling AUTH
const response = await apiWorker.fetch("http://example.com/api/protected");
await authWorker.dispose();
await apiWorker.dispose();
```
### Mock External APIs
```typescript
const worker = await startWorker({
config: "wrangler.jsonc",
outboundService: (req) => {
const url = new URL(req.url);
if (url.hostname === "api.external.com") {
return new Response(JSON.stringify({ mocked: true }), {
headers: { "content-type": "application/json" }
});
}
return fetch(req); // Pass through other requests
}
});
// Test Worker that calls external API
const response = await worker.fetch("http://example.com/proxy");
// Worker internally fetches api.external.com - gets mocked response
```
## Monitoring & Versions
```bash
wrangler tail # Real-time logs
wrangler tail --status error # Filter errors
wrangler versions list
wrangler rollback [id]
```
## TypeScript
```bash
wrangler types # Generate types from config
```
```typescript
export default {
async fetch(request: Request, env: Env): Promise<Response> {
return Response.json({ value: await env.MY_KV.get("key") });
}
} satisfies ExportedHandler<Env>;
```
## Workers Assets
```jsonc
{ "assets": { "directory": "./dist", "binding": "ASSETS" } }
```
```typescript
export default {
async fetch(request, env) {
// API routes first
if (new URL(request.url).pathname.startsWith("/api/")) {
return Response.json({ data: "from API" });
}
return env.ASSETS.fetch(request); // Static assets
}
}
```
## See Also
- [README.md](./README.md) - Commands
- [configuration.md](./configuration.md) - Config
- [api.md](./api.md) - Programmatic API
- [gotchas.md](./gotchas.md) - Issues