@punks/cli 0.1.16 → 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/AGENTS.md +10 -0
- package/README.md +64 -0
- package/dist/data/AGENTS.md +123 -0
- package/dist/data/catalog/lint.ts +349 -0
- package/dist/data/catalog/packs.ts +44 -0
- package/dist/data/catalog/skills.ts +47 -0
- package/dist/data/catalog/tools.ts +22 -0
- package/dist/data/hooks/format-edited-file.mjs +554 -0
- package/dist/data/hooks/format-edited-file.py +157 -0
- package/dist/data/hooks/format-edited-file.sh +37 -0
- package/dist/data/hooks/require-tests-for-pr.mjs +144 -0
- package/dist/data/scripts/sync-subagents.mjs +420 -0
- package/dist/data/subagents/manifest.mjs +253 -0
- package/dist/index.js +46415 -0
- package/dist/skills/agnostic/backend/backend-domain-structure/SKILL.md +50 -0
- package/dist/skills/agnostic/backend/backend-domain-structure/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/backend/backend-domain-structure/references/layout.md +167 -0
- package/dist/skills/agnostic/backend/backend-recoverable-actions/SKILL.md +49 -0
- package/dist/skills/agnostic/backend/backend-recoverable-actions/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/backend/backend-recoverable-actions/references/strategy-matrix.md +34 -0
- package/dist/skills/agnostic/backend/backend-recoverable-actions/references/test-matrix.md +34 -0
- package/dist/skills/agnostic/docs/docs-maintenance/SKILL.md +193 -0
- package/dist/skills/agnostic/docs/docs-maintenance/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/docs/docs-maintenance/references/concept-pages.md +48 -0
- package/dist/skills/agnostic/docs/docs-maintenance/references/flow-pages.md +41 -0
- package/dist/skills/agnostic/frontend/agent-browser/.clawdhub/origin.json +7 -0
- package/dist/skills/agnostic/frontend/agent-browser/SKILL.md +229 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/authentication.md +202 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/commands.md +259 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/proxy-support.md +188 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/session-management.md +193 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/snapshot-refs.md +194 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/video-recording.md +173 -0
- package/dist/skills/agnostic/frontend/agent-browser/templates/authenticated-session.sh +97 -0
- package/dist/skills/agnostic/frontend/agent-browser/templates/capture-workflow.sh +69 -0
- package/dist/skills/agnostic/frontend/agent-browser/templates/form-automation.sh +62 -0
- package/dist/skills/agnostic/frontend/design-taste-frontend/SKILL.md +226 -0
- package/dist/skills/agnostic/frontend/frontend-domain-structure/SKILL.md +55 -0
- package/dist/skills/agnostic/frontend/frontend-domain-structure/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/frontend/frontend-domain-structure/references/react/structure.md +102 -0
- package/dist/skills/agnostic/frontend/frontend-domain-structure/references/structure.md +257 -0
- package/dist/skills/agnostic/frontend/gpt-taste/SKILL.md +74 -0
- package/dist/skills/agnostic/frontend/image-taste-frontend/SKILL.md +1102 -0
- package/dist/skills/agnostic/frontend/redesign-existing-projects/SKILL.md +178 -0
- package/dist/skills/agnostic/planning/create-plan/REFERENCE.md +37 -0
- package/dist/skills/agnostic/planning/create-plan/SKILL.md +69 -0
- package/dist/skills/agnostic/planning/create-plan/references/backlog-sync.md +44 -0
- package/dist/skills/agnostic/planning/create-plan/references/grill-phase.md +86 -0
- package/dist/skills/agnostic/planning/create-plan/references/plan-schema.md +66 -0
- package/dist/skills/agnostic/planning/create-plan/references/planner-phase.md +39 -0
- package/dist/skills/agnostic/planning/create-plan/references/stop-conditions.md +18 -0
- package/dist/skills/agnostic/planning/create-plan/references/tdd-phase.md +26 -0
- package/dist/skills/agnostic/planning/create-spec/SKILL.md +57 -0
- package/dist/skills/agnostic/planning/create-spec/assets/SPEC-TEMPLATE.md +91 -0
- package/dist/skills/agnostic/planning/create-spec/references/discovery.md +44 -0
- package/dist/skills/agnostic/planning/create-spec/references/folder-naming.md +27 -0
- package/dist/skills/agnostic/planning/create-spec/references/handoff.md +47 -0
- package/dist/skills/agnostic/planning/create-spec/references/questioning.md +41 -0
- package/dist/skills/agnostic/planning/create-spec/references/spec-quality-bar.md +58 -0
- package/dist/skills/agnostic/planning/create-spec/references/wiki-bookkeeping.md +26 -0
- package/dist/skills/agnostic/planning/grill-me/SKILL.md +28 -0
- package/dist/skills/agnostic/planning/implement-spec/SKILL.md +72 -0
- package/dist/skills/agnostic/planning/implement-spec/assets/IMPLEMENTATION-NOTES-TEMPLATE.md +47 -0
- package/dist/skills/agnostic/planning/implement-spec/references/lifecycle.md +149 -0
- package/dist/skills/agnostic/planning/implement-spec/references/parallel-orchestration.md +102 -0
- package/dist/skills/agnostic/planning/implement-spec/references/parallel-worker-brief.md +65 -0
- package/dist/skills/agnostic/planning/implement-spec/references/parallel.md +56 -0
- package/dist/skills/agnostic/planning/implement-spec/references/sequential.md +28 -0
- package/dist/skills/agnostic/planning/swarm-planner/SKILL.md +179 -0
- package/dist/skills/agnostic/quality/simplify/SKILL.md +14 -0
- package/dist/skills/agnostic/quality/tdd/SKILL.md +107 -0
- package/dist/skills/agnostic/quality/tdd/deep-modules.md +33 -0
- package/dist/skills/agnostic/quality/tdd/interface-design.md +31 -0
- package/dist/skills/agnostic/quality/tdd/mocking.md +59 -0
- package/dist/skills/agnostic/quality/tdd/refactoring.md +10 -0
- package/dist/skills/agnostic/quality/tdd/tests.md +61 -0
- package/dist/skills/agnostic/requirements/requirements-grill/SKILL.md +42 -0
- package/dist/skills/agnostic/requirements/requirements-grill/references/artifact-output.md +73 -0
- package/dist/skills/agnostic/requirements/requirements-grill/references/grilling-flow.md +57 -0
- package/dist/skills/agnostic/requirements/requirements-grill/references/wiki-output.md +94 -0
- package/dist/skills/agnostic/requirements/write-backlog/EXAMPLES.md +67 -0
- package/dist/skills/agnostic/requirements/write-backlog/REFERENCE.md +253 -0
- package/dist/skills/agnostic/requirements/write-backlog/SKILL.md +68 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/concepts/backlog-model.md +69 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/concepts/story-shape.md +66 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/providers/azure-devops-create-payload.md +63 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/providers/github-issues-create-payload.md +48 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/providers/linear-create-payload.md +76 -0
- package/dist/skills/agnostic/research/improve-codebase-architecture/REFERENCE.md +78 -0
- package/dist/skills/agnostic/research/improve-codebase-architecture/SKILL.md +76 -0
- package/dist/skills/agnostic/research/parallel-research/SKILL.md +68 -0
- package/dist/skills/agnostic/research/parallel-research/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/subagents/swarm-planner/SKILL.md +179 -0
- package/dist/skills/agnostic/write-a-skill/SKILL.md +117 -0
- package/dist/skills/frameworks/better-auth/better-auth-best-practices/SKILL.md +166 -0
- package/dist/skills/frameworks/better-auth/better-auth-security-best-practices/SKILL.MD +432 -0
- package/dist/skills/frameworks/effect/effect-authoring/SKILL.md +116 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/branded-types.md +98 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/effect-atom-patterns.md +257 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/effect-primitives.md +144 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/error-patterns.md +156 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/otel-patterns.md +113 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/test-patterns.md +146 -0
- package/dist/skills/frameworks/effect/effect-backend-structure/SKILL.md +96 -0
- package/dist/skills/frameworks/effect/effect-backend-structure/agents/openai.yaml +4 -0
- package/dist/skills/frameworks/effect/effect-backend-structure/references/layout.md +68 -0
- package/dist/skills/frameworks/effect/effect-best-practices/SKILL.md +517 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/anti-patterns.md +392 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/effect-atom-patterns.md +653 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/error-patterns.md +464 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/language-server.md +287 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/layer-patterns.md +495 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/observability-patterns.md +342 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/rpc-cluster-patterns.md +418 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/schema-patterns.md +353 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/service-patterns.md +299 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/SKILL.md +65 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/agents/openai.yaml +4 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/references/flow-examples.md +154 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/references/source-backed-primitives.md +104 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/references/strategy-matrix.md +34 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/references/test-matrix.md +36 -0
- package/dist/skills/frameworks/elysia/elysiajs/SKILL.md +475 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/basic.ts +9 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/body-parser.ts +33 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/complex.ts +112 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/cookie.ts +45 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/error.ts +38 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/file.ts +10 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/guard.ts +34 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/map-response.ts +15 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/redirect.ts +6 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/rename.ts +32 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/schema.ts +61 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/state.ts +6 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/upload-file.ts +20 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/websocket.ts +25 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/ai-sdk.md +92 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/astro.md +59 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/better-auth.md +117 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/cloudflare-worker.md +95 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/deno.md +34 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/drizzle.md +258 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/expo.md +95 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/nextjs.md +103 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/nodejs.md +64 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/nuxt.md +67 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/prisma.md +93 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/react-email.md +134 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/sveltekit.md +53 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/tanstack-start.md +87 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/vercel.md +55 -0
- package/dist/skills/frameworks/elysia/elysiajs/patterns/mvc.md +380 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/bearer.md +30 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/cors.md +141 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/cron.md +265 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/graphql-apollo.md +90 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/graphql-yoga.md +87 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/html.md +188 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/jwt.md +197 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/openapi.md +246 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/opentelemetry.md +167 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/server-timing.md +71 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/static.md +84 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/bun-fullstack-dev-server.md +129 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/cookie.md +187 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/deployment.md +413 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/eden.md +158 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/lifecycle.md +198 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/macro.md +83 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/plugin.md +207 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/route.md +331 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/testing.md +385 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/validation.md +491 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/websocket.md +250 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/.github/workflows/branch-protection.yml +24 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/.github/workflows/deploy.yml +61 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/AGENTS.md +5958 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/SKILL.md +130 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/api-use-dto-serialization.md +182 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/api-use-interceptors.md +202 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/api-use-pipes.md +205 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/api-versioning.md +191 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-avoid-circular-deps.md +80 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-feature-modules.md +82 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-module-sharing.md +141 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-single-responsibility.md +106 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-use-events.md +108 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-use-repository-pattern.md +97 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/db-avoid-n-plus-one.md +139 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/db-use-migrations.md +129 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/db-use-transactions.md +140 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/devops-graceful-shutdown.md +222 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/devops-use-config-module.md +167 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/devops-use-logging.md +232 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-avoid-service-locator.md +104 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-interface-segregation.md +165 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-liskov-substitution.md +221 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-prefer-constructor-injection.md +86 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-scope-awareness.md +94 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-use-interfaces-tokens.md +101 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/error-handle-async-errors.md +125 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/error-throw-http-exceptions.md +114 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/error-use-exception-filters.md +140 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/micro-use-health-checks.md +226 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/micro-use-patterns.md +167 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/micro-use-queues.md +252 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/perf-async-hooks.md +109 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/perf-lazy-loading.md +121 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/perf-optimize-database.md +131 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/perf-use-caching.md +128 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-auth-jwt.md +146 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-rate-limiting.md +125 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-sanitize-output.md +139 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-use-guards.md +135 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-validate-all-input.md +150 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/test-e2e-supertest.md +178 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/test-mock-external-services.md +179 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/test-use-testing-module.md +153 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/scripts/build-agents.ts +299 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/scripts/build.sh +16 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/scripts/package-lock.json +237 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/scripts/package.json +15 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/SKILL.md +208 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/authentication.md +166 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/controllers-routing.md +111 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/dtos-validation.md +153 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/migration-from-express.md +1237 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/services-di.md +140 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/testing-patterns.md +186 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/SKILL.md +153 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/async-patterns.md +87 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/bundling.md +180 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/data-patterns.md +297 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/debug-tricks.md +105 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/directives.md +73 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/error-handling.md +227 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/file-conventions.md +140 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/font.md +245 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/functions.md +108 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/hydration-error.md +91 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/image.md +173 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/metadata.md +301 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/parallel-routes.md +287 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/route-handlers.md +146 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/rsc-boundaries.md +159 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/runtime-selection.md +39 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/scripts.md +141 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/self-hosting.md +371 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/suspense-boundaries.md +67 -0
- package/dist/skills/frameworks/nextjs/next-cache-components/SKILL.md +360 -0
- package/dist/skills/frameworks/react/async-react-patterns/SKILL.md +78 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/AGENTS.md +946 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/SKILL.md +89 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/state-context-interface.md +191 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/state-lift-state.md +125 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/AGENTS.md +3750 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/SKILL.md +148 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/advanced-effect-event-deps.md +56 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-defer-await.md +82 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-barrel-imports.md +60 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-request-idle-callback.md +105 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-hoist-static-io.md +149 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-no-shared-module-state.md +50 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/.claude-plugin/plugin.json +12 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/SKILL.md +1058 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/assets/example-template.txt +14 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/best-practices.md +304 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/common-patterns.md +271 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/example-reference.md +26 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/testing.md +282 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/top-errors.md +332 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/typescript-patterns.md +291 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/v4-to-v5-migration.md +231 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/rules/tanstack-query.md +126 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/scripts/example-script.sh +15 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/custom-hooks-pattern.tsx +281 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/devtools-setup.tsx +248 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/error-boundary.tsx +243 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/package.json +31 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/provider-setup.tsx +50 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/query-client-config.ts +72 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/use-infinite-query.tsx +214 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/use-mutation-basic.tsx +201 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/use-mutation-optimistic.tsx +234 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/use-query-basic.tsx +119 -0
- package/dist/skills/frameworks/trpc/tanstack-query/.claude-plugin/plugin.json +12 -0
- package/dist/skills/frameworks/trpc/tanstack-query/SKILL.md +1058 -0
- package/dist/skills/frameworks/trpc/tanstack-query/assets/example-template.txt +14 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/best-practices.md +304 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/common-patterns.md +271 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/example-reference.md +26 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/testing.md +282 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/top-errors.md +332 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/typescript-patterns.md +291 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/v4-to-v5-migration.md +231 -0
- package/dist/skills/frameworks/trpc/tanstack-query/rules/tanstack-query.md +126 -0
- package/dist/skills/frameworks/trpc/tanstack-query/scripts/example-script.sh +15 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/custom-hooks-pattern.tsx +281 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/devtools-setup.tsx +248 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/error-boundary.tsx +243 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/package.json +31 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/provider-setup.tsx +50 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/query-client-config.ts +72 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/use-infinite-query.tsx +214 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/use-mutation-basic.tsx +201 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/use-mutation-optimistic.tsx +234 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/use-query-basic.tsx +119 -0
- package/dist/skills/frameworks/turborepo/turborepo/SKILL.md +914 -0
- package/dist/skills/frameworks/turborepo/turborepo/command/turborepo.md +70 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/best-practices/RULE.md +241 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/best-practices/dependencies.md +246 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/best-practices/packages.md +335 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/best-practices/structure.md +270 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/boundaries/RULE.md +126 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/caching/RULE.md +107 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/caching/gotchas.md +169 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/caching/remote-cache.md +127 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/ci/RULE.md +79 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/ci/github-actions.md +162 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/ci/patterns.md +145 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/ci/vercel.md +103 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/cli/RULE.md +100 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/cli/commands.md +297 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/configuration/RULE.md +211 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/configuration/global-options.md +187 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/configuration/gotchas.md +348 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/configuration/tasks.md +285 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/environment/RULE.md +96 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/environment/gotchas.md +141 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/environment/modes.md +101 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/filtering/RULE.md +148 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/filtering/patterns.md +152 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/watch/RULE.md +99 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/docs/README.md +20 -0
- package/docs/reference/dp-requirements.md +210 -0
- package/docs/runbooks/dp-cli-scaffolding.md +187 -0
- package/package.json +24 -50
- package/.eslintignore +0 -4
- package/.eslintrc +0 -127
- package/.prettierignore +0 -4
- package/.prettierrc +0 -7
- package/bin/abstractions/builder.d.ts +0 -4
- package/bin/abstractions/builder.js +0 -7
- package/bin/builders/dotnet/base.d.ts +0 -18
- package/bin/builders/dotnet/base.js +0 -47
- package/bin/builders/dotnet/entity-configuration/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-configuration/index.js +0 -29
- package/bin/builders/dotnet/entity-converter/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-converter/index.js +0 -29
- package/bin/builders/dotnet/entity-model-create/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-model-create/index.js +0 -29
- package/bin/builders/dotnet/entity-model-dto/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-model-dto/index.js +0 -29
- package/bin/builders/dotnet/entity-model-list-item-dto/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-model-list-item-dto/index.js +0 -29
- package/bin/builders/dotnet/entity-model-update/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-model-update/index.js +0 -29
- package/bin/builders/dotnet/entity-search-parameters/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-search-parameters/index.js +0 -29
- package/bin/builders/dotnet/entity-search-query-builder/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-search-query-builder/index.js +0 -29
- package/bin/builders/dotnet/firestore-connector/index.d.ts +0 -8
- package/bin/builders/dotnet/firestore-connector/index.js +0 -29
- package/bin/builders/dotnet/firestore-mapper/index.d.ts +0 -8
- package/bin/builders/dotnet/firestore-mapper/index.js +0 -29
- package/bin/builders/dotnet/types.d.ts +0 -10
- package/bin/builders/dotnet/types.js +0 -3
- package/bin/commands/entity-add/__test__/dotnet/common.d.ts +0 -2
- package/bin/commands/entity-add/__test__/dotnet/common.js +0 -11
- package/bin/commands/entity-add/__test__/dotnet/render.configuration.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.configuration.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.converter.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.converter.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.firestore-connector.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.firestore-connector.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.firestore-mapper.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.firestore-mapper.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.model-create.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.model-create.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.model-dto.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.model-dto.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.model-list-item-dto.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.model-list-item-dto.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.model-update.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.model-update.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.search-parameters.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.search-parameters.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.search-query.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.search-query.spec.js +0 -22
- package/bin/commands/entity-add/index.d.ts +0 -26
- package/bin/commands/entity-add/index.js +0 -44
- package/bin/logging/index.d.ts +0 -8
- package/bin/logging/index.js +0 -28
- package/bin/providers/rendering/base.d.ts +0 -3
- package/bin/providers/rendering/base.js +0 -7
- package/bin/providers/rendering/factory.d.ts +0 -5
- package/bin/providers/rendering/factory.js +0 -16
- package/bin/providers/rendering/handlebars.d.ts +0 -4
- package/bin/providers/rendering/handlebars.js +0 -16
- package/bin/renderer/index.d.ts +0 -6
- package/bin/renderer/index.js +0 -27
- package/bin/run.d.ts +0 -2
- package/bin/run.js +0 -70
- package/bin/services/folders.d.ts +0 -1
- package/bin/services/folders.js +0 -31
- package/bin/types/commands.d.ts +0 -5
- package/bin/types/commands.js +0 -3
- package/bin/utils/collections.d.ts +0 -1
- package/bin/utils/collections.js +0 -6
- package/bin/utils/files.d.ts +0 -3
- package/bin/utils/files.js +0 -19
- package/bin/utils/strings.d.ts +0 -4
- package/bin/utils/strings.js +0 -22
- package/bin/utils/text.d.ts +0 -1
- package/bin/utils/text.js +0 -8
- package/em-cli +0 -0
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.configuration.spec.ts.snap +0 -49
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.converter.spec.ts.snap +0 -53
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.firestore-connector.spec.ts.snap +0 -20
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.firestore-mapper.spec.ts.snap +0 -29
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.model-create.spec.ts.snap +0 -10
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.model-dto.spec.ts.snap +0 -9
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.model-list-item-dto.spec.ts.snap +0 -11
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.model-update.spec.ts.snap +0 -11
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.search-parameters.spec.ts.snap +0 -29
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.search-query.spec.ts.snap +0 -42
- package/templates/dotnet/NewEntity/Configuration/<PluralizedEntity>Configuration.cs.template +0 -48
- package/templates/dotnet/NewEntity/Connectors/<PluralizedEntity>FirestoreConnector.cs.template +0 -15
- package/templates/dotnet/NewEntity/Converters/<PluralizedEntity>Converter.cs.template +0 -48
- package/templates/dotnet/NewEntity/Mappers/<PluralizedEntity>FirestoreMapper.cs.template +0 -25
- package/templates/dotnet/NewEntity/Models/<Entity>CreateInput.cs.template +0 -6
- package/templates/dotnet/NewEntity/Models/<Entity>Dto.cs.template +0 -5
- package/templates/dotnet/NewEntity/Models/<Entity>ListItemDto.cs.template +0 -6
- package/templates/dotnet/NewEntity/Models/<Entity>UpdateInput.cs.template +0 -6
- package/templates/dotnet/NewEntity/Search/<PluralizedEntity>QueryBuilder.cs.template +0 -38
- package/templates/dotnet/NewEntity/Search/<PluralizedEntity>SearchParameters.cs.template +0 -24
- package/tsconfig.json +0 -25
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Injection Tokens for Interfaces
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Enables interface-based DI at runtime
|
|
5
|
+
tags: dependency-injection, tokens, interfaces
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Injection Tokens for Interfaces
|
|
9
|
+
|
|
10
|
+
TypeScript interfaces are erased at compile time and can't be used as injection tokens. Use string tokens, symbols, or abstract classes when you want to inject implementations of interfaces. This enables swapping implementations for testing or different environments.
|
|
11
|
+
|
|
12
|
+
**Incorrect (interface can't be used as token):**
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// Interface can't be used as injection token
|
|
16
|
+
interface PaymentGateway {
|
|
17
|
+
charge(amount: number): Promise<PaymentResult>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Injectable()
|
|
21
|
+
export class StripeService implements PaymentGateway {
|
|
22
|
+
charge(amount: number) { /* ... */ }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Injectable()
|
|
26
|
+
export class OrdersService {
|
|
27
|
+
// This WON'T work - PaymentGateway doesn't exist at runtime
|
|
28
|
+
constructor(private payment: PaymentGateway) {}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Correct (symbol tokens or abstract classes):**
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
// Option 1: String/Symbol tokens (most flexible)
|
|
36
|
+
export const PAYMENT_GATEWAY = Symbol('PAYMENT_GATEWAY');
|
|
37
|
+
|
|
38
|
+
export interface PaymentGateway {
|
|
39
|
+
charge(amount: number): Promise<PaymentResult>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@Injectable()
|
|
43
|
+
export class StripeService implements PaymentGateway {
|
|
44
|
+
async charge(amount: number): Promise<PaymentResult> {
|
|
45
|
+
// Stripe implementation
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@Injectable()
|
|
50
|
+
export class MockPaymentService implements PaymentGateway {
|
|
51
|
+
async charge(amount: number): Promise<PaymentResult> {
|
|
52
|
+
return { success: true, id: 'mock-id' };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Module registration
|
|
57
|
+
@Module({
|
|
58
|
+
providers: [
|
|
59
|
+
{
|
|
60
|
+
provide: PAYMENT_GATEWAY,
|
|
61
|
+
useClass: process.env.NODE_ENV === 'test'
|
|
62
|
+
? MockPaymentService
|
|
63
|
+
: StripeService,
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
exports: [PAYMENT_GATEWAY],
|
|
67
|
+
})
|
|
68
|
+
export class PaymentModule {}
|
|
69
|
+
|
|
70
|
+
// Injection
|
|
71
|
+
@Injectable()
|
|
72
|
+
export class OrdersService {
|
|
73
|
+
constructor(
|
|
74
|
+
@Inject(PAYMENT_GATEWAY) private payment: PaymentGateway,
|
|
75
|
+
) {}
|
|
76
|
+
|
|
77
|
+
async createOrder(dto: CreateOrderDto) {
|
|
78
|
+
await this.payment.charge(dto.amount);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Option 2: Abstract class (carries runtime type info)
|
|
83
|
+
export abstract class PaymentGateway {
|
|
84
|
+
abstract charge(amount: number): Promise<PaymentResult>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@Injectable()
|
|
88
|
+
export class StripeService extends PaymentGateway {
|
|
89
|
+
async charge(amount: number): Promise<PaymentResult> {
|
|
90
|
+
// Implementation
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// No @Inject needed with abstract class
|
|
95
|
+
@Injectable()
|
|
96
|
+
export class OrdersService {
|
|
97
|
+
constructor(private payment: PaymentGateway) {}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Reference: [NestJS Custom Providers](https://docs.nestjs.com/fundamentals/custom-providers)
|
package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/error-handle-async-errors.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Handle Async Errors Properly
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Prevents process crashes from unhandled rejections
|
|
5
|
+
tags: error-handling, async, promises
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Handle Async Errors Properly
|
|
9
|
+
|
|
10
|
+
NestJS automatically catches errors from async route handlers, but errors from background tasks, event handlers, and manually created promises can crash your application. Always handle async errors explicitly and use global handlers as a safety net.
|
|
11
|
+
|
|
12
|
+
**Incorrect (fire-and-forget without error handling):**
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// Fire-and-forget without error handling
|
|
16
|
+
@Injectable()
|
|
17
|
+
export class UsersService {
|
|
18
|
+
async createUser(dto: CreateUserDto): Promise<User> {
|
|
19
|
+
const user = await this.repo.save(dto);
|
|
20
|
+
|
|
21
|
+
// Fire and forget - if this fails, error is unhandled!
|
|
22
|
+
this.emailService.sendWelcome(user.email);
|
|
23
|
+
|
|
24
|
+
return user;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Unhandled promise in event handler
|
|
29
|
+
@Injectable()
|
|
30
|
+
export class OrdersService {
|
|
31
|
+
@OnEvent('order.created')
|
|
32
|
+
handleOrderCreated(event: OrderCreatedEvent) {
|
|
33
|
+
// This returns a promise but it's not awaited!
|
|
34
|
+
this.processOrder(event);
|
|
35
|
+
// Errors will crash the process
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private async processOrder(event: OrderCreatedEvent): Promise<void> {
|
|
39
|
+
await this.inventoryService.reserve(event.items);
|
|
40
|
+
await this.notificationService.send(event.userId);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Missing try-catch in scheduled tasks
|
|
45
|
+
@Cron('0 0 * * *')
|
|
46
|
+
async dailyCleanup(): Promise<void> {
|
|
47
|
+
await this.cleanupService.run();
|
|
48
|
+
// If this throws, no error handling
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Correct (explicit async error handling):**
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Handle fire-and-forget with explicit catch
|
|
56
|
+
@Injectable()
|
|
57
|
+
export class UsersService {
|
|
58
|
+
private readonly logger = new Logger(UsersService.name);
|
|
59
|
+
|
|
60
|
+
async createUser(dto: CreateUserDto): Promise<User> {
|
|
61
|
+
const user = await this.repo.save(dto);
|
|
62
|
+
|
|
63
|
+
// Explicitly catch and log errors
|
|
64
|
+
this.emailService.sendWelcome(user.email).catch((error) => {
|
|
65
|
+
this.logger.error('Failed to send welcome email', error.stack);
|
|
66
|
+
// Optionally queue for retry
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return user;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Properly handle async event handlers
|
|
74
|
+
@Injectable()
|
|
75
|
+
export class OrdersService {
|
|
76
|
+
private readonly logger = new Logger(OrdersService.name);
|
|
77
|
+
|
|
78
|
+
@OnEvent('order.created')
|
|
79
|
+
async handleOrderCreated(event: OrderCreatedEvent): Promise<void> {
|
|
80
|
+
try {
|
|
81
|
+
await this.processOrder(event);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
this.logger.error('Failed to process order', { event, error });
|
|
84
|
+
// Don't rethrow - would crash the process
|
|
85
|
+
await this.deadLetterQueue.add('order.created', event);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Safe scheduled tasks
|
|
91
|
+
@Injectable()
|
|
92
|
+
export class CleanupService {
|
|
93
|
+
private readonly logger = new Logger(CleanupService.name);
|
|
94
|
+
|
|
95
|
+
@Cron('0 0 * * *')
|
|
96
|
+
async dailyCleanup(): Promise<void> {
|
|
97
|
+
try {
|
|
98
|
+
await this.cleanupService.run();
|
|
99
|
+
this.logger.log('Daily cleanup completed');
|
|
100
|
+
} catch (error) {
|
|
101
|
+
this.logger.error('Daily cleanup failed', error.stack);
|
|
102
|
+
// Alert or retry logic
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Global unhandled rejection handler in main.ts
|
|
108
|
+
async function bootstrap() {
|
|
109
|
+
const app = await NestFactory.create(AppModule);
|
|
110
|
+
const logger = new Logger('Bootstrap');
|
|
111
|
+
|
|
112
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
113
|
+
logger.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
process.on('uncaughtException', (error) => {
|
|
117
|
+
logger.error('Uncaught Exception:', error);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
await app.listen(3000);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Reference: [Node.js Unhandled Rejections](https://nodejs.org/api/process.html#event-unhandledrejection)
|
package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/error-throw-http-exceptions.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Throw HTTP Exceptions from Services
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Keeps controllers thin and simplifies error handling
|
|
5
|
+
tags: error-handling, exceptions, services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Throw HTTP Exceptions from Services
|
|
9
|
+
|
|
10
|
+
It's acceptable (and often preferable) to throw `HttpException` subclasses from services in HTTP applications. This keeps controllers thin and allows services to communicate appropriate error states. For truly layer-agnostic services, use domain exceptions that map to HTTP status codes.
|
|
11
|
+
|
|
12
|
+
**Incorrect (return error objects instead of throwing):**
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// Return error objects instead of throwing
|
|
16
|
+
@Injectable()
|
|
17
|
+
export class UsersService {
|
|
18
|
+
async findById(id: string): Promise<{ user?: User; error?: string }> {
|
|
19
|
+
const user = await this.repo.findOne({ where: { id } });
|
|
20
|
+
if (!user) {
|
|
21
|
+
return { error: 'User not found' }; // Controller must check this
|
|
22
|
+
}
|
|
23
|
+
return { user };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Controller('users')
|
|
28
|
+
export class UsersController {
|
|
29
|
+
@Get(':id')
|
|
30
|
+
async findOne(@Param('id') id: string) {
|
|
31
|
+
const result = await this.usersService.findById(id);
|
|
32
|
+
if (result.error) {
|
|
33
|
+
throw new NotFoundException(result.error);
|
|
34
|
+
}
|
|
35
|
+
return result.user;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Correct (throw exceptions directly from service):**
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// Throw exceptions directly from service
|
|
44
|
+
@Injectable()
|
|
45
|
+
export class UsersService {
|
|
46
|
+
constructor(private readonly repo: UserRepository) {}
|
|
47
|
+
|
|
48
|
+
async findById(id: string): Promise<User> {
|
|
49
|
+
const user = await this.repo.findOne({ where: { id } });
|
|
50
|
+
if (!user) {
|
|
51
|
+
throw new NotFoundException(`User #${id} not found`);
|
|
52
|
+
}
|
|
53
|
+
return user;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async create(dto: CreateUserDto): Promise<User> {
|
|
57
|
+
const existing = await this.repo.findOne({
|
|
58
|
+
where: { email: dto.email },
|
|
59
|
+
});
|
|
60
|
+
if (existing) {
|
|
61
|
+
throw new ConflictException('Email already registered');
|
|
62
|
+
}
|
|
63
|
+
return this.repo.save(dto);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async update(id: string, dto: UpdateUserDto): Promise<User> {
|
|
67
|
+
const user = await this.findById(id); // Throws if not found
|
|
68
|
+
Object.assign(user, dto);
|
|
69
|
+
return this.repo.save(user);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Controller stays thin
|
|
74
|
+
@Controller('users')
|
|
75
|
+
export class UsersController {
|
|
76
|
+
@Get(':id')
|
|
77
|
+
findOne(@Param('id') id: string): Promise<User> {
|
|
78
|
+
return this.usersService.findById(id);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@Post()
|
|
82
|
+
create(@Body() dto: CreateUserDto): Promise<User> {
|
|
83
|
+
return this.usersService.create(dto);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// For layer-agnostic services, use domain exceptions
|
|
88
|
+
export class EntityNotFoundException extends Error {
|
|
89
|
+
constructor(
|
|
90
|
+
public readonly entity: string,
|
|
91
|
+
public readonly id: string,
|
|
92
|
+
) {
|
|
93
|
+
super(`${entity} with ID "${id}" not found`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Map to HTTP in exception filter
|
|
98
|
+
@Catch(EntityNotFoundException)
|
|
99
|
+
export class EntityNotFoundFilter implements ExceptionFilter {
|
|
100
|
+
catch(exception: EntityNotFoundException, host: ArgumentsHost) {
|
|
101
|
+
const ctx = host.switchToHttp();
|
|
102
|
+
const response = ctx.getResponse<Response>();
|
|
103
|
+
|
|
104
|
+
response.status(404).json({
|
|
105
|
+
statusCode: 404,
|
|
106
|
+
message: exception.message,
|
|
107
|
+
entity: exception.entity,
|
|
108
|
+
id: exception.id,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Reference: [NestJS Exception Filters](https://docs.nestjs.com/exception-filters)
|
package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/error-use-exception-filters.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Exception Filters for Error Handling
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Consistent, centralized error handling
|
|
5
|
+
tags: error-handling, exception-filters, consistency
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Exception Filters for Error Handling
|
|
9
|
+
|
|
10
|
+
Never catch exceptions and manually format error responses in controllers. Use NestJS exception filters to handle errors consistently across your application. Create custom exception filters for specific error types and a global filter for unhandled exceptions.
|
|
11
|
+
|
|
12
|
+
**Incorrect (manual error handling in controllers):**
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// Manual error handling in controllers
|
|
16
|
+
@Controller('users')
|
|
17
|
+
export class UsersController {
|
|
18
|
+
@Get(':id')
|
|
19
|
+
async findOne(@Param('id') id: string, @Res() res: Response) {
|
|
20
|
+
try {
|
|
21
|
+
const user = await this.usersService.findById(id);
|
|
22
|
+
if (!user) {
|
|
23
|
+
return res.status(404).json({
|
|
24
|
+
statusCode: 404,
|
|
25
|
+
message: 'User not found',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return res.json(user);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error(error);
|
|
31
|
+
return res.status(500).json({
|
|
32
|
+
statusCode: 500,
|
|
33
|
+
message: 'Internal server error',
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Correct (exception filters with consistent handling):**
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// Use built-in and custom exceptions
|
|
44
|
+
@Controller('users')
|
|
45
|
+
export class UsersController {
|
|
46
|
+
@Get(':id')
|
|
47
|
+
async findOne(@Param('id') id: string): Promise<User> {
|
|
48
|
+
const user = await this.usersService.findById(id);
|
|
49
|
+
if (!user) {
|
|
50
|
+
throw new NotFoundException(`User #${id} not found`);
|
|
51
|
+
}
|
|
52
|
+
return user;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Custom domain exception
|
|
57
|
+
export class UserNotFoundException extends NotFoundException {
|
|
58
|
+
constructor(userId: string) {
|
|
59
|
+
super({
|
|
60
|
+
statusCode: 404,
|
|
61
|
+
error: 'Not Found',
|
|
62
|
+
message: `User with ID "${userId}" not found`,
|
|
63
|
+
code: 'USER_NOT_FOUND',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Custom exception filter for domain errors
|
|
69
|
+
@Catch(DomainException)
|
|
70
|
+
export class DomainExceptionFilter implements ExceptionFilter {
|
|
71
|
+
catch(exception: DomainException, host: ArgumentsHost) {
|
|
72
|
+
const ctx = host.switchToHttp();
|
|
73
|
+
const response = ctx.getResponse<Response>();
|
|
74
|
+
const request = ctx.getRequest<Request>();
|
|
75
|
+
|
|
76
|
+
const status = exception.getStatus?.() || 400;
|
|
77
|
+
|
|
78
|
+
response.status(status).json({
|
|
79
|
+
statusCode: status,
|
|
80
|
+
code: exception.code,
|
|
81
|
+
message: exception.message,
|
|
82
|
+
timestamp: new Date().toISOString(),
|
|
83
|
+
path: request.url,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Global exception filter for unhandled errors
|
|
89
|
+
@Catch()
|
|
90
|
+
export class AllExceptionsFilter implements ExceptionFilter {
|
|
91
|
+
constructor(private readonly logger: Logger) {}
|
|
92
|
+
|
|
93
|
+
catch(exception: unknown, host: ArgumentsHost) {
|
|
94
|
+
const ctx = host.switchToHttp();
|
|
95
|
+
const response = ctx.getResponse<Response>();
|
|
96
|
+
const request = ctx.getRequest<Request>();
|
|
97
|
+
|
|
98
|
+
const status =
|
|
99
|
+
exception instanceof HttpException
|
|
100
|
+
? exception.getStatus()
|
|
101
|
+
: HttpStatus.INTERNAL_SERVER_ERROR;
|
|
102
|
+
|
|
103
|
+
const message =
|
|
104
|
+
exception instanceof HttpException
|
|
105
|
+
? exception.message
|
|
106
|
+
: 'Internal server error';
|
|
107
|
+
|
|
108
|
+
this.logger.error(
|
|
109
|
+
`${request.method} ${request.url}`,
|
|
110
|
+
exception instanceof Error ? exception.stack : exception,
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
response.status(status).json({
|
|
114
|
+
statusCode: status,
|
|
115
|
+
message,
|
|
116
|
+
timestamp: new Date().toISOString(),
|
|
117
|
+
path: request.url,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Register globally in main.ts
|
|
123
|
+
app.useGlobalFilters(
|
|
124
|
+
new AllExceptionsFilter(app.get(Logger)),
|
|
125
|
+
new DomainExceptionFilter(),
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
// Or via module
|
|
129
|
+
@Module({
|
|
130
|
+
providers: [
|
|
131
|
+
{
|
|
132
|
+
provide: APP_FILTER,
|
|
133
|
+
useClass: AllExceptionsFilter,
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
})
|
|
137
|
+
export class AppModule {}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Reference: [NestJS Exception Filters](https://docs.nestjs.com/exception-filters)
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Implement Health Checks for Microservices
|
|
3
|
+
impact: MEDIUM-HIGH
|
|
4
|
+
impactDescription: Health checks enable orchestrators to manage service lifecycle
|
|
5
|
+
tags: microservices, health-checks, terminus, kubernetes
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Implement Health Checks for Microservices
|
|
9
|
+
|
|
10
|
+
Implement liveness and readiness probes using `@nestjs/terminus`. Liveness checks determine if the service should be restarted. Readiness checks determine if the service can accept traffic. Proper health checks enable Kubernetes and load balancers to route traffic correctly.
|
|
11
|
+
|
|
12
|
+
**Incorrect (simple ping that doesn't check dependencies):**
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// Simple ping that doesn't check dependencies
|
|
16
|
+
@Controller('health')
|
|
17
|
+
export class HealthController {
|
|
18
|
+
@Get()
|
|
19
|
+
check(): string {
|
|
20
|
+
return 'OK'; // Service might be unhealthy but returns OK
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Health check that blocks on slow dependencies
|
|
25
|
+
@Controller('health')
|
|
26
|
+
export class HealthController {
|
|
27
|
+
@Get()
|
|
28
|
+
async check(): Promise<string> {
|
|
29
|
+
// If database is slow, health check times out
|
|
30
|
+
await this.userRepo.findOne({ where: { id: '1' } });
|
|
31
|
+
await this.redis.ping();
|
|
32
|
+
await this.externalApi.healthCheck();
|
|
33
|
+
return 'OK';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Correct (use @nestjs/terminus for comprehensive health checks):**
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
// Use @nestjs/terminus for comprehensive health checks
|
|
42
|
+
import {
|
|
43
|
+
HealthCheckService,
|
|
44
|
+
HttpHealthIndicator,
|
|
45
|
+
TypeOrmHealthIndicator,
|
|
46
|
+
HealthCheck,
|
|
47
|
+
DiskHealthIndicator,
|
|
48
|
+
MemoryHealthIndicator,
|
|
49
|
+
} from '@nestjs/terminus';
|
|
50
|
+
|
|
51
|
+
@Controller('health')
|
|
52
|
+
export class HealthController {
|
|
53
|
+
constructor(
|
|
54
|
+
private health: HealthCheckService,
|
|
55
|
+
private http: HttpHealthIndicator,
|
|
56
|
+
private db: TypeOrmHealthIndicator,
|
|
57
|
+
private disk: DiskHealthIndicator,
|
|
58
|
+
private memory: MemoryHealthIndicator,
|
|
59
|
+
) {}
|
|
60
|
+
|
|
61
|
+
// Liveness probe - is the service alive?
|
|
62
|
+
@Get('live')
|
|
63
|
+
@HealthCheck()
|
|
64
|
+
liveness() {
|
|
65
|
+
return this.health.check([
|
|
66
|
+
// Basic checks only
|
|
67
|
+
() => this.memory.checkHeap('memory_heap', 200 * 1024 * 1024), // 200MB
|
|
68
|
+
]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Readiness probe - can the service handle traffic?
|
|
72
|
+
@Get('ready')
|
|
73
|
+
@HealthCheck()
|
|
74
|
+
readiness() {
|
|
75
|
+
return this.health.check([
|
|
76
|
+
() => this.db.pingCheck('database'),
|
|
77
|
+
() =>
|
|
78
|
+
this.http.pingCheck('redis', 'http://redis:6379', { timeout: 1000 }),
|
|
79
|
+
() =>
|
|
80
|
+
this.disk.checkStorage('disk', { path: '/', thresholdPercent: 0.9 }),
|
|
81
|
+
]);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Deep health check for debugging
|
|
85
|
+
@Get('deep')
|
|
86
|
+
@HealthCheck()
|
|
87
|
+
deepCheck() {
|
|
88
|
+
return this.health.check([
|
|
89
|
+
() => this.db.pingCheck('database'),
|
|
90
|
+
() => this.memory.checkHeap('memory_heap', 200 * 1024 * 1024),
|
|
91
|
+
() => this.memory.checkRSS('memory_rss', 300 * 1024 * 1024),
|
|
92
|
+
() =>
|
|
93
|
+
this.disk.checkStorage('disk', { path: '/', thresholdPercent: 0.9 }),
|
|
94
|
+
() =>
|
|
95
|
+
this.http.pingCheck('external-api', 'https://api.example.com/health'),
|
|
96
|
+
]);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Custom indicator for business-specific health
|
|
101
|
+
@Injectable()
|
|
102
|
+
export class QueueHealthIndicator extends HealthIndicator {
|
|
103
|
+
constructor(private queueService: QueueService) {
|
|
104
|
+
super();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async isHealthy(key: string): Promise<HealthIndicatorResult> {
|
|
108
|
+
const queueStats = await this.queueService.getStats();
|
|
109
|
+
|
|
110
|
+
const isHealthy = queueStats.failedCount < 100;
|
|
111
|
+
const result = this.getStatus(key, isHealthy, {
|
|
112
|
+
waiting: queueStats.waitingCount,
|
|
113
|
+
active: queueStats.activeCount,
|
|
114
|
+
failed: queueStats.failedCount,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (!isHealthy) {
|
|
118
|
+
throw new HealthCheckError('Queue unhealthy', result);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Redis health indicator
|
|
126
|
+
@Injectable()
|
|
127
|
+
export class RedisHealthIndicator extends HealthIndicator {
|
|
128
|
+
constructor(@InjectRedis() private redis: Redis) {
|
|
129
|
+
super();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async isHealthy(key: string): Promise<HealthIndicatorResult> {
|
|
133
|
+
try {
|
|
134
|
+
const pong = await this.redis.ping();
|
|
135
|
+
return this.getStatus(key, pong === 'PONG');
|
|
136
|
+
} catch (error) {
|
|
137
|
+
throw new HealthCheckError('Redis check failed', this.getStatus(key, false));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Use custom indicators
|
|
143
|
+
@Get('ready')
|
|
144
|
+
@HealthCheck()
|
|
145
|
+
readiness() {
|
|
146
|
+
return this.health.check([
|
|
147
|
+
() => this.db.pingCheck('database'),
|
|
148
|
+
() => this.redis.isHealthy('redis'),
|
|
149
|
+
() => this.queue.isHealthy('job-queue'),
|
|
150
|
+
]);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Graceful shutdown handling
|
|
154
|
+
@Injectable()
|
|
155
|
+
export class GracefulShutdownService implements OnApplicationShutdown {
|
|
156
|
+
private isShuttingDown = false;
|
|
157
|
+
|
|
158
|
+
isShutdown(): boolean {
|
|
159
|
+
return this.isShuttingDown;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async onApplicationShutdown(signal: string): Promise<void> {
|
|
163
|
+
this.isShuttingDown = true;
|
|
164
|
+
console.log(`Shutting down on ${signal}`);
|
|
165
|
+
|
|
166
|
+
// Wait for in-flight requests
|
|
167
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Health check respects shutdown state
|
|
172
|
+
@Get('ready')
|
|
173
|
+
@HealthCheck()
|
|
174
|
+
readiness() {
|
|
175
|
+
if (this.shutdownService.isShutdown()) {
|
|
176
|
+
throw new ServiceUnavailableException('Shutting down');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return this.health.check([
|
|
180
|
+
() => this.db.pingCheck('database'),
|
|
181
|
+
]);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Kubernetes Configuration
|
|
186
|
+
|
|
187
|
+
```yaml
|
|
188
|
+
# Kubernetes deployment with probes
|
|
189
|
+
apiVersion: apps/v1
|
|
190
|
+
kind: Deployment
|
|
191
|
+
metadata:
|
|
192
|
+
name: api-service
|
|
193
|
+
spec:
|
|
194
|
+
template:
|
|
195
|
+
spec:
|
|
196
|
+
containers:
|
|
197
|
+
- name: api
|
|
198
|
+
image: api-service:latest
|
|
199
|
+
ports:
|
|
200
|
+
- containerPort: 3000
|
|
201
|
+
livenessProbe:
|
|
202
|
+
httpGet:
|
|
203
|
+
path: /health/live
|
|
204
|
+
port: 3000
|
|
205
|
+
initialDelaySeconds: 30
|
|
206
|
+
periodSeconds: 10
|
|
207
|
+
timeoutSeconds: 5
|
|
208
|
+
failureThreshold: 3
|
|
209
|
+
readinessProbe:
|
|
210
|
+
httpGet:
|
|
211
|
+
path: /health/ready
|
|
212
|
+
port: 3000
|
|
213
|
+
initialDelaySeconds: 5
|
|
214
|
+
periodSeconds: 5
|
|
215
|
+
timeoutSeconds: 3
|
|
216
|
+
failureThreshold: 3
|
|
217
|
+
startupProbe:
|
|
218
|
+
httpGet:
|
|
219
|
+
path: /health/live
|
|
220
|
+
port: 3000
|
|
221
|
+
initialDelaySeconds: 0
|
|
222
|
+
periodSeconds: 5
|
|
223
|
+
failureThreshold: 30
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Reference: [NestJS Terminus](https://docs.nestjs.com/recipes/terminus)
|