claudeinone-cli 1.0.2 → 1.0.3
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/kit/.claude/.ck.json +9 -0
- package/kit/.claude/.ckignore +12 -0
- package/kit/.claude/agents/accessibility-auditor.md +46 -0
- package/kit/.claude/agents/api-designer.md +43 -0
- package/kit/.claude/agents/backend-developer.md +54 -0
- package/kit/.claude/agents/brainstormer.md +33 -0
- package/kit/.claude/agents/campaign-manager.md +36 -0
- package/kit/.claude/agents/code-reviewer.md +39 -0
- package/kit/.claude/agents/content-creator.md +38 -0
- package/kit/.claude/agents/copywriter.md +42 -0
- package/kit/.claude/agents/database-admin.md +37 -0
- package/kit/.claude/agents/debugger.md +46 -0
- package/kit/.claude/agents/devops-engineer.md +41 -0
- package/kit/.claude/agents/docs-manager.md +33 -0
- package/kit/.claude/agents/email-wizard.md +40 -0
- package/kit/.claude/agents/frontend-developer.md +52 -0
- package/kit/.claude/agents/fullstack-developer.md +55 -0
- package/kit/.claude/agents/git-manager.md +40 -0
- package/kit/.claude/agents/i18n-specialist.md +46 -0
- package/kit/.claude/agents/integration-specialist.md +48 -0
- package/kit/.claude/agents/journal-writer.md +39 -0
- package/kit/.claude/agents/mcp-manager.md +57 -0
- package/kit/.claude/agents/mobile-developer.md +38 -0
- package/kit/.claude/agents/performance-optimizer.md +38 -0
- package/kit/.claude/agents/planner.md +56 -0
- package/kit/.claude/agents/project-manager.md +34 -0
- package/kit/.claude/agents/refactorer.md +43 -0
- package/kit/.claude/agents/researcher.md +45 -0
- package/kit/.claude/agents/risk-analyst.md +33 -0
- package/kit/.claude/agents/scalability-consultant.md +39 -0
- package/kit/.claude/agents/scout.md +25 -0
- package/kit/.claude/agents/security-auditor.md +42 -0
- package/kit/.claude/agents/seo-specialist.md +44 -0
- package/kit/.claude/agents/skill-creator.md +64 -0
- package/kit/.claude/agents/social-media-manager.md +35 -0
- package/kit/.claude/agents/systems-designer.md +35 -0
- package/kit/.claude/agents/technology-strategist.md +43 -0
- package/kit/.claude/agents/tester.md +40 -0
- package/kit/.claude/agents/ui-ux-designer.md +40 -0
- package/kit/.claude/commands/co/ask.md +29 -0
- package/kit/.claude/commands/co/bootstrap-auto-fast.md +28 -0
- package/kit/.claude/commands/co/bootstrap-auto-parallel.md +29 -0
- package/kit/.claude/commands/co/bootstrap-auto.md +30 -0
- package/kit/.claude/commands/co/bootstrap.md +31 -0
- package/kit/.claude/commands/co/brainstorm.md +27 -0
- package/kit/.claude/commands/co/campaign.md +28 -0
- package/kit/.claude/commands/co/changelog.md +25 -0
- package/kit/.claude/commands/co/checkpoint.md +25 -0
- package/kit/.claude/commands/co/ci.md +26 -0
- package/kit/.claude/commands/co/ck-help.md +24 -0
- package/kit/.claude/commands/co/coding-level.md +24 -0
- package/kit/.claude/commands/co/content-cro.md +26 -0
- package/kit/.claude/commands/co/content-enhance.md +26 -0
- package/kit/.claude/commands/co/content-fast.md +24 -0
- package/kit/.claude/commands/co/content-good.md +26 -0
- package/kit/.claude/commands/co/cook.md +33 -0
- package/kit/.claude/commands/co/debug.md +26 -0
- package/kit/.claude/commands/co/deploy.md +25 -0
- package/kit/.claude/commands/co/design-3d.md +27 -0
- package/kit/.claude/commands/co/design-describe.md +25 -0
- package/kit/.claude/commands/co/design-fast.md +25 -0
- package/kit/.claude/commands/co/design-good.md +28 -0
- package/kit/.claude/commands/co/design-screenshot.md +26 -0
- package/kit/.claude/commands/co/design-video.md +26 -0
- package/kit/.claude/commands/co/docker.md +24 -0
- package/kit/.claude/commands/co/docs-api.md +25 -0
- package/kit/.claude/commands/co/docs-init.md +26 -0
- package/kit/.claude/commands/co/docs-readme.md +24 -0
- package/kit/.claude/commands/co/docs-summarize.md +25 -0
- package/kit/.claude/commands/co/docs-update.md +25 -0
- package/kit/.claude/commands/co/env-check.md +25 -0
- package/kit/.claude/commands/co/fix-ci.md +29 -0
- package/kit/.claude/commands/co/fix-fast.md +28 -0
- package/kit/.claude/commands/co/fix-hard.md +33 -0
- package/kit/.claude/commands/co/fix-logs.md +28 -0
- package/kit/.claude/commands/co/fix-types.md +28 -0
- package/kit/.claude/commands/co/fix-ui.md +28 -0
- package/kit/.claude/commands/co/fix.md +27 -0
- package/kit/.claude/commands/co/git-cm.md +26 -0
- package/kit/.claude/commands/co/git-cp.md +26 -0
- package/kit/.claude/commands/co/git-pr.md +26 -0
- package/kit/.claude/commands/co/index.md +24 -0
- package/kit/.claude/commands/co/integrate-polar.md +29 -0
- package/kit/.claude/commands/co/integrate-sepay.md +29 -0
- package/kit/.claude/commands/co/journal.md +27 -0
- package/kit/.claude/commands/co/k8s.md +24 -0
- package/kit/.claude/commands/co/kanban.md +25 -0
- package/kit/.claude/commands/co/lint-fix.md +24 -0
- package/kit/.claude/commands/co/load.md +25 -0
- package/kit/.claude/commands/co/migrate.md +28 -0
- package/kit/.claude/commands/co/mock.md +26 -0
- package/kit/.claude/commands/co/mode.md +24 -0
- package/kit/.claude/commands/co/monitor.md +25 -0
- package/kit/.claude/commands/co/new-feature.md +27 -0
- package/kit/.claude/commands/co/optimize.md +26 -0
- package/kit/.claude/commands/co/plan-archive.md +24 -0
- package/kit/.claude/commands/co/plan-ci.md +28 -0
- package/kit/.claude/commands/co/plan-cro.md +27 -0
- package/kit/.claude/commands/co/plan-fast.md +24 -0
- package/kit/.claude/commands/co/plan-hard.md +27 -0
- package/kit/.claude/commands/co/plan-parallel.md +25 -0
- package/kit/.claude/commands/co/plan-two.md +29 -0
- package/kit/.claude/commands/co/plan-validate.md +27 -0
- package/kit/.claude/commands/co/plan.md +27 -0
- package/kit/.claude/commands/co/pr.md +25 -0
- package/kit/.claude/commands/co/preview.md +26 -0
- package/kit/.claude/commands/co/refactor.md +25 -0
- package/kit/.claude/commands/co/release.md +25 -0
- package/kit/.claude/commands/co/review-a11y.md +24 -0
- package/kit/.claude/commands/co/review-codebase-parallel.md +27 -0
- package/kit/.claude/commands/co/review-codebase.md +27 -0
- package/kit/.claude/commands/co/review-perf.md +24 -0
- package/kit/.claude/commands/co/review-security.md +25 -0
- package/kit/.claude/commands/co/scaffold.md +25 -0
- package/kit/.claude/commands/co/scout.md +26 -0
- package/kit/.claude/commands/co/secure.md +26 -0
- package/kit/.claude/commands/co/seed.md +25 -0
- package/kit/.claude/commands/co/seo-audit.md +24 -0
- package/kit/.claude/commands/co/seo-keywords.md +25 -0
- package/kit/.claude/commands/co/skill-create.md +29 -0
- package/kit/.claude/commands/co/skill-fix-logs.md +28 -0
- package/kit/.claude/commands/co/slide-create.md +24 -0
- package/kit/.claude/commands/co/spawn.md +24 -0
- package/kit/.claude/commands/co/terraform.md +24 -0
- package/kit/.claude/commands/co/test-gen.md +24 -0
- package/kit/.claude/commands/co/test-ui.md +27 -0
- package/kit/.claude/commands/co/test.md +26 -0
- package/kit/.claude/commands/co/use-mcp.md +25 -0
- package/kit/.claude/commands/co/video-script.md +25 -0
- package/kit/.claude/commands/co/watzup.md +25 -0
- package/kit/.claude/commands/co/worktree.md +25 -0
- package/kit/.claude/commands/co/write-blog.md +25 -0
- package/kit/.claude/commands/co/write-copy.md +24 -0
- package/kit/.claude/commands/co/write-email.md +25 -0
- package/kit/.claude/commands/content/content-cro.md +26 -0
- package/kit/.claude/commands/content/content-enhance.md +26 -0
- package/kit/.claude/commands/content/content-fast.md +24 -0
- package/kit/.claude/commands/content/content-good.md +26 -0
- package/kit/.claude/commands/content/enhance.md +26 -0
- package/kit/.claude/commands/content/good.md +26 -0
- package/kit/.claude/commands/core/ask.md +29 -0
- package/kit/.claude/commands/core/bootstrap-auto-fast.md +28 -0
- package/kit/.claude/commands/core/bootstrap-auto-parallel.md +29 -0
- package/kit/.claude/commands/core/bootstrap-auto.md +30 -0
- package/kit/.claude/commands/core/bootstrap.md +31 -0
- package/kit/.claude/commands/core/ck-help.md +24 -0
- package/kit/.claude/commands/core/coding-level.md +24 -0
- package/kit/.claude/commands/core/cook.md +33 -0
- package/kit/.claude/commands/core/debug.md +26 -0
- package/kit/.claude/commands/core/journal.md +27 -0
- package/kit/.claude/commands/core/kanban.md +25 -0
- package/kit/.claude/commands/core/preview.md +26 -0
- package/kit/.claude/commands/core/scout.md +26 -0
- package/kit/.claude/commands/core/test-ui.md +27 -0
- package/kit/.claude/commands/core/test.md +26 -0
- package/kit/.claude/commands/core/use-mcp.md +25 -0
- package/kit/.claude/commands/core/watzup.md +25 -0
- package/kit/.claude/commands/core/worktree.md +25 -0
- package/kit/.claude/commands/design/3d.md +27 -0
- package/kit/.claude/commands/design/design-3d.md +27 -0
- package/kit/.claude/commands/design/design-describe.md +25 -0
- package/kit/.claude/commands/design/design-fast.md +25 -0
- package/kit/.claude/commands/design/design-good.md +28 -0
- package/kit/.claude/commands/design/design-screenshot.md +26 -0
- package/kit/.claude/commands/design/design-video.md +26 -0
- package/kit/.claude/commands/design/good.md +28 -0
- package/kit/.claude/commands/design/video.md +26 -0
- package/kit/.claude/commands/docs/docs-init.md +26 -0
- package/kit/.claude/commands/docs/docs-summarize.md +25 -0
- package/kit/.claude/commands/docs/docs-update.md +25 -0
- package/kit/.claude/commands/docs/init.md +26 -0
- package/kit/.claude/commands/docs/summarize.md +25 -0
- package/kit/.claude/commands/fix/ci.md +29 -0
- package/kit/.claude/commands/fix/fast.md +28 -0
- package/kit/.claude/commands/fix/fix-ci.md +29 -0
- package/kit/.claude/commands/fix/fix-fast.md +28 -0
- package/kit/.claude/commands/fix/fix-hard.md +33 -0
- package/kit/.claude/commands/fix/fix-logs.md +28 -0
- package/kit/.claude/commands/fix/fix-types.md +28 -0
- package/kit/.claude/commands/fix/fix-ui.md +28 -0
- package/kit/.claude/commands/fix/hard.md +33 -0
- package/kit/.claude/commands/fix/logs.md +28 -0
- package/kit/.claude/commands/fix/types.md +28 -0
- package/kit/.claude/commands/fix/ui.md +28 -0
- package/kit/.claude/commands/git/cp.md +26 -0
- package/kit/.claude/commands/git/git-cm.md +26 -0
- package/kit/.claude/commands/git/git-cp.md +26 -0
- package/kit/.claude/commands/git/git-pr.md +26 -0
- package/kit/.claude/commands/integrate/integrate-polar.md +29 -0
- package/kit/.claude/commands/integrate/integrate-sepay.md +29 -0
- package/kit/.claude/commands/integrate/sepay.md +29 -0
- package/kit/.claude/commands/plan/ci.md +28 -0
- package/kit/.claude/commands/plan/cro.md +27 -0
- package/kit/.claude/commands/plan/hard.md +27 -0
- package/kit/.claude/commands/plan/plan-archive.md +24 -0
- package/kit/.claude/commands/plan/plan-ci.md +28 -0
- package/kit/.claude/commands/plan/plan-cro.md +27 -0
- package/kit/.claude/commands/plan/plan-fast.md +24 -0
- package/kit/.claude/commands/plan/plan-hard.md +27 -0
- package/kit/.claude/commands/plan/plan-parallel.md +25 -0
- package/kit/.claude/commands/plan/plan-two.md +29 -0
- package/kit/.claude/commands/plan/plan-validate.md +27 -0
- package/kit/.claude/commands/plan/plan.md +27 -0
- package/kit/.claude/commands/plan/validate.md +27 -0
- package/kit/.claude/commands/skill/fix-logs.md +28 -0
- package/kit/.claude/commands/skill/skill-create.md +29 -0
- package/kit/.claude/commands/skill/skill-fix-logs.md +28 -0
- package/kit/.claude/settings.json +16 -0
- package/kit/.claude/skills/ai-anthropic.md +100 -0
- package/kit/.claude/skills/ai-context-engineering.md +113 -0
- package/kit/.claude/skills/ai-gemini.md +152 -0
- package/kit/.claude/skills/ai-langchain.md +93 -0
- package/kit/.claude/skills/ai-llamaindex.md +179 -0
- package/kit/.claude/skills/ai-mcp-builder.md +101 -0
- package/kit/.claude/skills/ai-openai.md +250 -0
- package/kit/.claude/skills/ai-prompt-engineering.md +173 -0
- package/kit/.claude/skills/ai-rag.md +91 -0
- package/kit/.claude/skills/ai-vectordb.md +215 -0
- package/kit/.claude/skills/analytics-segment.md +161 -0
- package/kit/.claude/skills/api-caching.md +103 -0
- package/kit/.claude/skills/api-documentation.md +50 -0
- package/kit/.claude/skills/api-graphql.md +234 -0
- package/kit/.claude/skills/api-openapi.md +116 -0
- package/kit/.claude/skills/api-pagination-filtering.md +239 -0
- package/kit/.claude/skills/api-rate-limiting.md +179 -0
- package/kit/.claude/skills/api-rest-advanced.md +50 -0
- package/kit/.claude/skills/api-rest.md +217 -0
- package/kit/.claude/skills/api-trpc.md +173 -0
- package/kit/.claude/skills/api-versioning.md +70 -0
- package/kit/.claude/skills/api-webhooks.md +226 -0
- package/kit/.claude/skills/arch-clean-code.md +226 -0
- package/kit/.claude/skills/arch-clean.md +91 -0
- package/kit/.claude/skills/arch-cqrs.md +229 -0
- package/kit/.claude/skills/arch-ddd.md +85 -0
- package/kit/.claude/skills/arch-event-driven.md +189 -0
- package/kit/.claude/skills/arch-microservices.md +80 -0
- package/kit/.claude/skills/arch-monorepo.md +87 -0
- package/kit/.claude/skills/arch-multi-tenant.md +81 -0
- package/kit/.claude/skills/arch-serverless.md +86 -0
- package/kit/.claude/skills/auth-clerk.md +97 -0
- package/kit/.claude/skills/auth-jwt.md +143 -0
- package/kit/.claude/skills/auth-lucia.md +93 -0
- package/kit/.claude/skills/auth-nextauth.md +446 -0
- package/kit/.claude/skills/auth-oauth.md +208 -0
- package/kit/.claude/skills/auth-oauth2.md +110 -0
- package/kit/.claude/skills/auth-passkeys.md +109 -0
- package/kit/.claude/skills/auth-session.md +88 -0
- package/kit/.claude/skills/backend-dotnet.md +414 -0
- package/kit/.claude/skills/backend-express.md +129 -0
- package/kit/.claude/skills/backend-fastify.md +104 -0
- package/kit/.claude/skills/backend-go.md +205 -0
- package/kit/.claude/skills/backend-graphql.md +149 -0
- package/kit/.claude/skills/backend-grpc.md +382 -0
- package/kit/.claude/skills/backend-hono.md +95 -0
- package/kit/.claude/skills/backend-java-spring.md +198 -0
- package/kit/.claude/skills/backend-nodejs-express.md +165 -0
- package/kit/.claude/skills/backend-nodejs.md +143 -0
- package/kit/.claude/skills/backend-php-laravel.md +156 -0
- package/kit/.claude/skills/backend-python-django.md +200 -0
- package/kit/.claude/skills/backend-python-fastapi.md +169 -0
- package/kit/.claude/skills/backend-ruby-rails.md +190 -0
- package/kit/.claude/skills/backend-rust.md +182 -0
- package/kit/.claude/skills/backend-websockets.md +392 -0
- package/kit/.claude/skills/cache-redis.md +195 -0
- package/kit/.claude/skills/caching-strategies.md +100 -0
- package/kit/.claude/skills/cloud-aws.md +165 -0
- package/kit/.claude/skills/cloud-azure.md +187 -0
- package/kit/.claude/skills/cloud-cloudflare.md +74 -0
- package/kit/.claude/skills/cloud-fly.md +94 -0
- package/kit/.claude/skills/cloud-gcp.md +160 -0
- package/kit/.claude/skills/cloud-railway.md +92 -0
- package/kit/.claude/skills/cloud-render.md +70 -0
- package/kit/.claude/skills/cloud-serverless.md +68 -0
- package/kit/.claude/skills/cloud-vercel.md +76 -0
- package/kit/.claude/skills/component-patterns.md +50 -0
- package/kit/.claude/skills/content-management.md +197 -0
- package/kit/.claude/skills/cors-security.md +50 -0
- package/kit/.claude/skills/data-csv-excel.md +210 -0
- package/kit/.claude/skills/database-optimization.md +196 -0
- package/kit/.claude/skills/databases-transactions.md +68 -0
- package/kit/.claude/skills/db-cassandra.md +89 -0
- package/kit/.claude/skills/db-drizzle.md +363 -0
- package/kit/.claude/skills/db-dynamodb.md +83 -0
- package/kit/.claude/skills/db-elasticsearch.md +105 -0
- package/kit/.claude/skills/db-firebase-firestore.md +191 -0
- package/kit/.claude/skills/db-mongodb.md +198 -0
- package/kit/.claude/skills/db-mysql.md +50 -0
- package/kit/.claude/skills/db-neon.md +72 -0
- package/kit/.claude/skills/db-planetscale.md +76 -0
- package/kit/.claude/skills/db-postgresql.md +50 -0
- package/kit/.claude/skills/db-prisma.md +414 -0
- package/kit/.claude/skills/db-redis.md +50 -0
- package/kit/.claude/skills/db-sqlite.md +149 -0
- package/kit/.claude/skills/db-supabase.md +445 -0
- package/kit/.claude/skills/devops-ci-cd.md +271 -0
- package/kit/.claude/skills/devops-database-backup.md +77 -0
- package/kit/.claude/skills/devops-docker.md +93 -0
- package/kit/.claude/skills/devops-github-actions.md +82 -0
- package/kit/.claude/skills/devops-health-checks.md +50 -0
- package/kit/.claude/skills/devops-kubernetes.md +109 -0
- package/kit/.claude/skills/devops-logging.md +163 -0
- package/kit/.claude/skills/devops-monitoring.md +203 -0
- package/kit/.claude/skills/devops-pulumi.md +94 -0
- package/kit/.claude/skills/devops-secrets.md +166 -0
- package/kit/.claude/skills/devops-terraform.md +226 -0
- package/kit/.claude/skills/error-boundaries.md +84 -0
- package/kit/.claude/skills/file-storage.md +50 -0
- package/kit/.claude/skills/frontend-angular.md +104 -0
- package/kit/.claude/skills/frontend-astro.md +94 -0
- package/kit/.claude/skills/frontend-bundle-analysis.md +147 -0
- package/kit/.claude/skills/frontend-forms.md +134 -0
- package/kit/.claude/skills/frontend-htmx.md +86 -0
- package/kit/.claude/skills/frontend-nextjs.md +188 -0
- package/kit/.claude/skills/frontend-pwa.md +105 -0
- package/kit/.claude/skills/frontend-react-hooks.md +238 -0
- package/kit/.claude/skills/frontend-react.md +129 -0
- package/kit/.claude/skills/frontend-remix-advanced.md +106 -0
- package/kit/.claude/skills/frontend-remix.md +101 -0
- package/kit/.claude/skills/frontend-solid.md +99 -0
- package/kit/.claude/skills/frontend-state-management.md +134 -0
- package/kit/.claude/skills/frontend-state.md +106 -0
- package/kit/.claude/skills/frontend-svelte.md +121 -0
- package/kit/.claude/skills/frontend-testing.md +100 -0
- package/kit/.claude/skills/frontend-vite.md +94 -0
- package/kit/.claude/skills/frontend-vue.md +133 -0
- package/kit/.claude/skills/frontend-webpack.md +93 -0
- package/kit/.claude/skills/functional-programming.md +50 -0
- package/kit/.claude/skills/hooks-custom.md +50 -0
- package/kit/.claude/skills/http-server.md +50 -0
- package/kit/.claude/skills/i18n-general.md +89 -0
- package/kit/.claude/skills/i18n-localization.md +191 -0
- package/kit/.claude/skills/i18n-nextjs.md +127 -0
- package/kit/.claude/skills/infrastructure-docker-compose.md +77 -0
- package/kit/.claude/skills/infrastructure-serverless.md +177 -0
- package/kit/.claude/skills/jwt-tokens.md +50 -0
- package/kit/.claude/skills/logging-winston.md +106 -0
- package/kit/.claude/skills/messaging-kafka.md +102 -0
- package/kit/.claude/skills/messaging-rabbitmq.md +50 -0
- package/kit/.claude/skills/mobile-capacitor.md +109 -0
- package/kit/.claude/skills/mobile-expo.md +101 -0
- package/kit/.claude/skills/mobile-flutter.md +259 -0
- package/kit/.claude/skills/mobile-react-native.md +238 -0
- package/kit/.claude/skills/monitoring-apm.md +50 -0
- package/kit/.claude/skills/monitoring-error-tracking.md +217 -0
- package/kit/.claude/skills/nodejs-streams.md +168 -0
- package/kit/.claude/skills/oauth-integration.md +50 -0
- package/kit/.claude/skills/patterns-dependency-injection.md +218 -0
- package/kit/.claude/skills/patterns-factory-singleton.md +209 -0
- package/kit/.claude/skills/patterns-observer-pubsub.md +210 -0
- package/kit/.claude/skills/payment-lemonsqueezy.md +101 -0
- package/kit/.claude/skills/payment-square.md +178 -0
- package/kit/.claude/skills/payment-stripe.md +206 -0
- package/kit/.claude/skills/perf-bundle.md +100 -0
- package/kit/.claude/skills/perf-web-vitals.md +102 -0
- package/kit/.claude/skills/performance-database-connection-pooling.md +67 -0
- package/kit/.claude/skills/performance-metrics.md +73 -0
- package/kit/.claude/skills/performance-optimization.md +208 -0
- package/kit/.claude/skills/performance-web-vitals.md +169 -0
- package/kit/.claude/skills/rate-limiting.md +77 -0
- package/kit/.claude/skills/reactive-programming.md +50 -0
- package/kit/.claude/skills/realtime-database.md +50 -0
- package/kit/.claude/skills/realtime-subscriptions.md +218 -0
- package/kit/.claude/skills/saas-ab-testing.md +90 -0
- package/kit/.claude/skills/saas-analytics.md +113 -0
- package/kit/.claude/skills/saas-billing.md +106 -0
- package/kit/.claude/skills/saas-email.md +88 -0
- package/kit/.claude/skills/saas-feature-flags.md +83 -0
- package/kit/.claude/skills/saas-onboarding.md +96 -0
- package/kit/.claude/skills/saas-user-onboarding.md +207 -0
- package/kit/.claude/skills/security-encryption.md +216 -0
- package/kit/.claude/skills/security-owasp.md +212 -0
- package/kit/.claude/skills/security-secrets-rotation.md +64 -0
- package/kit/.claude/skills/seo-content.md +94 -0
- package/kit/.claude/skills/seo-technical.md +101 -0
- package/kit/.claude/skills/serverless-framework.md +151 -0
- package/kit/.claude/skills/sharding-scaling.md +50 -0
- package/kit/.claude/skills/styling-css-modules.md +219 -0
- package/kit/.claude/skills/styling-styled-components.md +206 -0
- package/kit/.claude/skills/styling-tailwind.md +206 -0
- package/kit/.claude/skills/test-e2e.md +86 -0
- package/kit/.claude/skills/test-integration.md +216 -0
- package/kit/.claude/skills/test-performance.md +162 -0
- package/kit/.claude/skills/test-tdd.md +170 -0
- package/kit/.claude/skills/test-unit.md +301 -0
- package/kit/.claude/skills/testing-accessibility.md +117 -0
- package/kit/.claude/skills/testing-contract.md +75 -0
- package/kit/.claude/skills/testing-e2e-advanced.md +50 -0
- package/kit/.claude/skills/testing-load-stress.md +79 -0
- package/kit/.claude/skills/testing-mutation.md +92 -0
- package/kit/.claude/skills/testing-snapshot.md +50 -0
- package/kit/.claude/skills/testing-vitest.md +172 -0
- package/kit/.claude/skills/tooling-biome.md +91 -0
- package/kit/.claude/skills/tooling-build-tools.md +166 -0
- package/kit/.claude/skills/tooling-bun.md +94 -0
- package/kit/.claude/skills/tooling-eslint.md +103 -0
- package/kit/.claude/skills/tooling-git.md +79 -0
- package/kit/.claude/skills/tooling-monorepo.md +162 -0
- package/kit/.claude/skills/tooling-testing-frameworks.md +207 -0
- package/kit/.claude/skills/tooling-typescript.md +156 -0
- package/kit/.claude/skills/ui-a11y.md +106 -0
- package/kit/.claude/skills/ui-framer.md +106 -0
- package/kit/.claude/skills/ui-gsap.md +102 -0
- package/kit/.claude/skills/ui-radix.md +82 -0
- package/kit/.claude/skills/ui-shadcn.md +463 -0
- package/kit/.claude/skills/ui-tailwind.md +98 -0
- package/kit/.claude/skills/ui-threejs.md +110 -0
- package/kit/.claude/skills/ui-tokens.md +97 -0
- package/kit/.claude/skills/utilities-date-time.md +170 -0
- package/kit/.claude/skills/validation-schemas.md +110 -0
- package/kit/.claude/skills/version-control-git.md +144 -0
- package/kit/.claude/skills/web-accessibility-wcag.md +102 -0
- package/kit/.claude/skills/web-astro.md +197 -0
- package/kit/.claude/skills/web-html-css.md +224 -0
- package/kit/.claude/skills/web-htmx.md +99 -0
- package/kit/.claude/skills/web-nextjs-advanced.md +202 -0
- package/kit/.claude/skills/web-remix.md +194 -0
- package/kit/.claude/skills/web-seo.md +99 -0
- package/kit/.claude/skills/web-svelte.md +234 -0
- package/kit/.claude/skills/websocket-server.md +50 -0
- package/kit/.claude/skills/writing-marketing.md +89 -0
- package/kit/.claude/skills/writing-technical.md +119 -0
- package/kit/CLAUDE.md +206 -0
- package/kit/README.md +150 -0
- package/kit/SKILLS_INDEX.md +188 -0
- package/kit/docs/README.md +3 -0
- package/kit/journals/README.md +3 -0
- package/kit/plans/README.md +3 -0
- package/package.json +3 -1
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Rate Limiting & Throttling
|
|
2
|
+
|
|
3
|
+
Controlling request rates and protecting APIs.
|
|
4
|
+
|
|
5
|
+
## Token Bucket Algorithm
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
class TokenBucket {
|
|
9
|
+
private tokens: number;
|
|
10
|
+
private lastRefillTime: number;
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
private capacity: number,
|
|
14
|
+
private refillRate: number // tokens per second
|
|
15
|
+
) {
|
|
16
|
+
this.tokens = capacity;
|
|
17
|
+
this.lastRefillTime = Date.now();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
canConsume(tokens: number = 1): boolean {
|
|
21
|
+
this.refill();
|
|
22
|
+
|
|
23
|
+
if (this.tokens >= tokens) {
|
|
24
|
+
this.tokens -= tokens;
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
private refill() {
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
const timePassed = (now - this.lastRefillTime) / 1000;
|
|
34
|
+
const tokensToAdd = timePassed * this.refillRate;
|
|
35
|
+
|
|
36
|
+
this.tokens = Math.min(this.capacity, this.tokens + tokensToAdd);
|
|
37
|
+
this.lastRefillTime = now;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Usage
|
|
42
|
+
const bucket = new TokenBucket(10, 1); // 10 tokens, 1 per second
|
|
43
|
+
|
|
44
|
+
if (bucket.canConsume()) {
|
|
45
|
+
processRequest();
|
|
46
|
+
} else {
|
|
47
|
+
return res.status(429).json({ error: 'Rate limit exceeded' });
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Sliding Window Rate Limiting
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
class RateLimiter {
|
|
55
|
+
private requests = new Map<string, number[]>();
|
|
56
|
+
|
|
57
|
+
canMakeRequest(userId: string, limit: number, windowMs: number): boolean {
|
|
58
|
+
const now = Date.now();
|
|
59
|
+
const windowStart = now - windowMs;
|
|
60
|
+
|
|
61
|
+
// Get requests in current window
|
|
62
|
+
let userRequests = this.requests.get(userId) || [];
|
|
63
|
+
userRequests = userRequests.filter(time => time > windowStart);
|
|
64
|
+
|
|
65
|
+
if (userRequests.length >= limit) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Add new request
|
|
70
|
+
userRequests.push(now);
|
|
71
|
+
this.requests.set(userId, userRequests);
|
|
72
|
+
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Usage
|
|
78
|
+
const limiter = new RateLimiter();
|
|
79
|
+
|
|
80
|
+
app.get('/api/data', (req, res) => {
|
|
81
|
+
const userId = req.user.id;
|
|
82
|
+
|
|
83
|
+
if (!limiter.canMakeRequest(userId, 100, 60000)) {
|
|
84
|
+
return res.status(429).json({ error: 'Rate limit exceeded' });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
res.json(data);
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Redis Rate Limiting
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { Redis } from 'ioredis';
|
|
95
|
+
|
|
96
|
+
const redis = new Redis();
|
|
97
|
+
|
|
98
|
+
async function checkRateLimit(
|
|
99
|
+
userId: string,
|
|
100
|
+
limit: number = 100,
|
|
101
|
+
windowMs: number = 60000
|
|
102
|
+
): Promise<boolean> {
|
|
103
|
+
const key = `ratelimit:${userId}`;
|
|
104
|
+
const now = Date.now();
|
|
105
|
+
const windowStart = now - windowMs;
|
|
106
|
+
|
|
107
|
+
// Remove old requests
|
|
108
|
+
await redis.zremrangebyscore(key, 0, windowStart);
|
|
109
|
+
|
|
110
|
+
// Get request count
|
|
111
|
+
const count = await redis.zcard(key);
|
|
112
|
+
|
|
113
|
+
if (count >= limit) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Add current request
|
|
118
|
+
await redis.zadd(key, now, `${now}-${Math.random()}`);
|
|
119
|
+
|
|
120
|
+
// Set expiration
|
|
121
|
+
await redis.expire(key, Math.ceil(windowMs / 1000));
|
|
122
|
+
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Usage
|
|
127
|
+
app.use(async (req, res, next) => {
|
|
128
|
+
const userId = req.user?.id || req.ip;
|
|
129
|
+
|
|
130
|
+
if (!(await checkRateLimit(userId))) {
|
|
131
|
+
return res.status(429).json({ error: 'Rate limit exceeded' });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
next();
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Differentiated Rate Limits
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
function getRateLimit(user: any) {
|
|
142
|
+
switch (user.tier) {
|
|
143
|
+
case 'free':
|
|
144
|
+
return { limit: 100, windowMs: 3600000 }; // 100/hour
|
|
145
|
+
case 'pro':
|
|
146
|
+
return { limit: 10000, windowMs: 3600000 }; // 10k/hour
|
|
147
|
+
case 'enterprise':
|
|
148
|
+
return { limit: Infinity, windowMs: 0 }; // Unlimited
|
|
149
|
+
default:
|
|
150
|
+
return { limit: 100, windowMs: 3600000 };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
app.use(async (req, res, next) => {
|
|
155
|
+
const { limit, windowMs } = getRateLimit(req.user);
|
|
156
|
+
|
|
157
|
+
if (!await checkRateLimit(req.user.id, limit, windowMs)) {
|
|
158
|
+
return res.status(429).json({
|
|
159
|
+
error: 'Rate limit exceeded',
|
|
160
|
+
retryAfter: Math.ceil(windowMs / 1000)
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
next();
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Best Practices
|
|
169
|
+
|
|
170
|
+
✅ **User-based limits** - Per user, not per IP
|
|
171
|
+
✅ **Tiered limits** - Different for different users
|
|
172
|
+
✅ **Return headers** - X-RateLimit-Remaining
|
|
173
|
+
✅ **Graceful degradation** - Queue requests vs reject
|
|
174
|
+
✅ **Monitor abuse** - Track limit violations
|
|
175
|
+
|
|
176
|
+
## Resources
|
|
177
|
+
|
|
178
|
+
- [Express Rate Limit](https://github.com/nfriedly/express-rate-limit)
|
|
179
|
+
- [Node.js Rate Limiting](https://www.npmjs.com/package/bottleneck)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Production-Ready Skill Implementation
|
|
2
|
+
|
|
3
|
+
## Setup & Installation
|
|
4
|
+
|
|
5
|
+
Detailed installation and configuration steps for the technology.
|
|
6
|
+
|
|
7
|
+
## Core Concepts
|
|
8
|
+
|
|
9
|
+
Fundamental patterns and approaches.
|
|
10
|
+
|
|
11
|
+
## Implementation Examples
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// Real production code examples
|
|
15
|
+
// with error handling and best practices
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Advanced Patterns
|
|
19
|
+
|
|
20
|
+
Complex scenarios and optimization techniques.
|
|
21
|
+
|
|
22
|
+
## Performance Optimization
|
|
23
|
+
|
|
24
|
+
Tips for maximizing efficiency and speed.
|
|
25
|
+
|
|
26
|
+
## Security Considerations
|
|
27
|
+
|
|
28
|
+
Security best practices specific to this technology.
|
|
29
|
+
|
|
30
|
+
## Testing
|
|
31
|
+
|
|
32
|
+
How to properly test this feature.
|
|
33
|
+
|
|
34
|
+
## Monitoring & Debugging
|
|
35
|
+
|
|
36
|
+
Tools and techniques for production support.
|
|
37
|
+
|
|
38
|
+
## Best Practices
|
|
39
|
+
|
|
40
|
+
✅ Key recommendations
|
|
41
|
+
✅ Common pitfalls to avoid
|
|
42
|
+
✅ Performance considerations
|
|
43
|
+
✅ Security measures
|
|
44
|
+
✅ Production readiness
|
|
45
|
+
|
|
46
|
+
## Resources
|
|
47
|
+
|
|
48
|
+
- Official documentation
|
|
49
|
+
- Community guides
|
|
50
|
+
- Performance benchmarks
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# REST API Design
|
|
2
|
+
|
|
3
|
+
Best practices for designing RESTful APIs.
|
|
4
|
+
|
|
5
|
+
## HTTP Methods
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// GET - Retrieve resource
|
|
9
|
+
app.get('/api/users/:id', async (req, res) => {
|
|
10
|
+
const user = await db.users.findById(req.params.id);
|
|
11
|
+
res.json(user);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// POST - Create resource
|
|
15
|
+
app.post('/api/users', async (req, res) => {
|
|
16
|
+
const user = await db.users.create(req.body);
|
|
17
|
+
res.status(201).json(user);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// PUT - Replace entire resource
|
|
21
|
+
app.put('/api/users/:id', async (req, res) => {
|
|
22
|
+
const user = await db.users.update(req.params.id, req.body);
|
|
23
|
+
res.json(user);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// PATCH - Partial update
|
|
27
|
+
app.patch('/api/users/:id', async (req, res) => {
|
|
28
|
+
const user = await db.users.patch(req.params.id, req.body);
|
|
29
|
+
res.json(user);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// DELETE - Remove resource
|
|
33
|
+
app.delete('/api/users/:id', async (req, res) => {
|
|
34
|
+
await db.users.delete(req.params.id);
|
|
35
|
+
res.status(204).send();
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Status Codes
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// 2xx Success
|
|
43
|
+
// 200 OK - Request succeeded
|
|
44
|
+
// 201 Created - Resource created
|
|
45
|
+
// 204 No Content - Success, no response body
|
|
46
|
+
|
|
47
|
+
// 4xx Client Error
|
|
48
|
+
// 400 Bad Request - Invalid input
|
|
49
|
+
// 401 Unauthorized - Authentication required
|
|
50
|
+
// 403 Forbidden - No permission
|
|
51
|
+
// 404 Not Found - Resource doesn't exist
|
|
52
|
+
// 409 Conflict - Resource conflict (duplicate)
|
|
53
|
+
// 422 Unprocessable Entity - Validation failed
|
|
54
|
+
|
|
55
|
+
// 5xx Server Error
|
|
56
|
+
// 500 Internal Server Error
|
|
57
|
+
// 503 Service Unavailable
|
|
58
|
+
|
|
59
|
+
app.post('/api/users', async (req, res) => {
|
|
60
|
+
const { email, name } = req.body;
|
|
61
|
+
|
|
62
|
+
if (!email) {
|
|
63
|
+
return res.status(400).json({ error: 'Email required' });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const existing = await db.users.findByEmail(email);
|
|
67
|
+
if (existing) {
|
|
68
|
+
return res.status(409).json({ error: 'Email already exists' });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const user = await db.users.create({ email, name });
|
|
72
|
+
res.status(201).json(user);
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Pagination
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
app.get('/api/users', async (req, res) => {
|
|
80
|
+
const page = parseInt(req.query.page) || 1;
|
|
81
|
+
const limit = parseInt(req.query.limit) || 20;
|
|
82
|
+
const offset = (page - 1) * limit;
|
|
83
|
+
|
|
84
|
+
const users = await db.users.find()
|
|
85
|
+
.offset(offset)
|
|
86
|
+
.limit(limit);
|
|
87
|
+
|
|
88
|
+
const total = await db.users.count();
|
|
89
|
+
|
|
90
|
+
res.json({
|
|
91
|
+
data: users,
|
|
92
|
+
pagination: {
|
|
93
|
+
page,
|
|
94
|
+
limit,
|
|
95
|
+
total,
|
|
96
|
+
pages: Math.ceil(total / limit)
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Filtering & Sorting
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
app.get('/api/users', async (req, res) => {
|
|
106
|
+
let query = db.users;
|
|
107
|
+
|
|
108
|
+
// Filter
|
|
109
|
+
if (req.query.role) {
|
|
110
|
+
query = query.where('role', req.query.role);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (req.query.status) {
|
|
114
|
+
query = query.where('status', req.query.status);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Sort
|
|
118
|
+
const sortBy = req.query.sortBy || 'createdAt';
|
|
119
|
+
const order = req.query.order || 'desc';
|
|
120
|
+
query = query.orderBy(sortBy, order);
|
|
121
|
+
|
|
122
|
+
// Pagination
|
|
123
|
+
const page = parseInt(req.query.page) || 1;
|
|
124
|
+
const limit = parseInt(req.query.limit) || 20;
|
|
125
|
+
|
|
126
|
+
const users = await query
|
|
127
|
+
.offset((page - 1) * limit)
|
|
128
|
+
.limit(limit);
|
|
129
|
+
|
|
130
|
+
res.json(users);
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Error Response Format
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
interface ErrorResponse {
|
|
138
|
+
error: {
|
|
139
|
+
code: string;
|
|
140
|
+
message: string;
|
|
141
|
+
details?: Record<string, string[]>;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
app.use((err: any, req: any, res: any, next: any) => {
|
|
146
|
+
const status = err.statusCode || 500;
|
|
147
|
+
const code = err.code || 'INTERNAL_ERROR';
|
|
148
|
+
const message = err.message || 'An error occurred';
|
|
149
|
+
|
|
150
|
+
res.status(status).json({
|
|
151
|
+
error: {
|
|
152
|
+
code,
|
|
153
|
+
message,
|
|
154
|
+
details: err.details
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## API Versioning
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
// URL versioning
|
|
164
|
+
app.get('/api/v1/users', async (req, res) => {
|
|
165
|
+
// v1 implementation
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
app.get('/api/v2/users', async (req, res) => {
|
|
169
|
+
// v2 implementation with breaking changes
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Header versioning
|
|
173
|
+
app.get('/api/users', async (req, res) => {
|
|
174
|
+
const version = req.headers['api-version'] || '1';
|
|
175
|
+
|
|
176
|
+
if (version === '2') {
|
|
177
|
+
// v2 response format
|
|
178
|
+
} else {
|
|
179
|
+
// v1 response format
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Rate Limiting & Caching
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import rateLimit from 'express-rate-limit';
|
|
188
|
+
|
|
189
|
+
const limiter = rateLimit({
|
|
190
|
+
windowMs: 15 * 60 * 1000,
|
|
191
|
+
max: 100
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
app.use('/api/', limiter);
|
|
195
|
+
|
|
196
|
+
// Cache response
|
|
197
|
+
app.get('/api/users/:id', async (req, res) => {
|
|
198
|
+
res.set('Cache-Control', 'public, max-age=3600');
|
|
199
|
+
|
|
200
|
+
const user = await db.users.findById(req.params.id);
|
|
201
|
+
res.json(user);
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Best Practices
|
|
206
|
+
|
|
207
|
+
✅ **Consistent naming** - Use nouns, not verbs (/users not /getUsers)
|
|
208
|
+
✅ **Proper HTTP methods** - GET for retrieval, POST for creation
|
|
209
|
+
✅ **Meaningful status codes** - Indicate success/failure clearly
|
|
210
|
+
✅ **Document with OpenAPI** - Generate API documentation
|
|
211
|
+
✅ **CORS headers** - Control cross-origin requests
|
|
212
|
+
|
|
213
|
+
## Resources
|
|
214
|
+
|
|
215
|
+
- [REST API Best Practices](https://restfulapi.net/)
|
|
216
|
+
- [HTTP Status Codes](https://httpwg.org/specs/rfc7231.html#status.codes)
|
|
217
|
+
- [OpenAPI Specification](https://spec.openapis.org/)
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# tRPC
|
|
2
|
+
|
|
3
|
+
End-to-end typesafe APIs using TypeScript.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @trpc/server @trpc/client zod
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Router Definition
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import { router, publicProcedure } from './trpc';
|
|
16
|
+
|
|
17
|
+
export const userRouter = router({
|
|
18
|
+
get: publicProcedure
|
|
19
|
+
.input(z.string().uuid())
|
|
20
|
+
.query(async ({ input: userId }) => {
|
|
21
|
+
return await db.user.findUnique({
|
|
22
|
+
where: { id: userId }
|
|
23
|
+
});
|
|
24
|
+
}),
|
|
25
|
+
|
|
26
|
+
list: publicProcedure
|
|
27
|
+
.input(z.object({
|
|
28
|
+
limit: z.number().default(10),
|
|
29
|
+
offset: z.number().default(0)
|
|
30
|
+
}))
|
|
31
|
+
.query(async ({ input }) => {
|
|
32
|
+
return await db.user.findMany({
|
|
33
|
+
take: input.limit,
|
|
34
|
+
skip: input.offset
|
|
35
|
+
});
|
|
36
|
+
}),
|
|
37
|
+
|
|
38
|
+
create: publicProcedure
|
|
39
|
+
.input(z.object({
|
|
40
|
+
email: z.string().email(),
|
|
41
|
+
name: z.string()
|
|
42
|
+
}))
|
|
43
|
+
.mutation(async ({ input }) => {
|
|
44
|
+
return await db.user.create({ data: input });
|
|
45
|
+
}),
|
|
46
|
+
|
|
47
|
+
update: publicProcedure
|
|
48
|
+
.input(z.object({
|
|
49
|
+
id: z.string().uuid(),
|
|
50
|
+
name: z.string().optional()
|
|
51
|
+
}))
|
|
52
|
+
.mutation(async ({ input }) => {
|
|
53
|
+
return await db.user.update({
|
|
54
|
+
where: { id: input.id },
|
|
55
|
+
data: input
|
|
56
|
+
});
|
|
57
|
+
})
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export const appRouter = router({
|
|
61
|
+
user: userRouter,
|
|
62
|
+
post: postRouter
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export type AppRouter = typeof appRouter;
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Server Setup
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { createHTTPServer } from '@trpc/server/adapters/standalone';
|
|
72
|
+
import { appRouter } from './router';
|
|
73
|
+
|
|
74
|
+
const server = createHTTPServer({
|
|
75
|
+
router: appRouter,
|
|
76
|
+
createContext: () => ({
|
|
77
|
+
user: null // Add auth context
|
|
78
|
+
})
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
server.listen(3000);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Middleware & Auth
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { TRPCError } from '@trpc/server';
|
|
88
|
+
|
|
89
|
+
const isAuthenticated = t.middleware(({ ctx, next }) => {
|
|
90
|
+
if (!ctx.user) {
|
|
91
|
+
throw new TRPCError({ code: 'UNAUTHORIZED' });
|
|
92
|
+
}
|
|
93
|
+
return next({
|
|
94
|
+
ctx: { user: ctx.user }
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const protectedProcedure = t.procedure.use(isAuthenticated);
|
|
99
|
+
|
|
100
|
+
export const protectedRouter = router({
|
|
101
|
+
getProfile: protectedProcedure
|
|
102
|
+
.query(({ ctx }) => {
|
|
103
|
+
return ctx.user;
|
|
104
|
+
}),
|
|
105
|
+
|
|
106
|
+
updateProfile: protectedProcedure
|
|
107
|
+
.input(z.object({ name: z.string() }))
|
|
108
|
+
.mutation(async ({ input, ctx }) => {
|
|
109
|
+
return await db.user.update({
|
|
110
|
+
where: { id: ctx.user.id },
|
|
111
|
+
data: input
|
|
112
|
+
});
|
|
113
|
+
})
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## React Client
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { createTRPCReact } from '@trpc/react-query';
|
|
121
|
+
import type { AppRouter } from '../server/router';
|
|
122
|
+
|
|
123
|
+
const trpc = createTRPCReact<AppRouter>();
|
|
124
|
+
|
|
125
|
+
function App() {
|
|
126
|
+
const client = trpc.createClient({
|
|
127
|
+
url: 'http://localhost:3000'
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<trpc.Provider client={client}>
|
|
132
|
+
<UserList />
|
|
133
|
+
</trpc.Provider>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function UserList() {
|
|
138
|
+
// Full type safety!
|
|
139
|
+
const users = trpc.user.list.useQuery({ limit: 10 });
|
|
140
|
+
|
|
141
|
+
const createUser = trpc.user.create.useMutation();
|
|
142
|
+
|
|
143
|
+
if (users.isLoading) return <div>Loading...</div>;
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<div>
|
|
147
|
+
{users.data?.map(user => (
|
|
148
|
+
<div key={user.id}>{user.name}</div>
|
|
149
|
+
))}
|
|
150
|
+
|
|
151
|
+
<button onClick={() => createUser.mutate({
|
|
152
|
+
email: 'new@example.com',
|
|
153
|
+
name: 'New User'
|
|
154
|
+
})}>
|
|
155
|
+
Add User
|
|
156
|
+
</button>
|
|
157
|
+
</div>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Best Practices
|
|
163
|
+
|
|
164
|
+
✅ **Input validation** - Use Zod for schema validation
|
|
165
|
+
✅ **Error handling** - Use TRPCError with proper codes
|
|
166
|
+
✅ **Type safety** - Leverage full end-to-end types
|
|
167
|
+
✅ **Middleware** - Authentication, logging, rate limiting
|
|
168
|
+
✅ **Batch requests** - Reduce HTTP calls
|
|
169
|
+
|
|
170
|
+
## Resources
|
|
171
|
+
|
|
172
|
+
- [tRPC Documentation](https://trpc.io/)
|
|
173
|
+
- [Zod Schema Validation](https://zod.dev/)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# API Versioning
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Strategies for evolving APIs without breaking existing clients.
|
|
5
|
+
|
|
6
|
+
## URL Path Versioning
|
|
7
|
+
|
|
8
|
+
```typescript
|
|
9
|
+
// Express versioned routes
|
|
10
|
+
const v1 = express.Router();
|
|
11
|
+
v1.get('/users', async (req, res) => {
|
|
12
|
+
const users = await db.user.findMany({ select: { id: true, name: true, email: true } });
|
|
13
|
+
res.json(users);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const v2 = express.Router();
|
|
17
|
+
v2.get('/users', async (req, res) => {
|
|
18
|
+
const { page = 1, limit = 20 } = req.query;
|
|
19
|
+
const skip = (Number(page) - 1) * Number(limit);
|
|
20
|
+
const [users, total] = await Promise.all([
|
|
21
|
+
db.user.findMany({ skip, take: Number(limit) }),
|
|
22
|
+
db.user.count()
|
|
23
|
+
]);
|
|
24
|
+
res.json({ data: users, meta: { page: Number(page), limit: Number(limit), total } });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
app.use('/api/v1', v1);
|
|
28
|
+
app.use('/api/v2', v2);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Next.js App Router Versioning
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// app/api/v1/users/route.ts
|
|
35
|
+
export async function GET() {
|
|
36
|
+
const users = await prisma.user.findMany();
|
|
37
|
+
return Response.json(users);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// app/api/v2/users/route.ts
|
|
41
|
+
export async function GET(req: Request) {
|
|
42
|
+
const { searchParams } = new URL(req.url);
|
|
43
|
+
const page = Number(searchParams.get('page') ?? 1);
|
|
44
|
+
const limit = Number(searchParams.get('limit') ?? 20);
|
|
45
|
+
const [users, total] = await Promise.all([
|
|
46
|
+
prisma.user.findMany({ skip: (page - 1) * limit, take: limit }),
|
|
47
|
+
prisma.user.count()
|
|
48
|
+
]);
|
|
49
|
+
return Response.json({ data: users, meta: { page, limit, total } });
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Deprecation Headers
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
function addDeprecationHeaders(res: Response, sunset: string) {
|
|
57
|
+
res.setHeader('Deprecation', 'true');
|
|
58
|
+
res.setHeader('Sunset', sunset);
|
|
59
|
+
res.setHeader('Link', '</api/v2/users>; rel="successor-version"');
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Best Practices
|
|
64
|
+
- Version from day one
|
|
65
|
+
- Keep v1 alive for 12+ months after v2 launch
|
|
66
|
+
- Always return `X-API-Version` response header
|
|
67
|
+
- Use `Sunset` header to communicate deprecation timelines
|
|
68
|
+
|
|
69
|
+
## Resources
|
|
70
|
+
- [Stripe API versioning](https://stripe.com/docs/api/versioning)
|