@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,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Message and Event Patterns Correctly
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Proper patterns ensure reliable microservice communication
|
|
5
|
+
tags: microservices, message-pattern, event-pattern, communication
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Message and Event Patterns Correctly
|
|
9
|
+
|
|
10
|
+
NestJS microservices support two communication patterns: request-response (MessagePattern) and event-based (EventPattern). Use MessagePattern when you need a response, and EventPattern for fire-and-forget notifications. Understanding the difference prevents communication bugs.
|
|
11
|
+
|
|
12
|
+
**Incorrect (using wrong pattern for use case):**
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// Use @MessagePattern for fire-and-forget
|
|
16
|
+
@Controller()
|
|
17
|
+
export class NotificationsController {
|
|
18
|
+
@MessagePattern('user.created')
|
|
19
|
+
async handleUserCreated(data: UserCreatedEvent) {
|
|
20
|
+
// This WAITS for response, blocking the sender
|
|
21
|
+
await this.emailService.sendWelcome(data.email);
|
|
22
|
+
// If email fails, sender gets an error (coupling!)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Use @EventPattern expecting a response
|
|
27
|
+
@Controller()
|
|
28
|
+
export class OrdersController {
|
|
29
|
+
@EventPattern('inventory.check')
|
|
30
|
+
async checkInventory(data: CheckInventoryDto) {
|
|
31
|
+
const available = await this.inventory.check(data);
|
|
32
|
+
return available; // This return value is IGNORED with @EventPattern!
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Tight coupling in client
|
|
37
|
+
@Injectable()
|
|
38
|
+
export class UsersService {
|
|
39
|
+
async createUser(dto: CreateUserDto): Promise<User> {
|
|
40
|
+
const user = await this.repo.save(dto);
|
|
41
|
+
|
|
42
|
+
// Blocks until notification service responds
|
|
43
|
+
await this.client.send('user.created', user).toPromise();
|
|
44
|
+
// If notification service is down, user creation fails!
|
|
45
|
+
|
|
46
|
+
return user;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Correct (use MessagePattern for request-response, EventPattern for fire-and-forget):**
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// MessagePattern: Request-Response (when you NEED a response)
|
|
55
|
+
@Controller()
|
|
56
|
+
export class InventoryController {
|
|
57
|
+
@MessagePattern({ cmd: 'check_inventory' })
|
|
58
|
+
async checkInventory(data: CheckInventoryDto): Promise<InventoryResult> {
|
|
59
|
+
const result = await this.inventoryService.check(data.productId, data.quantity);
|
|
60
|
+
return result; // Response sent back to caller
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Client expects response
|
|
65
|
+
@Injectable()
|
|
66
|
+
export class OrdersService {
|
|
67
|
+
async createOrder(dto: CreateOrderDto): Promise<Order> {
|
|
68
|
+
// Check inventory - we NEED this response to proceed
|
|
69
|
+
const inventory = await firstValueFrom(
|
|
70
|
+
this.inventoryClient.send<InventoryResult>(
|
|
71
|
+
{ cmd: 'check_inventory' },
|
|
72
|
+
{ productId: dto.productId, quantity: dto.quantity },
|
|
73
|
+
),
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if (!inventory.available) {
|
|
77
|
+
throw new BadRequestException('Insufficient inventory');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return this.repo.save(dto);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// EventPattern: Fire-and-Forget (for notifications, side effects)
|
|
85
|
+
@Controller()
|
|
86
|
+
export class NotificationsController {
|
|
87
|
+
@EventPattern('user.created')
|
|
88
|
+
async handleUserCreated(data: UserCreatedEvent): Promise<void> {
|
|
89
|
+
// No return value needed - just process the event
|
|
90
|
+
await this.emailService.sendWelcome(data.email);
|
|
91
|
+
await this.analyticsService.track('user_signup', data);
|
|
92
|
+
// If this fails, it doesn't affect the sender
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Client emits event without waiting
|
|
97
|
+
@Injectable()
|
|
98
|
+
export class UsersService {
|
|
99
|
+
async createUser(dto: CreateUserDto): Promise<User> {
|
|
100
|
+
const user = await this.repo.save(dto);
|
|
101
|
+
|
|
102
|
+
// Fire and forget - doesn't block, doesn't wait
|
|
103
|
+
this.eventClient.emit('user.created', {
|
|
104
|
+
userId: user.id,
|
|
105
|
+
email: user.email,
|
|
106
|
+
timestamp: new Date(),
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return user; // User creation succeeds regardless of event handling
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Hybrid pattern for critical events
|
|
114
|
+
@Injectable()
|
|
115
|
+
export class OrdersService {
|
|
116
|
+
async createOrder(dto: CreateOrderDto): Promise<Order> {
|
|
117
|
+
const order = await this.repo.save(dto);
|
|
118
|
+
|
|
119
|
+
// Critical: inventory reservation (use MessagePattern)
|
|
120
|
+
const reserved = await firstValueFrom(
|
|
121
|
+
this.inventoryClient.send({ cmd: 'reserve_inventory' }, {
|
|
122
|
+
orderId: order.id,
|
|
123
|
+
items: dto.items,
|
|
124
|
+
}),
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (!reserved.success) {
|
|
128
|
+
await this.repo.delete(order.id);
|
|
129
|
+
throw new BadRequestException('Could not reserve inventory');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Non-critical: notifications (use EventPattern)
|
|
133
|
+
this.eventClient.emit('order.created', {
|
|
134
|
+
orderId: order.id,
|
|
135
|
+
userId: dto.userId,
|
|
136
|
+
total: dto.total,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return order;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Error handling patterns
|
|
144
|
+
// MessagePattern errors propagate to caller
|
|
145
|
+
@MessagePattern({ cmd: 'get_user' })
|
|
146
|
+
async getUser(userId: string): Promise<User> {
|
|
147
|
+
const user = await this.repo.findOne({ where: { id: userId } });
|
|
148
|
+
if (!user) {
|
|
149
|
+
throw new RpcException('User not found'); // Received by caller
|
|
150
|
+
}
|
|
151
|
+
return user;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// EventPattern errors should be handled locally
|
|
155
|
+
@EventPattern('order.created')
|
|
156
|
+
async handleOrderCreated(data: OrderCreatedEvent): Promise<void> {
|
|
157
|
+
try {
|
|
158
|
+
await this.processOrder(data);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
// Log and potentially retry - don't throw
|
|
161
|
+
this.logger.error('Failed to process order event', error);
|
|
162
|
+
await this.deadLetterQueue.add(data);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Reference: [NestJS Microservices](https://docs.nestjs.com/microservices/basics)
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Message Queues for Background Jobs
|
|
3
|
+
impact: MEDIUM-HIGH
|
|
4
|
+
impactDescription: Queues enable reliable background processing
|
|
5
|
+
tags: microservices, queues, bullmq, background-jobs
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Message Queues for Background Jobs
|
|
9
|
+
|
|
10
|
+
Use `@nestjs/bullmq` for background job processing. Queues decouple long-running tasks from HTTP requests, enable retry logic, and distribute workload across workers. Use them for emails, file processing, notifications, and any task that shouldn't block user requests.
|
|
11
|
+
|
|
12
|
+
**Incorrect (long-running tasks in HTTP handlers):**
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// Long-running tasks in HTTP handlers
|
|
16
|
+
@Controller('reports')
|
|
17
|
+
export class ReportsController {
|
|
18
|
+
@Post()
|
|
19
|
+
async generate(@Body() dto: GenerateReportDto): Promise<Report> {
|
|
20
|
+
// This blocks the request for potentially minutes
|
|
21
|
+
const data = await this.fetchLargeDataset(dto);
|
|
22
|
+
const report = await this.processData(data); // Slow!
|
|
23
|
+
await this.sendEmail(dto.email, report); // Can fail!
|
|
24
|
+
return report; // Client times out
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Fire-and-forget without retry
|
|
29
|
+
@Injectable()
|
|
30
|
+
export class EmailService {
|
|
31
|
+
async sendWelcome(email: string): Promise<void> {
|
|
32
|
+
// If this fails, email is never sent
|
|
33
|
+
await this.mailer.send({ to: email, template: 'welcome' });
|
|
34
|
+
// No retry, no tracking, no visibility
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Use setInterval for scheduled tasks
|
|
39
|
+
setInterval(async () => {
|
|
40
|
+
await cleanupOldRecords();
|
|
41
|
+
}, 60000); // No error handling, memory leaks
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Correct (use BullMQ for background processing):**
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// Configure BullMQ
|
|
48
|
+
import { BullModule } from '@nestjs/bullmq';
|
|
49
|
+
|
|
50
|
+
@Module({
|
|
51
|
+
imports: [
|
|
52
|
+
BullModule.forRoot({
|
|
53
|
+
connection: {
|
|
54
|
+
host: 'localhost',
|
|
55
|
+
port: 6379,
|
|
56
|
+
},
|
|
57
|
+
defaultJobOptions: {
|
|
58
|
+
removeOnComplete: 1000,
|
|
59
|
+
removeOnFail: 5000,
|
|
60
|
+
attempts: 3,
|
|
61
|
+
backoff: {
|
|
62
|
+
type: 'exponential',
|
|
63
|
+
delay: 1000,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
BullModule.registerQueue(
|
|
68
|
+
{ name: 'email' },
|
|
69
|
+
{ name: 'reports' },
|
|
70
|
+
{ name: 'notifications' },
|
|
71
|
+
),
|
|
72
|
+
],
|
|
73
|
+
})
|
|
74
|
+
export class QueueModule {}
|
|
75
|
+
|
|
76
|
+
// Producer: Add jobs to queue
|
|
77
|
+
@Injectable()
|
|
78
|
+
export class ReportsService {
|
|
79
|
+
constructor(
|
|
80
|
+
@InjectQueue('reports') private reportsQueue: Queue,
|
|
81
|
+
) {}
|
|
82
|
+
|
|
83
|
+
async requestReport(dto: GenerateReportDto): Promise<{ jobId: string }> {
|
|
84
|
+
// Return immediately, process in background
|
|
85
|
+
const job = await this.reportsQueue.add('generate', dto, {
|
|
86
|
+
priority: dto.urgent ? 1 : 10,
|
|
87
|
+
delay: dto.scheduledFor ? Date.parse(dto.scheduledFor) - Date.now() : 0,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return { jobId: job.id };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async getJobStatus(jobId: string): Promise<JobStatus> {
|
|
94
|
+
const job = await this.reportsQueue.getJob(jobId);
|
|
95
|
+
return {
|
|
96
|
+
status: await job.getState(),
|
|
97
|
+
progress: job.progress,
|
|
98
|
+
result: job.returnvalue,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Consumer: Process jobs
|
|
104
|
+
@Processor('reports')
|
|
105
|
+
export class ReportsProcessor {
|
|
106
|
+
private readonly logger = new Logger(ReportsProcessor.name);
|
|
107
|
+
|
|
108
|
+
@Process('generate')
|
|
109
|
+
async generateReport(job: Job<GenerateReportDto>): Promise<Report> {
|
|
110
|
+
this.logger.log(`Processing report job ${job.id}`);
|
|
111
|
+
|
|
112
|
+
// Update progress
|
|
113
|
+
await job.updateProgress(10);
|
|
114
|
+
|
|
115
|
+
const data = await this.fetchData(job.data);
|
|
116
|
+
await job.updateProgress(50);
|
|
117
|
+
|
|
118
|
+
const report = await this.processData(data);
|
|
119
|
+
await job.updateProgress(90);
|
|
120
|
+
|
|
121
|
+
await this.saveReport(report);
|
|
122
|
+
await job.updateProgress(100);
|
|
123
|
+
|
|
124
|
+
return report;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@OnQueueActive()
|
|
128
|
+
onActive(job: Job) {
|
|
129
|
+
this.logger.log(`Processing job ${job.id}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@OnQueueCompleted()
|
|
133
|
+
onCompleted(job: Job, result: any) {
|
|
134
|
+
this.logger.log(`Job ${job.id} completed`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@OnQueueFailed()
|
|
138
|
+
onFailed(job: Job, error: Error) {
|
|
139
|
+
this.logger.error(`Job ${job.id} failed: ${error.message}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Email queue with retry
|
|
144
|
+
@Processor('email')
|
|
145
|
+
export class EmailProcessor {
|
|
146
|
+
@Process('send')
|
|
147
|
+
async sendEmail(job: Job<SendEmailDto>): Promise<void> {
|
|
148
|
+
const { to, template, data } = job.data;
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
await this.mailer.send({
|
|
152
|
+
to,
|
|
153
|
+
template,
|
|
154
|
+
context: data,
|
|
155
|
+
});
|
|
156
|
+
} catch (error) {
|
|
157
|
+
// BullMQ will retry based on job options
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Usage
|
|
164
|
+
@Injectable()
|
|
165
|
+
export class NotificationService {
|
|
166
|
+
constructor(@InjectQueue('email') private emailQueue: Queue) {}
|
|
167
|
+
|
|
168
|
+
async sendWelcome(user: User): Promise<void> {
|
|
169
|
+
await this.emailQueue.add(
|
|
170
|
+
'send',
|
|
171
|
+
{
|
|
172
|
+
to: user.email,
|
|
173
|
+
template: 'welcome',
|
|
174
|
+
data: { name: user.name },
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
attempts: 5,
|
|
178
|
+
backoff: { type: 'exponential', delay: 5000 },
|
|
179
|
+
},
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Scheduled jobs
|
|
185
|
+
@Injectable()
|
|
186
|
+
export class ScheduledJobsService implements OnModuleInit {
|
|
187
|
+
constructor(@InjectQueue('maintenance') private queue: Queue) {}
|
|
188
|
+
|
|
189
|
+
async onModuleInit(): Promise<void> {
|
|
190
|
+
// Clean up old reports daily at midnight
|
|
191
|
+
await this.queue.add(
|
|
192
|
+
'cleanup',
|
|
193
|
+
{},
|
|
194
|
+
{
|
|
195
|
+
repeat: { cron: '0 0 * * *' },
|
|
196
|
+
jobId: 'daily-cleanup', // Prevent duplicates
|
|
197
|
+
},
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
// Send digest every hour
|
|
201
|
+
await this.queue.add(
|
|
202
|
+
'digest',
|
|
203
|
+
{},
|
|
204
|
+
{
|
|
205
|
+
repeat: { every: 60 * 60 * 1000 },
|
|
206
|
+
jobId: 'hourly-digest',
|
|
207
|
+
},
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
@Processor('maintenance')
|
|
213
|
+
export class MaintenanceProcessor {
|
|
214
|
+
@Process('cleanup')
|
|
215
|
+
async cleanup(): Promise<void> {
|
|
216
|
+
await this.cleanupOldReports();
|
|
217
|
+
await this.cleanupExpiredSessions();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
@Process('digest')
|
|
221
|
+
async sendDigest(): Promise<void> {
|
|
222
|
+
const users = await this.getUsersForDigest();
|
|
223
|
+
for (const user of users) {
|
|
224
|
+
await this.emailQueue.add('send', { to: user.email, template: 'digest' });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Queue monitoring with Bull Board
|
|
230
|
+
import { BullBoardModule } from '@bull-board/nestjs';
|
|
231
|
+
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
|
232
|
+
|
|
233
|
+
@Module({
|
|
234
|
+
imports: [
|
|
235
|
+
BullBoardModule.forRoot({
|
|
236
|
+
route: '/admin/queues',
|
|
237
|
+
adapter: ExpressAdapter,
|
|
238
|
+
}),
|
|
239
|
+
BullBoardModule.forFeature({
|
|
240
|
+
name: 'email',
|
|
241
|
+
adapter: BullMQAdapter,
|
|
242
|
+
}),
|
|
243
|
+
BullBoardModule.forFeature({
|
|
244
|
+
name: 'reports',
|
|
245
|
+
adapter: BullMQAdapter,
|
|
246
|
+
}),
|
|
247
|
+
],
|
|
248
|
+
})
|
|
249
|
+
export class AdminModule {}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Reference: [NestJS Queues](https://docs.nestjs.com/techniques/queues)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Async Lifecycle Hooks Correctly
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Improper async handling blocks application startup
|
|
5
|
+
tags: performance, lifecycle, async, hooks
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Async Lifecycle Hooks Correctly
|
|
9
|
+
|
|
10
|
+
NestJS lifecycle hooks (`onModuleInit`, `onApplicationBootstrap`, etc.) support async operations. However, misusing them can block application startup or cause race conditions. Understand the lifecycle order and use hooks appropriately.
|
|
11
|
+
|
|
12
|
+
**Incorrect (fire-and-forget async without await):**
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// Fire-and-forget async without await
|
|
16
|
+
@Injectable()
|
|
17
|
+
export class DatabaseService implements OnModuleInit {
|
|
18
|
+
onModuleInit() {
|
|
19
|
+
// This runs but doesn't block - app starts before DB is ready!
|
|
20
|
+
this.connect();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private async connect() {
|
|
24
|
+
await this.pool.connect();
|
|
25
|
+
console.log('Database connected');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Heavy blocking operations in constructor
|
|
30
|
+
@Injectable()
|
|
31
|
+
export class ConfigService {
|
|
32
|
+
private config: Config;
|
|
33
|
+
|
|
34
|
+
constructor() {
|
|
35
|
+
// BLOCKS entire module instantiation synchronously
|
|
36
|
+
this.config = fs.readFileSync('config.json');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Correct (return promises from async hooks):**
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// Return promise from async hooks
|
|
45
|
+
@Injectable()
|
|
46
|
+
export class DatabaseService implements OnModuleInit {
|
|
47
|
+
private pool: Pool;
|
|
48
|
+
|
|
49
|
+
async onModuleInit(): Promise<void> {
|
|
50
|
+
// NestJS waits for this to complete before continuing
|
|
51
|
+
await this.pool.connect();
|
|
52
|
+
console.log('Database connected');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async onModuleDestroy(): Promise<void> {
|
|
56
|
+
// Clean up resources on shutdown
|
|
57
|
+
await this.pool.end();
|
|
58
|
+
console.log('Database disconnected');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Use onApplicationBootstrap for cross-module dependencies
|
|
63
|
+
@Injectable()
|
|
64
|
+
export class CacheWarmerService implements OnApplicationBootstrap {
|
|
65
|
+
constructor(
|
|
66
|
+
private cache: CacheService,
|
|
67
|
+
private products: ProductsService,
|
|
68
|
+
) {}
|
|
69
|
+
|
|
70
|
+
async onApplicationBootstrap(): Promise<void> {
|
|
71
|
+
// All modules are initialized, safe to warm cache
|
|
72
|
+
const products = await this.products.findPopular();
|
|
73
|
+
await this.cache.warmup(products);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Heavy init in async hooks, not constructor
|
|
78
|
+
@Injectable()
|
|
79
|
+
export class ConfigService implements OnModuleInit {
|
|
80
|
+
private config: Config;
|
|
81
|
+
|
|
82
|
+
constructor() {
|
|
83
|
+
// Keep constructor synchronous and fast
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async onModuleInit(): Promise<void> {
|
|
87
|
+
// Async loading in lifecycle hook
|
|
88
|
+
this.config = await this.loadConfig();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private async loadConfig(): Promise<Config> {
|
|
92
|
+
const file = await fs.promises.readFile('config.json');
|
|
93
|
+
return JSON.parse(file.toString());
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get<T>(key: string): T {
|
|
97
|
+
return this.config[key];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Enable shutdown hooks in main.ts
|
|
102
|
+
async function bootstrap() {
|
|
103
|
+
const app = await NestFactory.create(AppModule);
|
|
104
|
+
app.enableShutdownHooks(); // Enable SIGTERM/SIGINT handling
|
|
105
|
+
await app.listen(3000);
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Reference: [NestJS Lifecycle Events](https://docs.nestjs.com/fundamentals/lifecycle-events)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Lazy Loading for Large Modules
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Improves startup time for large applications
|
|
5
|
+
tags: performance, lazy-loading, modules, optimization
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Lazy Loading for Large Modules
|
|
9
|
+
|
|
10
|
+
NestJS supports lazy-loading modules, which defers initialization until first use. This is valuable for large applications where some features are rarely used, serverless deployments where cold start time matters, or when certain modules have heavy initialization costs.
|
|
11
|
+
|
|
12
|
+
**Incorrect (loading everything eagerly):**
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// Load everything eagerly in a large app
|
|
16
|
+
@Module({
|
|
17
|
+
imports: [
|
|
18
|
+
UsersModule,
|
|
19
|
+
OrdersModule,
|
|
20
|
+
PaymentsModule,
|
|
21
|
+
ReportsModule, // Heavy, rarely used
|
|
22
|
+
AnalyticsModule, // Heavy, rarely used
|
|
23
|
+
AdminModule, // Only admins use this
|
|
24
|
+
LegacyModule, // Migration module, rarely used
|
|
25
|
+
BulkImportModule, // Used once a month
|
|
26
|
+
],
|
|
27
|
+
})
|
|
28
|
+
export class AppModule {}
|
|
29
|
+
|
|
30
|
+
// All modules initialize at startup, even if never used
|
|
31
|
+
// Slow cold starts in serverless
|
|
32
|
+
// Memory wasted on unused modules
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Correct (lazy load rarely-used modules):**
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// Use LazyModuleLoader for optional modules
|
|
39
|
+
import { LazyModuleLoader } from '@nestjs/core';
|
|
40
|
+
|
|
41
|
+
@Injectable()
|
|
42
|
+
export class ReportsService {
|
|
43
|
+
constructor(private lazyModuleLoader: LazyModuleLoader) {}
|
|
44
|
+
|
|
45
|
+
async generateReport(type: string): Promise<Report> {
|
|
46
|
+
// Load module only when needed
|
|
47
|
+
const { ReportsModule } = await import('./reports/reports.module');
|
|
48
|
+
const moduleRef = await this.lazyModuleLoader.load(() => ReportsModule);
|
|
49
|
+
|
|
50
|
+
const reportsService = moduleRef.get(ReportsGeneratorService);
|
|
51
|
+
return reportsService.generate(type);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Lazy load admin features with caching
|
|
56
|
+
@Injectable()
|
|
57
|
+
export class AdminService {
|
|
58
|
+
private adminModule: ModuleRef | null = null;
|
|
59
|
+
|
|
60
|
+
constructor(private lazyModuleLoader: LazyModuleLoader) {}
|
|
61
|
+
|
|
62
|
+
private async getAdminModule(): Promise<ModuleRef> {
|
|
63
|
+
if (!this.adminModule) {
|
|
64
|
+
const { AdminModule } = await import('./admin/admin.module');
|
|
65
|
+
this.adminModule = await this.lazyModuleLoader.load(() => AdminModule);
|
|
66
|
+
}
|
|
67
|
+
return this.adminModule;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async runAdminTask(task: string): Promise<void> {
|
|
71
|
+
const moduleRef = await this.getAdminModule();
|
|
72
|
+
const taskRunner = moduleRef.get(AdminTaskRunner);
|
|
73
|
+
await taskRunner.run(task);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Reusable lazy loader service
|
|
78
|
+
@Injectable()
|
|
79
|
+
export class ModuleLoaderService {
|
|
80
|
+
private loadedModules = new Map<string, ModuleRef>();
|
|
81
|
+
|
|
82
|
+
constructor(private lazyModuleLoader: LazyModuleLoader) {}
|
|
83
|
+
|
|
84
|
+
async load<T>(
|
|
85
|
+
key: string,
|
|
86
|
+
importFn: () => Promise<{ default: Type<T> } | Type<T>>,
|
|
87
|
+
): Promise<ModuleRef> {
|
|
88
|
+
if (!this.loadedModules.has(key)) {
|
|
89
|
+
const module = await importFn();
|
|
90
|
+
const moduleType = 'default' in module ? module.default : module;
|
|
91
|
+
const moduleRef = await this.lazyModuleLoader.load(() => moduleType);
|
|
92
|
+
this.loadedModules.set(key, moduleRef);
|
|
93
|
+
}
|
|
94
|
+
return this.loadedModules.get(key)!;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Preload modules in background after startup
|
|
99
|
+
@Injectable()
|
|
100
|
+
export class ModulePreloader implements OnApplicationBootstrap {
|
|
101
|
+
constructor(private lazyModuleLoader: LazyModuleLoader) {}
|
|
102
|
+
|
|
103
|
+
async onApplicationBootstrap(): Promise<void> {
|
|
104
|
+
setTimeout(async () => {
|
|
105
|
+
await this.preloadModule(() => import('./reports/reports.module'));
|
|
106
|
+
}, 5000); // 5 seconds after startup
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private async preloadModule(importFn: () => Promise<any>): Promise<void> {
|
|
110
|
+
try {
|
|
111
|
+
const module = await importFn();
|
|
112
|
+
const moduleType = module.default || Object.values(module)[0];
|
|
113
|
+
await this.lazyModuleLoader.load(() => moduleType);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.warn('Failed to preload module', error);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Reference: [NestJS Lazy Loading Modules](https://docs.nestjs.com/fundamentals/lazy-loading-modules)
|