opencodekit 0.15.4 → 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/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,699 @@
|
|
|
1
|
+
# Cloudflare TURN Service
|
|
2
|
+
|
|
3
|
+
Expert guidance for implementing Cloudflare TURN Service in WebRTC applications.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Cloudflare TURN (Traversal Using Relays around NAT) Service is a managed relay service for WebRTC applications. TURN acts as a relay point for traffic between WebRTC clients and SFUs, particularly when direct peer-to-peer communication is obstructed by NATs or firewalls. The service runs on Cloudflare's global anycast network across 310+ cities.
|
|
8
|
+
|
|
9
|
+
## Key Characteristics
|
|
10
|
+
|
|
11
|
+
- **Anycast Architecture**: Automatically connects clients to the closest Cloudflare location
|
|
12
|
+
- **Global Network**: Available across Cloudflare's entire network (excluding China Network)
|
|
13
|
+
- **Zero Configuration**: No need to manually select regions or servers
|
|
14
|
+
- **Protocol Support**: STUN/TURN over UDP, TCP, and TLS
|
|
15
|
+
- **Free Tier**: Free when used with Cloudflare Calls SFU, otherwise $0.05/GB outbound
|
|
16
|
+
|
|
17
|
+
## Service Addresses and Ports
|
|
18
|
+
|
|
19
|
+
### STUN over UDP
|
|
20
|
+
- **Primary**: `stun.cloudflare.com:3478/udp`
|
|
21
|
+
- **Alternate**: `stun.cloudflare.com:53/udp` (not recommended as primary, blocked by many ISPs/browsers)
|
|
22
|
+
|
|
23
|
+
### TURN over UDP
|
|
24
|
+
- **Primary**: `turn.cloudflare.com:3478/udp`
|
|
25
|
+
- **Alternate**: `turn.cloudflare.com:53/udp`
|
|
26
|
+
|
|
27
|
+
### TURN over TCP
|
|
28
|
+
- **Primary**: `turn.cloudflare.com:3478/tcp`
|
|
29
|
+
- **Alternate**: `turn.cloudflare.com:80/tcp`
|
|
30
|
+
|
|
31
|
+
### TURN over TLS
|
|
32
|
+
- **Primary**: `turn.cloudflare.com:5349/tcp`
|
|
33
|
+
- **Alternate**: `turn.cloudflare.com:443/tcp`
|
|
34
|
+
|
|
35
|
+
## API Endpoints
|
|
36
|
+
|
|
37
|
+
All API endpoints require authentication with a Cloudflare API token with "Calls Write" permission.
|
|
38
|
+
|
|
39
|
+
Base URL: `https://api.cloudflare.com/client/v4`
|
|
40
|
+
|
|
41
|
+
### List TURN Keys
|
|
42
|
+
```
|
|
43
|
+
GET /accounts/{account_id}/calls/turn_keys
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Get TURN Key Details
|
|
47
|
+
```
|
|
48
|
+
GET /accounts/{account_id}/calls/turn_keys/{key_id}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Create TURN Key
|
|
52
|
+
```
|
|
53
|
+
POST /accounts/{account_id}/calls/turn_keys
|
|
54
|
+
Content-Type: application/json
|
|
55
|
+
|
|
56
|
+
{
|
|
57
|
+
"name": "my-turn-key"
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Response includes**:
|
|
62
|
+
- `uid`: Key identifier
|
|
63
|
+
- `key`: The actual secret key (only returned on creation)
|
|
64
|
+
- `name`: Human-readable name
|
|
65
|
+
- `created`: ISO 8601 timestamp
|
|
66
|
+
- `modified`: ISO 8601 timestamp
|
|
67
|
+
|
|
68
|
+
### Update TURN Key
|
|
69
|
+
```
|
|
70
|
+
PUT /accounts/{account_id}/calls/turn_keys/{key_id}
|
|
71
|
+
Content-Type: application/json
|
|
72
|
+
|
|
73
|
+
{
|
|
74
|
+
"name": "updated-name"
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Delete TURN Key
|
|
79
|
+
```
|
|
80
|
+
DELETE /accounts/{account_id}/calls/turn_keys/{key_id}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Generate Temporary Credentials
|
|
84
|
+
|
|
85
|
+
To use TURN, clients need temporary credentials. Generate them via:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
POST https://rtc.live.cloudflare.com/v1/turn/keys/{key_id}/credentials/generate
|
|
89
|
+
Authorization: Bearer {key_secret}
|
|
90
|
+
Content-Type: application/json
|
|
91
|
+
|
|
92
|
+
{
|
|
93
|
+
"ttl": 86400 // optional, defaults to reasonable value
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Response**:
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"iceServers": {
|
|
101
|
+
"urls": [
|
|
102
|
+
"stun:stun.cloudflare.com:3478",
|
|
103
|
+
"turn:turn.cloudflare.com:3478?transport=udp",
|
|
104
|
+
"turn:turn.cloudflare.com:3478?transport=tcp",
|
|
105
|
+
"turns:turn.cloudflare.com:5349?transport=tcp"
|
|
106
|
+
],
|
|
107
|
+
"username": "generated-username",
|
|
108
|
+
"credential": "generated-credential"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Implementation Patterns
|
|
114
|
+
|
|
115
|
+
### Basic TURN Configuration (Browser)
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
interface RTCIceServer {
|
|
119
|
+
urls: string | string[];
|
|
120
|
+
username?: string;
|
|
121
|
+
credential?: string;
|
|
122
|
+
credentialType?: "password" | "oauth";
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function getTURNConfig(): Promise<RTCIceServer[]> {
|
|
126
|
+
const response = await fetch('/api/turn-credentials');
|
|
127
|
+
const data = await response.json();
|
|
128
|
+
|
|
129
|
+
return [
|
|
130
|
+
{
|
|
131
|
+
urls: 'stun:stun.cloudflare.com:3478'
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
urls: [
|
|
135
|
+
'turn:turn.cloudflare.com:3478?transport=udp',
|
|
136
|
+
'turn:turn.cloudflare.com:3478?transport=tcp',
|
|
137
|
+
'turns:turn.cloudflare.com:5349?transport=tcp'
|
|
138
|
+
],
|
|
139
|
+
username: data.username,
|
|
140
|
+
credential: data.credential,
|
|
141
|
+
credentialType: 'password'
|
|
142
|
+
}
|
|
143
|
+
];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Use in RTCPeerConnection
|
|
147
|
+
const iceServers = await getTURNConfig();
|
|
148
|
+
const peerConnection = new RTCPeerConnection({ iceServers });
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Credential Generation (Backend - Node.js/TypeScript)
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
async function generateTURNCredentials(
|
|
155
|
+
turnKeyId: string,
|
|
156
|
+
turnKeySecret: string,
|
|
157
|
+
ttl: number = 86400
|
|
158
|
+
): Promise<{ username: string; credential: string; urls: string[] }> {
|
|
159
|
+
const response = await fetch(
|
|
160
|
+
`https://rtc.live.cloudflare.com/v1/turn/keys/${turnKeyId}/credentials/generate`,
|
|
161
|
+
{
|
|
162
|
+
method: 'POST',
|
|
163
|
+
headers: {
|
|
164
|
+
'Authorization': `Bearer ${turnKeySecret}`,
|
|
165
|
+
'Content-Type': 'application/json'
|
|
166
|
+
},
|
|
167
|
+
body: JSON.stringify({ ttl })
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
if (!response.ok) {
|
|
172
|
+
throw new Error(`Failed to generate TURN credentials: ${response.statusText}`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const data = await response.json();
|
|
176
|
+
return {
|
|
177
|
+
username: data.iceServers.username,
|
|
178
|
+
credential: data.iceServers.credential,
|
|
179
|
+
urls: data.iceServers.urls
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Cloudflare Worker Integration
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
export default {
|
|
188
|
+
async fetch(request: Request, env: Env): Promise<Response> {
|
|
189
|
+
const url = new URL(request.url);
|
|
190
|
+
|
|
191
|
+
if (url.pathname !== '/turn-credentials') {
|
|
192
|
+
return new Response('Not found', { status: 404 });
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Validate client (implement your auth logic)
|
|
196
|
+
const authHeader = request.headers.get('Authorization');
|
|
197
|
+
if (!authHeader) {
|
|
198
|
+
return new Response('Unauthorized', { status: 401 });
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Generate credentials
|
|
202
|
+
const response = await fetch(
|
|
203
|
+
`https://rtc.live.cloudflare.com/v1/turn/keys/${env.TURN_KEY_ID}/credentials/generate`,
|
|
204
|
+
{
|
|
205
|
+
method: 'POST',
|
|
206
|
+
headers: {
|
|
207
|
+
'Authorization': `Bearer ${env.TURN_KEY_SECRET}`,
|
|
208
|
+
'Content-Type': 'application/json'
|
|
209
|
+
},
|
|
210
|
+
body: JSON.stringify({ ttl: 3600 })
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
if (!response.ok) {
|
|
215
|
+
return new Response('Failed to generate credentials', { status: 500 });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const data = await response.json();
|
|
219
|
+
|
|
220
|
+
return new Response(JSON.stringify({
|
|
221
|
+
iceServers: [
|
|
222
|
+
{
|
|
223
|
+
urls: 'stun:stun.cloudflare.com:3478'
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
urls: data.iceServers.urls,
|
|
227
|
+
username: data.iceServers.username,
|
|
228
|
+
credential: data.iceServers.credential
|
|
229
|
+
}
|
|
230
|
+
]
|
|
231
|
+
}), {
|
|
232
|
+
headers: { 'Content-Type': 'application/json' }
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Credentials Caching Pattern
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
class TURNCredentialsManager {
|
|
242
|
+
private credentials: {
|
|
243
|
+
username: string;
|
|
244
|
+
credential: string;
|
|
245
|
+
urls: string[];
|
|
246
|
+
expiresAt: number;
|
|
247
|
+
} | null = null;
|
|
248
|
+
|
|
249
|
+
async getCredentials(
|
|
250
|
+
turnKeyId: string,
|
|
251
|
+
turnKeySecret: string
|
|
252
|
+
): Promise<RTCIceServer[]> {
|
|
253
|
+
const now = Date.now();
|
|
254
|
+
|
|
255
|
+
// Return cached credentials if still valid
|
|
256
|
+
if (this.credentials && this.credentials.expiresAt > now) {
|
|
257
|
+
return this.buildIceServers(this.credentials);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Generate new credentials
|
|
261
|
+
const ttl = 3600; // 1 hour
|
|
262
|
+
const data = await this.generateCredentials(turnKeyId, turnKeySecret, ttl);
|
|
263
|
+
|
|
264
|
+
this.credentials = {
|
|
265
|
+
username: data.username,
|
|
266
|
+
credential: data.credential,
|
|
267
|
+
urls: data.urls,
|
|
268
|
+
expiresAt: now + (ttl * 1000) - 60000 // Refresh 1 min early
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
return this.buildIceServers(this.credentials);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
private async generateCredentials(
|
|
275
|
+
turnKeyId: string,
|
|
276
|
+
turnKeySecret: string,
|
|
277
|
+
ttl: number
|
|
278
|
+
) {
|
|
279
|
+
const response = await fetch(
|
|
280
|
+
`https://rtc.live.cloudflare.com/v1/turn/keys/${turnKeyId}/credentials/generate`,
|
|
281
|
+
{
|
|
282
|
+
method: 'POST',
|
|
283
|
+
headers: {
|
|
284
|
+
'Authorization': `Bearer ${turnKeySecret}`,
|
|
285
|
+
'Content-Type': 'application/json'
|
|
286
|
+
},
|
|
287
|
+
body: JSON.stringify({ ttl })
|
|
288
|
+
}
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
const data = await response.json();
|
|
292
|
+
return {
|
|
293
|
+
username: data.iceServers.username,
|
|
294
|
+
credential: data.iceServers.credential,
|
|
295
|
+
urls: data.iceServers.urls
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
private buildIceServers(creds: {
|
|
300
|
+
username: string;
|
|
301
|
+
credential: string;
|
|
302
|
+
urls: string[];
|
|
303
|
+
}): RTCIceServer[] {
|
|
304
|
+
return [
|
|
305
|
+
{ urls: 'stun:stun.cloudflare.com:3478' },
|
|
306
|
+
{
|
|
307
|
+
urls: creds.urls,
|
|
308
|
+
username: creds.username,
|
|
309
|
+
credential: creds.credential,
|
|
310
|
+
credentialType: 'password' as const
|
|
311
|
+
}
|
|
312
|
+
];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Type-Safe Configuration
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
interface CloudflareTURNConfig {
|
|
321
|
+
keyId: string;
|
|
322
|
+
keySecret: string;
|
|
323
|
+
ttl?: number;
|
|
324
|
+
protocols?: ('udp' | 'tcp' | 'tls')[];
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
interface TURNCredentials {
|
|
328
|
+
username: string;
|
|
329
|
+
credential: string;
|
|
330
|
+
urls: string[];
|
|
331
|
+
expiresAt: Date;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function validateRTCIceServer(obj: unknown): obj is RTCIceServer {
|
|
335
|
+
if (!obj || typeof obj !== 'object') {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const server = obj as Record<string, unknown>;
|
|
340
|
+
|
|
341
|
+
if (typeof server.urls !== 'string' && !Array.isArray(server.urls)) {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (server.username && typeof server.username !== 'string') {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (server.credential && typeof server.credential !== 'string') {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async function fetchTURNServers(
|
|
357
|
+
config: CloudflareTURNConfig
|
|
358
|
+
): Promise<RTCIceServer[]> {
|
|
359
|
+
const response = await fetch(
|
|
360
|
+
`https://rtc.live.cloudflare.com/v1/turn/keys/${config.keyId}/credentials/generate`,
|
|
361
|
+
{
|
|
362
|
+
method: 'POST',
|
|
363
|
+
headers: {
|
|
364
|
+
'Authorization': `Bearer ${config.keySecret}`,
|
|
365
|
+
'Content-Type': 'application/json'
|
|
366
|
+
},
|
|
367
|
+
body: JSON.stringify({ ttl: config.ttl ?? 3600 })
|
|
368
|
+
}
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
if (!response.ok) {
|
|
372
|
+
throw new Error(`TURN credential generation failed: ${response.status}`);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const data = await response.json();
|
|
376
|
+
const iceServers = [
|
|
377
|
+
{ urls: 'stun:stun.cloudflare.com:3478' },
|
|
378
|
+
{
|
|
379
|
+
urls: data.iceServers.urls,
|
|
380
|
+
username: data.iceServers.username,
|
|
381
|
+
credential: data.iceServers.credential,
|
|
382
|
+
credentialType: 'password' as const
|
|
383
|
+
}
|
|
384
|
+
];
|
|
385
|
+
|
|
386
|
+
// Validate before returning
|
|
387
|
+
if (!iceServers.every(validateRTCIceServer)) {
|
|
388
|
+
throw new Error('Invalid ICE server configuration received');
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return iceServers;
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## Common Use Cases
|
|
396
|
+
|
|
397
|
+
### 1. Video Conferencing
|
|
398
|
+
Use TURN as fallback when direct peer-to-peer fails due to restrictive NATs/firewalls.
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
const config: RTCConfiguration = {
|
|
402
|
+
iceServers: await getTURNConfig(),
|
|
403
|
+
iceTransportPolicy: 'all' // Try direct connection first
|
|
404
|
+
};
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### 2. Screen Sharing Applications
|
|
408
|
+
Ensure connectivity for high-bandwidth screen sharing streams.
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
const iceServers = await getTURNConfig();
|
|
412
|
+
const pc = new RTCPeerConnection({
|
|
413
|
+
iceServers,
|
|
414
|
+
bundlePolicy: 'max-bundle' // Reduce overhead
|
|
415
|
+
});
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### 3. IoT Device Communication
|
|
419
|
+
Enable WebRTC for devices behind restrictive NATs.
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
// Prefer relay for predictable connectivity
|
|
423
|
+
const config: RTCConfiguration = {
|
|
424
|
+
iceServers: await getTURNConfig(),
|
|
425
|
+
iceTransportPolicy: 'relay' // Force TURN usage
|
|
426
|
+
};
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### 4. Live Streaming (WHIP/WHEP)
|
|
430
|
+
Integrate with Cloudflare Stream for low-latency broadcasting.
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
const turnServers = await getTURNConfig();
|
|
434
|
+
// Use in WHIP/WHEP workflow with Cloudflare Stream
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## Limits and Quotas
|
|
438
|
+
|
|
439
|
+
Per TURN allocation (per user):
|
|
440
|
+
- **IP addresses**: >5 new unique IPs per second
|
|
441
|
+
- **Packet rate**: 5-10k packets per second (inbound/outbound)
|
|
442
|
+
- **Data rate**: 50-100 Mbps (inbound/outbound)
|
|
443
|
+
- **MTU**: No specific limit
|
|
444
|
+
- **Burst rates**: Higher than documented limits
|
|
445
|
+
|
|
446
|
+
Limits apply per allocation, not account-wide. Exceeding limits results in packet drops.
|
|
447
|
+
|
|
448
|
+
## TLS Configuration
|
|
449
|
+
|
|
450
|
+
### Supported TLS Versions
|
|
451
|
+
- TLS 1.1
|
|
452
|
+
- TLS 1.2
|
|
453
|
+
- TLS 1.3
|
|
454
|
+
|
|
455
|
+
### Recommended Ciphers (TLS 1.3)
|
|
456
|
+
- AEAD-AES128-GCM-SHA256
|
|
457
|
+
- AEAD-AES256-GCM-SHA384
|
|
458
|
+
- AEAD-CHACHA20-POLY1305-SHA256
|
|
459
|
+
|
|
460
|
+
### Recommended Ciphers (TLS 1.2)
|
|
461
|
+
- ECDHE-ECDSA-AES128-GCM-SHA256
|
|
462
|
+
- ECDHE-RSA-AES128-GCM-SHA256
|
|
463
|
+
- ECDHE-RSA-AES128-SHA (also TLS 1.1)
|
|
464
|
+
- AES128-GCM-SHA256
|
|
465
|
+
|
|
466
|
+
## Environment Variables Pattern
|
|
467
|
+
|
|
468
|
+
```bash
|
|
469
|
+
# .env
|
|
470
|
+
CLOUDFLARE_ACCOUNT_ID=your_account_id
|
|
471
|
+
CLOUDFLARE_API_TOKEN=your_api_token
|
|
472
|
+
TURN_KEY_ID=your_turn_key_id
|
|
473
|
+
TURN_KEY_SECRET=your_turn_key_secret
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
// config.ts
|
|
478
|
+
import { z } from 'zod';
|
|
479
|
+
|
|
480
|
+
const envSchema = z.object({
|
|
481
|
+
CLOUDFLARE_ACCOUNT_ID: z.string().min(1),
|
|
482
|
+
CLOUDFLARE_API_TOKEN: z.string().min(1),
|
|
483
|
+
TURN_KEY_ID: z.string().min(1),
|
|
484
|
+
TURN_KEY_SECRET: z.string().min(1)
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
export const config = envSchema.parse(process.env);
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## Wrangler Configuration
|
|
491
|
+
|
|
492
|
+
```toml
|
|
493
|
+
# wrangler.toml
|
|
494
|
+
name = "turn-credentials-api"
|
|
495
|
+
main = "src/index.ts"
|
|
496
|
+
compatibility_date = "2024-01-01"
|
|
497
|
+
|
|
498
|
+
[vars]
|
|
499
|
+
TURN_KEY_ID = "your-turn-key-id"
|
|
500
|
+
|
|
501
|
+
[[env.production.kv_namespaces]]
|
|
502
|
+
binding = "CREDENTIALS_CACHE"
|
|
503
|
+
id = "your-kv-namespace-id"
|
|
504
|
+
|
|
505
|
+
[env.production]
|
|
506
|
+
vars = { ENVIRONMENT = "production" }
|
|
507
|
+
|
|
508
|
+
# Store TURN_KEY_SECRET in secrets
|
|
509
|
+
# wrangler secret put TURN_KEY_SECRET
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
## Security Best Practices
|
|
513
|
+
|
|
514
|
+
1. **Never expose TURN key secrets client-side**
|
|
515
|
+
- Always generate credentials server-side
|
|
516
|
+
- Use a backend API endpoint
|
|
517
|
+
|
|
518
|
+
2. **Implement rate limiting**
|
|
519
|
+
```typescript
|
|
520
|
+
// Limit credential generation per client
|
|
521
|
+
const rateLimiter = new Map<string, number>();
|
|
522
|
+
|
|
523
|
+
function checkRateLimit(clientId: string): boolean {
|
|
524
|
+
const lastRequest = rateLimiter.get(clientId) ?? 0;
|
|
525
|
+
const now = Date.now();
|
|
526
|
+
|
|
527
|
+
if (now - lastRequest < 5000) { // 5 second cooldown
|
|
528
|
+
return false;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
rateLimiter.set(clientId, now);
|
|
532
|
+
return true;
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
3. **Set appropriate TTLs**
|
|
537
|
+
- Short-lived sessions: 1800-3600 seconds (30 min - 1 hour)
|
|
538
|
+
- Long-lived sessions: 86400 seconds (24 hours max recommended)
|
|
539
|
+
|
|
540
|
+
4. **Validate client authentication**
|
|
541
|
+
```typescript
|
|
542
|
+
async function validateClient(request: Request): Promise<boolean> {
|
|
543
|
+
const token = request.headers.get('Authorization')?.split(' ')[1];
|
|
544
|
+
if (!token) return false;
|
|
545
|
+
|
|
546
|
+
// Implement JWT validation or session check
|
|
547
|
+
return validateToken(token);
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
5. **Monitor usage**
|
|
552
|
+
- Track credential generation requests
|
|
553
|
+
- Alert on unusual patterns
|
|
554
|
+
- Log failed authentication attempts
|
|
555
|
+
|
|
556
|
+
## Troubleshooting
|
|
557
|
+
|
|
558
|
+
### Issue: TURN credentials not working
|
|
559
|
+
**Check:**
|
|
560
|
+
- Key ID and secret are correct
|
|
561
|
+
- Credentials haven't expired (check TTL)
|
|
562
|
+
- Server can reach rtc.live.cloudflare.com
|
|
563
|
+
- Network allows outbound HTTPS
|
|
564
|
+
|
|
565
|
+
### Issue: Slow connection establishment
|
|
566
|
+
**Solutions:**
|
|
567
|
+
- Ensure proper ICE candidate gathering
|
|
568
|
+
- Check network latency to Cloudflare edge
|
|
569
|
+
- Verify firewall allows WebRTC ports
|
|
570
|
+
- Consider using TURN over TLS (port 443)
|
|
571
|
+
|
|
572
|
+
### Issue: High packet loss
|
|
573
|
+
**Check:**
|
|
574
|
+
- Not exceeding rate limits (5-10k pps)
|
|
575
|
+
- Not exceeding bandwidth limits (50-100 Mbps)
|
|
576
|
+
- Not connecting to too many unique IPs (>5/sec)
|
|
577
|
+
- Client network quality
|
|
578
|
+
|
|
579
|
+
### Debugging ICE Connectivity
|
|
580
|
+
|
|
581
|
+
```typescript
|
|
582
|
+
pc.addEventListener('icecandidate', (event) => {
|
|
583
|
+
if (event.candidate) {
|
|
584
|
+
console.log('ICE candidate:', {
|
|
585
|
+
type: event.candidate.type,
|
|
586
|
+
protocol: event.candidate.protocol,
|
|
587
|
+
address: event.candidate.address,
|
|
588
|
+
port: event.candidate.port
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
pc.addEventListener('iceconnectionstatechange', () => {
|
|
594
|
+
console.log('ICE connection state:', pc.iceConnectionState);
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
// Check which candidate pair was selected
|
|
598
|
+
const stats = await pc.getStats();
|
|
599
|
+
stats.forEach(report => {
|
|
600
|
+
if (report.type === 'candidate-pair' && report.selected) {
|
|
601
|
+
console.log('Selected candidate pair:', report);
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
## Monitoring and Analytics
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
interface TURNMetrics {
|
|
610
|
+
totalRequests: number;
|
|
611
|
+
failedRequests: number;
|
|
612
|
+
averageLatency: number;
|
|
613
|
+
activeConnections: number;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
class TURNMonitor {
|
|
617
|
+
private metrics: TURNMetrics = {
|
|
618
|
+
totalRequests: 0,
|
|
619
|
+
failedRequests: 0,
|
|
620
|
+
averageLatency: 0,
|
|
621
|
+
activeConnections: 0
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
async trackRequest<T>(
|
|
625
|
+
operation: () => Promise<T>
|
|
626
|
+
): Promise<T> {
|
|
627
|
+
const start = Date.now();
|
|
628
|
+
this.metrics.totalRequests++;
|
|
629
|
+
|
|
630
|
+
try {
|
|
631
|
+
const result = await operation();
|
|
632
|
+
this.updateLatency(Date.now() - start);
|
|
633
|
+
return result;
|
|
634
|
+
} catch (error) {
|
|
635
|
+
this.metrics.failedRequests++;
|
|
636
|
+
throw error;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
private updateLatency(latency: number): void {
|
|
641
|
+
this.metrics.averageLatency =
|
|
642
|
+
(this.metrics.averageLatency + latency) / 2;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
getMetrics(): TURNMetrics {
|
|
646
|
+
return { ...this.metrics };
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
## Architecture Considerations
|
|
652
|
+
|
|
653
|
+
### Anycast Benefits
|
|
654
|
+
- **Automatic routing**: Clients connect to nearest location
|
|
655
|
+
- **No region selection**: BGP handles routing
|
|
656
|
+
- **Low latency**: 95% of users within 50ms of edge
|
|
657
|
+
- **Fault tolerance**: Network handles failover
|
|
658
|
+
|
|
659
|
+
### When to Use TURN
|
|
660
|
+
- **Restrictive NATs**: Symmetric NATs that block direct connections
|
|
661
|
+
- **Corporate firewalls**: Environments blocking WebRTC ports
|
|
662
|
+
- **Mobile networks**: Carrier-grade NAT scenarios
|
|
663
|
+
- **Predictable connectivity**: When reliability > efficiency
|
|
664
|
+
|
|
665
|
+
### Integration with Cloudflare Calls SFU
|
|
666
|
+
```typescript
|
|
667
|
+
// TURN is automatically used when needed
|
|
668
|
+
// Cloudflare Calls handles TURN + SFU coordination
|
|
669
|
+
const session = await callsClient.createSession({
|
|
670
|
+
appId: 'your-app-id',
|
|
671
|
+
sessionId: 'meeting-123'
|
|
672
|
+
});
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
## Cost Optimization
|
|
676
|
+
|
|
677
|
+
1. **Use appropriate TTLs**: Don't over-provision credential lifetime
|
|
678
|
+
2. **Implement credential caching**: Reuse credentials when possible
|
|
679
|
+
3. **Set iceTransportPolicy wisely**:
|
|
680
|
+
- `'all'`: Try direct first (recommended for most cases)
|
|
681
|
+
- `'relay'`: Force TURN (only when necessary)
|
|
682
|
+
4. **Monitor usage**: Track bandwidth to avoid surprises
|
|
683
|
+
5. **Use with Cloudflare Calls**: Free when used with SFU
|
|
684
|
+
|
|
685
|
+
## Additional Resources
|
|
686
|
+
|
|
687
|
+
- [Cloudflare Calls Documentation](https://developers.cloudflare.com/calls/)
|
|
688
|
+
- [Cloudflare TURN Service Docs](https://developers.cloudflare.com/realtime/turn/)
|
|
689
|
+
- [Cloudflare API Reference](https://developers.cloudflare.com/api/resources/calls/subresources/turn/)
|
|
690
|
+
- [WebRTC for the Curious](https://webrtcforthecurious.com/)
|
|
691
|
+
- [Orange Meets (Open Source Example)](https://github.com/cloudflare/orange)
|
|
692
|
+
|
|
693
|
+
## Related Cloudflare Services
|
|
694
|
+
|
|
695
|
+
- **Cloudflare Calls SFU**: Managed Selective Forwarding Unit
|
|
696
|
+
- **Cloudflare Stream**: Video streaming with WHIP/WHEP support
|
|
697
|
+
- **Cloudflare Workers**: Backend for credential generation
|
|
698
|
+
- **Cloudflare KV**: Credential caching
|
|
699
|
+
- **Cloudflare Durable Objects**: Session state management
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Cloudflare Turnstile Implementation Skill Reference
|
|
2
|
+
|
|
3
|
+
Expert guidance for implementing Cloudflare Turnstile - a smart CAPTCHA alternative that protects websites from bots without showing traditional CAPTCHA puzzles....
|
|
4
|
+
|
|
5
|
+
## In This Reference
|
|
6
|
+
|
|
7
|
+
- **[configuration.md](./configuration.md)** - Setup, deployment, configuration
|
|
8
|
+
- **[api.md](./api.md)** - API endpoints, methods, interfaces
|
|
9
|
+
- **[patterns.md](./patterns.md)** - Common patterns, use cases, examples
|
|
10
|
+
- **[gotchas.md](./gotchas.md)** - Troubleshooting, best practices, limitations
|
|
11
|
+
|
|
12
|
+
## See Also
|
|
13
|
+
|
|
14
|
+
- [Cloudflare Docs](https://developers.cloudflare.com/)
|