memory-journal-mcp 7.7.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +126 -56
- package/dist/chunk-6OHRCNYW.js +3231 -0
- package/dist/chunk-JFMITANR.js +5168 -0
- package/dist/{chunk-QCQPAF4I.js → chunk-MWNLAEHR.js} +301 -4321
- package/dist/{chunk-ARLYSFSI.js → chunk-UHSO65A4.js} +4242 -6092
- package/dist/cli.js +21 -3
- package/dist/index.d.ts +16 -13
- package/dist/index.js +4 -2
- package/dist/resources-IJVKDFGS.js +2 -0
- package/dist/tools-44DGXE3V.js +2 -0
- package/dist/worker-script.js +201 -20
- package/package.json +7 -4
- package/skills/README.md +62 -25
- package/skills/adversarial-performance/SKILL.md +139 -0
- package/skills/adversarial-performance/references/audit-categories.md +462 -0
- package/skills/adversarial-performance/references/copilot-performance-prompts.md +44 -0
- package/skills/adversarial-performance/references/copilot-usage.md +16 -0
- package/skills/adversarial-performance/references/feedback-loop.md +177 -0
- package/skills/adversarial-performance/references/multi-pass-performance-protocol.md +398 -0
- package/skills/adversarial-planner/SKILL.md +23 -54
- package/skills/adversarial-planner/references/copilot-integration.md +25 -40
- package/skills/adversarial-planner/references/copilot-usage.md +16 -0
- package/skills/adversarial-planner/references/multi-pass-protocol.md +4 -0
- package/skills/adversarial-security/SKILL.md +149 -0
- package/skills/adversarial-security/references/adversarial-base-protocol.md +44 -0
- package/skills/adversarial-security/references/audit-categories.md +723 -0
- package/skills/adversarial-security/references/copilot-security-prompts.md +142 -0
- package/skills/adversarial-security/references/copilot-usage.md +16 -0
- package/skills/adversarial-security/references/feedback-loop.md +206 -0
- package/skills/adversarial-security/references/journal-opt-out.md +7 -0
- package/skills/adversarial-security/references/multi-pass-security-protocol.md +403 -0
- package/skills/adversarial-skill-audit/SKILL.md +118 -0
- package/skills/adversarial-skill-audit/references/audit-categories.md +308 -0
- package/skills/adversarial-skill-audit/references/copilot-skill-prompts.md +68 -0
- package/skills/adversarial-skill-audit/references/copilot-usage.md +16 -0
- package/skills/adversarial-skill-audit/references/feedback-loop.md +155 -0
- package/skills/adversarial-skill-audit/references/multi-pass-skill-protocol.md +367 -0
- package/skills/adversarial-skill-audit/scripts/check-skills.ps1 +48 -0
- package/skills/adversarial-skill-audit/scripts/run-copilot.ps1 +52 -0
- package/skills/adversarial-workflow-audit/SKILL.md +82 -0
- package/skills/adversarial-workflow-audit/references/audit-categories.md +28 -0
- package/skills/adversarial-workflow-audit/references/copilot-usage.md +16 -0
- package/skills/adversarial-workflow-audit/scripts/check-workflows.ps1 +24 -0
- package/skills/agents-sdk/SKILL.md +220 -0
- package/skills/agents-sdk/references/callable.md +92 -0
- package/skills/agents-sdk/references/codemode.md +209 -0
- package/skills/agents-sdk/references/email.md +144 -0
- package/skills/agents-sdk/references/mcp/SKILL.md +65 -0
- package/skills/agents-sdk/references/mcp/code-mode-reference.md +245 -0
- package/skills/agents-sdk/references/mcp/oauth-reference.md +359 -0
- package/skills/agents-sdk/references/mcp/references/architecture-reference.md +208 -0
- package/skills/agents-sdk/references/mcp/references/cloudflare-quickstart.md +156 -0
- package/skills/agents-sdk/references/mcp/references/error-handling.md +343 -0
- package/skills/agents-sdk/references/mcp/references/http-security.md +164 -0
- package/skills/agents-sdk/references/mcp/references/implementation-guide.md +507 -0
- package/skills/agents-sdk/references/mcp/references/testing-reference.md +171 -0
- package/skills/agents-sdk/references/mcp.md +157 -0
- package/skills/agents-sdk/references/state-scheduling.md +164 -0
- package/skills/agents-sdk/references/streaming-chat.md +168 -0
- package/skills/agents-sdk/references/workflows.md +136 -0
- package/skills/auth-identity/SKILL.md +48 -0
- package/skills/autonomous-dev/SKILL.md +46 -23
- package/skills/autonomous-dev/references/workflow_orchestration.md +22 -0
- package/skills/aws/SKILL.md +39 -0
- package/skills/azure/SKILL.md +38 -0
- package/skills/bin/sync.js +7 -1
- package/skills/biome/SKILL.md +59 -0
- package/skills/bun/SKILL.md +8 -2
- package/skills/cloudflare/SKILL.md +37 -0
- package/skills/cloudflare/references/agents-sdk/README.md +95 -0
- package/skills/cloudflare/references/agents-sdk/api.md +195 -0
- package/skills/cloudflare/references/agents-sdk/configuration.md +178 -0
- package/skills/cloudflare/references/agents-sdk/gotchas.md +173 -0
- package/skills/cloudflare/references/agents-sdk/patterns.md +215 -0
- package/skills/cloudflare/references/ai-gateway/README.md +176 -0
- package/skills/cloudflare/references/ai-gateway/configuration.md +117 -0
- package/skills/cloudflare/references/ai-gateway/dynamic-routing.md +88 -0
- package/skills/cloudflare/references/ai-gateway/features.md +96 -0
- package/skills/cloudflare/references/ai-gateway/sdk-integration.md +110 -0
- package/skills/cloudflare/references/ai-gateway/troubleshooting.md +90 -0
- package/skills/cloudflare/references/ai-search/README.md +145 -0
- package/skills/cloudflare/references/ai-search/api.md +87 -0
- package/skills/cloudflare/references/ai-search/configuration.md +91 -0
- package/skills/cloudflare/references/ai-search/gotchas.md +92 -0
- package/skills/cloudflare/references/ai-search/patterns.md +87 -0
- package/skills/cloudflare/references/analytics-engine/README.md +96 -0
- package/skills/cloudflare/references/analytics-engine/api.md +112 -0
- package/skills/cloudflare/references/analytics-engine/configuration.md +107 -0
- package/skills/cloudflare/references/analytics-engine/gotchas.md +87 -0
- package/skills/cloudflare/references/analytics-engine/patterns.md +83 -0
- package/skills/cloudflare/references/api/README.md +66 -0
- package/skills/cloudflare/references/api/api.md +205 -0
- package/skills/cloudflare/references/api/configuration.md +158 -0
- package/skills/cloudflare/references/api/gotchas.md +231 -0
- package/skills/cloudflare/references/api/patterns.md +208 -0
- package/skills/cloudflare/references/api-shield/README.md +44 -0
- package/skills/cloudflare/references/api-shield/api.md +153 -0
- package/skills/cloudflare/references/api-shield/configuration.md +210 -0
- package/skills/cloudflare/references/api-shield/gotchas.md +132 -0
- package/skills/cloudflare/references/api-shield/patterns.md +185 -0
- package/skills/cloudflare/references/argo-smart-routing/README.md +96 -0
- package/skills/cloudflare/references/argo-smart-routing/api.md +253 -0
- package/skills/cloudflare/references/argo-smart-routing/configuration.md +205 -0
- package/skills/cloudflare/references/argo-smart-routing/gotchas.md +115 -0
- package/skills/cloudflare/references/argo-smart-routing/patterns.md +107 -0
- package/skills/cloudflare/references/bindings/README.md +127 -0
- package/skills/cloudflare/references/bindings/api.md +214 -0
- package/skills/cloudflare/references/bindings/configuration.md +200 -0
- package/skills/cloudflare/references/bindings/gotchas.md +210 -0
- package/skills/cloudflare/references/bindings/patterns.md +205 -0
- package/skills/cloudflare/references/bot-management/README.md +95 -0
- package/skills/cloudflare/references/bot-management/api.md +175 -0
- package/skills/cloudflare/references/bot-management/configuration.md +175 -0
- package/skills/cloudflare/references/bot-management/gotchas.md +116 -0
- package/skills/cloudflare/references/bot-management/patterns.md +181 -0
- package/skills/cloudflare/references/browser-rendering/README.md +84 -0
- package/skills/cloudflare/references/browser-rendering/api.md +108 -0
- package/skills/cloudflare/references/browser-rendering/configuration.md +78 -0
- package/skills/cloudflare/references/browser-rendering/gotchas.md +91 -0
- package/skills/cloudflare/references/browser-rendering/patterns.md +93 -0
- package/skills/cloudflare/references/c3/README.md +111 -0
- package/skills/cloudflare/references/c3/api.md +71 -0
- package/skills/cloudflare/references/c3/configuration.md +85 -0
- package/skills/cloudflare/references/c3/gotchas.md +97 -0
- package/skills/cloudflare/references/c3/patterns.md +84 -0
- package/skills/cloudflare/references/cache-reserve/README.md +150 -0
- package/skills/cloudflare/references/cache-reserve/api.md +184 -0
- package/skills/cloudflare/references/cache-reserve/configuration.md +170 -0
- package/skills/cloudflare/references/cache-reserve/gotchas.md +136 -0
- package/skills/cloudflare/references/cache-reserve/patterns.md +197 -0
- package/skills/cloudflare/references/containers/README.md +87 -0
- package/skills/cloudflare/references/containers/api.md +197 -0
- package/skills/cloudflare/references/containers/configuration.md +191 -0
- package/skills/cloudflare/references/containers/gotchas.md +182 -0
- package/skills/cloudflare/references/containers/patterns.md +204 -0
- package/skills/cloudflare/references/cron-triggers/README.md +101 -0
- package/skills/cloudflare/references/cron-triggers/api.md +224 -0
- package/skills/cloudflare/references/cron-triggers/configuration.md +190 -0
- package/skills/cloudflare/references/cron-triggers/gotchas.md +207 -0
- package/skills/cloudflare/references/cron-triggers/patterns.md +274 -0
- package/skills/cloudflare/references/d1/README.md +137 -0
- package/skills/cloudflare/references/d1/api.md +213 -0
- package/skills/cloudflare/references/d1/configuration.md +198 -0
- package/skills/cloudflare/references/d1/gotchas.md +98 -0
- package/skills/cloudflare/references/d1/patterns.md +240 -0
- package/skills/cloudflare/references/ddos/README.md +42 -0
- package/skills/cloudflare/references/ddos/api.md +158 -0
- package/skills/cloudflare/references/ddos/configuration.md +94 -0
- package/skills/cloudflare/references/ddos/gotchas.md +114 -0
- package/skills/cloudflare/references/ddos/patterns.md +220 -0
- package/skills/cloudflare/references/decision-trees.md +95 -0
- package/skills/cloudflare/references/do-storage/README.md +79 -0
- package/skills/cloudflare/references/do-storage/api.md +107 -0
- package/skills/cloudflare/references/do-storage/configuration.md +114 -0
- package/skills/cloudflare/references/do-storage/gotchas.md +153 -0
- package/skills/cloudflare/references/do-storage/patterns.md +210 -0
- package/skills/cloudflare/references/do-storage/testing.md +186 -0
- package/skills/cloudflare/references/durable-objects/README.md +194 -0
- package/skills/cloudflare/references/durable-objects/api.md +205 -0
- package/skills/cloudflare/references/durable-objects/configuration.md +160 -0
- package/skills/cloudflare/references/durable-objects/gotchas.md +200 -0
- package/skills/cloudflare/references/durable-objects/patterns.md +205 -0
- package/skills/cloudflare/references/email-routing/README.md +89 -0
- package/skills/cloudflare/references/email-routing/api.md +192 -0
- package/skills/cloudflare/references/email-routing/configuration.md +187 -0
- package/skills/cloudflare/references/email-routing/gotchas.md +203 -0
- package/skills/cloudflare/references/email-routing/patterns.md +241 -0
- package/skills/cloudflare/references/email-workers/README.md +153 -0
- package/skills/cloudflare/references/email-workers/api.md +227 -0
- package/skills/cloudflare/references/email-workers/configuration.md +115 -0
- package/skills/cloudflare/references/email-workers/gotchas.md +133 -0
- package/skills/cloudflare/references/email-workers/patterns.md +108 -0
- package/skills/cloudflare/references/graphql-api/README.md +147 -0
- package/skills/cloudflare/references/graphql-api/api.md +175 -0
- package/skills/cloudflare/references/graphql-api/configuration.md +151 -0
- package/skills/cloudflare/references/graphql-api/gotchas.md +111 -0
- package/skills/cloudflare/references/graphql-api/patterns.md +276 -0
- package/skills/cloudflare/references/hyperdrive/README.md +84 -0
- package/skills/cloudflare/references/hyperdrive/api.md +149 -0
- package/skills/cloudflare/references/hyperdrive/configuration.md +166 -0
- package/skills/cloudflare/references/hyperdrive/gotchas.md +77 -0
- package/skills/cloudflare/references/hyperdrive/patterns.md +203 -0
- package/skills/cloudflare/references/images/README.md +65 -0
- package/skills/cloudflare/references/images/api.md +101 -0
- package/skills/cloudflare/references/images/configuration.md +206 -0
- package/skills/cloudflare/references/images/gotchas.md +106 -0
- package/skills/cloudflare/references/images/patterns.md +126 -0
- package/skills/cloudflare/references/kv/README.md +90 -0
- package/skills/cloudflare/references/kv/api.md +163 -0
- package/skills/cloudflare/references/kv/configuration.md +148 -0
- package/skills/cloudflare/references/kv/gotchas.md +133 -0
- package/skills/cloudflare/references/kv/patterns.md +195 -0
- package/skills/cloudflare/references/miniflare/README.md +113 -0
- package/skills/cloudflare/references/miniflare/api.md +204 -0
- package/skills/cloudflare/references/miniflare/configuration.md +174 -0
- package/skills/cloudflare/references/miniflare/gotchas.md +179 -0
- package/skills/cloudflare/references/miniflare/patterns.md +187 -0
- package/skills/cloudflare/references/network-interconnect/README.md +104 -0
- package/skills/cloudflare/references/network-interconnect/api.md +220 -0
- package/skills/cloudflare/references/network-interconnect/configuration.md +123 -0
- package/skills/cloudflare/references/network-interconnect/gotchas.md +175 -0
- package/skills/cloudflare/references/network-interconnect/patterns.md +174 -0
- package/skills/cloudflare/references/observability/README.md +93 -0
- package/skills/cloudflare/references/observability/api.md +168 -0
- package/skills/cloudflare/references/observability/configuration.md +178 -0
- package/skills/cloudflare/references/observability/gotchas.md +125 -0
- package/skills/cloudflare/references/observability/patterns.md +105 -0
- package/skills/cloudflare/references/pages/README.md +92 -0
- package/skills/cloudflare/references/pages/api.md +205 -0
- package/skills/cloudflare/references/pages/configuration.md +216 -0
- package/skills/cloudflare/references/pages/gotchas.md +218 -0
- package/skills/cloudflare/references/pages/patterns.md +215 -0
- package/skills/cloudflare/references/pages-functions/README.md +104 -0
- package/skills/cloudflare/references/pages-functions/api.md +159 -0
- package/skills/cloudflare/references/pages-functions/configuration.md +130 -0
- package/skills/cloudflare/references/pages-functions/gotchas.md +102 -0
- package/skills/cloudflare/references/pages-functions/patterns.md +148 -0
- package/skills/cloudflare/references/pipelines/README.md +109 -0
- package/skills/cloudflare/references/pipelines/api.md +214 -0
- package/skills/cloudflare/references/pipelines/configuration.md +98 -0
- package/skills/cloudflare/references/pipelines/gotchas.md +84 -0
- package/skills/cloudflare/references/pipelines/patterns.md +87 -0
- package/skills/cloudflare/references/product-index.md +112 -0
- package/skills/cloudflare/references/pulumi/README.md +113 -0
- package/skills/cloudflare/references/pulumi/api.md +230 -0
- package/skills/cloudflare/references/pulumi/configuration.md +213 -0
- package/skills/cloudflare/references/pulumi/gotchas.md +205 -0
- package/skills/cloudflare/references/pulumi/patterns.md +260 -0
- package/skills/cloudflare/references/queues/README.md +99 -0
- package/skills/cloudflare/references/queues/api.md +211 -0
- package/skills/cloudflare/references/queues/configuration.md +151 -0
- package/skills/cloudflare/references/queues/gotchas.md +210 -0
- package/skills/cloudflare/references/queues/patterns.md +220 -0
- package/skills/cloudflare/references/r2/README.md +97 -0
- package/skills/cloudflare/references/r2/api.md +235 -0
- package/skills/cloudflare/references/r2/configuration.md +176 -0
- package/skills/cloudflare/references/r2/gotchas.md +190 -0
- package/skills/cloudflare/references/r2/patterns.md +203 -0
- package/skills/cloudflare/references/r2-data-catalog/README.md +157 -0
- package/skills/cloudflare/references/r2-data-catalog/api.md +199 -0
- package/skills/cloudflare/references/r2-data-catalog/configuration.md +205 -0
- package/skills/cloudflare/references/r2-data-catalog/gotchas.md +170 -0
- package/skills/cloudflare/references/r2-data-catalog/patterns.md +191 -0
- package/skills/cloudflare/references/r2-sql/README.md +138 -0
- package/skills/cloudflare/references/r2-sql/SKILL.md.backup +512 -0
- package/skills/cloudflare/references/r2-sql/api.md +159 -0
- package/skills/cloudflare/references/r2-sql/configuration.md +152 -0
- package/skills/cloudflare/references/r2-sql/gotchas.md +228 -0
- package/skills/cloudflare/references/r2-sql/patterns.md +230 -0
- package/skills/cloudflare/references/realtime-sfu/README.md +66 -0
- package/skills/cloudflare/references/realtime-sfu/api.md +164 -0
- package/skills/cloudflare/references/realtime-sfu/configuration.md +141 -0
- package/skills/cloudflare/references/realtime-sfu/gotchas.md +138 -0
- package/skills/cloudflare/references/realtime-sfu/patterns.md +187 -0
- package/skills/cloudflare/references/realtimekit/README.md +118 -0
- package/skills/cloudflare/references/realtimekit/api.md +234 -0
- package/skills/cloudflare/references/realtimekit/configuration.md +226 -0
- package/skills/cloudflare/references/realtimekit/gotchas.md +206 -0
- package/skills/cloudflare/references/realtimekit/patterns.md +240 -0
- package/skills/cloudflare/references/sandbox/README.md +104 -0
- package/skills/cloudflare/references/sandbox/api.md +200 -0
- package/skills/cloudflare/references/sandbox/configuration.md +154 -0
- package/skills/cloudflare/references/sandbox/gotchas.md +201 -0
- package/skills/cloudflare/references/sandbox/patterns.md +195 -0
- package/skills/cloudflare/references/secrets-store/README.md +77 -0
- package/skills/cloudflare/references/secrets-store/api.md +199 -0
- package/skills/cloudflare/references/secrets-store/configuration.md +187 -0
- package/skills/cloudflare/references/secrets-store/gotchas.md +97 -0
- package/skills/cloudflare/references/secrets-store/patterns.md +218 -0
- package/skills/cloudflare/references/smart-placement/README.md +143 -0
- package/skills/cloudflare/references/smart-placement/api.md +192 -0
- package/skills/cloudflare/references/smart-placement/configuration.md +202 -0
- package/skills/cloudflare/references/smart-placement/gotchas.md +180 -0
- package/skills/cloudflare/references/smart-placement/patterns.md +190 -0
- package/skills/cloudflare/references/snippets/README.md +74 -0
- package/skills/cloudflare/references/snippets/api.md +214 -0
- package/skills/cloudflare/references/snippets/configuration.md +239 -0
- package/skills/cloudflare/references/snippets/gotchas.md +104 -0
- package/skills/cloudflare/references/snippets/patterns.md +135 -0
- package/skills/cloudflare/references/spectrum/README.md +52 -0
- package/skills/cloudflare/references/spectrum/api.md +184 -0
- package/skills/cloudflare/references/spectrum/configuration.md +203 -0
- package/skills/cloudflare/references/spectrum/gotchas.md +155 -0
- package/skills/cloudflare/references/spectrum/patterns.md +206 -0
- package/skills/cloudflare/references/static-assets/README.md +65 -0
- package/skills/cloudflare/references/static-assets/api.md +201 -0
- package/skills/cloudflare/references/static-assets/configuration.md +186 -0
- package/skills/cloudflare/references/static-assets/gotchas.md +164 -0
- package/skills/cloudflare/references/static-assets/patterns.md +189 -0
- package/skills/cloudflare/references/stream/README.md +123 -0
- package/skills/cloudflare/references/stream/api-live.md +202 -0
- package/skills/cloudflare/references/stream/api.md +206 -0
- package/skills/cloudflare/references/stream/configuration.md +151 -0
- package/skills/cloudflare/references/stream/gotchas.md +139 -0
- package/skills/cloudflare/references/stream/patterns.md +217 -0
- package/skills/cloudflare/references/tail-workers/README.md +92 -0
- package/skills/cloudflare/references/tail-workers/api.md +203 -0
- package/skills/cloudflare/references/tail-workers/configuration.md +178 -0
- package/skills/cloudflare/references/tail-workers/gotchas.md +206 -0
- package/skills/cloudflare/references/tail-workers/patterns.md +190 -0
- package/skills/cloudflare/references/terraform/README.md +100 -0
- package/skills/cloudflare/references/terraform/api.md +178 -0
- package/skills/cloudflare/references/terraform/configuration.md +197 -0
- package/skills/cloudflare/references/terraform/gotchas.md +150 -0
- package/skills/cloudflare/references/terraform/patterns.md +174 -0
- package/skills/cloudflare/references/tunnel/README.md +137 -0
- package/skills/cloudflare/references/tunnel/api.md +205 -0
- package/skills/cloudflare/references/tunnel/configuration.md +163 -0
- package/skills/cloudflare/references/tunnel/gotchas.md +159 -0
- package/skills/cloudflare/references/tunnel/networking.md +174 -0
- package/skills/cloudflare/references/tunnel/patterns.md +199 -0
- package/skills/cloudflare/references/turn/README.md +86 -0
- package/skills/cloudflare/references/turn/api.md +236 -0
- package/skills/cloudflare/references/turn/configuration.md +181 -0
- package/skills/cloudflare/references/turn/gotchas.md +236 -0
- package/skills/cloudflare/references/turn/patterns.md +228 -0
- package/skills/cloudflare/references/turnstile/README.md +102 -0
- package/skills/cloudflare/references/turnstile/api.md +253 -0
- package/skills/cloudflare/references/turnstile/configuration.md +242 -0
- package/skills/cloudflare/references/turnstile/gotchas.md +253 -0
- package/skills/cloudflare/references/turnstile/patterns.md +195 -0
- package/skills/cloudflare/references/vectorize/README.md +133 -0
- package/skills/cloudflare/references/vectorize/api.md +89 -0
- package/skills/cloudflare/references/vectorize/configuration.md +91 -0
- package/skills/cloudflare/references/vectorize/gotchas.md +83 -0
- package/skills/cloudflare/references/vectorize/patterns.md +92 -0
- package/skills/cloudflare/references/waf/README.md +125 -0
- package/skills/cloudflare/references/waf/api.md +203 -0
- package/skills/cloudflare/references/waf/configuration.md +215 -0
- package/skills/cloudflare/references/waf/gotchas.md +208 -0
- package/skills/cloudflare/references/waf/patterns.md +236 -0
- package/skills/cloudflare/references/web-analytics/README.md +149 -0
- package/skills/cloudflare/references/web-analytics/configuration.md +81 -0
- package/skills/cloudflare/references/web-analytics/gotchas.md +86 -0
- package/skills/cloudflare/references/web-analytics/integration.md +63 -0
- package/skills/cloudflare/references/web-analytics/patterns.md +98 -0
- package/skills/cloudflare/references/workerd/README.md +85 -0
- package/skills/cloudflare/references/workerd/api.md +219 -0
- package/skills/cloudflare/references/workerd/configuration.md +200 -0
- package/skills/cloudflare/references/workerd/gotchas.md +151 -0
- package/skills/cloudflare/references/workerd/patterns.md +205 -0
- package/skills/cloudflare/references/workers/README.md +110 -0
- package/skills/cloudflare/references/workers/api.md +197 -0
- package/skills/cloudflare/references/workers/configuration.md +184 -0
- package/skills/cloudflare/references/workers/frameworks.md +200 -0
- package/skills/cloudflare/references/workers/gotchas.md +145 -0
- package/skills/cloudflare/references/workers/patterns.md +220 -0
- package/skills/cloudflare/references/workers-ai/README.md +206 -0
- package/skills/cloudflare/references/workers-ai/api.md +115 -0
- package/skills/cloudflare/references/workers-ai/configuration.md +98 -0
- package/skills/cloudflare/references/workers-ai/gotchas.md +130 -0
- package/skills/cloudflare/references/workers-ai/patterns.md +122 -0
- package/skills/cloudflare/references/workers-for-platforms/README.md +95 -0
- package/skills/cloudflare/references/workers-for-platforms/api.md +212 -0
- package/skills/cloudflare/references/workers-for-platforms/configuration.md +178 -0
- package/skills/cloudflare/references/workers-for-platforms/gotchas.md +134 -0
- package/skills/cloudflare/references/workers-for-platforms/patterns.md +210 -0
- package/skills/cloudflare/references/workers-playground/README.md +131 -0
- package/skills/cloudflare/references/workers-playground/api.md +101 -0
- package/skills/cloudflare/references/workers-playground/configuration.md +169 -0
- package/skills/cloudflare/references/workers-playground/gotchas.md +88 -0
- package/skills/cloudflare/references/workers-playground/patterns.md +134 -0
- package/skills/cloudflare/references/workers-vpc/README.md +130 -0
- package/skills/cloudflare/references/workers-vpc/api.md +196 -0
- package/skills/cloudflare/references/workers-vpc/configuration.md +151 -0
- package/skills/cloudflare/references/workers-vpc/gotchas.md +171 -0
- package/skills/cloudflare/references/workers-vpc/patterns.md +235 -0
- package/skills/cloudflare/references/workflows/README.md +72 -0
- package/skills/cloudflare/references/workflows/api.md +237 -0
- package/skills/cloudflare/references/workflows/configuration.md +158 -0
- package/skills/cloudflare/references/workflows/gotchas.md +97 -0
- package/skills/cloudflare/references/workflows/patterns.md +245 -0
- package/skills/cloudflare/references/wrangler/README.md +143 -0
- package/skills/cloudflare/references/wrangler/api.md +188 -0
- package/skills/cloudflare/references/wrangler/configuration.md +198 -0
- package/skills/cloudflare/references/wrangler/gotchas.md +212 -0
- package/skills/cloudflare/references/wrangler/patterns.md +211 -0
- package/skills/cloudflare/references/zaraz/IMPLEMENTATION_SUMMARY.md +131 -0
- package/skills/cloudflare/references/zaraz/README.md +114 -0
- package/skills/cloudflare/references/zaraz/api.md +118 -0
- package/skills/cloudflare/references/zaraz/configuration.md +94 -0
- package/skills/cloudflare/references/zaraz/gotchas.md +88 -0
- package/skills/cloudflare/references/zaraz/patterns.md +77 -0
- package/skills/docker/SKILL.md +7 -101
- package/skills/docker/references/advanced-examples.md +71 -0
- package/skills/docker/references/templates.md +34 -0
- package/skills/docs-marketer/SKILL.md +178 -0
- package/skills/docs-marketer/references/audit-categories.md +328 -0
- package/skills/docs-marketer/references/copilot-docs-prompts.md +88 -0
- package/skills/docs-marketer/references/copilot-usage.md +16 -0
- package/skills/docs-marketer/references/feedback-loop.md +155 -0
- package/skills/docs-marketer/references/multi-pass-docs-protocol.md +410 -0
- package/skills/drizzle-orm/SKILL.md +82 -0
- package/skills/durable-objects/SKILL.md +167 -0
- package/skills/durable-objects/references/advanced_features.md +29 -0
- package/skills/durable-objects/references/rules.md +300 -0
- package/skills/durable-objects/references/testing.md +261 -0
- package/skills/durable-objects/references/workers.md +336 -0
- package/skills/gcp/SKILL.md +37 -0
- package/skills/github-actions/SKILL.md +5 -58
- package/skills/github-actions/references/templates.md +65 -0
- package/skills/github-commander/SKILL.md +13 -21
- package/skills/github-commander/workflows/copilot-audit.md +12 -12
- package/skills/github-copilot-cli/SKILL.md +21 -26
- package/skills/github-repo-setup/SKILL.md +136 -0
- package/skills/github-repo-setup/references/community-standards.md +136 -0
- package/skills/github-repo-setup/references/github-automation.md +490 -0
- package/skills/github-repo-setup/references/inline-templates.md +205 -0
- package/skills/github-repo-setup/references/project-config.md +320 -0
- package/skills/gitlab/SKILL.md +7 -2
- package/skills/gitlab/package-lock.json +389 -389
- package/skills/golang/SKILL.md +8 -1
- package/skills/graphql/SKILL.md +30 -0
- package/skills/hono/SKILL.md +82 -0
- package/skills/journal-optimizer/SKILL.md +206 -0
- package/skills/journal-optimizer/references/optimizer-scripts.md +169 -0
- package/skills/llm-app-engineering/SKILL.md +18 -0
- package/skills/monorepo/SKILL.md +56 -0
- package/skills/multi-agent-orchestration/SKILL.md +14 -0
- package/skills/mysql/SKILL.md +6 -2
- package/skills/next-best-practices/SKILL.md +86 -0
- package/skills/next-best-practices/references/cache-components-examples.md +234 -0
- package/skills/next-best-practices/references/cache-components.md +210 -0
- package/skills/next-best-practices/references/upgrade-decision-tree.md +33 -0
- package/skills/next-best-practices/references/upgrade.md +43 -0
- package/skills/next-cache-components/SKILL.md +441 -0
- package/skills/next-upgrade/SKILL.md +43 -0
- package/skills/next-upgrade/references/decision-tree.md +33 -0
- package/skills/nodejs/SKILL.md +46 -0
- package/skills/opentelemetry/SKILL.md +62 -0
- package/skills/package.json +39 -4
- package/skills/playwright-standard/SKILL.md +6 -11
- package/skills/playwright-standard/references/locators.md +7 -0
- package/skills/postgres/SKILL.md +6 -1
- package/skills/python/SKILL.md +8 -70
- package/skills/python/references/advanced-patterns.md +37 -0
- package/skills/python/references/config-templates.md +48 -0
- package/skills/rag-pipelines/SKILL.md +14 -0
- package/skills/redis/SKILL.md +31 -0
- package/skills/render/SKILL.md +35 -0
- package/skills/rust/SKILL.md +15 -25
- package/skills/rust/references/borrow-checker.md +13 -0
- package/skills/rust/references/ecosystem.md +11 -0
- package/skills/sandbox-sdk/SKILL.md +186 -0
- package/skills/sandbox-sdk/references/api-quick-ref.md +113 -0
- package/skills/sandbox-sdk/references/examples.md +52 -0
- package/skills/shadcn-ui/SKILL.md +22 -57
- package/skills/skill-builder/SKILL.md +23 -424
- package/skills/skill-builder/references/tutorial.md +457 -0
- package/skills/sqlite/SKILL.md +16 -5
- package/skills/table.md +59 -0
- package/skills/tailwind-css/SKILL.md +11 -60
- package/skills/tailwind-css/references/component-patterns.md +52 -0
- package/skills/trpc/SKILL.md +56 -0
- package/skills/typescript/SKILL.md +30 -433
- package/skills/typescript/references/tutorial.md +453 -0
- package/skills/vercel-ai-sdk/SKILL.md +48 -0
- package/skills/vitest-standard/SKILL.md +5 -11
- package/skills/vitest-standard/references/assertions.md +11 -0
- package/skills/web-perf/SKILL.md +207 -0
- package/skills/workers-best-practices/SKILL.md +120 -0
- package/skills/workers-best-practices/references/anti-patterns.md +18 -0
- package/skills/workers-best-practices/references/review.md +174 -0
- package/skills/workers-best-practices/references/rules.md +485 -0
- package/skills/wrangler/SKILL.md +43 -0
- package/skills/wrangler/references/cli-commands.md +861 -0
- package/skills/zod/SKILL.md +48 -0
- package/dist/tools-P4VGG4FH.js +0 -1
- package/skills/react-best-practices/AGENTS.md +0 -2883
- package/skills/react-best-practices/SKILL.md +0 -138
- /package/skills/{react-best-practices → next-best-practices}/README.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/metadata.json +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/_sections.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/_template.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/advanced-event-handler-refs.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/advanced-init-once.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/advanced-use-latest.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-api-routes.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-defer-await.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-dependencies.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-parallel.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-suspense-boundaries.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-barrel-imports.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-conditional.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-defer-third-party.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-dynamic-imports.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-preload.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/client-event-listeners.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/client-localstorage-schema.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/client-passive-event-listeners.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/client-swr-dedup.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-batch-dom-css.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-cache-function-results.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-cache-property-access.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-cache-storage.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-combine-iterations.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-early-exit.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-hoist-regexp.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-index-maps.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-length-check-first.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-min-max-loop.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-set-map-lookups.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-tosorted-immutable.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-activity.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-animate-svg-wrapper.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-conditional-render.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-content-visibility.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-hoist-jsx.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-hydration-no-flicker.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-hydration-suppress-warning.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-svg-precision.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-usetransition-loading.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-defer-reads.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-dependencies.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-derived-state-no-effect.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-derived-state.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-functional-setstate.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-lazy-state-init.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-memo-with-default-value.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-memo.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-move-effect-to-event.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-simple-expression-in-memo.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-transitions.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-use-ref-transient-values.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-after-nonblocking.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-auth-actions.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-cache-lru.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-cache-react.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-dedup-props.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-parallel-fetching.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-serialization.md +0 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# DO Storage Gotchas & Troubleshooting
|
|
2
|
+
|
|
3
|
+
## Concurrency Model (CRITICAL)
|
|
4
|
+
|
|
5
|
+
Durable Objects use **input/output gates** to prevent race conditions:
|
|
6
|
+
|
|
7
|
+
### Input Gates
|
|
8
|
+
|
|
9
|
+
Block new requests during storage reads from CURRENT request:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// SAFE: Input gate active during await
|
|
13
|
+
async increment() {
|
|
14
|
+
const val = await this.ctx.storage.get("counter"); // Input gate blocks other requests
|
|
15
|
+
await this.ctx.storage.put("counter", val + 1);
|
|
16
|
+
return val;
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Output Gates
|
|
21
|
+
|
|
22
|
+
Hold response until ALL writes from current request confirm:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// SAFE: Output gate waits for put() to confirm before returning response
|
|
26
|
+
async increment() {
|
|
27
|
+
const val = await this.ctx.storage.get("counter");
|
|
28
|
+
this.ctx.storage.put("counter", val + 1); // No await
|
|
29
|
+
return new Response(String(val)); // Response delayed until write confirms
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Write Coalescing
|
|
34
|
+
|
|
35
|
+
Multiple writes to same key = atomic (last write wins):
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// SAFE: All three writes coalesce atomically
|
|
39
|
+
this.ctx.storage.put('key', 1)
|
|
40
|
+
this.ctx.storage.put('key', 2)
|
|
41
|
+
this.ctx.storage.put('key', 3) // Final value: 3
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Breaking Gates (DANGER)
|
|
45
|
+
|
|
46
|
+
**fetch() breaks input/output gates** → allows request interleaving:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// UNSAFE: fetch() allows another request to interleave
|
|
50
|
+
async unsafe() {
|
|
51
|
+
const val = await this.ctx.storage.get("counter");
|
|
52
|
+
await fetch("https://api.example.com"); // Gate broken!
|
|
53
|
+
await this.ctx.storage.put("counter", val + 1); // Race condition possible
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Solution:** Use `blockConcurrencyWhile()` or `transaction()`:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// SAFE: Block concurrent requests explicitly
|
|
61
|
+
async safe() {
|
|
62
|
+
return await this.ctx.blockConcurrencyWhile(async () => {
|
|
63
|
+
const val = await this.ctx.storage.get("counter");
|
|
64
|
+
await fetch("https://api.example.com");
|
|
65
|
+
await this.ctx.storage.put("counter", val + 1);
|
|
66
|
+
return val;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### allowConcurrency Option
|
|
72
|
+
|
|
73
|
+
Opt out of input gate for reads that don't need protection:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// Allow concurrent reads (no consistency guarantee)
|
|
77
|
+
const val = await this.ctx.storage.get('metrics', { allowConcurrency: true })
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Common Errors
|
|
81
|
+
|
|
82
|
+
### "Race Condition in Concurrent Calls"
|
|
83
|
+
|
|
84
|
+
**Cause:** Multiple concurrent storage operations initiated from same event (e.g., `Promise.all()`) are not protected by input gate
|
|
85
|
+
**Solution:** Avoid concurrent storage operations within single event; input gate only serializes requests from different events, not operations within same event
|
|
86
|
+
|
|
87
|
+
### "Direct SQL Transaction Statements"
|
|
88
|
+
|
|
89
|
+
**Cause:** Using `BEGIN TRANSACTION` directly instead of transaction methods
|
|
90
|
+
**Solution:** Use `this.ctx.storage.transactionSync()` for sync operations or `this.ctx.storage.transaction()` for async operations
|
|
91
|
+
|
|
92
|
+
### "Async in transactionSync"
|
|
93
|
+
|
|
94
|
+
**Cause:** Using async operations inside `transactionSync()` callback
|
|
95
|
+
**Solution:** Use async `transaction()` method instead of `transactionSync()` when async operations needed
|
|
96
|
+
|
|
97
|
+
### "TypeScript Type Mismatch at Runtime"
|
|
98
|
+
|
|
99
|
+
**Cause:** Query doesn't return all fields specified in TypeScript type
|
|
100
|
+
**Solution:** Ensure SQL query selects all columns that match the TypeScript type definition
|
|
101
|
+
|
|
102
|
+
### "Silent Data Corruption with Large IDs"
|
|
103
|
+
|
|
104
|
+
**Cause:** JavaScript numbers have 53-bit precision; SQLite INTEGER is 64-bit
|
|
105
|
+
**Symptom:** IDs > 9007199254740991 (Number.MAX_SAFE_INTEGER) silently truncate/corrupt
|
|
106
|
+
**Solution:** Store large IDs as TEXT:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// BAD: Snowflake/Twitter IDs will corrupt
|
|
110
|
+
this.sql.exec('CREATE TABLE events(id INTEGER PRIMARY KEY)')
|
|
111
|
+
this.sql.exec('INSERT INTO events VALUES (?)', 1234567890123456789n) // Corrupts!
|
|
112
|
+
|
|
113
|
+
// GOOD: Store as TEXT
|
|
114
|
+
this.sql.exec('CREATE TABLE events(id TEXT PRIMARY KEY)')
|
|
115
|
+
this.sql.exec('INSERT INTO events VALUES (?)', '1234567890123456789')
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### "Alarm Not Deleted with deleteAll()"
|
|
119
|
+
|
|
120
|
+
**Cause:** `deleteAll()` doesn't delete alarms automatically
|
|
121
|
+
**Solution:** Call `deleteAlarm()` explicitly before `deleteAll()` to remove alarm
|
|
122
|
+
|
|
123
|
+
### "Slow Performance"
|
|
124
|
+
|
|
125
|
+
**Cause:** Using async KV API instead of sync API
|
|
126
|
+
**Solution:** Use sync KV API (`ctx.storage.kv`) for better performance with simple key-value operations
|
|
127
|
+
|
|
128
|
+
### "High Billing from Storage Operations"
|
|
129
|
+
|
|
130
|
+
**Cause:** Excessive `rowsRead`/`rowsWritten` or unused objects not cleaned up
|
|
131
|
+
**Solution:** Monitor `rowsRead`/`rowsWritten` metrics and ensure unused objects call `deleteAll()`
|
|
132
|
+
|
|
133
|
+
### "Durable Object Overloaded"
|
|
134
|
+
|
|
135
|
+
**Cause:** Single DO exceeding ~1K req/sec soft limit
|
|
136
|
+
**Solution:** Shard across multiple DOs with random IDs or other distribution strategy
|
|
137
|
+
|
|
138
|
+
## Limits
|
|
139
|
+
|
|
140
|
+
| Limit | Value | Notes |
|
|
141
|
+
| ------------------------- | ----------- | --------------------- |
|
|
142
|
+
| Max columns per table | 100 | SQL limitation |
|
|
143
|
+
| Max string/BLOB per row | 2 MB | SQL limitation |
|
|
144
|
+
| Max row size | 2 MB | SQL limitation |
|
|
145
|
+
| Max SQL statement size | 100 KB | SQL limitation |
|
|
146
|
+
| Max SQL parameters | 100 | SQL limitation |
|
|
147
|
+
| Max LIKE/GLOB pattern | 50 B | SQL limitation |
|
|
148
|
+
| SQLite storage per object | 10 GB | SQLite-backed storage |
|
|
149
|
+
| SQLite key+value size | 2 MB | SQLite-backed storage |
|
|
150
|
+
| KV storage per object | Unlimited | KV-style storage |
|
|
151
|
+
| KV key size | 2 KiB | KV-style storage |
|
|
152
|
+
| KV value size | 128 KiB | KV-style storage |
|
|
153
|
+
| Request throughput | ~1K req/sec | Soft limit per DO |
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# DO Storage Patterns & Best Practices
|
|
2
|
+
|
|
3
|
+
## Schema Migration
|
|
4
|
+
|
|
5
|
+
**Note:** `PRAGMA user_version` is **not supported** in Durable Objects SQLite storage. Use a `_sql_schema_migrations` table instead:
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
export class MyDurableObject extends DurableObject {
|
|
9
|
+
constructor(ctx: DurableObjectState, env: Env) {
|
|
10
|
+
super(ctx, env)
|
|
11
|
+
this.sql = ctx.storage.sql
|
|
12
|
+
|
|
13
|
+
this.sql.exec(`
|
|
14
|
+
CREATE TABLE IF NOT EXISTS _sql_schema_migrations (
|
|
15
|
+
id INTEGER PRIMARY KEY,
|
|
16
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
17
|
+
)
|
|
18
|
+
`)
|
|
19
|
+
|
|
20
|
+
const ver = this.sql
|
|
21
|
+
.exec<{
|
|
22
|
+
version: number
|
|
23
|
+
}>('SELECT COALESCE(MAX(id), 0) as version FROM _sql_schema_migrations')
|
|
24
|
+
.one().version
|
|
25
|
+
|
|
26
|
+
if (ver < 1) {
|
|
27
|
+
this.sql.exec(`CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT)`)
|
|
28
|
+
this.sql.exec('INSERT INTO _sql_schema_migrations (id) VALUES (1)')
|
|
29
|
+
}
|
|
30
|
+
if (ver < 2) {
|
|
31
|
+
this.sql.exec(`ALTER TABLE users ADD COLUMN email TEXT`)
|
|
32
|
+
this.sql.exec('INSERT INTO _sql_schema_migrations (id) VALUES (2)')
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
For production apps, consider [`durable-utils`](https://github.com/lambrospetrou/durable-utils#sqlite-schema-migrations) — provides a `SQLSchemaMigrations` class that tracks executed migrations both in memory and in storage. Also see [`@cloudflare/actors` storage utilities](https://github.com/cloudflare/actors/blob/main/packages/storage/src/sql-schema-migrations.ts) — a reference implementation of the same pattern used by the Cloudflare Actors framework.
|
|
39
|
+
|
|
40
|
+
## In-Memory Caching
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
export class UserCache extends DurableObject {
|
|
44
|
+
cache = new Map<string, User>()
|
|
45
|
+
async getUser(id: string): Promise<User | undefined> {
|
|
46
|
+
if (this.cache.has(id)) {
|
|
47
|
+
const cached = this.cache.get(id)
|
|
48
|
+
if (cached) return cached
|
|
49
|
+
}
|
|
50
|
+
const user = await this.ctx.storage.get<User>(`user:${id}`)
|
|
51
|
+
if (user) this.cache.set(id, user)
|
|
52
|
+
return user
|
|
53
|
+
}
|
|
54
|
+
async updateUser(id: string, data: Partial<User>) {
|
|
55
|
+
const updated = { ...(await this.getUser(id)), ...data }
|
|
56
|
+
this.cache.set(id, updated)
|
|
57
|
+
await this.ctx.storage.put(`user:${id}`, updated)
|
|
58
|
+
return updated
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Rate Limiting
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
export class RateLimiter extends DurableObject {
|
|
67
|
+
async checkLimit(key: string, limit: number, window: number): Promise<boolean> {
|
|
68
|
+
const now = Date.now()
|
|
69
|
+
this.sql.exec('DELETE FROM requests WHERE key = ? AND timestamp < ?', key, now - window)
|
|
70
|
+
const count = this.sql
|
|
71
|
+
.exec('SELECT COUNT(*) as count FROM requests WHERE key = ?', key)
|
|
72
|
+
.one().count
|
|
73
|
+
if (count >= limit) return false
|
|
74
|
+
this.sql.exec('INSERT INTO requests (key, timestamp) VALUES (?, ?)', key, now)
|
|
75
|
+
return true
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Batch Processing with Alarms
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
export class BatchProcessor extends DurableObject {
|
|
84
|
+
pending: string[] = []
|
|
85
|
+
async addItem(item: string) {
|
|
86
|
+
this.pending.push(item)
|
|
87
|
+
if (!(await this.ctx.storage.getAlarm())) await this.ctx.storage.setAlarm(Date.now() + 5000)
|
|
88
|
+
}
|
|
89
|
+
async alarm() {
|
|
90
|
+
const items = [...this.pending]
|
|
91
|
+
this.pending = []
|
|
92
|
+
this.sql.exec(
|
|
93
|
+
`INSERT INTO processed_items (item, timestamp) VALUES ${items.map(() => '(?, ?)').join(', ')}`,
|
|
94
|
+
...items.flatMap((item) => [item, Date.now()])
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Initialization Pattern
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
export class Counter extends DurableObject {
|
|
104
|
+
value: number
|
|
105
|
+
constructor(ctx: DurableObjectState, env: Env) {
|
|
106
|
+
super(ctx, env)
|
|
107
|
+
ctx.blockConcurrencyWhile(async () => {
|
|
108
|
+
this.value = (await ctx.storage.get('value')) || 0
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
async increment() {
|
|
112
|
+
this.value++
|
|
113
|
+
this.ctx.storage.put('value', this.value) // Don't await (output gate protects)
|
|
114
|
+
return this.value
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Safe Counter / Optimized Write
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// Input gate blocks other requests
|
|
123
|
+
async getUniqueNumber(): Promise<number> {
|
|
124
|
+
let val = await this.ctx.storage.get("counter");
|
|
125
|
+
await this.ctx.storage.put("counter", val + 1);
|
|
126
|
+
return val;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// No await on write - output gate delays response until write confirms
|
|
130
|
+
async increment(): Promise<Response> {
|
|
131
|
+
let val = await this.ctx.storage.get("counter");
|
|
132
|
+
this.ctx.storage.put("counter", val + 1);
|
|
133
|
+
return new Response(String(val));
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Parent-Child Coordination
|
|
138
|
+
|
|
139
|
+
Hierarchical DO pattern where parent manages child DOs:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
// Parent DO coordinates children
|
|
143
|
+
export class Workspace extends DurableObject {
|
|
144
|
+
async createDocument(name: string): Promise<string> {
|
|
145
|
+
const docId = crypto.randomUUID()
|
|
146
|
+
const childId = this.env.DOCUMENT.idFromName(`${this.ctx.id.toString()}:${docId}`)
|
|
147
|
+
const childStub = this.env.DOCUMENT.get(childId)
|
|
148
|
+
await childStub.initialize(name)
|
|
149
|
+
|
|
150
|
+
// Track child in parent storage
|
|
151
|
+
this.sql.exec(
|
|
152
|
+
'INSERT INTO documents (id, name, created) VALUES (?, ?, ?)',
|
|
153
|
+
docId,
|
|
154
|
+
name,
|
|
155
|
+
Date.now()
|
|
156
|
+
)
|
|
157
|
+
return docId
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async listDocuments(): Promise<string[]> {
|
|
161
|
+
return this.sql
|
|
162
|
+
.exec('SELECT id FROM documents')
|
|
163
|
+
.toArray()
|
|
164
|
+
.map((r) => r.id)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Child DO
|
|
169
|
+
export class Document extends DurableObject {
|
|
170
|
+
async initialize(name: string) {
|
|
171
|
+
this.sql.exec('CREATE TABLE IF NOT EXISTS content(key TEXT PRIMARY KEY, value TEXT)')
|
|
172
|
+
this.sql.exec('INSERT INTO content VALUES (?, ?)', 'name', name)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Write Coalescing Pattern
|
|
178
|
+
|
|
179
|
+
Multiple writes to same key coalesce atomically (last write wins):
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
async updateMetrics(userId: string, actions: Action[]) {
|
|
183
|
+
// All writes coalesce - no await needed
|
|
184
|
+
for (const action of actions) {
|
|
185
|
+
this.ctx.storage.put(`user:${userId}:lastAction`, action.type);
|
|
186
|
+
this.ctx.storage.put(`user:${userId}:count`,
|
|
187
|
+
await this.ctx.storage.get(`user:${userId}:count`) + 1);
|
|
188
|
+
}
|
|
189
|
+
// Output gate ensures all writes confirm before response
|
|
190
|
+
return new Response("OK");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Atomic batch with SQL
|
|
194
|
+
async batchUpdate(items: Item[]) {
|
|
195
|
+
this.sql.exec('BEGIN');
|
|
196
|
+
for (const item of items) {
|
|
197
|
+
this.sql.exec('INSERT OR REPLACE INTO items VALUES (?, ?)', item.id, item.value);
|
|
198
|
+
}
|
|
199
|
+
this.sql.exec('COMMIT');
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Cleanup
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
async cleanup() {
|
|
207
|
+
await this.ctx.storage.deleteAlarm(); // Separate from deleteAll
|
|
208
|
+
await this.ctx.storage.deleteAll();
|
|
209
|
+
}
|
|
210
|
+
```
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# DO Storage Testing
|
|
2
|
+
|
|
3
|
+
Testing Durable Objects with storage using `vitest-pool-workers`.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
**vitest.config.ts:**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config'
|
|
11
|
+
|
|
12
|
+
export default defineWorkersConfig({
|
|
13
|
+
test: {
|
|
14
|
+
poolOptions: {
|
|
15
|
+
workers: { wrangler: { configPath: './wrangler.toml' } },
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
})
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**package.json:** Add `@cloudflare/vitest-pool-workers` and `vitest` to devDependencies
|
|
22
|
+
|
|
23
|
+
## Basic Testing
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { env, runInDurableObject } from 'cloudflare:test'
|
|
27
|
+
import { describe, it, expect } from 'vitest'
|
|
28
|
+
|
|
29
|
+
describe('Counter DO', () => {
|
|
30
|
+
it('increments counter', async () => {
|
|
31
|
+
const id = env.COUNTER.idFromName('test')
|
|
32
|
+
const result = await runInDurableObject(env.COUNTER, id, async (instance, state) => {
|
|
33
|
+
const val1 = await instance.increment()
|
|
34
|
+
const val2 = await instance.increment()
|
|
35
|
+
return { val1, val2 }
|
|
36
|
+
})
|
|
37
|
+
expect(result.val1).toBe(1)
|
|
38
|
+
expect(result.val2).toBe(2)
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Testing SQL Storage
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
it('creates and queries users', async () => {
|
|
47
|
+
const id = env.USER_MANAGER.idFromName('test')
|
|
48
|
+
await runInDurableObject(env.USER_MANAGER, id, async (instance, state) => {
|
|
49
|
+
await instance.createUser('alice@example.com', 'Alice')
|
|
50
|
+
const user = await instance.getUser('alice@example.com')
|
|
51
|
+
expect(user).toEqual({ email: 'alice@example.com', name: 'Alice' })
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('handles schema migrations', async () => {
|
|
56
|
+
const id = env.USER_MANAGER.idFromName('migration-test')
|
|
57
|
+
await runInDurableObject(env.USER_MANAGER, id, async (instance, state) => {
|
|
58
|
+
const version = state.storage.sql
|
|
59
|
+
.exec("SELECT value FROM _meta WHERE key = 'schema_version'")
|
|
60
|
+
.one()?.value
|
|
61
|
+
expect(version).toBe('1')
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Testing Alarms
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { runDurableObjectAlarm } from 'cloudflare:test'
|
|
70
|
+
|
|
71
|
+
it('processes batch on alarm', async () => {
|
|
72
|
+
const id = env.BATCH_PROCESSOR.idFromName('test')
|
|
73
|
+
|
|
74
|
+
// Add items
|
|
75
|
+
await runInDurableObject(env.BATCH_PROCESSOR, id, async (instance) => {
|
|
76
|
+
await instance.addItem('item1')
|
|
77
|
+
await instance.addItem('item2')
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
// Trigger alarm
|
|
81
|
+
await runDurableObjectAlarm(env.BATCH_PROCESSOR, id)
|
|
82
|
+
|
|
83
|
+
// Verify processed
|
|
84
|
+
await runInDurableObject(env.BATCH_PROCESSOR, id, async (instance, state) => {
|
|
85
|
+
const count = state.storage.sql
|
|
86
|
+
.exec('SELECT COUNT(*) as count FROM processed_items')
|
|
87
|
+
.one().count
|
|
88
|
+
expect(count).toBe(2)
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Testing Concurrency
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
it('handles concurrent increments safely', async () => {
|
|
97
|
+
const id = env.COUNTER.idFromName('concurrent-test')
|
|
98
|
+
|
|
99
|
+
// Parallel increments
|
|
100
|
+
const results = await Promise.all([
|
|
101
|
+
runInDurableObject(env.COUNTER, id, (i) => i.increment()),
|
|
102
|
+
runInDurableObject(env.COUNTER, id, (i) => i.increment()),
|
|
103
|
+
runInDurableObject(env.COUNTER, id, (i) => i.increment()),
|
|
104
|
+
])
|
|
105
|
+
|
|
106
|
+
// All should get unique values
|
|
107
|
+
expect(new Set(results).size).toBe(3)
|
|
108
|
+
expect(Math.max(...results)).toBe(3)
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Test Isolation
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// Per-test unique IDs
|
|
116
|
+
let testId: string
|
|
117
|
+
beforeEach(() => {
|
|
118
|
+
testId = crypto.randomUUID()
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('isolated test', async () => {
|
|
122
|
+
const id = env.MY_DO.idFromName(testId)
|
|
123
|
+
// Uses unique DO instance
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
// Cleanup pattern
|
|
127
|
+
it('with cleanup', async () => {
|
|
128
|
+
const id = env.MY_DO.idFromName('cleanup-test')
|
|
129
|
+
try {
|
|
130
|
+
await runInDurableObject(env.MY_DO, id, async (instance) => {})
|
|
131
|
+
} finally {
|
|
132
|
+
await runInDurableObject(env.MY_DO, id, async (instance, state) => {
|
|
133
|
+
await state.storage.deleteAll()
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Testing PITR
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
it('restores from bookmark', async () => {
|
|
143
|
+
const id = env.MY_DO.idFromName('pitr-test')
|
|
144
|
+
|
|
145
|
+
// Create checkpoint
|
|
146
|
+
const bookmark = await runInDurableObject(env.MY_DO, id, async (instance, state) => {
|
|
147
|
+
await state.storage.put('value', 1)
|
|
148
|
+
return await state.storage.getCurrentBookmark()
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// Modify and restore
|
|
152
|
+
await runInDurableObject(env.MY_DO, id, async (instance, state) => {
|
|
153
|
+
await state.storage.put('value', 2)
|
|
154
|
+
await state.storage.onNextSessionRestoreBookmark(bookmark)
|
|
155
|
+
state.abort()
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
// Verify restored
|
|
159
|
+
await runInDurableObject(env.MY_DO, id, async (instance, state) => {
|
|
160
|
+
const value = await state.storage.get('value')
|
|
161
|
+
expect(value).toBe(1)
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Testing Transactions
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
it('rolls back on error', async () => {
|
|
170
|
+
const id = env.BANK.idFromName('transaction-test')
|
|
171
|
+
|
|
172
|
+
await runInDurableObject(env.BANK, id, async (instance, state) => {
|
|
173
|
+
await state.storage.put('balance', 100)
|
|
174
|
+
|
|
175
|
+
await expect(
|
|
176
|
+
state.storage.transaction(async () => {
|
|
177
|
+
await state.storage.put('balance', 50)
|
|
178
|
+
throw new Error('Cancel')
|
|
179
|
+
})
|
|
180
|
+
).rejects.toThrow('Cancel')
|
|
181
|
+
|
|
182
|
+
const balance = await state.storage.get('balance')
|
|
183
|
+
expect(balance).toBe(100) // Rolled back
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
```
|