mirror of
https://github.com/ksyasuda/dotfiles.git
synced 2026-03-20 06:11:27 -07:00
update skills
This commit is contained in:
141
.agents/skills/cloudflare-deploy/references/wrangler/README.md
Normal file
141
.agents/skills/cloudflare-deploy/references/wrangler/README.md
Normal 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`
|
||||
188
.agents/skills/cloudflare-deploy/references/wrangler/api.md
Normal file
188
.agents/skills/cloudflare-deploy/references/wrangler/api.md
Normal 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
|
||||
73
.agents/skills/cloudflare-deploy/references/wrangler/auth.md
Normal file
73
.agents/skills/cloudflare-deploy/references/wrangler/auth.md
Normal 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
|
||||
@@ -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
|
||||
197
.agents/skills/cloudflare-deploy/references/wrangler/gotchas.md
Normal file
197
.agents/skills/cloudflare-deploy/references/wrangler/gotchas.md
Normal 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
|
||||
209
.agents/skills/cloudflare-deploy/references/wrangler/patterns.md
Normal file
209
.agents/skills/cloudflare-deploy/references/wrangler/patterns.md
Normal 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
|
||||
Reference in New Issue
Block a user