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,420 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-versioning
|
|
3
|
+
description: "Manage API versioning and evolution with URL/header/query strategies, deprecation workflows, breaking change classification, sunset headers, and consumer-driven contract testing. Use when designing versioning strategy, deprecating endpoints, or evolving API contracts."
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# API Versioning & Evolution
|
|
8
|
+
|
|
9
|
+
APIs are contracts with consumers. Breaking that contract destroys trust. This skill covers how to version, evolve, and deprecate APIs without breaking clients.
|
|
10
|
+
|
|
11
|
+
## Versioning Strategies
|
|
12
|
+
|
|
13
|
+
### Strategy Comparison
|
|
14
|
+
|
|
15
|
+
| Strategy | Example | Pros | Cons |
|
|
16
|
+
|----------|---------|------|------|
|
|
17
|
+
| **URL path** | `/api/v2/models` | Obvious, cacheable, easy routing | URL represents resource not version; copies endpoints |
|
|
18
|
+
| **Header** | `API-Version: 2` | Clean URLs, content negotiation | Hidden from browser, harder to test |
|
|
19
|
+
| **Query param** | `/api/models?version=2` | Easy to test, no routing changes | Pollutes query string, cache key complexity |
|
|
20
|
+
| **Accept header** | `Accept: application/vnd.api.v2+json` | Proper content negotiation | Verbose, often misunderstood |
|
|
21
|
+
|
|
22
|
+
### Recommendation
|
|
23
|
+
|
|
24
|
+
Use **URL path versioning** for public APIs (simplicity and discoverability). Use **header versioning** for internal/partner APIs (cleaner resource model).
|
|
25
|
+
|
|
26
|
+
### URL Path Versioning
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
// src/pages/api/v1/models/[id].ts
|
|
30
|
+
export async function GET({ params }: APIContext) {
|
|
31
|
+
// V1 response shape
|
|
32
|
+
return new Response(JSON.stringify({
|
|
33
|
+
id: params.id,
|
|
34
|
+
name: model.name,
|
|
35
|
+
provider: model.provider,
|
|
36
|
+
// V1 had a flat pricing field
|
|
37
|
+
price_per_token: model.pricePerToken,
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/pages/api/v2/models/[id].ts
|
|
42
|
+
export async function GET({ params }: APIContext) {
|
|
43
|
+
// V2 response shape (nested pricing)
|
|
44
|
+
return new Response(JSON.stringify({
|
|
45
|
+
id: params.id,
|
|
46
|
+
name: model.name,
|
|
47
|
+
provider: model.provider,
|
|
48
|
+
// V2 has structured pricing
|
|
49
|
+
pricing: {
|
|
50
|
+
input: model.inputPrice,
|
|
51
|
+
output: model.outputPrice,
|
|
52
|
+
currency: 'USD',
|
|
53
|
+
unit: 'per_million_tokens',
|
|
54
|
+
},
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Header Versioning
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// Version routing middleware
|
|
63
|
+
function versionRouter(handlers: Record<string, Handler>): Handler {
|
|
64
|
+
return async (context) => {
|
|
65
|
+
const version = context.request.headers.get('API-Version')
|
|
66
|
+
?? context.url.searchParams.get('version')
|
|
67
|
+
?? DEFAULT_VERSION;
|
|
68
|
+
|
|
69
|
+
const handler = handlers[version];
|
|
70
|
+
if (!handler) {
|
|
71
|
+
return new Response(JSON.stringify({
|
|
72
|
+
type: 'https://api.example.com/problems/unsupported-version',
|
|
73
|
+
title: 'Unsupported API Version',
|
|
74
|
+
status: 400,
|
|
75
|
+
detail: `API version '${version}' is not supported. Supported versions: ${Object.keys(handlers).join(', ')}`,
|
|
76
|
+
}), { status: 400, headers: { 'Content-Type': 'application/problem+json' } });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const response = await handler(context);
|
|
80
|
+
response.headers.set('API-Version', version);
|
|
81
|
+
return response;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Usage
|
|
86
|
+
export const GET = versionRouter({
|
|
87
|
+
'1': handleV1,
|
|
88
|
+
'2': handleV2,
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Default Version Behavior
|
|
95
|
+
|
|
96
|
+
When a client does not specify a version, the API must behave predictably.
|
|
97
|
+
|
|
98
|
+
| Strategy | Behavior | When to Use |
|
|
99
|
+
|----------|----------|-------------|
|
|
100
|
+
| **Default to latest** | Unversioned requests get the newest version | Internal APIs with controlled consumers |
|
|
101
|
+
| **Default to oldest supported** | Unversioned requests get V1 | Public APIs (avoid surprise breakage) |
|
|
102
|
+
| **Require explicit version** | Return 400 if no version specified | Strict APIs where ambiguity is unacceptable |
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const DEFAULT_VERSION = '1'; // Conservative default for public APIs
|
|
106
|
+
|
|
107
|
+
function resolveVersion(request: Request): string {
|
|
108
|
+
return request.headers.get('API-Version')
|
|
109
|
+
?? request.url.searchParams.get('version')
|
|
110
|
+
?? DEFAULT_VERSION;
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Breaking vs Non-Breaking Changes
|
|
117
|
+
|
|
118
|
+
### Non-Breaking (Safe to Ship)
|
|
119
|
+
|
|
120
|
+
| Change | Example | Why It Is Safe |
|
|
121
|
+
|--------|---------|---------------|
|
|
122
|
+
| Add optional field to response | `"avatar_url": "..."` added to user response | Clients ignore unknown fields |
|
|
123
|
+
| Add optional query parameter | `?sort=name` now supported | Existing queries still work |
|
|
124
|
+
| Add new endpoint | `POST /api/v1/webhooks` | Does not affect existing endpoints |
|
|
125
|
+
| Widen accepted input types | Field accepts `string \| number` instead of just `string` | Existing valid inputs remain valid |
|
|
126
|
+
| Add optional request field | `"metadata": {}` now accepted | Existing requests without it still work |
|
|
127
|
+
| Relax validation | Max length changed from 100 to 200 | Previously valid inputs still valid |
|
|
128
|
+
|
|
129
|
+
### Breaking (Requires New Version)
|
|
130
|
+
|
|
131
|
+
| Change | Example | Why It Breaks |
|
|
132
|
+
|--------|---------|---------------|
|
|
133
|
+
| Remove field from response | `price_per_token` removed | Clients reading this field break |
|
|
134
|
+
| Rename field | `price_per_token` renamed to `pricing` | Clients reading old name break |
|
|
135
|
+
| Change field type | `price` from number to object | Parsing breaks |
|
|
136
|
+
| Remove endpoint | `DELETE /api/v1/legacy` | Clients calling it get 404 |
|
|
137
|
+
| Add required request field | `"region"` now required | Existing requests missing it fail |
|
|
138
|
+
| Tighten validation | Max length changed from 200 to 100 | Previously valid inputs now rejected |
|
|
139
|
+
| Change error response format | Different error shape | Client error handling breaks |
|
|
140
|
+
| Change authentication scheme | Bearer token to API key | Auth headers break |
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Additive-Only API Policy
|
|
145
|
+
|
|
146
|
+
The safest evolution strategy: never remove or rename, only add.
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// V1 response (original)
|
|
150
|
+
interface ModelV1 {
|
|
151
|
+
id: string;
|
|
152
|
+
name: string;
|
|
153
|
+
price_per_token: number; // original flat field
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// V1.1 response (additive evolution --- no new version needed)
|
|
157
|
+
interface ModelV1_1 {
|
|
158
|
+
id: string;
|
|
159
|
+
name: string;
|
|
160
|
+
price_per_token: number; // KEPT for backward compatibility
|
|
161
|
+
pricing: { // ADDED new structured field
|
|
162
|
+
input: number;
|
|
163
|
+
output: number;
|
|
164
|
+
currency: string;
|
|
165
|
+
unit: string;
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
// Clients reading price_per_token still work.
|
|
169
|
+
// New clients use pricing object.
|
|
170
|
+
// Remove price_per_token only in V2.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Sunset Headers and Deprecation Workflow
|
|
176
|
+
|
|
177
|
+
### Sunset Header (RFC 8594)
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
function addDeprecationHeaders(response: Response, sunsetDate: string, docUrl: string): Response {
|
|
181
|
+
response.headers.set('Deprecation', 'true');
|
|
182
|
+
response.headers.set('Sunset', sunsetDate); // HTTP date format
|
|
183
|
+
response.headers.set('Link', `<${docUrl}>; rel="sunset"`);
|
|
184
|
+
return response;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Usage
|
|
188
|
+
const response = await handleV1Request(context);
|
|
189
|
+
addDeprecationHeaders(
|
|
190
|
+
response,
|
|
191
|
+
'Sat, 01 Mar 2026 00:00:00 GMT',
|
|
192
|
+
'https://docs.example.com/migration/v1-to-v2'
|
|
193
|
+
);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Deprecation Timeline
|
|
197
|
+
|
|
198
|
+
| Phase | Duration | Actions |
|
|
199
|
+
|-------|----------|---------|
|
|
200
|
+
| **Announce** | T-6 months | Add `Deprecation: true` header, publish migration guide |
|
|
201
|
+
| **Warn** | T-3 months | Add `Sunset` header with date, send email to consumers |
|
|
202
|
+
| **Monitor** | T-1 month | Track usage, notify active consumers directly |
|
|
203
|
+
| **Sunset** | T-0 | Return 410 Gone with migration link |
|
|
204
|
+
| **Remove** | T+3 months | Remove code (keep tests to prevent regression) |
|
|
205
|
+
|
|
206
|
+
### Sunset Response
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
function sunsetResponse(migrationUrl: string): Response {
|
|
210
|
+
return new Response(JSON.stringify({
|
|
211
|
+
type: 'https://api.example.com/problems/gone',
|
|
212
|
+
title: 'API Version Removed',
|
|
213
|
+
status: 410,
|
|
214
|
+
detail: `This API version has been sunset. Please migrate to the latest version.`,
|
|
215
|
+
migrationGuide: migrationUrl,
|
|
216
|
+
}), {
|
|
217
|
+
status: 410,
|
|
218
|
+
headers: {
|
|
219
|
+
'Content-Type': 'application/problem+json',
|
|
220
|
+
'Link': `<${migrationUrl}>; rel="successor-version"`,
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Consumer-Driven Contract Testing
|
|
229
|
+
|
|
230
|
+
Consumers define the contract they depend on. The provider runs these contracts in CI to ensure backward compatibility.
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// consumer-contracts/model-service.contract.test.ts
|
|
234
|
+
import { describe, it, expect } from 'vitest';
|
|
235
|
+
|
|
236
|
+
describe('Model API Contract (Consumer: Dashboard)', () => {
|
|
237
|
+
it('GET /api/v1/models/:id returns expected shape', async () => {
|
|
238
|
+
const response = await fetch(`${API_URL}/api/v1/models/gpt-4`);
|
|
239
|
+
const data = await response.json();
|
|
240
|
+
|
|
241
|
+
// Consumer only depends on these fields --- adding fields is fine
|
|
242
|
+
expect(data).toMatchObject({
|
|
243
|
+
id: expect.any(String),
|
|
244
|
+
name: expect.any(String),
|
|
245
|
+
provider: expect.any(String),
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// These fields must exist with these types
|
|
249
|
+
expect(typeof data.id).toBe('string');
|
|
250
|
+
expect(typeof data.name).toBe('string');
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('returns 404 for unknown model', async () => {
|
|
254
|
+
const response = await fetch(`${API_URL}/api/v1/models/nonexistent`);
|
|
255
|
+
expect(response.status).toBe(404);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Provider CI pipeline runs all consumer contracts before deploy:**
|
|
261
|
+
```yaml
|
|
262
|
+
# .github/workflows/api-deploy.yml
|
|
263
|
+
jobs:
|
|
264
|
+
contract-tests:
|
|
265
|
+
runs-on: ubuntu-latest
|
|
266
|
+
steps:
|
|
267
|
+
- name: Run consumer contracts
|
|
268
|
+
run: pnpm test:contracts
|
|
269
|
+
# Deploy only if contracts pass
|
|
270
|
+
deploy:
|
|
271
|
+
needs: contract-tests
|
|
272
|
+
# ...
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Changelog Automation
|
|
278
|
+
|
|
279
|
+
### Conventional Commits for API Changes
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
feat(api): add /api/v1/webhooks endpoint
|
|
283
|
+
fix(api): correct pagination cursor encoding in /api/v1/models
|
|
284
|
+
deprecate(api): mark /api/v1/legacy/search as deprecated
|
|
285
|
+
breaking(api): remove price_per_token field from /api/v2/models response
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Generated Changelog
|
|
289
|
+
|
|
290
|
+
```markdown
|
|
291
|
+
## API Changelog
|
|
292
|
+
|
|
293
|
+
### v2.3.0 (2026-02-15)
|
|
294
|
+
|
|
295
|
+
#### Added
|
|
296
|
+
- `GET /api/v1/webhooks` - List registered webhooks
|
|
297
|
+
- `POST /api/v1/webhooks` - Register a new webhook
|
|
298
|
+
|
|
299
|
+
#### Deprecated
|
|
300
|
+
- `GET /api/v1/legacy/search` - Use `GET /api/v1/search` instead. Sunset: 2026-08-01.
|
|
301
|
+
|
|
302
|
+
#### Fixed
|
|
303
|
+
- Pagination cursor encoding now handles special characters correctly
|
|
304
|
+
|
|
305
|
+
### v2.0.0 (2026-01-01)
|
|
306
|
+
|
|
307
|
+
#### Breaking Changes
|
|
308
|
+
- Removed `price_per_token` field from model responses. Use `pricing` object instead.
|
|
309
|
+
- See [migration guide](https://docs.example.com/migration/v1-to-v2).
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Migration Guides
|
|
315
|
+
|
|
316
|
+
Every version bump must include a migration guide that covers:
|
|
317
|
+
|
|
318
|
+
```markdown
|
|
319
|
+
# Migrating from API v1 to v2
|
|
320
|
+
|
|
321
|
+
## Timeline
|
|
322
|
+
- **v1 deprecated:** January 1, 2026
|
|
323
|
+
- **v1 sunset:** July 1, 2026
|
|
324
|
+
- **v1 removed:** October 1, 2026
|
|
325
|
+
|
|
326
|
+
## Breaking Changes
|
|
327
|
+
|
|
328
|
+
### Model pricing field restructured
|
|
329
|
+
|
|
330
|
+
**Before (v1):**
|
|
331
|
+
```json
|
|
332
|
+
{ "price_per_token": 0.00003 }
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**After (v2):**
|
|
336
|
+
```json
|
|
337
|
+
{ "pricing": { "input": 0.00001, "output": 0.00003, "currency": "USD", "unit": "per_million_tokens" } }
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Migration steps:**
|
|
341
|
+
1. Update your response type definitions
|
|
342
|
+
2. Replace `model.price_per_token` with `model.pricing.output`
|
|
343
|
+
3. Test with v2 endpoint
|
|
344
|
+
4. Update API-Version header to `2`
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Version Routing Middleware
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
// src/middleware/api-version.ts
|
|
353
|
+
type VersionedHandlers = Record<string, Handler>;
|
|
354
|
+
|
|
355
|
+
export function createVersionedRoute(
|
|
356
|
+
handlers: VersionedHandlers,
|
|
357
|
+
options: {
|
|
358
|
+
defaultVersion?: string;
|
|
359
|
+
deprecated?: Record<string, { sunset: string; migrationUrl: string }>;
|
|
360
|
+
} = {}
|
|
361
|
+
): Handler {
|
|
362
|
+
const { defaultVersion, deprecated = {} } = options;
|
|
363
|
+
|
|
364
|
+
return async (context) => {
|
|
365
|
+
const version = resolveVersion(context.request) ?? defaultVersion;
|
|
366
|
+
|
|
367
|
+
if (!version) {
|
|
368
|
+
return problemResponse({
|
|
369
|
+
type: 'https://api.example.com/problems/version-required',
|
|
370
|
+
title: 'API Version Required',
|
|
371
|
+
status: 400,
|
|
372
|
+
detail: 'Please specify an API version via the API-Version header.',
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (!(version in handlers)) {
|
|
377
|
+
return problemResponse({
|
|
378
|
+
type: 'https://api.example.com/problems/unsupported-version',
|
|
379
|
+
title: 'Unsupported API Version',
|
|
380
|
+
status: 400,
|
|
381
|
+
detail: `Version '${version}' is not supported.`,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const response = await handlers[version](context);
|
|
386
|
+
response.headers.set('API-Version', version);
|
|
387
|
+
|
|
388
|
+
// Add deprecation headers if applicable
|
|
389
|
+
if (version in deprecated) {
|
|
390
|
+
const { sunset, migrationUrl } = deprecated[version];
|
|
391
|
+
response.headers.set('Deprecation', 'true');
|
|
392
|
+
response.headers.set('Sunset', sunset);
|
|
393
|
+
response.headers.set('Link', `<${migrationUrl}>; rel="sunset"`);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return response;
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Anti-Patterns
|
|
404
|
+
|
|
405
|
+
| Anti-Pattern | Correct Approach |
|
|
406
|
+
|-------------|------------------|
|
|
407
|
+
| Increment version for every change | Version only on breaking changes |
|
|
408
|
+
| Remove old version without notice | Follow deprecation timeline (6+ months) |
|
|
409
|
+
| Different versioning per endpoint | Consistent strategy across the entire API |
|
|
410
|
+
| Version in the response body only | Use URL path or headers --- visible and consistent |
|
|
411
|
+
| No default version behavior | Define and document the default |
|
|
412
|
+
| Breaking change without migration guide | Every breaking change needs a guide |
|
|
413
|
+
| No consumer notification | Email, changelog, and headers all used together |
|
|
414
|
+
|
|
415
|
+
## References
|
|
416
|
+
|
|
417
|
+
- [RFC 8594: Sunset Header](https://tools.ietf.org/html/rfc8594)
|
|
418
|
+
- [Stripe API Versioning](https://stripe.com/docs/api/versioning)
|
|
419
|
+
- [Microsoft REST API Guidelines: Versioning](https://github.com/microsoft/api-guidelines)
|
|
420
|
+
- [Pact Contract Testing](https://docs.pact.io/)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: email-best-practices
|
|
3
|
+
description: Use when building email features, emails going to spam, high bounce rates, setting up SPF/DKIM/DMARC authentication, implementing email capture, ensuring compliance (CAN-SPAM, GDPR, CASL), handling webhooks, retry logic, or deciding transactional vs marketing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Email Best Practices
|
|
7
|
+
|
|
8
|
+
Guidance for building deliverable, compliant, user-friendly emails.
|
|
9
|
+
|
|
10
|
+
## Architecture Overview
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
[User] → [Email Form] → [Validation] → [Double Opt-In]
|
|
14
|
+
↓
|
|
15
|
+
[Consent Recorded]
|
|
16
|
+
↓
|
|
17
|
+
[Suppression Check] ←──────────────[Ready to Send]
|
|
18
|
+
↓
|
|
19
|
+
[Idempotent Send + Retry] ──────→ [Email API]
|
|
20
|
+
↓
|
|
21
|
+
[Webhook Events]
|
|
22
|
+
↓
|
|
23
|
+
┌────────┬────────┬─────────────┐
|
|
24
|
+
↓ ↓ ↓ ↓
|
|
25
|
+
Delivered Bounced Complained Opened/Clicked
|
|
26
|
+
↓ ↓
|
|
27
|
+
[Suppression List Updated]
|
|
28
|
+
↓
|
|
29
|
+
[List Hygiene Jobs]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Reference
|
|
33
|
+
|
|
34
|
+
| Need to... | See |
|
|
35
|
+
|------------|-----|
|
|
36
|
+
| Set up SPF/DKIM/DMARC, fix spam issues | [Deliverability](./resources/deliverability.md) |
|
|
37
|
+
| Build password reset, OTP, confirmations | [Transactional Emails](./resources/transactional-emails.md) |
|
|
38
|
+
| Plan which emails your app needs | [Transactional Email Catalog](./resources/transactional-email-catalog.md) |
|
|
39
|
+
| Build newsletter signup, validate emails | [Email Capture](./resources/email-capture.md) |
|
|
40
|
+
| Send newsletters, promotions | [Marketing Emails](./resources/marketing-emails.md) |
|
|
41
|
+
| Ensure CAN-SPAM/GDPR/CASL compliance | [Compliance](./resources/compliance.md) |
|
|
42
|
+
| Decide transactional vs marketing | [Email Types](./resources/email-types.md) |
|
|
43
|
+
| Handle retries, idempotency, errors | [Sending Reliability](./resources/sending-reliability.md) |
|
|
44
|
+
| Process delivery events, set up webhooks | [Webhooks & Events](./resources/webhooks-events.md) |
|
|
45
|
+
| Manage bounces, complaints, suppression | [List Management](./resources/list-management.md) |
|
|
46
|
+
|
|
47
|
+
## Start Here
|
|
48
|
+
|
|
49
|
+
**New app?**
|
|
50
|
+
Start with the [Catalog](./resources/transactional-email-catalog.md) to plan which emails your app needs (password reset, verification, etc.), then set up [Deliverability](./resources/deliverability.md) (DNS authentication) before sending your first email.
|
|
51
|
+
|
|
52
|
+
**Spam issues?**
|
|
53
|
+
Check [Deliverability](./resources/deliverability.md) first—authentication problems are the most common cause. Gmail/Yahoo reject unauthenticated emails.
|
|
54
|
+
|
|
55
|
+
**Marketing emails?**
|
|
56
|
+
Follow this path: [Email Capture](./resources/email-capture.md) (collect consent) → [Compliance](./resources/compliance.md) (legal requirements) → [Marketing Emails](./resources/marketing-emails.md) (best practices).
|
|
57
|
+
|
|
58
|
+
**Production-ready sending?**
|
|
59
|
+
Add reliability: [Sending Reliability](./resources/sending-reliability.md) (retry + idempotency) → [Webhooks & Events](./resources/webhooks-events.md) (track delivery) → [List Management](./resources/list-management.md) (handle bounces).
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rate-limiting-abuse-protection
|
|
3
|
+
description: Implements rate limiting and abuse prevention with per-route policies, IP/user-based limits, sliding windows, safe error responses, and observability. Use when adding "rate limiting", "API protection", "abuse prevention", or "DDoS protection".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rate Limiting & Abuse Protection
|
|
7
|
+
|
|
8
|
+
Protect APIs from abuse with intelligent rate limiting.
|
|
9
|
+
|
|
10
|
+
## Rate Limit Strategies
|
|
11
|
+
|
|
12
|
+
**Fixed Window**: 100 requests per hour
|
|
13
|
+
**Sliding Window**: More accurate, prevents bursts
|
|
14
|
+
**Token Bucket**: Allow bursts up to limit
|
|
15
|
+
**Leaky Bucket**: Smooth request rate
|
|
16
|
+
|
|
17
|
+
## Implementation (Express)
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import rateLimit from "express-rate-limit";
|
|
21
|
+
|
|
22
|
+
// Global rate limit
|
|
23
|
+
const globalLimiter = rateLimit({
|
|
24
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
25
|
+
max: 100, // 100 requests per window
|
|
26
|
+
message: "Too many requests, please try again later",
|
|
27
|
+
standardHeaders: true, // Return rate limit info in headers
|
|
28
|
+
legacyHeaders: false,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Stricter limit for auth endpoints
|
|
32
|
+
const authLimiter = rateLimit({
|
|
33
|
+
windowMs: 15 * 60 * 1000,
|
|
34
|
+
max: 5, // Only 5 attempts
|
|
35
|
+
skipSuccessfulRequests: true, // Don't count successful logins
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
app.use("/api/", globalLimiter);
|
|
39
|
+
app.use("/api/auth/login", authLimiter);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Redis-based Rate Limiting
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import Redis from "ioredis";
|
|
46
|
+
|
|
47
|
+
const redis = new Redis();
|
|
48
|
+
|
|
49
|
+
export const checkRateLimit = async (
|
|
50
|
+
key: string,
|
|
51
|
+
max: number,
|
|
52
|
+
window: number
|
|
53
|
+
): Promise<{ allowed: boolean; remaining: number }> => {
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
const windowStart = now - window;
|
|
56
|
+
|
|
57
|
+
await redis
|
|
58
|
+
.multi()
|
|
59
|
+
.zremrangebyscore(key, 0, windowStart)
|
|
60
|
+
.zadd(key, now, `${now}`)
|
|
61
|
+
.zcard(key)
|
|
62
|
+
.expire(key, Math.ceil(window / 1000))
|
|
63
|
+
.exec();
|
|
64
|
+
|
|
65
|
+
const count = await redis.zcard(key);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
allowed: count <= max,
|
|
69
|
+
remaining: Math.max(0, max - count),
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Per-User Rate Limiting
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
export const userRateLimit = (max: number, window: number) => {
|
|
78
|
+
return async (req, res, next) => {
|
|
79
|
+
if (!req.user) return next();
|
|
80
|
+
|
|
81
|
+
const key = `rate_limit:user:${req.user.id}`;
|
|
82
|
+
const result = await checkRateLimit(key, max, window);
|
|
83
|
+
|
|
84
|
+
res.setHeader("X-RateLimit-Limit", max);
|
|
85
|
+
res.setHeader("X-RateLimit-Remaining", result.remaining);
|
|
86
|
+
|
|
87
|
+
if (!result.allowed) {
|
|
88
|
+
return res.status(429).json({
|
|
89
|
+
error: "Rate limit exceeded",
|
|
90
|
+
retryAfter: window / 1000,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
next();
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## IP-based Protection
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// Block suspicious IPs
|
|
103
|
+
const ipBlocklist = new Set<string>();
|
|
104
|
+
|
|
105
|
+
export const checkIPReputation = async (ip: string): Promise<boolean> => {
|
|
106
|
+
if (ipBlocklist.has(ip)) return false;
|
|
107
|
+
|
|
108
|
+
// Check against threat intelligence API
|
|
109
|
+
const reputation = await checkThreatIntel(ip);
|
|
110
|
+
if (reputation.isMalicious) {
|
|
111
|
+
ipBlocklist.add(ip);
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return true;
|
|
116
|
+
};
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Response Headers
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
X-RateLimit-Limit: 100
|
|
123
|
+
X-RateLimit-Remaining: 95
|
|
124
|
+
X-RateLimit-Reset: 1640000000
|
|
125
|
+
Retry-After: 3600
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Best Practices
|
|
129
|
+
|
|
130
|
+
- Different limits for different endpoints
|
|
131
|
+
- Lower limits for expensive operations
|
|
132
|
+
- Skip rate limit for internal services
|
|
133
|
+
- Return helpful error messages
|
|
134
|
+
- Log rate limit violations
|
|
135
|
+
- Monitor for abuse patterns
|
|
136
|
+
- Allowlist trusted IPs
|
|
137
|
+
|
|
138
|
+
## Output Checklist
|
|
139
|
+
|
|
140
|
+
- [ ] Rate limiter middleware
|
|
141
|
+
- [ ] Per-route policies
|
|
142
|
+
- [ ] User-based limiting
|
|
143
|
+
- [ ] IP-based limiting
|
|
144
|
+
- [ ] Rate limit headers
|
|
145
|
+
- [ ] Safe error responses
|
|
146
|
+
- [ ] Observability/logging
|
|
147
|
+
- [ ] Bypass for internal services
|