opencastle 0.33.9 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +39 -17
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/stack-config.d.ts.map +1 -1
- package/dist/cli/stack-config.js +5 -0
- package/dist/cli/stack-config.js.map +1 -1
- package/dist/cli/types.d.ts +1 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/orchestrator/plugins/cloudflare/config.d.ts +3 -0
- package/dist/orchestrator/plugins/cloudflare/config.d.ts.map +1 -0
- package/dist/orchestrator/plugins/cloudflare/config.js +23 -0
- package/dist/orchestrator/plugins/cloudflare/config.js.map +1 -0
- package/dist/orchestrator/plugins/coolify/config.d.ts +3 -0
- package/dist/orchestrator/plugins/coolify/config.d.ts.map +1 -0
- package/dist/orchestrator/plugins/coolify/config.js +28 -0
- package/dist/orchestrator/plugins/coolify/config.js.map +1 -0
- package/dist/orchestrator/plugins/drizzle/config.d.ts +3 -0
- package/dist/orchestrator/plugins/drizzle/config.d.ts.map +1 -0
- package/dist/orchestrator/plugins/drizzle/config.js +15 -0
- package/dist/orchestrator/plugins/drizzle/config.js.map +1 -0
- package/dist/orchestrator/plugins/expo/config.d.ts +3 -0
- package/dist/orchestrator/plugins/expo/config.d.ts.map +1 -0
- package/dist/orchestrator/plugins/expo/config.js +23 -0
- package/dist/orchestrator/plugins/expo/config.js.map +1 -0
- package/dist/orchestrator/plugins/index.d.ts.map +1 -1
- package/dist/orchestrator/plugins/index.js +12 -0
- package/dist/orchestrator/plugins/index.js.map +1 -1
- package/dist/orchestrator/plugins/sentry/config.d.ts +3 -0
- package/dist/orchestrator/plugins/sentry/config.d.ts.map +1 -0
- package/dist/orchestrator/plugins/sentry/config.js +28 -0
- package/dist/orchestrator/plugins/sentry/config.js.map +1 -0
- package/dist/orchestrator/plugins/stripe/config.d.ts +3 -0
- package/dist/orchestrator/plugins/stripe/config.d.ts.map +1 -0
- package/dist/orchestrator/plugins/stripe/config.js +42 -0
- package/dist/orchestrator/plugins/stripe/config.js.map +1 -0
- package/dist/orchestrator/plugins/types.d.ts +1 -1
- package/dist/orchestrator/plugins/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/init.ts +43 -22
- package/src/cli/stack-config.ts +5 -0
- package/src/cli/types.ts +1 -1
- package/src/dashboard/dist/data/convoys/demo-api-v2.json +3 -3
- package/src/dashboard/dist/data/convoys/demo-auth-revamp.json +4 -4
- package/src/dashboard/dist/data/convoys/demo-dashboard-ui.json +12 -12
- package/src/dashboard/dist/data/convoys/demo-data-pipeline.json +3 -3
- package/src/dashboard/dist/data/convoys/demo-deploy-ci.json +1 -1
- package/src/dashboard/dist/data/convoys/demo-docs-update.json +3 -3
- package/src/dashboard/dist/data/convoys/demo-perf-opt.json +4 -4
- package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
- package/src/dashboard/public/data/convoys/demo-api-v2.json +3 -3
- package/src/dashboard/public/data/convoys/demo-auth-revamp.json +4 -4
- package/src/dashboard/public/data/convoys/demo-dashboard-ui.json +12 -12
- package/src/dashboard/public/data/convoys/demo-data-pipeline.json +3 -3
- package/src/dashboard/public/data/convoys/demo-deploy-ci.json +1 -1
- package/src/dashboard/public/data/convoys/demo-docs-update.json +3 -3
- package/src/dashboard/public/data/convoys/demo-perf-opt.json +4 -4
- package/src/orchestrator/customizations/agents/skill-matrix.json +24 -4
- package/src/orchestrator/customizations/agents/skill-matrix.md +5 -0
- package/src/orchestrator/plugins/cloudflare/SKILL.md +111 -0
- package/src/orchestrator/plugins/cloudflare/config.ts +24 -0
- package/src/orchestrator/plugins/cloudflare/references/deployment.md +147 -0
- package/src/orchestrator/plugins/cloudflare/references/storage.md +118 -0
- package/src/orchestrator/plugins/cloudflare/references/workers.md +135 -0
- package/src/orchestrator/plugins/convex/SKILL.md +62 -20
- package/src/orchestrator/plugins/convex/references/auth-auth0.md +116 -0
- package/src/orchestrator/plugins/convex/references/auth-clerk.md +113 -0
- package/src/orchestrator/plugins/convex/references/auth-convex-auth.md +143 -0
- package/src/orchestrator/plugins/convex/references/auth-setup.md +87 -0
- package/src/orchestrator/plugins/convex/references/auth-workos.md +114 -0
- package/src/orchestrator/plugins/convex/references/components-advanced.md +134 -0
- package/src/orchestrator/plugins/convex/references/components.md +171 -0
- package/src/orchestrator/plugins/convex/references/function-budget.md +232 -0
- package/src/orchestrator/plugins/convex/references/hot-path-rules.md +371 -0
- package/src/orchestrator/plugins/convex/references/migrations-component.md +170 -0
- package/src/orchestrator/plugins/convex/references/migrations.md +259 -0
- package/src/orchestrator/plugins/convex/references/occ-conflicts.md +126 -0
- package/src/orchestrator/plugins/convex/references/performance-audit.md +80 -0
- package/src/orchestrator/plugins/convex/references/quickstart.md +176 -0
- package/src/orchestrator/plugins/convex/references/subscription-cost.md +252 -0
- package/src/orchestrator/plugins/coolify/SKILL.md +134 -0
- package/src/orchestrator/plugins/coolify/config.ts +29 -0
- package/src/orchestrator/plugins/coolify/references/applications.md +65 -0
- package/src/orchestrator/plugins/coolify/references/ci-cd-webhooks.md +73 -0
- package/src/orchestrator/plugins/coolify/references/databases-services.md +57 -0
- package/src/orchestrator/plugins/coolify/references/docker-compose.md +121 -0
- package/src/orchestrator/plugins/coolify/references/infrastructure.md +77 -0
- package/src/orchestrator/plugins/drizzle/SKILL.md +123 -0
- package/src/orchestrator/plugins/drizzle/config.ts +16 -0
- package/src/orchestrator/plugins/drizzle/references/migrations.md +112 -0
- package/src/orchestrator/plugins/drizzle/references/query-patterns.md +127 -0
- package/src/orchestrator/plugins/drizzle/references/schema-patterns.md +105 -0
- package/src/orchestrator/plugins/expo/SKILL.md +114 -0
- package/src/orchestrator/plugins/expo/config.ts +24 -0
- package/src/orchestrator/plugins/expo/references/eas-build.md +73 -0
- package/src/orchestrator/plugins/expo/references/native-modules.md +71 -0
- package/src/orchestrator/plugins/expo/references/routing.md +83 -0
- package/src/orchestrator/plugins/index.ts +12 -0
- package/src/orchestrator/plugins/linear/SKILL.md +21 -3
- package/src/orchestrator/plugins/sentry/SKILL.md +94 -0
- package/src/orchestrator/plugins/sentry/config.ts +29 -0
- package/src/orchestrator/plugins/sentry/references/error-patterns.md +112 -0
- package/src/orchestrator/plugins/sentry/references/performance.md +66 -0
- package/src/orchestrator/plugins/sentry/references/sdk-setup.md +108 -0
- package/src/orchestrator/plugins/stripe/SKILL.md +138 -0
- package/src/orchestrator/plugins/stripe/config.ts +43 -0
- package/src/orchestrator/plugins/stripe/references/api-patterns.md +57 -0
- package/src/orchestrator/plugins/stripe/references/projects-setup.md +30 -0
- package/src/orchestrator/plugins/stripe/references/upgrade-guide.md +105 -0
- package/src/orchestrator/plugins/types.ts +1 -1
- package/src/orchestrator/skills/backbone-scaffolding/EXAMPLES.md +1 -1
- package/src/orchestrator/skills/backbone-scaffolding/SKILL.md +32 -16
- package/src/orchestrator/plugins/convex/REFERENCE.md +0 -9
|
@@ -77,6 +77,11 @@ When resolving, load **all** skills listed in the slot's entries.
|
|
|
77
77
|
| `e2e-testing` | Browser automation | UI/UX Expert, Testing Expert |
|
|
78
78
|
| `task-management` | Issue tracking, workflow states | Team Lead |
|
|
79
79
|
| `knowledge-management` | Knowledge base, research, ADRs, specs | Team Lead, Researcher, Documentation Writer, Architect |
|
|
80
|
+
| `design` | Design tokens, component inspection, asset export | UI/UX Expert |
|
|
81
|
+
| `email` | Transactional email, templates, delivery | Developer |
|
|
82
|
+
| `payments` | Payment processing, subscriptions, webhooks | Developer |
|
|
83
|
+
| `observability` | Error tracking, performance monitoring, tracing | DevOps Expert, Performance Expert |
|
|
84
|
+
| `notifications` | Team messaging, alerts, bot integrations | Developer |
|
|
80
85
|
|
|
81
86
|
### Example: Add a second plugin
|
|
82
87
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cloudflare-platform
|
|
3
|
+
description: "Creates and deploys Cloudflare Workers, configures wrangler.toml bindings, sets up KV/D1/R2 storage and Durable Objects, manages Pages deployments, and implements edge function patterns. Use when building or deploying Cloudflare Workers, setting up Pages, working with KV/D1/R2 storage, configuring wrangler.toml, or deploying edge applications."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cloudflare Platform
|
|
7
|
+
|
|
8
|
+
## Topic Routing
|
|
9
|
+
|
|
10
|
+
Read the matching reference before writing code for any of these topics:
|
|
11
|
+
|
|
12
|
+
| Topic | Reference |
|
|
13
|
+
|-------|-----------|
|
|
14
|
+
| Workers & edge functions | `references/workers.md` |
|
|
15
|
+
| Storage (KV, D1, R2) | `references/storage.md` |
|
|
16
|
+
| Pages & deployment | `references/deployment.md` |
|
|
17
|
+
|
|
18
|
+
## Critical Rules
|
|
19
|
+
|
|
20
|
+
**Workers**
|
|
21
|
+
- Use Web standard Fetch API, not Node.js globals (`process`, `Buffer`, `fs`) — Workers run in V8 isolates
|
|
22
|
+
- Define all bindings (KV, D1, R2, secrets) in `wrangler.toml` and access them via the `env` parameter
|
|
23
|
+
- Workers have 0ms cold starts — keep dependencies minimal; free tier has a 1MB bundle limit
|
|
24
|
+
- Use `ctx.waitUntil(promise)` for non-blocking side effects (logging, analytics) that outlast the response
|
|
25
|
+
|
|
26
|
+
**Storage Selection**
|
|
27
|
+
- **KV** — key-value store for config, sessions, cache (eventually consistent reads)
|
|
28
|
+
- **D1** — SQLite at the edge for relational SQL; strongly consistent
|
|
29
|
+
- **R2** — object/file storage (S3-compatible); no egress costs
|
|
30
|
+
- **Durable Objects** — stateful coordination; use for real-time collaboration, rate limiters, and counters
|
|
31
|
+
- **Queues** — async message processing; use for background tasks
|
|
32
|
+
|
|
33
|
+
**D1**
|
|
34
|
+
- Use `env.DB.prepare(sql).bind(...params).run()` for all DML; always use parameterized queries
|
|
35
|
+
- Use `env.DB.batch([...stmts])` for multiple queries in a single round trip
|
|
36
|
+
- D1 is SQLite — avoid MySQL/Postgres-only SQL syntax
|
|
37
|
+
|
|
38
|
+
**MCP Code Mode**
|
|
39
|
+
- The Cloudflare MCP uses Code Mode: only 2 tools are available — `search` and `execute`
|
|
40
|
+
- `search` searches the Cloudflare API spec; `execute` runs JavaScript against the Cloudflare API
|
|
41
|
+
- This approach uses ~1k tokens per operation vs ~244k for native tool exposure
|
|
42
|
+
|
|
43
|
+
**Wrangler**
|
|
44
|
+
- Use `wrangler.toml` (or `wrangler.jsonc`) for all config — `npx wrangler dev` for local dev
|
|
45
|
+
- `npx wrangler deploy` for production; `wrangler tail` for live log streaming
|
|
46
|
+
- Store secrets with `wrangler secret put VAR_NAME` — never hardcode in `wrangler.toml`
|
|
47
|
+
|
|
48
|
+
**Security**
|
|
49
|
+
- Access secrets via `env.VAR_NAME` — never hardcode credentials in Worker code
|
|
50
|
+
- Use Cloudflare Turnstile for CAPTCHA; configure WAF rules for API protection
|
|
51
|
+
- Validate all inputs at the Worker boundary — Workers are publicly accessible
|
|
52
|
+
|
|
53
|
+
## Basic Worker with KV
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// src/index.ts
|
|
57
|
+
export interface Env {
|
|
58
|
+
SESSIONS: KVNamespace; // bound in wrangler.toml
|
|
59
|
+
API_SECRET: string; // secret bound in wrangler.toml
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export default {
|
|
63
|
+
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
64
|
+
const url = new URL(request.url);
|
|
65
|
+
|
|
66
|
+
if (url.pathname === '/session') {
|
|
67
|
+
const sessionId = request.headers.get('x-session-id');
|
|
68
|
+
if (!sessionId) return new Response('Missing session', { status: 400 });
|
|
69
|
+
|
|
70
|
+
const data = await env.SESSIONS.get(sessionId, { type: 'json' });
|
|
71
|
+
if (!data) return new Response('Not found', { status: 404 });
|
|
72
|
+
|
|
73
|
+
// Non-blocking analytics — does not delay the response
|
|
74
|
+
ctx.waitUntil(logAnalytics(sessionId));
|
|
75
|
+
|
|
76
|
+
return Response.json(data);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return new Response('Not found', { status: 404 });
|
|
80
|
+
},
|
|
81
|
+
} satisfies ExportedHandler<Env>;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Storage Decision Guide
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
I need to store data → What type?
|
|
88
|
+
├── Key-value pairs (cache, sessions, feature flags) → KV
|
|
89
|
+
├── Relational/SQL data → D1
|
|
90
|
+
├── Files, images, blobs → R2
|
|
91
|
+
├── Stateful coordination (counters, locks, chat) → Durable Objects
|
|
92
|
+
└── Async job queue → Queues
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Reference Files
|
|
96
|
+
|
|
97
|
+
- `references/workers.md` — Worker structure, bindings, env, waitUntil, Durable Objects, Cron Triggers, Wrangler commands
|
|
98
|
+
- `references/storage.md` — KV, D1, R2 APIs; decision guide for choosing between storage types
|
|
99
|
+
- `references/deployment.md` — Pages setup, wrangler.toml, secrets, custom domains, CI/CD integration
|
|
100
|
+
|
|
101
|
+
## Quick Workflow: Deploy a Cloudflare Worker
|
|
102
|
+
1. Create project: `npm create cloudflare@latest` and select "Hello World" Worker template
|
|
103
|
+
2. Define bindings (KV, D1, secrets) in `wrangler.toml` under `[[kv_namespaces]]` / `[[d1_databases]]`
|
|
104
|
+
3. Verify resources exist: `npx wrangler kv:namespace list` / `npx wrangler d1 list` — create any missing resources before continuing
|
|
105
|
+
- **If resource missing:** `npx wrangler kv:namespace create <NAME>` or `npx wrangler d1 create <DB>` → copy the ID into `wrangler.toml`
|
|
106
|
+
4. Implement the `fetch` handler in `src/index.ts` — type the `Env` interface to match your bindings
|
|
107
|
+
5. Test locally: `npx wrangler dev` — verify the worker responds correctly at `http://localhost:8787`
|
|
108
|
+
- **If dev fails:** check `wrangler.toml` syntax → verify binding IDs match → run `npx wrangler whoami` to confirm account auth
|
|
109
|
+
6. Deploy: `npx wrangler deploy` — confirm the deployment URL is returned
|
|
110
|
+
- **If deploy fails:** check `wrangler.toml` bindings match created resources → verify `compatibility_date` is set → check account permissions
|
|
111
|
+
7. Monitor with `wrangler tail` for live logs from production
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PluginConfig } from '../types.js';
|
|
2
|
+
|
|
3
|
+
export const config: PluginConfig = {
|
|
4
|
+
id: 'cloudflare',
|
|
5
|
+
name: 'Cloudflare',
|
|
6
|
+
category: 'tech',
|
|
7
|
+
subCategory: 'deployment',
|
|
8
|
+
label: 'Cloudflare',
|
|
9
|
+
hint: 'Workers, Pages, KV, D1, R2, and edge computing',
|
|
10
|
+
skillName: 'cloudflare-platform',
|
|
11
|
+
mcpServerKey: 'Cloudflare',
|
|
12
|
+
mcpConfig: {
|
|
13
|
+
type: 'http',
|
|
14
|
+
url: 'https://mcp.cloudflare.com/mcp',
|
|
15
|
+
},
|
|
16
|
+
authType: 'oauth',
|
|
17
|
+
envVars: [],
|
|
18
|
+
agentToolMap: {
|
|
19
|
+
'developer': ['search', 'execute'],
|
|
20
|
+
'devops-expert': ['search', 'execute'],
|
|
21
|
+
},
|
|
22
|
+
docsUrl: null,
|
|
23
|
+
officialDocs: 'https://developers.cloudflare.com/',
|
|
24
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Cloudflare Deployment
|
|
2
|
+
|
|
3
|
+
## wrangler.toml Reference
|
|
4
|
+
|
|
5
|
+
```toml
|
|
6
|
+
name = "my-app"
|
|
7
|
+
main = "src/index.ts"
|
|
8
|
+
compatibility_date = "2024-12-01"
|
|
9
|
+
compatibility_flags = ["nodejs_compat"] # enable Node.js compat layer
|
|
10
|
+
|
|
11
|
+
# Environment variables (non-secret)
|
|
12
|
+
[vars]
|
|
13
|
+
ENVIRONMENT = "production"
|
|
14
|
+
API_BASE_URL = "https://api.example.com"
|
|
15
|
+
|
|
16
|
+
# Secrets — set via CLI, NOT stored here:
|
|
17
|
+
# wrangler secret put DB_PASSWORD
|
|
18
|
+
|
|
19
|
+
# KV binding
|
|
20
|
+
[[kv_namespaces]]
|
|
21
|
+
binding = "CACHE"
|
|
22
|
+
id = "abc123def456"
|
|
23
|
+
preview_id = "preview_abc123" # for `wrangler dev --remote`
|
|
24
|
+
|
|
25
|
+
# D1 binding
|
|
26
|
+
[[d1_databases]]
|
|
27
|
+
binding = "DB"
|
|
28
|
+
database_name = "my-database"
|
|
29
|
+
database_id = "xyz789"
|
|
30
|
+
|
|
31
|
+
# R2 binding
|
|
32
|
+
[[r2_buckets]]
|
|
33
|
+
binding = "ASSETS"
|
|
34
|
+
bucket_name = "my-assets"
|
|
35
|
+
|
|
36
|
+
# Service binding (call another Worker)
|
|
37
|
+
[[services]]
|
|
38
|
+
binding = "AUTH_WORKER"
|
|
39
|
+
service = "auth-service"
|
|
40
|
+
|
|
41
|
+
# Cron Triggers
|
|
42
|
+
[triggers]
|
|
43
|
+
crons = ["0 0 * * *"] # midnight UTC daily
|
|
44
|
+
|
|
45
|
+
# Per-environment overrides
|
|
46
|
+
[env.staging]
|
|
47
|
+
name = "my-app-staging"
|
|
48
|
+
vars = { ENVIRONMENT = "staging" }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Pages Setup
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Create a new Pages project
|
|
55
|
+
npm create cloudflare@latest my-app -- --framework=nextjs
|
|
56
|
+
|
|
57
|
+
# Deploy from CLI
|
|
58
|
+
npx wrangler pages deploy ./dist --project-name=my-app
|
|
59
|
+
|
|
60
|
+
# Deploy a specific branch (creates preview)
|
|
61
|
+
npx wrangler pages deploy ./dist --project-name=my-app --branch=feature-xyz
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Pages Functions
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// functions/api/hello.ts — file-based routing in /functions
|
|
68
|
+
interface Env {
|
|
69
|
+
MY_KV: KVNamespace;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const onRequest: PagesFunction<Env> = async (context) => {
|
|
73
|
+
const data = await context.env.MY_KV.get('greeting');
|
|
74
|
+
return Response.json({ message: data ?? 'Hello!' });
|
|
75
|
+
};
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Environment Variables & Secrets
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# List current secrets
|
|
82
|
+
wrangler secret list
|
|
83
|
+
|
|
84
|
+
# Add a secret (prompts for value)
|
|
85
|
+
wrangler secret put DATABASE_URL
|
|
86
|
+
|
|
87
|
+
# Add a secret for a specific environment
|
|
88
|
+
wrangler secret put DATABASE_URL --env staging
|
|
89
|
+
|
|
90
|
+
# Bulk secrets from .dev.vars (local dev only — never commit this file)
|
|
91
|
+
# .dev.vars format: KEY=value (one per line)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Custom Domains
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Add a custom domain via dashboard or CLI
|
|
98
|
+
wrangler domains add my-worker.example.com
|
|
99
|
+
|
|
100
|
+
# For Pages: configure in the Cloudflare Dashboard under
|
|
101
|
+
# Pages → Project → Custom Domains
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## CI/CD Integration
|
|
105
|
+
|
|
106
|
+
### GitHub Actions
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
# .github/workflows/deploy.yml
|
|
110
|
+
name: Deploy
|
|
111
|
+
|
|
112
|
+
on:
|
|
113
|
+
push:
|
|
114
|
+
branches: [main]
|
|
115
|
+
|
|
116
|
+
jobs:
|
|
117
|
+
deploy:
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
steps:
|
|
120
|
+
- uses: actions/checkout@v4
|
|
121
|
+
- uses: cloudflare/wrangler-action@v3
|
|
122
|
+
with:
|
|
123
|
+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
124
|
+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Generate an API token at Cloudflare Dashboard → My Profile → API Tokens → Create Token (use the "Edit Cloudflare Workers" template).
|
|
128
|
+
|
|
129
|
+
## Preview Deployments
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Create a preview deployment (does not affect production)
|
|
133
|
+
npx wrangler deploy --env staging
|
|
134
|
+
|
|
135
|
+
# View deployment history
|
|
136
|
+
npx wrangler deployments list
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Rollback
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# List recent deployments with version IDs
|
|
143
|
+
npx wrangler deployments list
|
|
144
|
+
|
|
145
|
+
# Roll back to a previous deployment
|
|
146
|
+
npx wrangler rollback <version-id>
|
|
147
|
+
```
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Cloudflare Storage
|
|
2
|
+
|
|
3
|
+
## Storage Decision Guide
|
|
4
|
+
|
|
5
|
+
| Need | Use |
|
|
6
|
+
|------|-----|
|
|
7
|
+
| Config, feature flags, sessions, cache | KV (eventually consistent) |
|
|
8
|
+
| Relational SQL data, strong consistency | D1 (SQLite) |
|
|
9
|
+
| Files, images, large blobs | R2 (S3-compatible) |
|
|
10
|
+
| Stateful coordination, locks, real-time sync | Durable Objects |
|
|
11
|
+
| Background job queues | Queues |
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## KV (Key-Value)
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// Read
|
|
19
|
+
const value = await env.MY_KV.get('key');
|
|
20
|
+
const json = await env.MY_KV.get<MyType>('key', { type: 'json' });
|
|
21
|
+
const buffer = await env.MY_KV.get('key', { type: 'arrayBuffer' });
|
|
22
|
+
|
|
23
|
+
// Write
|
|
24
|
+
await env.MY_KV.put('key', 'value');
|
|
25
|
+
await env.MY_KV.put('key', JSON.stringify(data));
|
|
26
|
+
await env.MY_KV.put('key', 'value', {
|
|
27
|
+
expirationTtl: 3600, // expire in 1 hour
|
|
28
|
+
metadata: { userId: '123' }, // up to 1024 bytes of metadata
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Delete
|
|
32
|
+
await env.MY_KV.delete('key');
|
|
33
|
+
|
|
34
|
+
// List keys
|
|
35
|
+
const { keys, list_complete, cursor } = await env.MY_KV.list({ prefix: 'user:' });
|
|
36
|
+
for (const key of keys) {
|
|
37
|
+
console.log(key.name, key.metadata);
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**KV limits:** Reads are eventually consistent (up to 60s lag). Max value size: 25MB. Max key size: 512 bytes.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## D1 (SQLite at Edge)
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// Single query
|
|
49
|
+
const stmt = env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(userId);
|
|
50
|
+
const { results } = await stmt.all<User>();
|
|
51
|
+
const user = await stmt.first<User>();
|
|
52
|
+
|
|
53
|
+
// Insert / update
|
|
54
|
+
const result = await env.DB
|
|
55
|
+
.prepare('INSERT INTO posts (id, title, author_id) VALUES (?, ?, ?)')
|
|
56
|
+
.bind(id, title, authorId)
|
|
57
|
+
.run();
|
|
58
|
+
console.log(result.meta.changes); // rows affected
|
|
59
|
+
|
|
60
|
+
// Batch (multiple queries in one round trip)
|
|
61
|
+
const results = await env.DB.batch([
|
|
62
|
+
env.DB.prepare('INSERT INTO logs (event) VALUES (?)').bind('login'),
|
|
63
|
+
env.DB.prepare('UPDATE users SET last_seen = ? WHERE id = ?').bind(now, userId),
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
// Dump (returns all results)
|
|
67
|
+
const { results: allUsers } = await env.DB.prepare('SELECT * FROM users').all<User>();
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Always use parameterized queries** — never interpolate user input into SQL strings.
|
|
71
|
+
|
|
72
|
+
### D1 Migrations
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Create migration file
|
|
76
|
+
wrangler d1 migrations create my-db add-users-table
|
|
77
|
+
|
|
78
|
+
# Apply migrations (local)
|
|
79
|
+
wrangler d1 migrations apply my-db --local
|
|
80
|
+
|
|
81
|
+
# Apply migrations (remote/production)
|
|
82
|
+
wrangler d1 migrations apply my-db --remote
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## R2 (Object Storage)
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// Upload
|
|
91
|
+
await env.MY_BUCKET.put('images/photo.jpg', imageBuffer, {
|
|
92
|
+
httpMetadata: { contentType: 'image/jpeg' },
|
|
93
|
+
customMetadata: { uploadedBy: userId },
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Download
|
|
97
|
+
const object = await env.MY_BUCKET.get('images/photo.jpg');
|
|
98
|
+
if (!object) return new Response('Not found', { status: 404 });
|
|
99
|
+
|
|
100
|
+
// Stream the body directly to the response
|
|
101
|
+
return new Response(object.body, {
|
|
102
|
+
headers: { 'Content-Type': object.httpMetadata?.contentType ?? 'application/octet-stream' },
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Delete
|
|
106
|
+
await env.MY_BUCKET.delete('images/photo.jpg');
|
|
107
|
+
|
|
108
|
+
// List
|
|
109
|
+
const { objects, truncated, cursor } = await env.MY_BUCKET.list({ prefix: 'images/' });
|
|
110
|
+
|
|
111
|
+
// Multipart upload (large files >100MB)
|
|
112
|
+
const upload = await env.MY_BUCKET.createMultipartUpload('large-file.zip');
|
|
113
|
+
const part1 = await upload.uploadPart(1, chunk1);
|
|
114
|
+
const part2 = await upload.uploadPart(2, chunk2);
|
|
115
|
+
await upload.complete([part1, part2]);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**R2 is S3-compatible** — existing S3 SDKs work with R2 by pointing to the R2 endpoint URL.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Cloudflare Workers
|
|
2
|
+
|
|
3
|
+
## Worker Structure
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
// src/index.ts
|
|
7
|
+
export interface Env {
|
|
8
|
+
// Declare all bindings here — must match wrangler.toml
|
|
9
|
+
MY_KV: KVNamespace;
|
|
10
|
+
MY_DB: D1Database;
|
|
11
|
+
MY_BUCKET: R2Bucket;
|
|
12
|
+
MY_SECRET: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
17
|
+
// Handle HTTP requests
|
|
18
|
+
return new Response('Hello World');
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext): Promise<void> {
|
|
22
|
+
// Handle Cron Triggers
|
|
23
|
+
ctx.waitUntil(doScheduledWork(env));
|
|
24
|
+
},
|
|
25
|
+
} satisfies ExportedHandler<Env>;
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Bindings in wrangler.toml
|
|
29
|
+
|
|
30
|
+
```toml
|
|
31
|
+
name = "my-worker"
|
|
32
|
+
main = "src/index.ts"
|
|
33
|
+
compatibility_date = "2024-12-01"
|
|
34
|
+
|
|
35
|
+
[[kv_namespaces]]
|
|
36
|
+
binding = "MY_KV"
|
|
37
|
+
id = "abc123"
|
|
38
|
+
|
|
39
|
+
[[d1_databases]]
|
|
40
|
+
binding = "MY_DB"
|
|
41
|
+
database_name = "my-db"
|
|
42
|
+
database_id = "xyz789"
|
|
43
|
+
|
|
44
|
+
[[r2_buckets]]
|
|
45
|
+
binding = "MY_BUCKET"
|
|
46
|
+
bucket_name = "my-bucket"
|
|
47
|
+
|
|
48
|
+
[vars]
|
|
49
|
+
ENVIRONMENT = "production"
|
|
50
|
+
|
|
51
|
+
# Secrets are NOT stored in wrangler.toml — use: wrangler secret put SECRET_NAME
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## ctx.waitUntil
|
|
55
|
+
|
|
56
|
+
Use `ctx.waitUntil()` for async work that must not block the response:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
export default {
|
|
60
|
+
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
61
|
+
const response = await handleRequest(request, env);
|
|
62
|
+
|
|
63
|
+
// Logs, analytics, cache warming — run after response is sent
|
|
64
|
+
ctx.waitUntil(logToAnalytics(request, response, env));
|
|
65
|
+
|
|
66
|
+
return response;
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Routing
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { Router } from 'itty-router'; // popular lightweight router
|
|
75
|
+
|
|
76
|
+
const router = Router();
|
|
77
|
+
|
|
78
|
+
router
|
|
79
|
+
.get('/api/users', (request, env) => handleGetUsers(env))
|
|
80
|
+
.post('/api/users', (request, env) => handleCreateUser(request, env))
|
|
81
|
+
.all('*', () => new Response('Not found', { status: 404 }));
|
|
82
|
+
|
|
83
|
+
export default { fetch: router.fetch } satisfies ExportedHandler<Env>;
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Durable Objects (basics)
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// src/counter.ts
|
|
90
|
+
export class Counter implements DurableObject {
|
|
91
|
+
state: DurableObjectState;
|
|
92
|
+
|
|
93
|
+
constructor(state: DurableObjectState, env: Env) {
|
|
94
|
+
this.state = state;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async fetch(request: Request): Promise<Response> {
|
|
98
|
+
const count = (await this.state.storage.get<number>('count')) ?? 0;
|
|
99
|
+
const newCount = count + 1;
|
|
100
|
+
await this.state.storage.put('count', newCount);
|
|
101
|
+
return Response.json({ count: newCount });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
```toml
|
|
107
|
+
# wrangler.toml
|
|
108
|
+
[[durable_objects.bindings]]
|
|
109
|
+
name = "COUNTER"
|
|
110
|
+
class_name = "Counter"
|
|
111
|
+
|
|
112
|
+
[[migrations]]
|
|
113
|
+
tag = "v1"
|
|
114
|
+
new_classes = ["Counter"]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Cron Triggers
|
|
118
|
+
|
|
119
|
+
```toml
|
|
120
|
+
# wrangler.toml
|
|
121
|
+
[triggers]
|
|
122
|
+
crons = ["0 * * * *"] # every hour
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Wrangler Commands
|
|
126
|
+
|
|
127
|
+
| Command | Purpose |
|
|
128
|
+
|---------|---------|
|
|
129
|
+
| `npx wrangler dev` | Local development server (hot reload) |
|
|
130
|
+
| `npx wrangler deploy` | Deploy to production |
|
|
131
|
+
| `npx wrangler tail` | Live log streaming from production |
|
|
132
|
+
| `wrangler secret put NAME` | Store a secret securely |
|
|
133
|
+
| `wrangler kv:key put --binding=KV key value` | Write a KV value |
|
|
134
|
+
| `wrangler d1 execute DB --command="SELECT 1"` | Run a D1 SQL command |
|
|
135
|
+
| `wrangler whoami` | Verify authenticated account |
|