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,127 @@
# Cloudflare Workers Playground Skill Reference
## Overview
Cloudflare Workers Playground is a browser-based sandbox for instantly experimenting with, testing, and deploying Cloudflare Workers without authentication or setup. This skill provides patterns, APIs, and best practices specifically for Workers Playground development.
**URL:** [workers.cloudflare.com/playground](https://workers.cloudflare.com/playground)
## ⚠️ Playground Constraints
**Playground is NOT production-equivalent:**
- ✅ Real Workers runtime, instant testing, shareable URLs
- ❌ No TypeScript (JavaScript only)
- ❌ No bindings (KV, D1, R2, Durable Objects)
- ❌ No environment variables or secrets
- ❌ ES modules only (no Service Worker format)
- ⚠️ Safari broken (use Chrome/Firefox)
**For production:** Use `wrangler` CLI. Playground is for rapid prototyping.
## Quick Start
Minimal Worker:
```javascript
export default {
async fetch(request, env, ctx) {
return new Response('Hello World');
}
};
```
JSON API:
```javascript
export default {
async fetch(request, env, ctx) {
const data = { message: 'Hello', timestamp: Date.now() };
return Response.json(data);
}
};
```
Proxy with modification:
```javascript
export default {
async fetch(request, env, ctx) {
const response = await fetch('https://example.com');
const modified = new Response(response.body, response);
modified.headers.set('X-Custom-Header', 'added-by-worker');
return modified;
}
};
```
Import from CDN:
```javascript
import { Hono } from 'https://esm.sh/hono@3';
export default {
async fetch(request) {
const app = new Hono();
app.get('/', (c) => c.text('Hello Hono!'));
return app.fetch(request);
}
};
```
## Reading Order
1. **[configuration.md](configuration.md)** - Start here: playground setup, constraints, deployment
2. **[api.md](api.md)** - Core APIs: Request, Response, ExecutionContext, fetch, Cache
3. **[patterns.md](patterns.md)** - Common use cases: routing, proxying, A/B testing, multi-module code
4. **[gotchas.md](gotchas.md)** - Troubleshooting: errors, browser issues, limits, best practices
## In This Reference
- **[configuration.md](configuration.md)** - Setup, deployment, configuration
- **[api.md](api.md)** - API endpoints, methods, interfaces
- **[patterns.md](patterns.md)** - Common patterns, use cases, examples
- **[gotchas.md](gotchas.md)** - Troubleshooting, best practices, limitations
## Key Features
**No Setup Required:**
- Open URL and start coding
- No CLI, no account, no config files
- Code executes in real Cloudflare Workers runtime
**Instant Preview:**
- Live preview pane with browser tab or HTTP tester
- Auto-reload on code changes
- DevTools integration (right-click → Inspect)
**Share & Deploy:**
- Copy Link generates permanent shareable URL
- Deploy button publishes to production in ~30 seconds
- Get `*.workers.dev` subdomain immediately
## Common Use Cases
- **API development:** Test endpoints before wrangler setup
- **Learning Workers:** Experiment with APIs without local environment
- **Prototyping:** Quick POCs for edge logic
- **Sharing examples:** Generate shareable links for bug reports or demos
- **Framework testing:** Import from CDN (Hono, itty-router, etc.)
## Limitations vs Production
| Feature | Playground | Production (wrangler) |
|---------|------------|----------------------|
| Language | JavaScript only | JS + TypeScript |
| Bindings | None | KV, D1, R2, DO, AI, etc. |
| Environment vars | None | Full support |
| Module format | ES only | ES + Service Worker |
| CPU time | 10ms (Free plan) | 10ms Free / 50ms Paid |
| Custom domains | No | Yes |
| Analytics | No | Yes |
## See Also
- [Cloudflare Workers Docs](https://developers.cloudflare.com/workers/)
- [Workers Examples](https://developers.cloudflare.com/workers/examples/)
- [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/)
- [Workers API Reference](https://developers.cloudflare.com/workers/runtime-apis/)

View File

@@ -0,0 +1,101 @@
# Workers Playground API
## Handler
```javascript
export default {
async fetch(request, env, ctx) {
// request: Request, env: {} (empty in playground), ctx: ExecutionContext
return new Response('Hello');
}
};
```
## Request
```javascript
const method = request.method; // "GET", "POST"
const url = new URL(request.url); // Parse URL
const headers = request.headers; // Headers object
const body = await request.json(); // Read body (consumes stream)
const clone = request.clone(); // Clone before reading body
// Query params
url.searchParams.get('page'); // Single value
url.searchParams.getAll('tag'); // Array
// Cloudflare metadata
request.cf.country; // "US"
request.cf.colo; // "SFO"
```
## Response
```javascript
// Text
return new Response('Hello', { status: 200 });
// JSON
return Response.json({ data }, { status: 200, headers: {...} });
// Redirect
return Response.redirect('/new-path', 301);
// Modify existing
const modified = new Response(response.body, response);
modified.headers.set('X-Custom', 'value');
```
## ExecutionContext
```javascript
// Background work (after response sent)
ctx.waitUntil(fetch('https://logs.example.com', { method: 'POST', body: '...' }));
return new Response('OK'); // Returns immediately
```
## Fetch
```javascript
const response = await fetch('https://api.example.com');
const data = await response.json();
// With options
await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice' })
});
```
## Cache
```javascript
const cache = caches.default;
// Check cache
let response = await cache.match(request);
if (!response) {
response = await fetch(origin);
await cache.put(request, response.clone()); // Clone before put!
}
return response;
```
## Crypto
```javascript
crypto.randomUUID(); // UUID v4
crypto.getRandomValues(new Uint8Array(16));
// SHA-256 hash
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(data));
```
## Limits (Playground = Free Plan)
| Resource | Limit |
|----------|-------|
| CPU time | 10ms |
| Subrequests | 50 |
| Memory | 128 MB |

View File

@@ -0,0 +1,163 @@
# Configuration
## Getting Started
Navigate to [workers.cloudflare.com/playground](https://workers.cloudflare.com/playground)
- **No account required** for testing
- **No CLI or local setup** needed
- Code executes in real Cloudflare Workers runtime
- Share code via URL (never expires)
## Playground Constraints
⚠️ **Important Limitations**
| Constraint | Playground | Production Workers |
|------------|------------|-------------------|
| **Module Format** | ES modules only | ES modules or Service Worker |
| **TypeScript** | Not supported (JS only) | Supported via build step |
| **Bindings** | Not available | KV, D1, R2, Durable Objects, etc. |
| **wrangler.toml** | Not used | Required for config |
| **Environment Variables** | Not available | Full support |
| **Secrets** | Not available | Full support |
| **Custom Domains** | Not available | Full support |
**Playground is for rapid prototyping only.** For production apps, use `wrangler` CLI.
## Code Editor
### Syntax Requirements
Must export default object with `fetch` handler:
```javascript
export default {
async fetch(request, env, ctx) {
return new Response('Hello World');
}
};
```
**Key Points:**
- Must use ES modules (`export default`)
- `fetch` method receives `(request, env, ctx)`
- Must return `Response` object
- TypeScript not supported (use plain JavaScript)
### Multi-Module Code
Import from external URLs or inline modules:
```javascript
// Import from CDN
import { Hono } from 'https://esm.sh/hono@3';
// Or paste library code and import relatively
// (See patterns.md for multi-module examples)
export default {
async fetch(request) {
const app = new Hono();
app.get('/', (c) => c.text('Hello'));
return app.fetch(request);
}
};
```
## Preview Panel
### Browser Tab
Default interactive preview with address bar:
- Enter custom URL paths
- Automatic reload on code changes
- DevTools available (right-click → Inspect)
### HTTP Test Panel
Switch to **HTTP** tab for raw HTTP testing:
- Change HTTP method (GET, POST, PUT, DELETE, PATCH, etc.)
- Add/edit request headers
- Modify request body (JSON, form data, text)
- View response headers and body
- Test different content types
Example HTTP test:
```
Method: POST
URL: /api/users
Headers:
Content-Type: application/json
Authorization: Bearer token123
Body:
{
"name": "Alice",
"email": "alice@example.com"
}
```
## Sharing Code
**Copy Link** button generates shareable URL:
- Code embedded in URL fragment
- Links never expire
- No account required
- Can be bookmarked for later
Example: `https://workers.cloudflare.com/playground#abc123...`
## Deploying from Playground
Click **Deploy** button to move code to production:
1. **Log in** to Cloudflare account (creates free account if needed)
2. **Review** Worker name and code
3. **Deploy** to global network (takes ~30 seconds)
4. **Get URL**: Deployed to `<name>.workers.dev` subdomain
5. **Manage** from dashboard: add bindings, custom domains, analytics
**After deploy:**
- Code runs on Cloudflare's global network (300+ cities)
- Can add KV, D1, R2, Durable Objects bindings
- Configure custom domains and routes
- View analytics and logs
- Set environment variables and secrets
**Note:** Deployed Workers are production-ready but start on Free plan (100k requests/day).
## Browser Compatibility
| Browser | Status | Notes |
|---------|--------|-------|
| Chrome/Edge | ✅ Full support | Recommended |
| Firefox | ✅ Full support | Works well |
| Safari | ⚠️ Broken | Preview fails with "PreviewRequestFailed" |
**Safari users:** Use Chrome, Firefox, or Edge for Workers Playground.
## DevTools Integration
1. **Open preview** in browser tab
2. **Right-click** → Inspect Element
3. **Console tab** shows Worker logs:
- `console.log()` output
- Uncaught errors
- Network requests (subrequests)
**Note:** DevTools show client-side console, not Worker execution logs. For production logging, use Logpush or Tail Workers.
## Limits in Playground
Same as production Free plan:
| Resource | Limit | Notes |
|----------|-------|-------|
| CPU time | 10ms | Per request |
| Memory | 128 MB | Per request |
| Script size | 1 MB | After compression |
| Subrequests | 50 | Outbound fetch calls |
| Request size | 100 MB | Incoming |
| Response size | Unlimited | Outgoing (streamed) |
**Exceeding CPU time** throws error immediately. Optimize hot paths or upgrade to Paid plan (50ms CPU).

View File

@@ -0,0 +1,88 @@
# Workers Playground Gotchas
## Platform Limitations
| Limitation | Impact | Workaround |
|------------|--------|------------|
| Safari broken | Preview fails | Use Chrome/Firefox/Edge |
| TypeScript unsupported | TS syntax errors | Write plain JS or use JSDoc |
| No bindings | `env` always `{}` | Mock data or use external APIs |
| No env vars | Can't access secrets | Hardcode for testing |
## Common Runtime Errors
### "Response body already read"
```javascript
// ❌ Body consumed twice
const body = await request.text();
await fetch(url, { body: request.body }); // Error!
// ✅ Clone first
const clone = request.clone();
const body = await request.text();
await fetch(url, { body: clone.body });
```
### "Worker exceeded CPU time"
**Limit:** 10ms (free), 50ms (paid)
```javascript
// ✅ Move slow work to background
ctx.waitUntil(fetch('https://analytics.example.com', {...}));
return new Response('OK'); // Return immediately
```
### "Too many subrequests"
**Limit:** 50 (free), 1000 (paid)
```javascript
// ❌ 100 individual fetches
// ✅ Batch into single API call
await fetch('https://api.example.com/batch', {
body: JSON.stringify({ ids: [...] })
});
```
## Best Practices
```javascript
// Clone before caching
await cache.put(request, response.clone());
return response;
// Validate input early
if (request.method !== 'POST') return new Response('', { status: 405 });
// Handle errors
try { ... } catch (e) {
return Response.json({ error: e.message }, { status: 500 });
}
```
## Limits
| Resource | Free | Paid |
|----------|------|------|
| CPU time | 10ms | 50ms |
| Memory | 128 MB | 128 MB |
| Subrequests | 50 | 1000 |
## Browser Support
| Browser | Status |
|---------|--------|
| Chrome | ✅ Recommended |
| Firefox | ✅ Works |
| Edge | ✅ Works |
| Safari | ❌ Broken |
## Debugging
```javascript
console.log('URL:', request.url); // View in browser DevTools Console
```
**Note:** `console.log` works in playground. For production, use Logpush or Tail Workers.

View File

@@ -0,0 +1,132 @@
# Workers Playground Patterns
## JSON API
```javascript
export default {
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === '/api/hello') return Response.json({ message: 'Hello' });
if (url.pathname === '/api/echo' && request.method === 'POST') {
return Response.json({ received: await request.json() });
}
return Response.json({ error: 'Not found' }, { status: 404 });
}
};
```
## Router Pattern
```javascript
const routes = {
'/': () => new Response('Home'),
'/api/users': () => Response.json([{ id: 1, name: 'Alice' }])
};
export default {
async fetch(request) {
const handler = routes[new URL(request.url).pathname];
return handler ? handler() : new Response('Not Found', { status: 404 });
}
};
```
## Proxy Pattern
```javascript
export default {
async fetch(request) {
const url = new URL(request.url);
url.hostname = 'api.example.com';
return fetch(url.toString(), {
method: request.method, headers: request.headers, body: request.body
});
}
};
```
## CORS Handling
```javascript
export default {
async fetch(request) {
if (request.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
'Access-Control-Allow-Headers': 'Content-Type, Authorization'
}
});
}
const response = await fetch('https://api.example.com', request);
const modified = new Response(response.body, response);
modified.headers.set('Access-Control-Allow-Origin', '*');
return modified;
}
};
```
## Caching
```javascript
export default {
async fetch(request) {
if (request.method !== 'GET') return fetch(request);
const cache = caches.default;
let response = await cache.match(request);
if (!response) {
response = await fetch('https://api.example.com');
if (response.status === 200) await cache.put(request, response.clone());
}
return response;
}
};
```
## Hono Framework
```javascript
import { Hono } from 'https://esm.sh/hono@3';
const app = new Hono();
app.get('/', (c) => c.text('Hello'));
app.get('/api/users/:id', (c) => c.json({ id: c.req.param('id') }));
app.notFound((c) => c.json({ error: 'Not found' }, 404));
export default app;
```
## Authentication
```javascript
export default {
async fetch(request) {
const auth = request.headers.get('Authorization');
if (!auth?.startsWith('Bearer ')) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
const token = auth.substring(7);
if (token !== 'secret-token') {
return Response.json({ error: 'Invalid token' }, { status: 403 });
}
return Response.json({ message: 'Authenticated' });
}
};
```
## Error Handling
```javascript
export default {
async fetch(request) {
try {
const response = await fetch('https://api.example.com');
if (!response.ok) throw new Error(`API returned ${response.status}`);
return response;
} catch (error) {
return Response.json({ error: error.message }, { status: 500 });
}
}
};
```
**Note:** In-memory state (Maps, variables) resets on Worker cold start. Use Durable Objects or KV for persistence.