cfsa-antigravity 1.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/bin/cli.mjs +324 -0
- package/package.json +34 -0
- package/template/.agent/instructions/commands.md +48 -0
- package/template/.agent/instructions/patterns.md +61 -0
- package/template/.agent/instructions/structure.md +29 -0
- package/template/.agent/instructions/tech-stack.md +43 -0
- package/template/.agent/instructions/workflow.md +41 -0
- package/template/.agent/kit-sync.md +15 -0
- package/template/.agent/rules/boundary-not-placeholder.md +146 -0
- package/template/.agent/rules/completion-checklist.md +48 -0
- package/template/.agent/rules/decision-classification.md +103 -0
- package/template/.agent/rules/extensibility.md +47 -0
- package/template/.agent/rules/question-vs-command.md +81 -0
- package/template/.agent/rules/security-first.md +43 -0
- package/template/.agent/rules/specificity-standards.md +54 -0
- package/template/.agent/rules/tdd-contract-first.md +57 -0
- package/template/.agent/rules/vertical-slices.md +42 -0
- package/template/.agent/skill-library/MANIFEST.md +480 -0
- package/template/.agent/skill-library/README.md +38 -0
- package/template/.agent/skill-library/meta/brand-guidelines/SKILL.md +73 -0
- package/template/.agent/skill-library/meta/claude-code/README.md +9 -0
- package/template/.agent/skill-library/meta/claude-code/agent-development/SKILL.md +415 -0
- package/template/.agent/skill-library/meta/claude-code/hook-development/SKILL.md +712 -0
- package/template/.agent/skill-library/meta/claude-code/plugin-structure/SKILL.md +476 -0
- package/template/.agent/skill-library/meta/git-advanced/SKILL.md +972 -0
- package/template/.agent/skill-library/meta/mcp-builder/SKILL.md +236 -0
- package/template/.agent/skill-library/meta/product-marketing-context/SKILL.md +241 -0
- package/template/.agent/skill-library/meta/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skill-library/meta/tmux-processes/SKILL.md +210 -0
- package/template/.agent/skill-library/meta/using-tmux-for-interactive-commands/SKILL.md +178 -0
- package/template/.agent/skill-library/stack/3d/threejs-pro/SKILL.md +300 -0
- package/template/.agent/skill-library/stack/ai/ai-sdk/SKILL.md +77 -0
- package/template/.agent/skill-library/stack/ai/langchain/SKILL.md +530 -0
- package/template/.agent/skill-library/stack/ai/ollama/SKILL.md +321 -0
- package/template/.agent/skill-library/stack/ai/openai-sdk/SKILL.md +549 -0
- package/template/.agent/skill-library/stack/analytics/google-analytics/SKILL.md +153 -0
- package/template/.agent/skill-library/stack/api/graphql/SKILL.md +1061 -0
- package/template/.agent/skill-library/stack/api/trpc/SKILL.md +576 -0
- package/template/.agent/skill-library/stack/auth/authjs/SKILL.md +569 -0
- package/template/.agent/skill-library/stack/auth/clerk/SKILL.md +590 -0
- package/template/.agent/skill-library/stack/auth/firebase-auth/SKILL.md +734 -0
- package/template/.agent/skill-library/stack/cms/payload-cms/SKILL.md +573 -0
- package/template/.agent/skill-library/stack/cms/shopify/SKILL.md +1193 -0
- package/template/.agent/skill-library/stack/cms/wordpress/SKILL.md +1104 -0
- package/template/.agent/skill-library/stack/css/sass-scss/SKILL.md +1121 -0
- package/template/.agent/skill-library/stack/css/tailwind-css-patterns/SKILL.md +863 -0
- package/template/.agent/skill-library/stack/css/tailwind-design-system/SKILL.md +490 -0
- package/template/.agent/skill-library/stack/css/vanilla-css/SKILL.md +1078 -0
- package/template/.agent/skill-library/stack/databases/clickhouse/SKILL.md +311 -0
- package/template/.agent/skill-library/stack/databases/influxdb/SKILL.md +280 -0
- package/template/.agent/skill-library/stack/databases/lancedb/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/databases/mongodb/SKILL.md +1169 -0
- package/template/.agent/skill-library/stack/databases/neo4j/SKILL.md +839 -0
- package/template/.agent/skill-library/stack/databases/pgvector/SKILL.md +241 -0
- package/template/.agent/skill-library/stack/databases/pinecone/SKILL.md +212 -0
- package/template/.agent/skill-library/stack/databases/postgresql/SKILL.md +658 -0
- package/template/.agent/skill-library/stack/databases/qdrant/SKILL.md +312 -0
- package/template/.agent/skill-library/stack/databases/redis/SKILL.md +1079 -0
- package/template/.agent/skill-library/stack/databases/spacetimedb/SKILL.md +532 -0
- package/template/.agent/skill-library/stack/databases/sqlite/SKILL.md +1132 -0
- package/template/.agent/skill-library/stack/databases/supabase/SKILL.md +640 -0
- package/template/.agent/skill-library/stack/databases/surrealdb-expert/SKILL.md +945 -0
- package/template/.agent/skill-library/stack/databases/timescaledb/SKILL.md +745 -0
- package/template/.agent/skill-library/stack/databases/weaviate/SKILL.md +218 -0
- package/template/.agent/skill-library/stack/devops/github-actions/SKILL.md +554 -0
- package/template/.agent/skill-library/stack/devops/kubernetes/SKILL.md +950 -0
- package/template/.agent/skill-library/stack/devops/nginx/SKILL.md +841 -0
- package/template/.agent/skill-library/stack/devops/terraform/SKILL.md +860 -0
- package/template/.agent/skill-library/stack/email/resend/SKILL.md +391 -0
- package/template/.agent/skill-library/stack/engines/godot/SKILL.md +488 -0
- package/template/.agent/skill-library/stack/extensions/chrome-extension/SKILL.md +375 -0
- package/template/.agent/skill-library/stack/extensions/vscode-extension/SKILL.md +453 -0
- package/template/.agent/skill-library/stack/frameworks/astro-framework/SKILL.md +162 -0
- package/template/.agent/skill-library/stack/frameworks/electron/SKILL.md +1286 -0
- package/template/.agent/skill-library/stack/frameworks/fastapi/SKILL.md +650 -0
- package/template/.agent/skill-library/stack/frameworks/hono/SKILL.md +90 -0
- package/template/.agent/skill-library/stack/frameworks/nestjs/SKILL.md +878 -0
- package/template/.agent/skill-library/stack/frameworks/nextjs/SKILL.md +635 -0
- package/template/.agent/skill-library/stack/frameworks/nuxt/SKILL.md +564 -0
- package/template/.agent/skill-library/stack/frameworks/sveltekit/SKILL.md +614 -0
- package/template/.agent/skill-library/stack/frameworks/tauri/SKILL.md +920 -0
- package/template/.agent/skill-library/stack/gamedev/godot/SKILL.md +1032 -0
- package/template/.agent/skill-library/stack/gamedev/unity/SKILL.md +1175 -0
- package/template/.agent/skill-library/stack/hosting/aws/SKILL.md +467 -0
- package/template/.agent/skill-library/stack/hosting/cloudflare/SKILL.md +201 -0
- package/template/.agent/skill-library/stack/hosting/docker-expert/SKILL.md +409 -0
- package/template/.agent/skill-library/stack/hosting/vercel/SKILL.md +484 -0
- package/template/.agent/skill-library/stack/languages/bash-scripting/SKILL.md +773 -0
- package/template/.agent/skill-library/stack/languages/c-cpp/SKILL.md +712 -0
- package/template/.agent/skill-library/stack/languages/gdscript/SKILL.md +789 -0
- package/template/.agent/skill-library/stack/languages/go/SKILL.md +664 -0
- package/template/.agent/skill-library/stack/languages/java/SKILL.md +778 -0
- package/template/.agent/skill-library/stack/languages/kotlin/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/languages/python/SKILL.md +678 -0
- package/template/.agent/skill-library/stack/languages/rust/SKILL.md +673 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/SKILL.md +141 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/advanced-generics.md +90 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/branded-types.md +57 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/builder-pattern.md +71 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/common-pitfalls.md +135 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/conditional-types.md +27 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/decorators.md +98 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/discriminated-unions.md +62 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/mapped-types.md +53 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/performance-best-practices.md +104 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/template-literal-types.md +49 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/testing-types.md +112 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-guards.md +70 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-inference.md +101 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/utility-types.md +98 -0
- package/template/.agent/skill-library/stack/languages/vanilla-javascript/SKILL.md +803 -0
- package/template/.agent/skill-library/stack/messaging/kafka/SKILL.md +235 -0
- package/template/.agent/skill-library/stack/mobile/expo-react-native/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/mobile/flutter/SKILL.md +316 -0
- package/template/.agent/skill-library/stack/mobile/react-native/SKILL.md +337 -0
- package/template/.agent/skill-library/stack/monitoring/posthog/SKILL.md +396 -0
- package/template/.agent/skill-library/stack/monitoring/sentry/SKILL.md +509 -0
- package/template/.agent/skill-library/stack/observability/datadog/SKILL.md +179 -0
- package/template/.agent/skill-library/stack/observability/distributed-tracing/SKILL.md +140 -0
- package/template/.agent/skill-library/stack/observability/logging-best-practices/SKILL.md +168 -0
- package/template/.agent/skill-library/stack/observability/opentelemetry/SKILL.md +164 -0
- package/template/.agent/skill-library/stack/observability/prometheus-grafana/SKILL.md +246 -0
- package/template/.agent/skill-library/stack/observability/python-observability/SKILL.md +158 -0
- package/template/.agent/skill-library/stack/orm/drizzle-orm/SKILL.md +613 -0
- package/template/.agent/skill-library/stack/orm/prisma/SKILL.md +744 -0
- package/template/.agent/skill-library/stack/payments/lemonsqueezy/SKILL.md +393 -0
- package/template/.agent/skill-library/stack/payments/stripe-integration/SKILL.md +457 -0
- package/template/.agent/skill-library/stack/queue/bullmq/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/queue/inngest/SKILL.md +438 -0
- package/template/.agent/skill-library/stack/realtime/socketio/SKILL.md +595 -0
- package/template/.agent/skill-library/stack/search/elasticsearch/SKILL.md +248 -0
- package/template/.agent/skill-library/stack/search/meilisearch/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/security/crypto-patterns/SKILL.md +437 -0
- package/template/.agent/skill-library/stack/security/csp-cors-headers/SKILL.md +588 -0
- package/template/.agent/skill-library/stack/security/dependency-auditing/SKILL.md +560 -0
- package/template/.agent/skill-library/stack/security/input-sanitization/SKILL.md +430 -0
- package/template/.agent/skill-library/stack/security/owasp-web-security/SKILL.md +421 -0
- package/template/.agent/skill-library/stack/state/tanstack-query/SKILL.md +637 -0
- package/template/.agent/skill-library/stack/state/zustand/SKILL.md +483 -0
- package/template/.agent/skill-library/stack/storage/aws-s3/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/testing/playwright/SKILL.md +641 -0
- package/template/.agent/skill-library/stack/testing/storybook/SKILL.md +923 -0
- package/template/.agent/skill-library/stack/testing/testing-library/SKILL.md +872 -0
- package/template/.agent/skill-library/stack/testing/vitest/SKILL.md +714 -0
- package/template/.agent/skill-library/stack/ui/react-best-practices/SKILL.md +877 -0
- package/template/.agent/skill-library/stack/ui/react-composition-patterns/SKILL.md +1107 -0
- package/template/.agent/skill-library/stack/ui/react-flow/SKILL.md +425 -0
- package/template/.agent/skill-library/stack/ui/shadcn-ui/SKILL.md +703 -0
- package/template/.agent/skill-library/surface/api/api-caching/SKILL.md +458 -0
- package/template/.agent/skill-library/surface/api/api-documentation-openapi/SKILL.md +697 -0
- package/template/.agent/skill-library/surface/api/api-error-handling/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/api-security-checklist/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/api-versioning/SKILL.md +420 -0
- package/template/.agent/skill-library/surface/api/email-best-practices/SKILL.md +59 -0
- package/template/.agent/skill-library/surface/api/rate-limiting-abuse-protection/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/webhook-design/SKILL.md +752 -0
- package/template/.agent/skill-library/surface/cli/cli-configuration-management/SKILL.md +445 -0
- package/template/.agent/skill-library/surface/cli/cli-error-diagnostics/SKILL.md +515 -0
- package/template/.agent/skill-library/surface/cli/cli-shell-integration/SKILL.md +479 -0
- package/template/.agent/skill-library/surface/cli/cli-ux-design/SKILL.md +477 -0
- package/template/.agent/skill-library/surface/desktop/desktop-app-distribution/SKILL.md +416 -0
- package/template/.agent/skill-library/surface/desktop/desktop-security-sandboxing/SKILL.md +407 -0
- package/template/.agent/skill-library/surface/desktop/desktop-ux-conventions/SKILL.md +361 -0
- package/template/.agent/skill-library/surface/desktop/native-os-integration/SKILL.md +563 -0
- package/template/.agent/skill-library/surface/extension/browser-extension-patterns/SKILL.md +482 -0
- package/template/.agent/skill-library/surface/extension/plugin-architecture-design/SKILL.md +632 -0
- package/template/.agent/skill-library/surface/extension/vscode-extension-development/SKILL.md +728 -0
- package/template/.agent/skill-library/surface/mobile/app-store-submission/SKILL.md +304 -0
- package/template/.agent/skill-library/surface/mobile/mobile-offline-sync/SKILL.md +443 -0
- package/template/.agent/skill-library/surface/mobile/mobile-responsive-patterns/SKILL.md +432 -0
- package/template/.agent/skill-library/surface/mobile/push-notifications/SKILL.md +495 -0
- package/template/.agent/skill-library/surface/web/accessibility-compliance/SKILL.md +827 -0
- package/template/.agent/skill-library/surface/web/ai-seo/SKILL.md +398 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/content-patterns.md +285 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/platform-ranking-factors.md +152 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/SKILL.md +309 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/event-library.md +260 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/ga4-implementation.md +300 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/gtm-implementation.md +390 -0
- package/template/.agent/skill-library/surface/web/authentication-ui-flows/SKILL.md +530 -0
- package/template/.agent/skill-library/surface/web/dark-mode-theming/SKILL.md +516 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/SKILL.md +105 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/charts.csv +26 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/colors.csv +97 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/landing.csv +31 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/styles.csv +59 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/typography.csv +58 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/ux-guidelines.csv +100 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/core.py +258 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/design_system.py +1067 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/search.py +106 -0
- package/template/.agent/skill-library/surface/web/form-handling-validation/SKILL.md +675 -0
- package/template/.agent/skill-library/surface/web/frontend-design/SKILL.md +1393 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/cppn-hero.tsx +299 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/wave-hero.tsx +875 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/SKILL.md +111 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/scripts/ux_audit.py +739 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +154 -0
- package/template/.agent/skill-library/surface/web/offline-first-pwa/SKILL.md +657 -0
- package/template/.agent/skill-library/surface/web/page-cro/SKILL.md +182 -0
- package/template/.agent/skill-library/surface/web/page-cro/references/experiments.md +248 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/SKILL.md +238 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/references/playbooks.md +308 -0
- package/template/.agent/skill-library/surface/web/schema-markup/SKILL.md +179 -0
- package/template/.agent/skill-library/surface/web/schema-markup/references/schema-examples.md +398 -0
- package/template/.agent/skill-library/surface/web/seo-audit/SKILL.md +394 -0
- package/template/.agent/skill-library/surface/web/seo-audit/references/ai-writing-detection.md +200 -0
- package/template/.agent/skill-library/surface/web/web-performance-optimization/SKILL.md +646 -0
- package/template/.agent/skill-library/surface/web/web-scraping/SKILL.md +58 -0
- package/template/.agent/skills/accessibility/SKILL.md +522 -0
- package/template/.agent/skills/accessibility/references/WCAG.md +162 -0
- package/template/.agent/skills/adversarial-review/SKILL.md +90 -0
- package/template/.agent/skills/antigravity-workflows/SKILL.md +81 -0
- package/template/.agent/skills/antigravity-workflows/resources/implementation-playbook.md +36 -0
- package/template/.agent/skills/api-design-principles/SKILL.md +37 -0
- package/template/.agent/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/template/.agent/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/template/.agent/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/template/.agent/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/template/.agent/skills/api-design-principles/resources/implementation-playbook.md +513 -0
- package/template/.agent/skills/api-versioning/SKILL.md +420 -0
- package/template/.agent/skills/architecture-mapping/SKILL.md +219 -0
- package/template/.agent/skills/bootstrap-agents/SKILL.md +259 -0
- package/template/.agent/skills/brainstorming/SKILL.md +236 -0
- package/template/.agent/skills/brand-guidelines/SKILL.md +44 -0
- package/template/.agent/skills/clean-code/SKILL.md +94 -0
- package/template/.agent/skills/code-review-pro/SKILL.md +152 -0
- package/template/.agent/skills/concise-planning/SKILL.md +68 -0
- package/template/.agent/skills/cross-layer-consistency/SKILL.md +117 -0
- package/template/.agent/skills/database-schema-design/SKILL.md +429 -0
- package/template/.agent/skills/deployment-procedures/SKILL.md +241 -0
- package/template/.agent/skills/design-anti-cliche/SKILL.md +159 -0
- package/template/.agent/skills/design-direction/SKILL.md +45 -0
- package/template/.agent/skills/error-handling-patterns/SKILL.md +721 -0
- package/template/.agent/skills/find-skills/SKILL.md +145 -0
- package/template/.agent/skills/git-advanced/SKILL.md +972 -0
- package/template/.agent/skills/git-workflow/SKILL.md +420 -0
- package/template/.agent/skills/idea-extraction/SKILL.md +271 -0
- package/template/.agent/skills/logging-best-practices/SKILL.md +851 -0
- package/template/.agent/skills/migration-management/SKILL.md +384 -0
- package/template/.agent/skills/minimalist-surgical-development/SKILL.md +69 -0
- package/template/.agent/skills/parallel-agents/SKILL.md +165 -0
- package/template/.agent/skills/parallel-debugging/SKILL.md +135 -0
- package/template/.agent/skills/parallel-feature-development/SKILL.md +166 -0
- package/template/.agent/skills/performance-budgeting/SKILL.md +144 -0
- package/template/.agent/skills/pipeline-rubrics/SKILL.md +51 -0
- package/template/.agent/skills/pipeline-rubrics/references/architecture-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/be-rubric.md +21 -0
- package/template/.agent/skills/pipeline-rubrics/references/fe-rubric.md +20 -0
- package/template/.agent/skills/pipeline-rubrics/references/ia-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/scoring.md +28 -0
- package/template/.agent/skills/pipeline-rubrics/references/vision-rubric.md +11 -0
- package/template/.agent/skills/prd-templates/SKILL.md +88 -0
- package/template/.agent/skills/prd-templates/references/architecture-design-template.md +88 -0
- package/template/.agent/skills/prd-templates/references/be-spec-template.md +101 -0
- package/template/.agent/skills/prd-templates/references/data-placement-template.md +74 -0
- package/template/.agent/skills/prd-templates/references/decomposition-templates.md +211 -0
- package/template/.agent/skills/prd-templates/references/design-system-decisions.md +198 -0
- package/template/.agent/skills/prd-templates/references/engineering-standards-template.md +124 -0
- package/template/.agent/skills/prd-templates/references/fe-classification-procedures.md +47 -0
- package/template/.agent/skills/prd-templates/references/fe-spec-template.md +84 -0
- package/template/.agent/skills/prd-templates/references/infrastructure-report-template.md +71 -0
- package/template/.agent/skills/prd-templates/references/operational-templates.md +116 -0
- package/template/.agent/skills/prd-templates/references/placeholder-guard-template.md +21 -0
- package/template/.agent/skills/prd-templates/references/surface-model.md +61 -0
- package/template/.agent/skills/prd-templates/references/vision-template.md +66 -0
- package/template/.agent/skills/prompt-engineer/README.md +659 -0
- package/template/.agent/skills/prompt-engineer/SKILL.md +249 -0
- package/template/.agent/skills/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skills/resolve-ambiguity/SKILL.md +278 -0
- package/template/.agent/skills/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skills/security-scanning-security-hardening/SKILL.md +231 -0
- package/template/.agent/skills/session-continuity/SKILL.md +730 -0
- package/template/.agent/skills/session-continuity/protocols/01-session-resumption.md +38 -0
- package/template/.agent/skills/session-continuity/protocols/02-progress-generation.md +85 -0
- package/template/.agent/skills/session-continuity/protocols/03-progress-update.md +70 -0
- package/template/.agent/skills/session-continuity/protocols/04-pattern-extraction.md +60 -0
- package/template/.agent/skills/session-continuity/protocols/05-session-close.md +37 -0
- package/template/.agent/skills/session-continuity/protocols/06-decision-analysis.md +84 -0
- package/template/.agent/skills/session-continuity/protocols/07-spec-pipeline-generation.md +48 -0
- package/template/.agent/skills/session-continuity/protocols/08-spec-pipeline-update.md +43 -0
- package/template/.agent/skills/session-continuity/protocols/09-parallel-claim.md +122 -0
- package/template/.agent/skills/session-continuity/protocols/10-placeholder-verification-gate.md +104 -0
- package/template/.agent/skills/session-continuity/protocols/ambiguity-gates.md +48 -0
- package/template/.agent/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.agent/skills/skill-creator/README.md +270 -0
- package/template/.agent/skills/skill-creator/SKILL.md +590 -0
- package/template/.agent/skills/skill-creator/references/output-patterns.md +82 -0
- package/template/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/template/.agent/skills/skill-creator/scripts/init_skill.py +303 -0
- package/template/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/template/.agent/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/template/.agent/skills/spec-writing/SKILL.md +110 -0
- package/template/.agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/template/.agent/skills/systematic-debugging/SKILL.md +297 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/template/.agent/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/template/.agent/skills/systematic-debugging/find-polluter.sh +63 -0
- package/template/.agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/template/.agent/skills/systematic-debugging/test-academic.md +14 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/template/.agent/skills/tdd-workflow/SKILL.md +409 -0
- package/template/.agent/skills/tech-stack-catalog/SKILL.md +49 -0
- package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +21 -0
- package/template/.agent/skills/tech-stack-catalog/references/dev-tooling-decisions.md +37 -0
- package/template/.agent/skills/tech-stack-catalog/references/surface-decision-tables.md +69 -0
- package/template/.agent/skills/technical-writer/SKILL.md +242 -0
- package/template/.agent/skills/testing-strategist/SKILL.md +932 -0
- package/template/.agent/skills/verification-before-completion/SKILL.md +145 -0
- package/template/.agent/skills/workflow-automation/SKILL.md +73 -0
- package/template/.agent/workflows/audit-ambiguity-execute.md +165 -0
- package/template/.agent/workflows/audit-ambiguity-rubrics.md +83 -0
- package/template/.agent/workflows/audit-ambiguity.md +64 -0
- package/template/.agent/workflows/bootstrap-agents-fill.md +201 -0
- package/template/.agent/workflows/bootstrap-agents-provision.md +197 -0
- package/template/.agent/workflows/bootstrap-agents.md +66 -0
- package/template/.agent/workflows/create-prd-architecture.md +119 -0
- package/template/.agent/workflows/create-prd-compile.md +138 -0
- package/template/.agent/workflows/create-prd-design-system.md +135 -0
- package/template/.agent/workflows/create-prd-security.md +113 -0
- package/template/.agent/workflows/create-prd-stack.md +91 -0
- package/template/.agent/workflows/create-prd.md +168 -0
- package/template/.agent/workflows/decompose-architecture-structure.md +82 -0
- package/template/.agent/workflows/decompose-architecture-validate.md +119 -0
- package/template/.agent/workflows/decompose-architecture.md +111 -0
- package/template/.agent/workflows/evolve-contract.md +98 -0
- package/template/.agent/workflows/evolve-feature-cascade.md +140 -0
- package/template/.agent/workflows/evolve-feature-classify.md +116 -0
- package/template/.agent/workflows/evolve-feature.md +56 -0
- package/template/.agent/workflows/ideate-discover.md +144 -0
- package/template/.agent/workflows/ideate-extract.md +129 -0
- package/template/.agent/workflows/ideate-validate.md +117 -0
- package/template/.agent/workflows/ideate.md +113 -0
- package/template/.agent/workflows/implement-slice-setup.md +113 -0
- package/template/.agent/workflows/implement-slice-tdd.md +198 -0
- package/template/.agent/workflows/implement-slice.md +50 -0
- package/template/.agent/workflows/plan-phase.md +202 -0
- package/template/.agent/workflows/propagate-decision-apply.md +135 -0
- package/template/.agent/workflows/propagate-decision-scan.md +147 -0
- package/template/.agent/workflows/propagate-decision.md +56 -0
- package/template/.agent/workflows/remediate-pipeline-assess.md +138 -0
- package/template/.agent/workflows/remediate-pipeline-execute.md +135 -0
- package/template/.agent/workflows/remediate-pipeline.md +55 -0
- package/template/.agent/workflows/resolve-ambiguity.md +82 -0
- package/template/.agent/workflows/sync-kit.md +209 -0
- package/template/.agent/workflows/update-architecture-map.md +74 -0
- package/template/.agent/workflows/validate-phase.md +219 -0
- package/template/.agent/workflows/verify-infrastructure.md +207 -0
- package/template/.agent/workflows/write-architecture-spec-deepen.md +139 -0
- package/template/.agent/workflows/write-architecture-spec-design.md +202 -0
- package/template/.agent/workflows/write-architecture-spec.md +63 -0
- package/template/.agent/workflows/write-be-spec-classify.md +165 -0
- package/template/.agent/workflows/write-be-spec-write.md +98 -0
- package/template/.agent/workflows/write-be-spec.md +76 -0
- package/template/.agent/workflows/write-fe-spec-classify.md +170 -0
- package/template/.agent/workflows/write-fe-spec-write.md +94 -0
- package/template/.agent/workflows/write-fe-spec.md +71 -0
- package/template/AGENTS.md +176 -0
- package/template/GEMINI.md +177 -0
- package/template/docs/README.md +187 -0
- package/template/docs/audits/.gitkeep +0 -0
- package/template/docs/audits/README.md +10 -0
- package/template/docs/plans/.gitkeep +0 -0
- package/template/docs/plans/README.md +21 -0
- package/template/docs/plans/be/.gitkeep +0 -0
- package/template/docs/plans/be/README.md +11 -0
- package/template/docs/plans/fe/.gitkeep +0 -0
- package/template/docs/plans/fe/README.md +11 -0
- package/template/docs/plans/ia/.gitkeep +0 -0
- package/template/docs/plans/ia/README.md +17 -0
- package/template/docs/plans/ia/deep-dives/.gitkeep +0 -0
- package/template/docs/plans/ia/deep-dives/README.md +5 -0
- package/template/docs/plans/phases/.gitkeep +0 -0
- package/template/docs/plans/phases/README.md +11 -0
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-caching
|
|
3
|
+
description: "Implement HTTP caching with Cache-Control, ETags, conditional requests, CDN invalidation, Vary headers, and application-level caching with Redis. Use when optimizing API response times, reducing server load, or designing cache invalidation strategies."
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# API Caching Strategies
|
|
8
|
+
|
|
9
|
+
Caching is the single highest-impact optimization for API performance. Done correctly, it reduces latency, server load, and bandwidth. Done incorrectly, it serves stale data and causes debugging nightmares.
|
|
10
|
+
|
|
11
|
+
## Cache-Control Directives
|
|
12
|
+
|
|
13
|
+
### Directive Reference
|
|
14
|
+
|
|
15
|
+
| Directive | Meaning | Example |
|
|
16
|
+
|-----------|---------|---------|
|
|
17
|
+
| `max-age=N` | Cache is fresh for N seconds | `max-age=3600` (1 hour) |
|
|
18
|
+
| `s-maxage=N` | CDN/proxy cache lifetime (overrides max-age for shared caches) | `s-maxage=86400` (1 day) |
|
|
19
|
+
| `no-cache` | Must revalidate with server before using (NOT "don't cache") | Conditional requests |
|
|
20
|
+
| `no-store` | Do not cache at all (sensitive data) | Auth responses, PII |
|
|
21
|
+
| `private` | Only browser may cache (not CDN/proxy) | User-specific data |
|
|
22
|
+
| `public` | Any cache may store (CDN, proxy, browser) | Public catalog data |
|
|
23
|
+
| `must-revalidate` | After max-age expires, must revalidate (no stale serving) | Critical data accuracy |
|
|
24
|
+
| `stale-while-revalidate=N` | Serve stale for N seconds while revalidating in background | Semi-fresh content |
|
|
25
|
+
| `stale-if-error=N` | Serve stale for N seconds if origin returns 5xx | Resilience |
|
|
26
|
+
| `immutable` | Content will never change (versioned assets) | `/assets/main.a1b2c3.js` |
|
|
27
|
+
|
|
28
|
+
### Common Patterns
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// Static assets with content hash (cache forever)
|
|
32
|
+
response.headers.set('Cache-Control', 'public, max-age=31536000, immutable');
|
|
33
|
+
|
|
34
|
+
// Public API data that changes occasionally
|
|
35
|
+
response.headers.set('Cache-Control', 'public, max-age=60, s-maxage=300, stale-while-revalidate=600');
|
|
36
|
+
|
|
37
|
+
// User-specific data (browser only, revalidate often)
|
|
38
|
+
response.headers.set('Cache-Control', 'private, max-age=0, must-revalidate');
|
|
39
|
+
|
|
40
|
+
// Sensitive data (never cache)
|
|
41
|
+
response.headers.set('Cache-Control', 'no-store');
|
|
42
|
+
|
|
43
|
+
// API list that can be slightly stale
|
|
44
|
+
response.headers.set('Cache-Control', 'public, s-maxage=60, stale-while-revalidate=120, stale-if-error=300');
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## ETags and Conditional Requests
|
|
50
|
+
|
|
51
|
+
ETags let clients ask "has this changed?" without downloading the full response.
|
|
52
|
+
|
|
53
|
+
### ETag Generation
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { createHash } from 'node:crypto';
|
|
57
|
+
|
|
58
|
+
function generateETag(content: string | Buffer): string {
|
|
59
|
+
const hash = createHash('md5').update(content).digest('hex');
|
|
60
|
+
return `"${hash}"`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// For database records, use version or updated timestamp
|
|
64
|
+
function recordETag(record: { id: string; updatedAt: Date }): string {
|
|
65
|
+
return `"${record.id}-${record.updatedAt.getTime()}"`;
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Conditional Request Handling
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
export async function GET({ request }: APIContext) {
|
|
73
|
+
const model = await getModel(id);
|
|
74
|
+
if (!model) return new Response(null, { status: 404 });
|
|
75
|
+
|
|
76
|
+
const etag = recordETag(model);
|
|
77
|
+
|
|
78
|
+
// If-None-Match: client has a cached version
|
|
79
|
+
const ifNoneMatch = request.headers.get('If-None-Match');
|
|
80
|
+
if (ifNoneMatch === etag) {
|
|
81
|
+
// Content has not changed --- return 304 with no body
|
|
82
|
+
return new Response(null, {
|
|
83
|
+
status: 304,
|
|
84
|
+
headers: { 'ETag': etag, 'Cache-Control': 'private, max-age=0, must-revalidate' },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const body = JSON.stringify(model);
|
|
89
|
+
return new Response(body, {
|
|
90
|
+
status: 200,
|
|
91
|
+
headers: {
|
|
92
|
+
'Content-Type': 'application/json',
|
|
93
|
+
'ETag': etag,
|
|
94
|
+
'Cache-Control': 'private, max-age=0, must-revalidate',
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Weak vs Strong ETags
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// Strong ETag: byte-for-byte identical
|
|
104
|
+
const strongETag = `"a1b2c3d4"`;
|
|
105
|
+
|
|
106
|
+
// Weak ETag: semantically equivalent (minor formatting differences OK)
|
|
107
|
+
const weakETag = `W/"a1b2c3d4"`;
|
|
108
|
+
|
|
109
|
+
// Use weak ETags for JSON APIs where field order may vary
|
|
110
|
+
// Use strong ETags for binary content (images, files)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Last-Modified / If-Modified-Since
|
|
116
|
+
|
|
117
|
+
Simpler alternative to ETags for time-based resources.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
export async function GET({ request }: APIContext) {
|
|
121
|
+
const article = await getArticle(id);
|
|
122
|
+
const lastModified = article.updatedAt.toUTCString();
|
|
123
|
+
|
|
124
|
+
const ifModifiedSince = request.headers.get('If-Modified-Since');
|
|
125
|
+
if (ifModifiedSince) {
|
|
126
|
+
const cachedDate = new Date(ifModifiedSince);
|
|
127
|
+
if (article.updatedAt <= cachedDate) {
|
|
128
|
+
return new Response(null, {
|
|
129
|
+
status: 304,
|
|
130
|
+
headers: { 'Last-Modified': lastModified },
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return new Response(JSON.stringify(article), {
|
|
136
|
+
status: 200,
|
|
137
|
+
headers: {
|
|
138
|
+
'Content-Type': 'application/json',
|
|
139
|
+
'Last-Modified': lastModified,
|
|
140
|
+
'Cache-Control': 'public, max-age=60',
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Vary Header
|
|
149
|
+
|
|
150
|
+
The `Vary` header tells caches that the response depends on specific request headers. Without it, a CDN might serve the wrong cached response.
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// Response varies by Accept-Encoding (compression) and Authorization (user)
|
|
154
|
+
response.headers.set('Vary', 'Accept-Encoding, Authorization');
|
|
155
|
+
|
|
156
|
+
// Response varies by API version header
|
|
157
|
+
response.headers.set('Vary', 'API-Version');
|
|
158
|
+
|
|
159
|
+
// Response varies by Accept-Language
|
|
160
|
+
response.headers.set('Vary', 'Accept-Language');
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Common Mistakes with Vary
|
|
164
|
+
|
|
165
|
+
| Mistake | Problem | Fix |
|
|
166
|
+
|---------|---------|-----|
|
|
167
|
+
| `Vary: *` | Effectively disables caching | List specific headers |
|
|
168
|
+
| Missing `Vary: Authorization` on personalized responses | CDN serves user A's data to user B | Always Vary on Authorization for private data |
|
|
169
|
+
| `Vary: Cookie` | Every unique cookie = separate cache entry (cache explosion) | Use `private` instead, or extract specific cookie |
|
|
170
|
+
| Missing `Vary: Accept-Encoding` | Compressed response served to client that cannot decompress | Most CDNs handle this automatically |
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## CDN Cache Invalidation
|
|
175
|
+
|
|
176
|
+
### Purge Strategies
|
|
177
|
+
|
|
178
|
+
| Strategy | How It Works | When to Use |
|
|
179
|
+
|----------|-------------|-------------|
|
|
180
|
+
| **TTL expiry** | Cache expires naturally after max-age | Default for most content |
|
|
181
|
+
| **Surrogate key purge** | Tag responses, purge by tag | Purge all "product" responses when any product changes |
|
|
182
|
+
| **Path purge** | Purge specific URL paths | Single resource updated |
|
|
183
|
+
| **Full purge** | Clear entire CDN cache | Deployment, emergency |
|
|
184
|
+
|
|
185
|
+
### Surrogate Keys (Cache Tags)
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// Tag responses for targeted invalidation
|
|
189
|
+
export async function GET({ params }: APIContext) {
|
|
190
|
+
const model = await getModel(params.id);
|
|
191
|
+
|
|
192
|
+
return new Response(JSON.stringify(model), {
|
|
193
|
+
headers: {
|
|
194
|
+
'Cache-Control': 'public, s-maxage=3600',
|
|
195
|
+
'Cache-Tag': `model-${params.id} models provider-${model.provider}`,
|
|
196
|
+
// Cloudflare equivalent:
|
|
197
|
+
'Surrogate-Key': `model-${params.id} models provider-${model.provider}`,
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// When a model is updated, purge its cache tag
|
|
203
|
+
async function onModelUpdated(modelId: string): Promise<void> {
|
|
204
|
+
// Cloudflare API
|
|
205
|
+
await fetch(`https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/purge_cache`, {
|
|
206
|
+
method: 'POST',
|
|
207
|
+
headers: {
|
|
208
|
+
'Authorization': `Bearer ${CF_API_TOKEN}`,
|
|
209
|
+
'Content-Type': 'application/json',
|
|
210
|
+
},
|
|
211
|
+
body: JSON.stringify({
|
|
212
|
+
tags: [`model-${modelId}`],
|
|
213
|
+
}),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Stale-While-Revalidate at HTTP Level
|
|
221
|
+
|
|
222
|
+
The `stale-while-revalidate` directive allows CDNs and browsers to serve stale content while fetching fresh content in the background. This gives instant responses with eventual consistency.
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
// CDN serves cached response instantly.
|
|
226
|
+
// If the cache is between 60-660 seconds old, CDN also fetches fresh from origin in background.
|
|
227
|
+
// If the cache is over 660 seconds old, CDN fetches from origin and waits.
|
|
228
|
+
response.headers.set('Cache-Control', 'public, s-maxage=60, stale-while-revalidate=600');
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### When to Use
|
|
232
|
+
|
|
233
|
+
| Content | Fresh (s-maxage) | Stale-While-Revalidate | Total |
|
|
234
|
+
|---------|-----------------|----------------------|-------|
|
|
235
|
+
| Model catalog | 60s | 600s | 11 min |
|
|
236
|
+
| User profile (public) | 30s | 300s | 5.5 min |
|
|
237
|
+
| Blog posts | 300s | 3600s | 65 min |
|
|
238
|
+
| Static config | 3600s | 86400s | 25 hours |
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Cache Key Design
|
|
243
|
+
|
|
244
|
+
The cache key determines which requests share a cached response. Poor key design leads to either stale data (too broad) or cache misses (too narrow).
|
|
245
|
+
|
|
246
|
+
### Default Cache Key
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
scheme + host + path + query string
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Custom Cache Key Considerations
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// These requests should share a cache entry:
|
|
256
|
+
// GET /api/v1/models?sort=name
|
|
257
|
+
// GET /api/v1/models?sort=name (identical)
|
|
258
|
+
|
|
259
|
+
// These should NOT share:
|
|
260
|
+
// GET /api/v1/models?sort=name
|
|
261
|
+
// GET /api/v1/models?sort=price (different query param value)
|
|
262
|
+
|
|
263
|
+
// Normalize query params for consistent cache keys
|
|
264
|
+
function normalizeUrl(url: URL): string {
|
|
265
|
+
const params = new URLSearchParams(url.searchParams);
|
|
266
|
+
// Sort params alphabetically for consistent keys
|
|
267
|
+
const sorted = new URLSearchParams([...params.entries()].sort());
|
|
268
|
+
// Remove cache-busting params
|
|
269
|
+
sorted.delete('_');
|
|
270
|
+
sorted.delete('t');
|
|
271
|
+
return `${url.pathname}?${sorted.toString()}`;
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Cache Key Pitfalls
|
|
276
|
+
|
|
277
|
+
| Pitfall | Problem | Fix |
|
|
278
|
+
|---------|---------|-----|
|
|
279
|
+
| Authorization in cache key | Every user gets their own cache entry | Use `private` or strip auth from key |
|
|
280
|
+
| Random query params (`?_=timestamp`) | Cache never hits | Strip cache-busting params at CDN |
|
|
281
|
+
| Case-sensitive paths | `/API/Models` and `/api/models` are different keys | Normalize to lowercase |
|
|
282
|
+
| Trailing slashes | `/api/models` and `/api/models/` are different keys | Redirect one to the other |
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Application-Level Caching (Redis / In-Memory)
|
|
287
|
+
|
|
288
|
+
### Redis Caching Pattern
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { Redis } from 'ioredis';
|
|
292
|
+
|
|
293
|
+
const redis = new Redis(process.env.REDIS_URL);
|
|
294
|
+
|
|
295
|
+
async function cachedQuery<T>(
|
|
296
|
+
key: string,
|
|
297
|
+
ttlSeconds: number,
|
|
298
|
+
fetcher: () => Promise<T>
|
|
299
|
+
): Promise<T> {
|
|
300
|
+
// Try cache first
|
|
301
|
+
const cached = await redis.get(key);
|
|
302
|
+
if (cached) {
|
|
303
|
+
return JSON.parse(cached) as T;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Cache miss: fetch from source
|
|
307
|
+
const data = await fetcher();
|
|
308
|
+
|
|
309
|
+
// Store in cache (non-blocking)
|
|
310
|
+
redis.setex(key, ttlSeconds, JSON.stringify(data)).catch((err) => {
|
|
311
|
+
console.error('Cache write failed:', err);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
return data;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Usage
|
|
318
|
+
const models = await cachedQuery(
|
|
319
|
+
'models:list:active',
|
|
320
|
+
300, // 5 minutes
|
|
321
|
+
() => db.query('SELECT * FROM models WHERE status = $1', ['active'])
|
|
322
|
+
);
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Cache Invalidation
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
// Invalidate specific key
|
|
329
|
+
await redis.del('models:list:active');
|
|
330
|
+
|
|
331
|
+
// Invalidate by pattern (use with caution --- SCAN, not KEYS)
|
|
332
|
+
async function invalidatePattern(pattern: string): Promise<void> {
|
|
333
|
+
let cursor = '0';
|
|
334
|
+
do {
|
|
335
|
+
const [nextCursor, keys] = await redis.scan(cursor, 'MATCH', pattern, 'COUNT', 100);
|
|
336
|
+
cursor = nextCursor;
|
|
337
|
+
if (keys.length > 0) {
|
|
338
|
+
await redis.del(...keys);
|
|
339
|
+
}
|
|
340
|
+
} while (cursor !== '0');
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Invalidate all model caches
|
|
344
|
+
await invalidatePattern('models:*');
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### In-Memory Cache (Single-Instance)
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
class MemoryCache<T> {
|
|
351
|
+
private cache = new Map<string, { data: T; expiresAt: number }>();
|
|
352
|
+
|
|
353
|
+
get(key: string): T | null {
|
|
354
|
+
const entry = this.cache.get(key);
|
|
355
|
+
if (!entry) return null;
|
|
356
|
+
if (Date.now() > entry.expiresAt) {
|
|
357
|
+
this.cache.delete(key);
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
return entry.data;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
set(key: string, data: T, ttlMs: number): void {
|
|
364
|
+
this.cache.set(key, { data, expiresAt: Date.now() + ttlMs });
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
delete(key: string): void {
|
|
368
|
+
this.cache.delete(key);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Cache Warming
|
|
376
|
+
|
|
377
|
+
Pre-populate caches for high-traffic endpoints to avoid cold-start cache misses.
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
// Run after deployment or on a schedule
|
|
381
|
+
async function warmCaches(): Promise<void> {
|
|
382
|
+
const popularModels = await db.query('SELECT id FROM models ORDER BY request_count DESC LIMIT 50');
|
|
383
|
+
|
|
384
|
+
await Promise.all(
|
|
385
|
+
popularModels.map(async (model) => {
|
|
386
|
+
const data = await getModelDetails(model.id);
|
|
387
|
+
await redis.setex(`model:${model.id}`, 300, JSON.stringify(data));
|
|
388
|
+
})
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
console.log(`Warmed cache for ${popularModels.length} models`);
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## Cache Busting for Deployments
|
|
398
|
+
|
|
399
|
+
### Asset Versioning
|
|
400
|
+
|
|
401
|
+
```html
|
|
402
|
+
<!-- Content hash in filename (best approach) -->
|
|
403
|
+
<script src="/assets/main.a1b2c3d4.js"></script>
|
|
404
|
+
<link rel="stylesheet" href="/assets/styles.e5f6a7b8.css" />
|
|
405
|
+
|
|
406
|
+
<!-- These are immutable: cache forever -->
|
|
407
|
+
<!-- Cache-Control: public, max-age=31536000, immutable -->
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### API Cache Busting
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
// After deploying a new API version, purge CDN cache
|
|
414
|
+
async function postDeploymentPurge(): Promise<void> {
|
|
415
|
+
await purgeByTag('api-responses');
|
|
416
|
+
await warmCaches();
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Response-Level vs Data-Level Caching
|
|
423
|
+
|
|
424
|
+
| Level | Where | What | TTL | Invalidation |
|
|
425
|
+
|-------|-------|------|-----|-------------|
|
|
426
|
+
| **CDN/HTTP** | Cloudflare, Fastly | Full HTTP response | Minutes to hours | Surrogate key purge |
|
|
427
|
+
| **Application** | Redis, Memcached | Serialized data | Seconds to minutes | On write/update |
|
|
428
|
+
| **Query** | Database query cache | Raw query results | Seconds | On schema change |
|
|
429
|
+
| **Computed** | In-memory | Derived/computed values | Seconds | On dependency change |
|
|
430
|
+
|
|
431
|
+
**Layer them together:**
|
|
432
|
+
```
|
|
433
|
+
Client → CDN (s-maxage) → App Server (Redis) → Database
|
|
434
|
+
↓ HIT? serve ↓ HIT? serve ↓ query
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## Anti-Patterns
|
|
440
|
+
|
|
441
|
+
| Anti-Pattern | Problem | Fix |
|
|
442
|
+
|-------------|---------|-----|
|
|
443
|
+
| `no-cache` thinking it means "don't cache" | It means "revalidate before use" | Use `no-store` to prevent all caching |
|
|
444
|
+
| Caching responses with `Set-Cookie` | CDN may serve another user's session | `private` or strip cookies at CDN |
|
|
445
|
+
| Same `max-age` for all endpoints | Over-caching dynamic data, under-caching static | Tune per endpoint based on change frequency |
|
|
446
|
+
| No `Vary` header on personalized responses | Wrong data served to wrong user | `Vary: Authorization` or `Cache-Control: private` |
|
|
447
|
+
| Cache invalidation on every write | Defeats the purpose of caching | Use TTL-based expiry, invalidate selectively |
|
|
448
|
+
| `KEYS *` in Redis for invalidation | Blocks Redis server on large keyspaces | Use `SCAN` with cursor |
|
|
449
|
+
| Caching error responses | 500 errors served from cache | Only cache 2xx responses |
|
|
450
|
+
| No cache-busting on deploys | Users get stale JS/CSS after deploy | Content-hash filenames + immutable |
|
|
451
|
+
|
|
452
|
+
## References
|
|
453
|
+
|
|
454
|
+
- [MDN: Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control)
|
|
455
|
+
- [MDN: ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag)
|
|
456
|
+
- [HTTP Caching (web.dev)](https://web.dev/http-cache/)
|
|
457
|
+
- [Cloudflare Cache Documentation](https://developers.cloudflare.com/cache/)
|
|
458
|
+
- [Heroku: HTTP Caching](https://devcenter.heroku.com/articles/increasing-application-performance-with-http-cache-headers)
|