opencodekit 0.15.3 → 0.15.5
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/index.js +1 -1
- package/dist/template/.opencode/AGENTS.md +209 -77
- package/dist/template/.opencode/agent/plan.md +4 -0
- package/dist/template/.opencode/command/cloudflare.md +70 -0
- package/dist/template/.opencode/package.json +1 -1
- package/dist/template/.opencode/skill/cloudflare/SKILL.md +233 -0
- package/dist/template/.opencode/skill/cloudflare/references/agents-sdk/README.md +35 -0
- package/dist/template/.opencode/skill/cloudflare/references/agents-sdk/api.md +100 -0
- package/dist/template/.opencode/skill/cloudflare/references/agents-sdk/configuration.md +99 -0
- package/dist/template/.opencode/skill/cloudflare/references/agents-sdk/gotchas.md +59 -0
- package/dist/template/.opencode/skill/cloudflare/references/agents-sdk/patterns.md +89 -0
- package/dist/template/.opencode/skill/cloudflare/references/ai-gateway/README.md +695 -0
- package/dist/template/.opencode/skill/cloudflare/references/ai-search/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/ai-search/api.md +38 -0
- package/dist/template/.opencode/skill/cloudflare/references/ai-search/configuration.md +52 -0
- package/dist/template/.opencode/skill/cloudflare/references/ai-search/gotchas.md +41 -0
- package/dist/template/.opencode/skill/cloudflare/references/ai-search/patterns.md +45 -0
- package/dist/template/.opencode/skill/cloudflare/references/analytics-engine/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/analytics-engine/api.md +27 -0
- package/dist/template/.opencode/skill/cloudflare/references/analytics-engine/configuration.md +45 -0
- package/dist/template/.opencode/skill/cloudflare/references/analytics-engine/gotchas.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/analytics-engine/patterns.md +36 -0
- package/dist/template/.opencode/skill/cloudflare/references/api/README.md +21 -0
- package/dist/template/.opencode/skill/cloudflare/references/api/api.md +31 -0
- package/dist/template/.opencode/skill/cloudflare/references/api/configuration.md +20 -0
- package/dist/template/.opencode/skill/cloudflare/references/api/gotchas.md +28 -0
- package/dist/template/.opencode/skill/cloudflare/references/api/patterns.md +47 -0
- package/dist/template/.opencode/skill/cloudflare/references/api-shield/README.md +20 -0
- package/dist/template/.opencode/skill/cloudflare/references/api-shield/api.md +78 -0
- package/dist/template/.opencode/skill/cloudflare/references/api-shield/configuration.md +128 -0
- package/dist/template/.opencode/skill/cloudflare/references/api-shield/gotchas.md +51 -0
- package/dist/template/.opencode/skill/cloudflare/references/api-shield/patterns.md +145 -0
- package/dist/template/.opencode/skill/cloudflare/references/argo-smart-routing/README.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/argo-smart-routing/api.md +50 -0
- package/dist/template/.opencode/skill/cloudflare/references/argo-smart-routing/configuration.md +53 -0
- package/dist/template/.opencode/skill/cloudflare/references/argo-smart-routing/gotchas.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/argo-smart-routing/patterns.md +45 -0
- package/dist/template/.opencode/skill/cloudflare/references/bindings/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/bindings/api.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/bindings/configuration.md +58 -0
- package/dist/template/.opencode/skill/cloudflare/references/bindings/gotchas.md +35 -0
- package/dist/template/.opencode/skill/cloudflare/references/bindings/patterns.md +37 -0
- package/dist/template/.opencode/skill/cloudflare/references/bot-management/README.md +71 -0
- package/dist/template/.opencode/skill/cloudflare/references/bot-management/api.md +168 -0
- package/dist/template/.opencode/skill/cloudflare/references/bot-management/configuration.md +114 -0
- package/dist/template/.opencode/skill/cloudflare/references/bot-management/gotchas.md +99 -0
- package/dist/template/.opencode/skill/cloudflare/references/bot-management/patterns.md +125 -0
- package/dist/template/.opencode/skill/cloudflare/references/browser-rendering/README.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/browser-rendering/api.md +54 -0
- package/dist/template/.opencode/skill/cloudflare/references/browser-rendering/configuration.md +47 -0
- package/dist/template/.opencode/skill/cloudflare/references/browser-rendering/gotchas.md +29 -0
- package/dist/template/.opencode/skill/cloudflare/references/browser-rendering/patterns.md +29 -0
- package/dist/template/.opencode/skill/cloudflare/references/c3/README.md +264 -0
- package/dist/template/.opencode/skill/cloudflare/references/cache-reserve/README.md +93 -0
- package/dist/template/.opencode/skill/cloudflare/references/cache-reserve/api.md +176 -0
- package/dist/template/.opencode/skill/cloudflare/references/cache-reserve/configuration.md +164 -0
- package/dist/template/.opencode/skill/cloudflare/references/cache-reserve/gotchas.md +203 -0
- package/dist/template/.opencode/skill/cloudflare/references/cache-reserve/patterns.md +180 -0
- package/dist/template/.opencode/skill/cloudflare/references/containers/README.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/containers/api.md +43 -0
- package/dist/template/.opencode/skill/cloudflare/references/containers/configuration.md +56 -0
- package/dist/template/.opencode/skill/cloudflare/references/containers/gotchas.md +21 -0
- package/dist/template/.opencode/skill/cloudflare/references/containers/patterns.md +40 -0
- package/dist/template/.opencode/skill/cloudflare/references/cron-triggers/README.md +85 -0
- package/dist/template/.opencode/skill/cloudflare/references/cron-triggers/api.md +198 -0
- package/dist/template/.opencode/skill/cloudflare/references/cron-triggers/configuration.md +151 -0
- package/dist/template/.opencode/skill/cloudflare/references/cron-triggers/gotchas.md +129 -0
- package/dist/template/.opencode/skill/cloudflare/references/cron-triggers/patterns.md +122 -0
- package/dist/template/.opencode/skill/cloudflare/references/d1/README.md +92 -0
- package/dist/template/.opencode/skill/cloudflare/references/d1/api.md +141 -0
- package/dist/template/.opencode/skill/cloudflare/references/d1/configuration.md +127 -0
- package/dist/template/.opencode/skill/cloudflare/references/d1/gotchas.md +70 -0
- package/dist/template/.opencode/skill/cloudflare/references/d1/patterns.md +144 -0
- package/dist/template/.opencode/skill/cloudflare/references/ddos/README.md +34 -0
- package/dist/template/.opencode/skill/cloudflare/references/ddos/api.md +136 -0
- package/dist/template/.opencode/skill/cloudflare/references/ddos/configuration.md +67 -0
- package/dist/template/.opencode/skill/cloudflare/references/ddos/gotchas.md +114 -0
- package/dist/template/.opencode/skill/cloudflare/references/ddos/patterns.md +158 -0
- package/dist/template/.opencode/skill/cloudflare/references/do-storage/README.md +62 -0
- package/dist/template/.opencode/skill/cloudflare/references/do-storage/api.md +89 -0
- package/dist/template/.opencode/skill/cloudflare/references/do-storage/configuration.md +116 -0
- package/dist/template/.opencode/skill/cloudflare/references/do-storage/gotchas.md +93 -0
- package/dist/template/.opencode/skill/cloudflare/references/do-storage/patterns.md +112 -0
- package/dist/template/.opencode/skill/cloudflare/references/durable-objects/README.md +125 -0
- package/dist/template/.opencode/skill/cloudflare/references/durable-objects/api.md +152 -0
- package/dist/template/.opencode/skill/cloudflare/references/durable-objects/configuration.md +148 -0
- package/dist/template/.opencode/skill/cloudflare/references/durable-objects/gotchas.md +158 -0
- package/dist/template/.opencode/skill/cloudflare/references/durable-objects/patterns.md +255 -0
- package/dist/template/.opencode/skill/cloudflare/references/email-routing/README.md +18 -0
- package/dist/template/.opencode/skill/cloudflare/references/email-routing/api.md +46 -0
- package/dist/template/.opencode/skill/cloudflare/references/email-routing/configuration.md +63 -0
- package/dist/template/.opencode/skill/cloudflare/references/email-routing/gotchas.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/email-routing/patterns.md +46 -0
- package/dist/template/.opencode/skill/cloudflare/references/email-workers/README.md +598 -0
- package/dist/template/.opencode/skill/cloudflare/references/hyperdrive/README.md +62 -0
- package/dist/template/.opencode/skill/cloudflare/references/hyperdrive/api.md +137 -0
- package/dist/template/.opencode/skill/cloudflare/references/hyperdrive/configuration.md +133 -0
- package/dist/template/.opencode/skill/cloudflare/references/hyperdrive/gotchas.md +184 -0
- package/dist/template/.opencode/skill/cloudflare/references/hyperdrive/patterns.md +176 -0
- package/dist/template/.opencode/skill/cloudflare/references/images/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/images/api.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/images/configuration.md +45 -0
- package/dist/template/.opencode/skill/cloudflare/references/images/gotchas.md +23 -0
- package/dist/template/.opencode/skill/cloudflare/references/images/patterns.md +31 -0
- package/dist/template/.opencode/skill/cloudflare/references/kv/README.md +60 -0
- package/dist/template/.opencode/skill/cloudflare/references/kv/api.md +114 -0
- package/dist/template/.opencode/skill/cloudflare/references/kv/configuration.md +92 -0
- package/dist/template/.opencode/skill/cloudflare/references/kv/gotchas.md +117 -0
- package/dist/template/.opencode/skill/cloudflare/references/kv/patterns.md +139 -0
- package/dist/template/.opencode/skill/cloudflare/references/miniflare/README.md +64 -0
- package/dist/template/.opencode/skill/cloudflare/references/miniflare/api.md +144 -0
- package/dist/template/.opencode/skill/cloudflare/references/miniflare/configuration.md +203 -0
- package/dist/template/.opencode/skill/cloudflare/references/miniflare/gotchas.md +187 -0
- package/dist/template/.opencode/skill/cloudflare/references/miniflare/patterns.md +211 -0
- package/dist/template/.opencode/skill/cloudflare/references/network-interconnect/README.md +60 -0
- package/dist/template/.opencode/skill/cloudflare/references/network-interconnect/api.md +240 -0
- package/dist/template/.opencode/skill/cloudflare/references/network-interconnect/configuration.md +127 -0
- package/dist/template/.opencode/skill/cloudflare/references/network-interconnect/gotchas.md +171 -0
- package/dist/template/.opencode/skill/cloudflare/references/network-interconnect/patterns.md +171 -0
- package/dist/template/.opencode/skill/cloudflare/references/observability/README.md +18 -0
- package/dist/template/.opencode/skill/cloudflare/references/observability/api.md +51 -0
- package/dist/template/.opencode/skill/cloudflare/references/observability/configuration.md +60 -0
- package/dist/template/.opencode/skill/cloudflare/references/observability/gotchas.md +36 -0
- package/dist/template/.opencode/skill/cloudflare/references/observability/patterns.md +42 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages/README.md +76 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages/api.md +200 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages/configuration.md +228 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages/gotchas.md +161 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages/patterns.md +145 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages-functions/README.md +57 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages-functions/api.md +201 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages-functions/configuration.md +159 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages-functions/gotchas.md +151 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages-functions/patterns.md +190 -0
- package/dist/template/.opencode/skill/cloudflare/references/pipelines/README.md +664 -0
- package/dist/template/.opencode/skill/cloudflare/references/pulumi/README.md +107 -0
- package/dist/template/.opencode/skill/cloudflare/references/pulumi/api.md +194 -0
- package/dist/template/.opencode/skill/cloudflare/references/pulumi/configuration.md +216 -0
- package/dist/template/.opencode/skill/cloudflare/references/pulumi/gotchas.md +223 -0
- package/dist/template/.opencode/skill/cloudflare/references/pulumi/patterns.md +139 -0
- package/dist/template/.opencode/skill/cloudflare/references/queues/README.md +69 -0
- package/dist/template/.opencode/skill/cloudflare/references/queues/api.md +138 -0
- package/dist/template/.opencode/skill/cloudflare/references/queues/configuration.md +125 -0
- package/dist/template/.opencode/skill/cloudflare/references/queues/gotchas.md +112 -0
- package/dist/template/.opencode/skill/cloudflare/references/queues/patterns.md +155 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2/README.md +61 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2/api.md +127 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2/configuration.md +76 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2/gotchas.md +94 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2/patterns.md +127 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2-data-catalog/README.md +18 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2-data-catalog/api.md +29 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2-data-catalog/configuration.md +39 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2-data-catalog/gotchas.md +20 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2-data-catalog/patterns.md +46 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2-sql/README.md +512 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtime-sfu/README.md +21 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtime-sfu/api.md +135 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtime-sfu/configuration.md +63 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtime-sfu/gotchas.md +75 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtime-sfu/patterns.md +102 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtimekit/README.md +81 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtimekit/api.md +164 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtimekit/configuration.md +147 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtimekit/gotchas.md +172 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtimekit/patterns.md +155 -0
- package/dist/template/.opencode/skill/cloudflare/references/sandbox/README.md +90 -0
- package/dist/template/.opencode/skill/cloudflare/references/sandbox/api.md +178 -0
- package/dist/template/.opencode/skill/cloudflare/references/sandbox/configuration.md +131 -0
- package/dist/template/.opencode/skill/cloudflare/references/sandbox/gotchas.md +156 -0
- package/dist/template/.opencode/skill/cloudflare/references/sandbox/patterns.md +203 -0
- package/dist/template/.opencode/skill/cloudflare/references/secrets-store/README.md +58 -0
- package/dist/template/.opencode/skill/cloudflare/references/secrets-store/api.md +182 -0
- package/dist/template/.opencode/skill/cloudflare/references/secrets-store/configuration.md +140 -0
- package/dist/template/.opencode/skill/cloudflare/references/secrets-store/gotchas.md +129 -0
- package/dist/template/.opencode/skill/cloudflare/references/secrets-store/patterns.md +218 -0
- package/dist/template/.opencode/skill/cloudflare/references/smart-placement/README.md +91 -0
- package/dist/template/.opencode/skill/cloudflare/references/smart-placement/api.md +139 -0
- package/dist/template/.opencode/skill/cloudflare/references/smart-placement/configuration.md +129 -0
- package/dist/template/.opencode/skill/cloudflare/references/smart-placement/gotchas.md +87 -0
- package/dist/template/.opencode/skill/cloudflare/references/smart-placement/patterns.md +135 -0
- package/dist/template/.opencode/skill/cloudflare/references/snippets/README.md +15 -0
- package/dist/template/.opencode/skill/cloudflare/references/snippets/api.md +47 -0
- package/dist/template/.opencode/skill/cloudflare/references/snippets/configuration.md +33 -0
- package/dist/template/.opencode/skill/cloudflare/references/snippets/gotchas.md +21 -0
- package/dist/template/.opencode/skill/cloudflare/references/snippets/patterns.md +34 -0
- package/dist/template/.opencode/skill/cloudflare/references/spectrum/README.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/spectrum/api.md +24 -0
- package/dist/template/.opencode/skill/cloudflare/references/spectrum/configuration.md +43 -0
- package/dist/template/.opencode/skill/cloudflare/references/spectrum/gotchas.md +42 -0
- package/dist/template/.opencode/skill/cloudflare/references/spectrum/patterns.md +40 -0
- package/dist/template/.opencode/skill/cloudflare/references/static-assets/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/static-assets/api.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/static-assets/configuration.md +47 -0
- package/dist/template/.opencode/skill/cloudflare/references/static-assets/gotchas.md +44 -0
- package/dist/template/.opencode/skill/cloudflare/references/static-assets/patterns.md +42 -0
- package/dist/template/.opencode/skill/cloudflare/references/stream/README.md +103 -0
- package/dist/template/.opencode/skill/cloudflare/references/stream/api.md +204 -0
- package/dist/template/.opencode/skill/cloudflare/references/stream/configuration.md +127 -0
- package/dist/template/.opencode/skill/cloudflare/references/stream/gotchas.md +131 -0
- package/dist/template/.opencode/skill/cloudflare/references/stream/patterns.md +152 -0
- package/dist/template/.opencode/skill/cloudflare/references/tail-workers/README.md +640 -0
- package/dist/template/.opencode/skill/cloudflare/references/terraform/README.md +76 -0
- package/dist/template/.opencode/skill/cloudflare/references/terraform/api.md +159 -0
- package/dist/template/.opencode/skill/cloudflare/references/terraform/configuration.md +156 -0
- package/dist/template/.opencode/skill/cloudflare/references/terraform/gotchas.md +207 -0
- package/dist/template/.opencode/skill/cloudflare/references/terraform/patterns.md +135 -0
- package/dist/template/.opencode/skill/cloudflare/references/tunnel/README.md +82 -0
- package/dist/template/.opencode/skill/cloudflare/references/tunnel/api.md +105 -0
- package/dist/template/.opencode/skill/cloudflare/references/tunnel/configuration.md +113 -0
- package/dist/template/.opencode/skill/cloudflare/references/tunnel/gotchas.md +115 -0
- package/dist/template/.opencode/skill/cloudflare/references/tunnel/patterns.md +157 -0
- package/dist/template/.opencode/skill/cloudflare/references/turn/README.md +699 -0
- package/dist/template/.opencode/skill/cloudflare/references/turnstile/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/turnstile/api.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/turnstile/configuration.md +19 -0
- package/dist/template/.opencode/skill/cloudflare/references/turnstile/gotchas.md +27 -0
- package/dist/template/.opencode/skill/cloudflare/references/turnstile/patterns.md +41 -0
- package/dist/template/.opencode/skill/cloudflare/references/vectorize/README.md +682 -0
- package/dist/template/.opencode/skill/cloudflare/references/waf/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/waf/api.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/waf/configuration.md +44 -0
- package/dist/template/.opencode/skill/cloudflare/references/waf/gotchas.md +24 -0
- package/dist/template/.opencode/skill/cloudflare/references/waf/patterns.md +29 -0
- package/dist/template/.opencode/skill/cloudflare/references/web-analytics/README.md +19 -0
- package/dist/template/.opencode/skill/cloudflare/references/web-analytics/api.md +52 -0
- package/dist/template/.opencode/skill/cloudflare/references/web-analytics/configuration.md +31 -0
- package/dist/template/.opencode/skill/cloudflare/references/web-analytics/gotchas.md +28 -0
- package/dist/template/.opencode/skill/cloudflare/references/web-analytics/patterns.md +52 -0
- package/dist/template/.opencode/skill/cloudflare/references/workerd/README.md +47 -0
- package/dist/template/.opencode/skill/cloudflare/references/workerd/api.md +199 -0
- package/dist/template/.opencode/skill/cloudflare/references/workerd/configuration.md +185 -0
- package/dist/template/.opencode/skill/cloudflare/references/workerd/gotchas.md +203 -0
- package/dist/template/.opencode/skill/cloudflare/references/workerd/patterns.md +216 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers/README.md +96 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers/api.md +137 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers/configuration.md +147 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers/gotchas.md +99 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers/patterns.md +149 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-ai/README.md +116 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-for-platforms/README.md +48 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-for-platforms/api.md +169 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-for-platforms/configuration.md +136 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-for-platforms/gotchas.md +130 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-for-platforms/patterns.md +170 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-playground/README.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-playground/api.md +20 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-playground/configuration.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-playground/gotchas.md +35 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-playground/patterns.md +42 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-vpc/README.md +579 -0
- package/dist/template/.opencode/skill/cloudflare/references/workflows/README.md +62 -0
- package/dist/template/.opencode/skill/cloudflare/references/workflows/api.md +125 -0
- package/dist/template/.opencode/skill/cloudflare/references/workflows/configuration.md +177 -0
- package/dist/template/.opencode/skill/cloudflare/references/workflows/gotchas.md +136 -0
- package/dist/template/.opencode/skill/cloudflare/references/workflows/patterns.md +132 -0
- package/dist/template/.opencode/skill/cloudflare/references/wrangler/README.md +90 -0
- package/dist/template/.opencode/skill/cloudflare/references/wrangler/api.md +140 -0
- package/dist/template/.opencode/skill/cloudflare/references/wrangler/configuration.md +128 -0
- package/dist/template/.opencode/skill/cloudflare/references/wrangler/gotchas.md +93 -0
- package/dist/template/.opencode/skill/cloudflare/references/wrangler/patterns.md +150 -0
- package/dist/template/.opencode/skill/cloudflare/references/zaraz/README.md +360 -0
- package/dist/template/.opencode/skill/react-best-practices/AGENTS.md +2410 -0
- package/dist/template/.opencode/skill/react-best-practices/README.md +123 -0
- package/dist/template/.opencode/skill/react-best-practices/SKILL.md +125 -0
- package/dist/template/.opencode/skill/react-best-practices/metadata.json +15 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/_sections.md +46 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/_template.md +28 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/async-api-routes.md +38 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/async-defer-await.md +80 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/async-dependencies.md +36 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/async-parallel.md +28 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/bundle-conditional.md +31 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/bundle-preload.md +50 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/client-event-listeners.md +74 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-cache-storage.md +70 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-early-exit.md +50 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-index-maps.md +37 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-length-check-first.md +49 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-activity.md +26 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-memo.md +44 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-transitions.md +40 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/server-cache-lru.md +41 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/server-cache-react.md +76 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/server-serialization.md +38 -0
- package/dist/template/.opencode/skill/supabase/SKILL.md +120 -0
- package/dist/template/.opencode/skill/supabase/mcp.json +27 -0
- package/dist/template/.opencode/skill/vercel-deploy-claimable/SKILL.md +112 -0
- package/dist/template/.opencode/skill/vercel-deploy-claimable/scripts/deploy.sh +249 -0
- package/dist/template/.opencode/skill/web-design-guidelines/SKILL.md +39 -0
- package/package.json +1 -1
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# D1 API Reference
|
|
2
|
+
|
|
3
|
+
## Prepared Statements (Required for Security)
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
// ❌ NEVER: Direct string interpolation (SQL injection risk)
|
|
7
|
+
const result = await env.DB.prepare(`SELECT * FROM users WHERE id = ${userId}`).all();
|
|
8
|
+
|
|
9
|
+
// ✅ CORRECT: Prepared statements with bind()
|
|
10
|
+
const result = await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(userId).all();
|
|
11
|
+
|
|
12
|
+
// Multiple parameters
|
|
13
|
+
const result = await env.DB.prepare('SELECT * FROM users WHERE email = ? AND active = ?').bind(email, true).all();
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Query Execution Methods
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
// .all() - Returns all rows
|
|
20
|
+
const { results, success, meta } = await env.DB.prepare('SELECT * FROM users WHERE active = ?').bind(true).all();
|
|
21
|
+
// results: Array of row objects; success: boolean
|
|
22
|
+
// meta: { duration: number, rows_read: number, rows_written: number }
|
|
23
|
+
|
|
24
|
+
// .first() - Returns first row or null
|
|
25
|
+
const user = await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(userId).first();
|
|
26
|
+
|
|
27
|
+
// .first(columnName) - Returns single column value
|
|
28
|
+
const email = await env.DB.prepare('SELECT email FROM users WHERE id = ?').bind(userId).first('email');
|
|
29
|
+
// Returns string | number | null
|
|
30
|
+
|
|
31
|
+
// .run() - For INSERT/UPDATE/DELETE (no row data returned)
|
|
32
|
+
const result = await env.DB.prepare('UPDATE users SET last_login = ? WHERE id = ?').bind(Date.now(), userId).run();
|
|
33
|
+
// result.meta: { duration, rows_read, rows_written, last_row_id, changes }
|
|
34
|
+
|
|
35
|
+
// .raw() - Returns array of arrays (efficient for large datasets)
|
|
36
|
+
const rawResults = await env.DB.prepare('SELECT id, name FROM users').raw();
|
|
37
|
+
// [[1, 'Alice'], [2, 'Bob']]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Batch Operations
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// Execute multiple queries in single round trip (atomic transaction)
|
|
44
|
+
const results = await env.DB.batch([
|
|
45
|
+
env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(1),
|
|
46
|
+
env.DB.prepare('SELECT * FROM posts WHERE author_id = ?').bind(1),
|
|
47
|
+
env.DB.prepare('UPDATE users SET last_access = ? WHERE id = ?').bind(Date.now(), 1)
|
|
48
|
+
]);
|
|
49
|
+
// results is array: [result1, result2, result3]
|
|
50
|
+
|
|
51
|
+
// Batch with same prepared statement, different params
|
|
52
|
+
const userIds = [1, 2, 3];
|
|
53
|
+
const stmt = env.DB.prepare('SELECT * FROM users WHERE id = ?');
|
|
54
|
+
const results = await env.DB.batch(userIds.map(id => stmt.bind(id)));
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Transactions (via batch)
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// D1 executes batch() as atomic transaction - all succeed or all fail
|
|
61
|
+
const results = await env.DB.batch([
|
|
62
|
+
env.DB.prepare('INSERT INTO accounts (id, balance) VALUES (?, ?)').bind(1, 100),
|
|
63
|
+
env.DB.prepare('INSERT INTO accounts (id, balance) VALUES (?, ?)').bind(2, 200),
|
|
64
|
+
env.DB.prepare('UPDATE accounts SET balance = balance - ? WHERE id = ?').bind(50, 1),
|
|
65
|
+
env.DB.prepare('UPDATE accounts SET balance = balance + ? WHERE id = ?').bind(50, 2)
|
|
66
|
+
]);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Error Handling
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
async function getUser(userId: number, env: Env): Promise<Response> {
|
|
73
|
+
try {
|
|
74
|
+
const result = await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(userId).all();
|
|
75
|
+
if (!result.success) return new Response('Database error', { status: 500 });
|
|
76
|
+
if (result.results.length === 0) return new Response('User not found', { status: 404 });
|
|
77
|
+
return Response.json(result.results[0]);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
return new Response('Internal error', { status: 500 });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Constraint violations
|
|
84
|
+
try {
|
|
85
|
+
await env.DB.prepare('INSERT INTO users (email, name) VALUES (?, ?)').bind(email, name).run();
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (error.message?.includes('UNIQUE constraint failed')) return new Response('Email exists', { status: 409 });
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## REST API (HTTP) Access
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// Access D1 via Cloudflare REST API (external to Workers)
|
|
96
|
+
const response = await fetch(
|
|
97
|
+
`https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/d1/database/${DATABASE_ID}/query`,
|
|
98
|
+
{
|
|
99
|
+
method: 'POST',
|
|
100
|
+
headers: {
|
|
101
|
+
'Authorization': `Bearer ${CLOUDFLARE_API_TOKEN}`,
|
|
102
|
+
'Content-Type': 'application/json'
|
|
103
|
+
},
|
|
104
|
+
body: JSON.stringify({
|
|
105
|
+
sql: 'SELECT * FROM users WHERE id = ?',
|
|
106
|
+
params: [userId]
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const data = await response.json();
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Testing
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { unstable_dev } from 'wrangler';
|
|
118
|
+
|
|
119
|
+
describe('D1 Tests', () => {
|
|
120
|
+
let worker: Awaited<ReturnType<typeof unstable_dev>>;
|
|
121
|
+
beforeAll(async () => { worker = await unstable_dev('src/index.ts', { experimental: { disableExperimentalWarning: true } }); });
|
|
122
|
+
afterAll(async () => { await worker.stop(); });
|
|
123
|
+
it('should query users', async () => { expect((await worker.fetch('/api/users')).status).toBe(200); });
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Debugging
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// Log query metadata
|
|
131
|
+
const result = await env.DB.prepare('SELECT * FROM users').all();
|
|
132
|
+
console.log('Duration:', result.meta.duration, 'ms', 'Rows:', result.meta.rows_read);
|
|
133
|
+
|
|
134
|
+
// EXPLAIN for query plans
|
|
135
|
+
const plan = await env.DB.prepare('EXPLAIN QUERY PLAN SELECT * FROM users WHERE email = ?').bind(email).all();
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
sqlite3 .wrangler/state/v3/d1/<database-id>.sqlite # Inspect local DB
|
|
140
|
+
.tables; .schema users; .indexes users; PRAGMA table_info(users);
|
|
141
|
+
```
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# D1 Configuration
|
|
2
|
+
|
|
3
|
+
## wrangler.toml Setup
|
|
4
|
+
|
|
5
|
+
```toml
|
|
6
|
+
name = "your-worker-name"; main = "src/index.ts"; compatibility_date = "2024-01-01"
|
|
7
|
+
|
|
8
|
+
[[d1_databases]]
|
|
9
|
+
binding = "DB" # Env variable name
|
|
10
|
+
database_name = "your-db-name" # Human-readable name
|
|
11
|
+
database_id = "your-database-id" # UUID from dashboard/CLI
|
|
12
|
+
migrations_dir = "migrations" # Optional
|
|
13
|
+
|
|
14
|
+
# Multiple databases
|
|
15
|
+
[[d1_databases]]
|
|
16
|
+
binding = "ANALYTICS_DB"; database_name = "analytics-db"; database_id = "yyy-yyy-yyy"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## TypeScript Types
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
interface Env { DB: D1Database; ANALYTICS_DB?: D1Database; }
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
26
|
+
const result = await env.DB.prepare('SELECT * FROM users').all();
|
|
27
|
+
return Response.json(result.results);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Migrations
|
|
33
|
+
|
|
34
|
+
File structure: `migrations/0001_initial_schema.sql`, `0002_add_posts.sql`, etc.
|
|
35
|
+
|
|
36
|
+
### Example Migration
|
|
37
|
+
|
|
38
|
+
```sql
|
|
39
|
+
-- migrations/0001_initial_schema.sql
|
|
40
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
41
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
42
|
+
email TEXT UNIQUE NOT NULL,
|
|
43
|
+
name TEXT NOT NULL,
|
|
44
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
45
|
+
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
CREATE INDEX idx_users_email ON users(email);
|
|
49
|
+
|
|
50
|
+
CREATE TABLE IF NOT EXISTS posts (
|
|
51
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
52
|
+
user_id INTEGER NOT NULL,
|
|
53
|
+
title TEXT NOT NULL,
|
|
54
|
+
content TEXT,
|
|
55
|
+
published BOOLEAN DEFAULT 0,
|
|
56
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
57
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
CREATE INDEX idx_posts_user_id ON posts(user_id);
|
|
61
|
+
CREATE INDEX idx_posts_published ON posts(published);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Running Migrations
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
wrangler d1 execute <db-name> --local --file=./migrations/0001_schema.sql # Local
|
|
68
|
+
wrangler d1 execute <db-name> --remote --file=./migrations/0001_schema.sql # Production
|
|
69
|
+
wrangler d1 execute <db-name> --remote --command="SELECT * FROM users" # Direct
|
|
70
|
+
|
|
71
|
+
# Track migrations: CREATE TABLE schema_version (version INT PRIMARY KEY, name TEXT, applied_at INT)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Indexing Strategy
|
|
75
|
+
|
|
76
|
+
```sql
|
|
77
|
+
-- Index frequently queried columns
|
|
78
|
+
CREATE INDEX idx_users_email ON users(email);
|
|
79
|
+
|
|
80
|
+
-- Composite indexes for multi-column queries
|
|
81
|
+
CREATE INDEX idx_posts_user_published ON posts(user_id, published);
|
|
82
|
+
|
|
83
|
+
-- Covering indexes (include queried columns)
|
|
84
|
+
CREATE INDEX idx_users_email_name ON users(email, name);
|
|
85
|
+
|
|
86
|
+
-- Partial indexes for filtered queries
|
|
87
|
+
CREATE INDEX idx_active_users ON users(email) WHERE active = 1;
|
|
88
|
+
|
|
89
|
+
-- Check if query uses index
|
|
90
|
+
EXPLAIN QUERY PLAN SELECT * FROM users WHERE email = ?;
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Drizzle ORM
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// drizzle.config.ts
|
|
97
|
+
export default {
|
|
98
|
+
schema: './src/schema.ts', out: './migrations', dialect: 'sqlite', driver: 'd1-http',
|
|
99
|
+
dbCredentials: { accountId: process.env.CLOUDFLARE_ACCOUNT_ID!, databaseId: process.env.D1_DATABASE_ID!, token: process.env.CLOUDFLARE_API_TOKEN! }
|
|
100
|
+
} satisfies Config;
|
|
101
|
+
|
|
102
|
+
// schema.ts
|
|
103
|
+
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
|
|
104
|
+
export const users = sqliteTable('users', {
|
|
105
|
+
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
106
|
+
email: text('email').notNull().unique(),
|
|
107
|
+
name: text('name').notNull()
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// worker.ts
|
|
111
|
+
import { drizzle } from 'drizzle-orm/d1';
|
|
112
|
+
import { users } from './schema';
|
|
113
|
+
export default {
|
|
114
|
+
async fetch(request: Request, env: Env) {
|
|
115
|
+
const db = drizzle(env.DB);
|
|
116
|
+
return Response.json(await db.select().from(users));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Local Development
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
wrangler dev --persist-to=./.wrangler/state # Persist across restarts
|
|
125
|
+
# Local DB: .wrangler/state/v3/d1/<database-id>.sqlite
|
|
126
|
+
sqlite3 .wrangler/state/v3/d1/<database-id>.sqlite # Inspect
|
|
127
|
+
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# D1 Gotchas & Troubleshooting
|
|
2
|
+
|
|
3
|
+
## SQL Injection Prevention (CRITICAL)
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
// ❌ NEVER: String interpolation - SQL injection vulnerability
|
|
7
|
+
await env.DB.prepare(`SELECT * FROM users WHERE id = ${userId}`).all(); // DANGEROUS!
|
|
8
|
+
|
|
9
|
+
// ✅ ALWAYS: Prepared statements with bind()
|
|
10
|
+
await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(userId).all();
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Attacker could pass `1 OR 1=1` to dump table or `1; DROP TABLE users;--` to delete data.
|
|
14
|
+
|
|
15
|
+
## Common Errors
|
|
16
|
+
|
|
17
|
+
**Missing Table:** "no such table" → Run migrations first
|
|
18
|
+
**Unique Constraint:** "UNIQUE constraint failed" → Catch and return 409
|
|
19
|
+
**Query Timeout:** 30s exceeded → Break into smaller queries or add indexes
|
|
20
|
+
|
|
21
|
+
## N+1 Query Problem
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// ❌ BAD: N+1 queries (multiple round trips)
|
|
25
|
+
for (const post of posts.results) {
|
|
26
|
+
const author = await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(post.user_id).first();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ✅ GOOD: Single JOIN or batch()
|
|
30
|
+
const postsWithAuthors = await env.DB.prepare(`
|
|
31
|
+
SELECT posts.*, users.name FROM posts JOIN users ON posts.user_id = users.id
|
|
32
|
+
`).all();
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Missing Indexes
|
|
36
|
+
|
|
37
|
+
```sql
|
|
38
|
+
EXPLAIN QUERY PLAN SELECT * FROM users WHERE email = ?; -- Check for "USING INDEX"
|
|
39
|
+
CREATE INDEX idx_users_email ON users(email); -- Add if missing
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Limits to Watch
|
|
43
|
+
|
|
44
|
+
| Limit | Value | Impact |
|
|
45
|
+
|-------|-------|--------|
|
|
46
|
+
| Database size | 10 GB | Design for multiple DBs per tenant |
|
|
47
|
+
| Row size | 1 MB | Store large files in R2, not D1 |
|
|
48
|
+
| Query timeout | 30s | Break long queries into smaller chunks |
|
|
49
|
+
| Batch size | 10,000 statements | Split large batches |
|
|
50
|
+
|
|
51
|
+
## Local vs Remote
|
|
52
|
+
|
|
53
|
+
Local uses `.wrangler/state/v3/d1/<database-id>.sqlite`. Always test migrations locally before remote.
|
|
54
|
+
|
|
55
|
+
## Data Types
|
|
56
|
+
|
|
57
|
+
**Boolean:** SQLite uses INTEGER (0/1) not boolean - bind 1 or 0, not true/false
|
|
58
|
+
**Date/Time:** Use TEXT (ISO 8601) or INTEGER (unix timestamp), not native DATE/TIME
|
|
59
|
+
|
|
60
|
+
## Best Practices
|
|
61
|
+
|
|
62
|
+
- ✅ Use prepared statements with bind() - ALWAYS
|
|
63
|
+
- ✅ Create indexes on frequently queried columns
|
|
64
|
+
- ✅ Use batch() for multiple queries (reduces latency)
|
|
65
|
+
- ✅ Design for horizontal scaling (multiple small DBs vs single large DB)
|
|
66
|
+
- ✅ Test migrations locally before applying remotely
|
|
67
|
+
- ✅ Monitor query performance via meta.duration
|
|
68
|
+
- ❌ Don't store binary data directly (use R2 for blobs)
|
|
69
|
+
- ❌ Don't use single large database (scale horizontally instead)
|
|
70
|
+
- ❌ Don't run long transactions (30s timeout)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# D1 Patterns & Best Practices
|
|
2
|
+
|
|
3
|
+
## Pagination
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
async function getUsers({ page, pageSize }: { page: number; pageSize: number }, env: Env) {
|
|
7
|
+
const offset = (page - 1) * pageSize;
|
|
8
|
+
const [countResult, dataResult] = await env.DB.batch([
|
|
9
|
+
env.DB.prepare('SELECT COUNT(*) as total FROM users'),
|
|
10
|
+
env.DB.prepare('SELECT * FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?').bind(pageSize, offset)
|
|
11
|
+
]);
|
|
12
|
+
return { data: dataResult.results, total: countResult.results[0].total, page, pageSize, totalPages: Math.ceil(countResult.results[0].total / pageSize) };
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Conditional Queries
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
async function searchUsers(filters: { name?: string; email?: string; active?: boolean }, env: Env) {
|
|
20
|
+
const conditions: string[] = [], params: any[] = [];
|
|
21
|
+
if (filters.name) { conditions.push('name LIKE ?'); params.push(`%${filters.name}%`); }
|
|
22
|
+
if (filters.email) { conditions.push('email = ?'); params.push(filters.email); }
|
|
23
|
+
if (filters.active !== undefined) { conditions.push('active = ?'); params.push(filters.active ? 1 : 0); }
|
|
24
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
25
|
+
return await env.DB.prepare(`SELECT * FROM users ${whereClause}`).bind(...params).all();
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Bulk Insert
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
async function bulkInsertUsers(users: Array<{ name: string; email: string }>, env: Env) {
|
|
33
|
+
const stmt = env.DB.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
|
|
34
|
+
const batch = users.map(user => stmt.bind(user.name, user.email));
|
|
35
|
+
return await env.DB.batch(batch);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Caching with KV
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
async function getCachedUser(userId: number, env: { DB: D1Database; CACHE: KVNamespace }) {
|
|
43
|
+
const cacheKey = `user:${userId}`;
|
|
44
|
+
const cached = await env.CACHE?.get(cacheKey, 'json');
|
|
45
|
+
if (cached) return cached;
|
|
46
|
+
const user = await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(userId).first();
|
|
47
|
+
if (user) await env.CACHE?.put(cacheKey, JSON.stringify(user), { expirationTtl: 300 });
|
|
48
|
+
return user;
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Query Optimization
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// ✅ Use indexes in WHERE clauses
|
|
56
|
+
const users = await env.DB.prepare('SELECT * FROM users WHERE email = ?').bind(email).all();
|
|
57
|
+
|
|
58
|
+
// ✅ Limit result sets
|
|
59
|
+
const recentPosts = await env.DB.prepare('SELECT * FROM posts ORDER BY created_at DESC LIMIT 100').all();
|
|
60
|
+
|
|
61
|
+
// ✅ Use batch() for multiple independent queries
|
|
62
|
+
const [user, posts, comments] = await env.DB.batch([
|
|
63
|
+
env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(userId),
|
|
64
|
+
env.DB.prepare('SELECT * FROM posts WHERE user_id = ?').bind(userId),
|
|
65
|
+
env.DB.prepare('SELECT * FROM comments WHERE user_id = ?').bind(userId)
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
// ❌ Avoid N+1 queries
|
|
69
|
+
for (const post of posts) {
|
|
70
|
+
const author = await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(post.user_id).first(); // Bad: multiple round trips
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ✅ Use JOINs instead
|
|
74
|
+
const postsWithAuthors = await env.DB.prepare(`
|
|
75
|
+
SELECT posts.*, users.name as author_name
|
|
76
|
+
FROM posts
|
|
77
|
+
JOIN users ON posts.user_id = users.id
|
|
78
|
+
`).all();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Multi-Tenant SaaS
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
// Each tenant gets own database
|
|
85
|
+
export default {
|
|
86
|
+
async fetch(request: Request, env: { [key: `TENANT_${string}`]: D1Database }) {
|
|
87
|
+
const tenantId = request.headers.get('X-Tenant-ID');
|
|
88
|
+
const data = await env[`TENANT_${tenantId}`].prepare('SELECT * FROM records').all();
|
|
89
|
+
return Response.json(data.results);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Session Storage
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
async function createSession(userId: number, token: string, env: Env) {
|
|
98
|
+
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString();
|
|
99
|
+
return await env.DB.prepare(`
|
|
100
|
+
INSERT INTO sessions (user_id, token, expires_at, created_at)
|
|
101
|
+
VALUES (?, ?, ?, CURRENT_TIMESTAMP)
|
|
102
|
+
`).bind(userId, token, expiresAt).run();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function validateSession(token: string, env: Env) {
|
|
106
|
+
return await env.DB.prepare(`
|
|
107
|
+
SELECT s.*, u.email, u.name
|
|
108
|
+
FROM sessions s
|
|
109
|
+
JOIN users u ON s.user_id = u.id
|
|
110
|
+
WHERE s.token = ? AND s.expires_at > CURRENT_TIMESTAMP
|
|
111
|
+
`).bind(token).first();
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Analytics/Events
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
async function logEvent(event: { type: string; userId?: number; metadata: any }, env: Env) {
|
|
119
|
+
return await env.DB.prepare(`
|
|
120
|
+
INSERT INTO events (type, user_id, metadata, timestamp)
|
|
121
|
+
VALUES (?, ?, ?, CURRENT_TIMESTAMP)
|
|
122
|
+
`).bind(event.type, event.userId || null, JSON.stringify(event.metadata)).run();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function getEventStats(startDate: string, endDate: string, env: Env) {
|
|
126
|
+
return await env.DB.prepare(`
|
|
127
|
+
SELECT type, COUNT(*) as count
|
|
128
|
+
FROM events
|
|
129
|
+
WHERE timestamp BETWEEN ? AND ?
|
|
130
|
+
GROUP BY type
|
|
131
|
+
ORDER BY count DESC
|
|
132
|
+
`).bind(startDate, endDate).all();
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Time Travel & Backups
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
wrangler d1 time-travel restore <db-name> --timestamp="2024-01-15T14:30:00Z" # Point-in-time
|
|
140
|
+
wrangler d1 time-travel info <db-name> # List restore points (30-day window)
|
|
141
|
+
wrangler d1 export <db-name> --remote --output=./backup.sql # Full export
|
|
142
|
+
wrangler d1 export <db-name> --remote --no-schema --output=./data.sql # Data only
|
|
143
|
+
wrangler d1 execute <db-name> --remote --file=./backup.sql # Import
|
|
144
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Cloudflare DDoS Protection
|
|
2
|
+
|
|
3
|
+
Autonomous, always-on protection against DDoS attacks across L3/4 and L7.
|
|
4
|
+
|
|
5
|
+
## Protection Types
|
|
6
|
+
|
|
7
|
+
- **HTTP DDoS (L7)**: Protects HTTP/HTTPS traffic, phase `ddos_l7`, zone/account level
|
|
8
|
+
- **Network DDoS (L3/4)**: UDP/SYN/DNS floods, phase `ddos_l4`, account level only
|
|
9
|
+
- **Adaptive DDoS**: Learns 7-day baseline, detects deviations (Enterprise)
|
|
10
|
+
|
|
11
|
+
## Key Features
|
|
12
|
+
|
|
13
|
+
- Always-on managed rulesets (cannot disable)
|
|
14
|
+
- Sensitivity levels: `default` (high), `medium`, `low`, `eoff` (essentially off)
|
|
15
|
+
- Actions: `block`, `managed_challenge`, `challenge`, `log` (Enterprise Advanced only)
|
|
16
|
+
- Override by category/tag or individual rule ID
|
|
17
|
+
- Custom expressions for traffic filtering (Enterprise Advanced)
|
|
18
|
+
- Alert configuration for attack notifications
|
|
19
|
+
|
|
20
|
+
## Rule Limits
|
|
21
|
+
|
|
22
|
+
- Free/Pro/Business: 1 override rule
|
|
23
|
+
- Enterprise Advanced: Up to 10 rules
|
|
24
|
+
|
|
25
|
+
## Scope Hierarchy
|
|
26
|
+
|
|
27
|
+
Zone overrides take precedence over account overrides.
|
|
28
|
+
|
|
29
|
+
## See Also
|
|
30
|
+
|
|
31
|
+
- [configuration.md](./configuration.md) - Dashboard & rule setup
|
|
32
|
+
- [api.md](./api.md) - API endpoints & management
|
|
33
|
+
- [patterns.md](./patterns.md) - Protection strategies
|
|
34
|
+
- [gotchas.md](./gotchas.md) - False positives & tuning
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# DDoS API
|
|
2
|
+
|
|
3
|
+
## Endpoints
|
|
4
|
+
|
|
5
|
+
### HTTP DDoS (L7)
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Zone-level
|
|
9
|
+
PUT /zones/{zoneId}/rulesets/phases/ddos_l7/entrypoint
|
|
10
|
+
GET /zones/{zoneId}/rulesets/phases/ddos_l7/entrypoint
|
|
11
|
+
|
|
12
|
+
// Account-level (Enterprise Advanced)
|
|
13
|
+
PUT /accounts/{accountId}/rulesets/phases/ddos_l7/entrypoint
|
|
14
|
+
GET /accounts/{accountId}/rulesets/phases/ddos_l7/entrypoint
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Network DDoS (L3/4)
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// Account-level only
|
|
21
|
+
PUT /accounts/{accountId}/rulesets/phases/ddos_l4/entrypoint
|
|
22
|
+
GET /accounts/{accountId}/rulesets/phases/ddos_l4/entrypoint
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## TypeScript SDK
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import Cloudflare from "cloudflare";
|
|
29
|
+
|
|
30
|
+
const client = new Cloudflare({ apiToken: process.env.CLOUDFLARE_API_TOKEN });
|
|
31
|
+
|
|
32
|
+
// Get HTTP DDoS ruleset
|
|
33
|
+
const ruleset = await client.zones.rulesets.phases.entrypoint.get("ddos_l7", {
|
|
34
|
+
zone_id: zoneId,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Update HTTP DDoS ruleset
|
|
38
|
+
await client.zones.rulesets.phases.entrypoint.update("ddos_l7", {
|
|
39
|
+
zone_id: zoneId,
|
|
40
|
+
rules: [
|
|
41
|
+
{
|
|
42
|
+
action: "execute",
|
|
43
|
+
expression: "true",
|
|
44
|
+
action_parameters: {
|
|
45
|
+
id: managedRulesetId,
|
|
46
|
+
overrides: {
|
|
47
|
+
sensitivity_level: "medium",
|
|
48
|
+
action: "managed_challenge",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Network DDoS (account level)
|
|
56
|
+
const l4Ruleset = await client.accounts.rulesets.phases.entrypoint.get("ddos_l4", {
|
|
57
|
+
account_id: accountId,
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Alert Configuration
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
interface DDoSAlertConfig {
|
|
65
|
+
name: string;
|
|
66
|
+
enabled: boolean;
|
|
67
|
+
alert_type: "http_ddos_attack_alert" | "layer_3_4_ddos_attack_alert"
|
|
68
|
+
| "advanced_http_ddos_attack_alert" | "advanced_layer_3_4_ddos_attack_alert";
|
|
69
|
+
filters?: {
|
|
70
|
+
zones?: string[];
|
|
71
|
+
hostnames?: string[];
|
|
72
|
+
requests_per_second?: number;
|
|
73
|
+
packets_per_second?: number;
|
|
74
|
+
megabits_per_second?: number;
|
|
75
|
+
ip_prefixes?: string[]; // CIDR
|
|
76
|
+
ip_addresses?: string[];
|
|
77
|
+
protocols?: string[];
|
|
78
|
+
};
|
|
79
|
+
mechanisms: {
|
|
80
|
+
email?: Array<{ id: string }>;
|
|
81
|
+
webhooks?: Array<{ id: string }>;
|
|
82
|
+
pagerduty?: Array<{ id: string }>;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Create alert
|
|
87
|
+
await fetch(
|
|
88
|
+
`https://api.cloudflare.com/client/v4/accounts/${accountId}/alerting/v3/policies`,
|
|
89
|
+
{
|
|
90
|
+
method: "POST",
|
|
91
|
+
headers: {
|
|
92
|
+
Authorization: `Bearer ${apiToken}`,
|
|
93
|
+
"Content-Type": "application/json",
|
|
94
|
+
},
|
|
95
|
+
body: JSON.stringify(alertConfig),
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Worker Integration
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// DDoS config management worker
|
|
104
|
+
interface Env {
|
|
105
|
+
CLOUDFLARE_API_TOKEN: string;
|
|
106
|
+
ZONE_ID: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export default {
|
|
110
|
+
async fetch(request: Request, env: Env): Promise<Response> {
|
|
111
|
+
const url = new URL(request.url);
|
|
112
|
+
|
|
113
|
+
if (url.pathname === "/configure") {
|
|
114
|
+
const response = await fetch(
|
|
115
|
+
`https://api.cloudflare.com/client/v4/zones/${env.ZONE_ID}/rulesets/phases/ddos_l7/entrypoint`,
|
|
116
|
+
{
|
|
117
|
+
method: "PUT",
|
|
118
|
+
headers: {
|
|
119
|
+
Authorization: `Bearer ${env.CLOUDFLARE_API_TOKEN}`,
|
|
120
|
+
"Content-Type": "application/json",
|
|
121
|
+
},
|
|
122
|
+
body: JSON.stringify({
|
|
123
|
+
description: "Dynamic DDoS config",
|
|
124
|
+
rules: [/* ... */],
|
|
125
|
+
}),
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
return response;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return new Response("Not found", { status: 404 });
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
See [patterns.md](./patterns.md) for complete worker examples.
|