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,23 @@
|
|
|
1
|
+
## Best Practices
|
|
2
|
+
|
|
3
|
+
### 1. Use Appropriate Fit Modes
|
|
4
|
+
- `cover`: Hero images, thumbnails, avatars (fills space, crops)
|
|
5
|
+
- `contain`: Product images, artwork (preserves full image)
|
|
6
|
+
- `scale-down`: Ensure images aren't unnecessarily enlarged
|
|
7
|
+
|
|
8
|
+
### 2. Format Selection
|
|
9
|
+
- Use `format=auto` for automatic AVIF/WebP/JPEG selection
|
|
10
|
+
- For Workers, parse `Accept` header for format negotiation
|
|
11
|
+
- AVIF: Best compression, use for modern browsers
|
|
12
|
+
- WebP: Wide support, good compression
|
|
13
|
+
- JPEG: Fallback for older browsers
|
|
14
|
+
|
|
15
|
+
### 3. Quality Settings
|
|
16
|
+
- `85`: Good default balance
|
|
17
|
+
- `90-95`: High-quality images (portfolios, product photos)
|
|
18
|
+
- `75-80`: Acceptable quality for faster loading
|
|
19
|
+
- WebP lossless: `quality=100`
|
|
20
|
+
|
|
21
|
+
### 4. Responsive Images
|
|
22
|
+
- Use `srcset` with multiple widths (400w, 800w, 1200w)
|
|
23
|
+
- Set appropriate
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#### Common Options
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
width=<PIXELS> # w=<PIXELS> (alias)
|
|
5
|
+
height=<PIXELS> # h=<PIXELS> (alias)
|
|
6
|
+
fit=scale-down # scale-down|contain|cover|crop|pad|squeeze
|
|
7
|
+
quality=85 # q=85 (1-100)
|
|
8
|
+
format=auto # f=auto (auto|webp|avif|jpeg|png)
|
|
9
|
+
dpr=2 # Device Pixel Ratio (1-3)
|
|
10
|
+
gravity=auto # auto|left|right|top|bottom|face|0.5x0.5
|
|
11
|
+
sharpen=2 # 0-10
|
|
12
|
+
blur=10 # 1-250
|
|
13
|
+
rotate=90 # 90|180|270
|
|
14
|
+
background=white # CSS color for pad fit mode
|
|
15
|
+
metadata=none # none|copyright|keep
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Transform via Workers
|
|
19
|
+
|
|
20
|
+
Use Cloudflare Workers for programmatic control:
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
export default {
|
|
24
|
+
async fetch(request: Request): Promise<Response> {
|
|
25
|
+
const url = new URL(request.url);
|
|
26
|
+
|
|
27
|
+
// Parse Accept header for format negotiation
|
|
28
|
+
const accept = request.headers.get('Accept') || '';
|
|
29
|
+
let format: 'avif' | 'webp' | undefined;
|
|
30
|
+
if (/image\/avif/.test(accept)) {
|
|
31
|
+
format = 'a
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Cloudflare Workers KV
|
|
2
|
+
|
|
3
|
+
Globally-distributed, eventually-consistent key-value store optimized for high read volume and low latency.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
KV provides:
|
|
8
|
+
- Eventual consistency (60s global propagation)
|
|
9
|
+
- Read-optimized performance
|
|
10
|
+
- 25 MiB value limit per key
|
|
11
|
+
- Auto-replication to Cloudflare edge
|
|
12
|
+
- Metadata support (1024 bytes)
|
|
13
|
+
|
|
14
|
+
**Use cases:** Config storage, user sessions, feature flags, caching, A/B testing
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
wrangler kv namespace create MY_NAMESPACE
|
|
20
|
+
# Add binding to wrangler.jsonc
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// Write
|
|
25
|
+
await env.MY_KV.put("key", "value", { expirationTtl: 300 });
|
|
26
|
+
|
|
27
|
+
// Read
|
|
28
|
+
const value = await env.MY_KV.get("key");
|
|
29
|
+
const json = await env.MY_KV.get<Config>("config", "json");
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Core Operations
|
|
33
|
+
|
|
34
|
+
| Method | Purpose | Returns |
|
|
35
|
+
|--------|---------|---------|
|
|
36
|
+
| `get(key, type?)` | Single read | `string \| null` |
|
|
37
|
+
| `get(keys, type?)` | Bulk read (≤100) | `Map<string, T \| null>` |
|
|
38
|
+
| `put(key, value, options?)` | Write | `Promise<void>` |
|
|
39
|
+
| `delete(key)` | Delete | `Promise<void>` |
|
|
40
|
+
| `list(options?)` | List keys | `{ keys, list_complete, cursor? }` |
|
|
41
|
+
| `getWithMetadata(key)` | Get + metadata | `{ value, metadata }` |
|
|
42
|
+
|
|
43
|
+
## Consistency Model
|
|
44
|
+
|
|
45
|
+
- **Write visibility:** Immediate in same location, ≤60s globally
|
|
46
|
+
- **Read path:** Eventually consistent
|
|
47
|
+
- **Write rate:** 1 write/second per key (429 on exceed)
|
|
48
|
+
|
|
49
|
+
## In This Reference
|
|
50
|
+
|
|
51
|
+
- [configuration.md](./configuration.md) - wrangler.jsonc setup, namespace creation, TypeScript types
|
|
52
|
+
- [api.md](./api.md) - KV methods, bulk operations, cacheTtl, content types
|
|
53
|
+
- [patterns.md](./patterns.md) - Caching, sessions, rate limiting, A/B testing
|
|
54
|
+
- [gotchas.md](./gotchas.md) - Eventual consistency, concurrent writes, value limits
|
|
55
|
+
|
|
56
|
+
## See Also
|
|
57
|
+
|
|
58
|
+
- [workers](../workers/) - Worker runtime for KV access
|
|
59
|
+
- [d1](../d1/) - Use D1 for strong consistency needs
|
|
60
|
+
- [durable-objects](../durable-objects/) - Strongly consistent alternative
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# KV API Reference
|
|
2
|
+
|
|
3
|
+
## Read Operations
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
// Single key (string)
|
|
7
|
+
const value = await env.MY_KV.get("user:123");
|
|
8
|
+
|
|
9
|
+
// JSON type (auto-parsed)
|
|
10
|
+
const config = await env.MY_KV.get<AppConfig>("config", "json");
|
|
11
|
+
|
|
12
|
+
// ArrayBuffer for binary
|
|
13
|
+
const buffer = await env.MY_KV.get("image", "arrayBuffer");
|
|
14
|
+
|
|
15
|
+
// Stream for large values
|
|
16
|
+
const stream = await env.MY_KV.get("large-file", "stream");
|
|
17
|
+
|
|
18
|
+
// With cache TTL (min 60s)
|
|
19
|
+
const value = await env.MY_KV.get("key", { type: "text", cacheTtl: 300 });
|
|
20
|
+
|
|
21
|
+
// Bulk get (max 100 keys, counts as 1 operation)
|
|
22
|
+
const values = await env.MY_KV.get(["user:1", "user:2", "user:3"]);
|
|
23
|
+
// Returns Map<string, string | null>
|
|
24
|
+
|
|
25
|
+
const configs = await env.MY_KV.get<Config>(["config:app", "config:feature"], "json");
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Write Operations
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// Basic put
|
|
32
|
+
await env.MY_KV.put("key", "value");
|
|
33
|
+
await env.MY_KV.put("config", JSON.stringify({ theme: "dark" }));
|
|
34
|
+
|
|
35
|
+
// With expiration (UNIX timestamp)
|
|
36
|
+
await env.MY_KV.put("session", token, {
|
|
37
|
+
expiration: Math.floor(Date.now() / 1000) + 3600
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// With TTL (seconds from now, min 60)
|
|
41
|
+
await env.MY_KV.put("cache", data, { expirationTtl: 300 });
|
|
42
|
+
|
|
43
|
+
// With metadata (max 1024 bytes)
|
|
44
|
+
await env.MY_KV.put("user:profile", userData, {
|
|
45
|
+
metadata: { version: 2, lastUpdated: Date.now() }
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Combined
|
|
49
|
+
await env.MY_KV.put("temp", value, {
|
|
50
|
+
expirationTtl: 3600,
|
|
51
|
+
metadata: { temporary: true }
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Get with Metadata
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// Single key
|
|
59
|
+
const result = await env.MY_KV.getWithMetadata("user:profile");
|
|
60
|
+
// { value: string | null, metadata: any | null }
|
|
61
|
+
|
|
62
|
+
if (result.value && result.metadata) {
|
|
63
|
+
const { version, lastUpdated } = result.metadata;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Multiple keys
|
|
67
|
+
const results = await env.MY_KV.getWithMetadata(["key1", "key2"]);
|
|
68
|
+
// Returns Map<string, { value, metadata }>
|
|
69
|
+
|
|
70
|
+
// With type
|
|
71
|
+
const result = await env.MY_KV.getWithMetadata<UserData>("user:123", "json");
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Delete Operations
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
await env.MY_KV.delete("key"); // Always succeeds (even if key missing)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## List Operations
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// List all
|
|
84
|
+
const keys = await env.MY_KV.list();
|
|
85
|
+
// { keys: [...], list_complete: boolean, cursor?: string }
|
|
86
|
+
|
|
87
|
+
// With prefix
|
|
88
|
+
const userKeys = await env.MY_KV.list({ prefix: "user:" });
|
|
89
|
+
|
|
90
|
+
// Pagination
|
|
91
|
+
let cursor: string | undefined;
|
|
92
|
+
let allKeys = [];
|
|
93
|
+
do {
|
|
94
|
+
const result = await env.MY_KV.list({ cursor, limit: 1000 });
|
|
95
|
+
allKeys.push(...result.keys);
|
|
96
|
+
cursor = result.cursor;
|
|
97
|
+
} while (!result.list_complete);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Limits
|
|
101
|
+
|
|
102
|
+
| Limit | Free | Paid |
|
|
103
|
+
|-------|------|------|
|
|
104
|
+
| Reads/day | 100,000 | Unlimited |
|
|
105
|
+
| Writes/day | 1,000 | Unlimited |
|
|
106
|
+
| Writes/second per key | 1 | 1 |
|
|
107
|
+
| Operations per Worker | 1,000 | 1,000 |
|
|
108
|
+
| Key size | 512 bytes | 512 bytes |
|
|
109
|
+
| Value size | 25 MiB | 25 MiB |
|
|
110
|
+
| Metadata size | 1024 bytes | 1024 bytes |
|
|
111
|
+
| Min cacheTtl | 60s | 60s |
|
|
112
|
+
| Bulk get max | 100 keys | 100 keys |
|
|
113
|
+
|
|
114
|
+
**Note:** Bulk requests count as 1 operation against 1,000 limit.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# KV Configuration
|
|
2
|
+
|
|
3
|
+
## Create Namespace
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
wrangler kv namespace create MY_NAMESPACE
|
|
7
|
+
# Output: { binding = "MY_NAMESPACE", id = "abc123..." }
|
|
8
|
+
|
|
9
|
+
wrangler kv namespace create MY_NAMESPACE --preview # For local dev
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Workers Binding
|
|
13
|
+
|
|
14
|
+
**wrangler.jsonc:**
|
|
15
|
+
```jsonc
|
|
16
|
+
{
|
|
17
|
+
"kv_namespaces": [
|
|
18
|
+
{
|
|
19
|
+
"binding": "MY_KV",
|
|
20
|
+
"id": "abc123xyz789"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**wrangler.toml:**
|
|
27
|
+
```toml
|
|
28
|
+
[[kv_namespaces]]
|
|
29
|
+
binding = "MY_KV"
|
|
30
|
+
id = "abc123xyz789"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## TypeScript Types
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
interface Env { MY_KV: KVNamespace; }
|
|
37
|
+
|
|
38
|
+
export default {
|
|
39
|
+
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
40
|
+
const value = await env.MY_KV.get("key");
|
|
41
|
+
return new Response(value || "Not found");
|
|
42
|
+
}
|
|
43
|
+
} satisfies ExportedHandler<Env>;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## CLI Operations
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Put
|
|
50
|
+
wrangler kv key put --binding=MY_KV "key" "value"
|
|
51
|
+
wrangler kv key put --binding=MY_KV "key" --path=./file.json --ttl=3600
|
|
52
|
+
|
|
53
|
+
# Get
|
|
54
|
+
wrangler kv key get --binding=MY_KV "key"
|
|
55
|
+
|
|
56
|
+
# Delete
|
|
57
|
+
wrangler kv key delete --binding=MY_KV "key"
|
|
58
|
+
|
|
59
|
+
# List
|
|
60
|
+
wrangler kv key list --binding=MY_KV --prefix="user:"
|
|
61
|
+
|
|
62
|
+
# Bulk operations (max 10,000 keys per file)
|
|
63
|
+
wrangler kv bulk put data.json --binding=MY_KV
|
|
64
|
+
wrangler kv bulk get keys.json --binding=MY_KV
|
|
65
|
+
wrangler kv bulk delete keys.json --binding=MY_KV --force
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Local Development
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
wrangler dev # Local KV (isolated)
|
|
72
|
+
wrangler dev --remote # Remote KV (production)
|
|
73
|
+
|
|
74
|
+
# Or in wrangler.jsonc:
|
|
75
|
+
# "kv_namespaces": [{ "binding": "MY_KV", "id": "...", "remote": true }]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## REST API
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import Cloudflare from 'cloudflare';
|
|
82
|
+
|
|
83
|
+
const client = new Cloudflare({
|
|
84
|
+
apiEmail: process.env.CLOUDFLARE_EMAIL,
|
|
85
|
+
apiKey: process.env.CLOUDFLARE_API_KEY
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
await client.kv.namespaces.values.update(namespaceId, 'key', {
|
|
89
|
+
account_id: accountId,
|
|
90
|
+
value: 'value'
|
|
91
|
+
});
|
|
92
|
+
```
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# KV Gotchas & Troubleshooting
|
|
2
|
+
|
|
3
|
+
## Eventual Consistency
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
// ❌ BAD: Read immediately after write (may see stale globally)
|
|
7
|
+
await env.MY_KV.put("key", "value");
|
|
8
|
+
const value = await env.MY_KV.get("key"); // May be null in other regions
|
|
9
|
+
|
|
10
|
+
// ✅ GOOD: Return confirmation without reading
|
|
11
|
+
await env.MY_KV.put("key", "value");
|
|
12
|
+
return new Response("Updated", { status: 200 });
|
|
13
|
+
|
|
14
|
+
// ✅ GOOD: Use local value
|
|
15
|
+
const newValue = "updated";
|
|
16
|
+
await env.MY_KV.put("key", newValue);
|
|
17
|
+
return new Response(newValue);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Propagation:** Writes visible immediately in same location, ≤60s globally.
|
|
21
|
+
|
|
22
|
+
## Concurrent Writes
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// ❌ BAD: Concurrent writes to same key (429 rate limit)
|
|
26
|
+
await Promise.all([
|
|
27
|
+
env.MY_KV.put("counter", "1"),
|
|
28
|
+
env.MY_KV.put("counter", "2")
|
|
29
|
+
]); // 429 error
|
|
30
|
+
|
|
31
|
+
// ✅ GOOD: Sequential writes
|
|
32
|
+
await env.MY_KV.put("counter", "3");
|
|
33
|
+
|
|
34
|
+
// ✅ GOOD: Unique keys for concurrent writes
|
|
35
|
+
await Promise.all([
|
|
36
|
+
env.MY_KV.put("counter:1", "1"),
|
|
37
|
+
env.MY_KV.put("counter:2", "2")
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
// ✅ GOOD: Retry with backoff
|
|
41
|
+
async function putWithRetry(kv: KVNamespace, key: string, value: string) {
|
|
42
|
+
let delay = 1000;
|
|
43
|
+
for (let i = 0; i < 5; i++) {
|
|
44
|
+
try {
|
|
45
|
+
await kv.put(key, value);
|
|
46
|
+
return;
|
|
47
|
+
} catch (err) {
|
|
48
|
+
if (err.message.includes("429") && i < 4) {
|
|
49
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
50
|
+
delay *= 2;
|
|
51
|
+
} else throw err;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Limit:** 1 write/second per key (all plans).
|
|
58
|
+
|
|
59
|
+
## Bulk Operations
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// ❌ BAD: Multiple individual gets (uses 3 operations)
|
|
63
|
+
const user1 = await env.USERS.get("user:1");
|
|
64
|
+
const user2 = await env.USERS.get("user:2");
|
|
65
|
+
const user3 = await env.USERS.get("user:3");
|
|
66
|
+
|
|
67
|
+
// ✅ GOOD: Single bulk get (uses 1 operation)
|
|
68
|
+
const users = await env.USERS.get(["user:1", "user:2", "user:3"]);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Note:** Bulk write NOT available in Workers (only via CLI/API).
|
|
72
|
+
|
|
73
|
+
## Null Handling
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// ❌ BAD: No null check
|
|
77
|
+
const value = await env.MY_KV.get("key");
|
|
78
|
+
const result = value.toUpperCase(); // Error if null
|
|
79
|
+
|
|
80
|
+
// ✅ GOOD: Check for null
|
|
81
|
+
const value = await env.MY_KV.get("key");
|
|
82
|
+
if (value === null) return new Response("Not found", { status: 404 });
|
|
83
|
+
return new Response(value);
|
|
84
|
+
|
|
85
|
+
// ✅ GOOD: Provide default
|
|
86
|
+
const value = (await env.MY_KV.get("config")) ?? "default-config";
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Value Limits
|
|
90
|
+
|
|
91
|
+
- Key size: 512 bytes max
|
|
92
|
+
- Value size: 25 MiB max
|
|
93
|
+
- Metadata: 1024 bytes max
|
|
94
|
+
- cacheTtl: 60s minimum
|
|
95
|
+
|
|
96
|
+
## Pricing
|
|
97
|
+
|
|
98
|
+
- **Reads:** $0.50 per 10M
|
|
99
|
+
- **Writes:** $5.00 per 1M
|
|
100
|
+
- **Deletes:** $5.00 per 1M
|
|
101
|
+
- **Storage:** $0.50 per GB-month
|
|
102
|
+
|
|
103
|
+
## When NOT to Use
|
|
104
|
+
|
|
105
|
+
- ❌ Strong consistency required → Durable Objects
|
|
106
|
+
- ❌ Write-heavy workloads → D1 or Durable Objects
|
|
107
|
+
- ❌ Relational queries → D1
|
|
108
|
+
- ❌ Large files (>25 MiB) → R2
|
|
109
|
+
- ❌ Atomic operations → Durable Objects
|
|
110
|
+
|
|
111
|
+
## When TO Use
|
|
112
|
+
|
|
113
|
+
- ✅ Read-heavy workloads
|
|
114
|
+
- ✅ Global distribution needed
|
|
115
|
+
- ✅ Eventually consistent acceptable
|
|
116
|
+
- ✅ Key-value access patterns
|
|
117
|
+
- ✅ Low-latency reads critical
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# KV Patterns & Best Practices
|
|
2
|
+
|
|
3
|
+
## API Response Caching
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
async function getCachedData(env: Env, key: string, fetcher: () => Promise<any>): Promise<any> {
|
|
7
|
+
const cached = await env.MY_KV.get(key, "json");
|
|
8
|
+
if (cached) return cached;
|
|
9
|
+
|
|
10
|
+
const data = await fetcher();
|
|
11
|
+
await env.MY_KV.put(key, JSON.stringify(data), { expirationTtl: 300 });
|
|
12
|
+
return data;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const apiData = await getCachedData(
|
|
16
|
+
env,
|
|
17
|
+
"cache:users",
|
|
18
|
+
() => fetch("https://api.example.com/users").then(r => r.json())
|
|
19
|
+
);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Session Management
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
interface Session { userId: string; expiresAt: number; }
|
|
26
|
+
|
|
27
|
+
async function createSession(env: Env, userId: string): Promise<string> {
|
|
28
|
+
const sessionId = crypto.randomUUID();
|
|
29
|
+
const expiresAt = Date.now() + (24 * 60 * 60 * 1000);
|
|
30
|
+
|
|
31
|
+
await env.SESSIONS.put(
|
|
32
|
+
`session:${sessionId}`,
|
|
33
|
+
JSON.stringify({ userId, expiresAt }),
|
|
34
|
+
{ expirationTtl: 86400, metadata: { createdAt: Date.now() } }
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return sessionId;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function getSession(env: Env, sessionId: string): Promise<Session | null> {
|
|
41
|
+
const data = await env.SESSIONS.get<Session>(`session:${sessionId}`, "json");
|
|
42
|
+
if (!data || data.expiresAt < Date.now()) return null;
|
|
43
|
+
return data;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Feature Flags
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
async function getFeatureFlags(env: Env): Promise<Record<string, boolean>> {
|
|
51
|
+
return await env.CONFIG.get<Record<string, boolean>>(
|
|
52
|
+
"features:flags",
|
|
53
|
+
{ type: "json", cacheTtl: 600 }
|
|
54
|
+
) || {};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default {
|
|
58
|
+
async fetch(request, env): Promise<Response> {
|
|
59
|
+
const flags = await getFeatureFlags(env);
|
|
60
|
+
if (flags.beta_feature) return handleBetaFeature(request);
|
|
61
|
+
return handleStandardFlow(request);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Rate Limiting
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
async function rateLimit(env: Env, identifier: string, limit: number, windowSeconds: number): Promise<boolean> {
|
|
70
|
+
const key = `ratelimit:${identifier}`;
|
|
71
|
+
const now = Date.now();
|
|
72
|
+
const data = await env.MY_KV.get<{ count: number, resetAt: number }>(key, "json");
|
|
73
|
+
|
|
74
|
+
if (!data || data.resetAt < now) {
|
|
75
|
+
await env.MY_KV.put(key, JSON.stringify({ count: 1, resetAt: now + windowSeconds * 1000 }), { expirationTtl: windowSeconds });
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (data.count >= limit) return false;
|
|
80
|
+
|
|
81
|
+
await env.MY_KV.put(key, JSON.stringify({ count: data.count + 1, resetAt: data.resetAt }), { expirationTtl: Math.ceil((data.resetAt - now) / 1000) });
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## A/B Testing
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
async function getVariant(env: Env, userId: string, testName: string): Promise<string> {
|
|
90
|
+
const assigned = await env.AB_TESTS.get(`test:${testName}:user:${userId}`);
|
|
91
|
+
if (assigned) return assigned;
|
|
92
|
+
|
|
93
|
+
const test = await env.AB_TESTS.get<{ variants: string[], weights: number[] }>(`test:${testName}:config`, { type: "json", cacheTtl: 3600 });
|
|
94
|
+
if (!test) return "control";
|
|
95
|
+
|
|
96
|
+
const hash = await hashString(userId);
|
|
97
|
+
const random = (hash % 100) / 100;
|
|
98
|
+
let cumulative = 0, variant = test.variants[0];
|
|
99
|
+
|
|
100
|
+
for (let i = 0; i < test.variants.length; i++) {
|
|
101
|
+
cumulative += test.weights[i];
|
|
102
|
+
if (random < cumulative) { variant = test.variants[i]; break; }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
await env.AB_TESTS.put(`test:${testName}:user:${userId}`, variant, { expirationTtl: 2592000 });
|
|
106
|
+
return variant;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Coalesce Cold Keys
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// ❌ BAD: Many individual keys
|
|
114
|
+
await env.KV.put("user:123:name", "John");
|
|
115
|
+
await env.KV.put("user:123:email", "john@example.com");
|
|
116
|
+
|
|
117
|
+
// ✅ GOOD: Single coalesced object
|
|
118
|
+
await env.USERS.put("user:123:profile", JSON.stringify({
|
|
119
|
+
name: "John",
|
|
120
|
+
email: "john@example.com",
|
|
121
|
+
role: "admin"
|
|
122
|
+
}));
|
|
123
|
+
|
|
124
|
+
// Benefits: Hot key cache, single read, reduced operations
|
|
125
|
+
// Trade-off: Harder to update individual fields
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Hierarchical Keys
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// Use prefixes for organization
|
|
132
|
+
"user:123:profile"
|
|
133
|
+
"user:123:settings"
|
|
134
|
+
"cache:api:users"
|
|
135
|
+
"session:abc-def"
|
|
136
|
+
"feature:flags:beta"
|
|
137
|
+
|
|
138
|
+
const userKeys = await env.MY_KV.list({ prefix: "user:123:" });
|
|
139
|
+
```
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Miniflare
|
|
2
|
+
|
|
3
|
+
Local simulator for Cloudflare Workers development/testing. Runs Workers in workerd sandbox implementing runtime APIs - no internet required.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Full-featured: KV, Durable Objects, R2, D1, WebSockets, Queues
|
|
8
|
+
- Fully-local: test without internet, instant reload
|
|
9
|
+
- TypeScript-native: detailed logging, source maps
|
|
10
|
+
- Advanced testing: dispatch events without HTTP, simulate Worker connections
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
- Integration tests for Workers
|
|
15
|
+
- Advanced use cases requiring fine-grained control
|
|
16
|
+
- Testing bindings/storage locally
|
|
17
|
+
- Multiple Workers with service bindings
|
|
18
|
+
|
|
19
|
+
**Note:** Most users should use Wrangler. Miniflare for advanced testing.
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm i -D miniflare
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Requires ES modules in `package.json`:
|
|
28
|
+
```json
|
|
29
|
+
{"type": "module"}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
import { Miniflare } from "miniflare";
|
|
36
|
+
|
|
37
|
+
const mf = new Miniflare({
|
|
38
|
+
modules: true,
|
|
39
|
+
script: `
|
|
40
|
+
export default {
|
|
41
|
+
async fetch(request, env, ctx) {
|
|
42
|
+
return new Response("Hello Miniflare!");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
`,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const res = await mf.dispatchFetch("http://localhost:8787/");
|
|
49
|
+
console.log(await res.text()); // Hello Miniflare!
|
|
50
|
+
await mf.dispose();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## See Also
|
|
54
|
+
|
|
55
|
+
- [configuration.md](./configuration.md) - Config options, bindings, wrangler.toml
|
|
56
|
+
- [api.md](./api.md) - Programmatic API, methods, event dispatching
|
|
57
|
+
- [patterns.md](./patterns.md) - Testing patterns, CI, mocking
|
|
58
|
+
- [gotchas.md](./gotchas.md) - Compatibility issues, limits, debugging
|
|
59
|
+
|
|
60
|
+
## Resources
|
|
61
|
+
|
|
62
|
+
- [Miniflare Docs](https://developers.cloudflare.com/workers/testing/miniflare/)
|
|
63
|
+
- [Miniflare GitHub](https://github.com/cloudflare/workers-sdk/tree/main/packages/miniflare)
|
|
64
|
+
- [Vitest Integration](https://developers.cloudflare.com/workers/testing/vitest-integration/) (recommended)
|