@biggora/claude-plugins 1.2.0 → 1.3.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/README.md +13 -4
- package/package.json +1 -1
- package/registry/registry.json +334 -244
- package/specs/coding.md +30 -0
- package/specs/pod.md +2 -0
- package/src/commands/skills/add.js +63 -7
- package/src/commands/skills/list.js +23 -52
- package/src/commands/skills/remove.js +26 -27
- package/src/commands/skills/resolve.js +155 -0
- package/src/commands/skills/update.js +58 -74
- package/src/skills/captcha/README.md +221 -0
- package/src/skills/captcha/SKILL.md +355 -0
- package/src/skills/captcha/references/captcha-types.md +254 -0
- package/src/skills/captcha/references/services.md +172 -0
- package/src/skills/captcha/references/stealth.md +238 -0
- package/src/skills/captcha/scripts/solve_captcha.py +323 -0
- package/src/skills/captcha/scripts/solve_image_grid.py +350 -0
- package/src/skills/google-merchant-api/SKILL.md +581 -0
- package/src/skills/google-merchant-api/references/accounts.md +247 -0
- package/src/skills/google-merchant-api/references/content-api-legacy.md +216 -0
- package/src/skills/google-merchant-api/references/datasources.md +233 -0
- package/src/skills/google-merchant-api/references/inventories.md +201 -0
- package/src/skills/google-merchant-api/references/migration.md +267 -0
- package/src/skills/google-merchant-api/references/products.md +316 -0
- package/src/skills/google-merchant-api/references/promotions.md +201 -0
- package/src/skills/google-merchant-api/references/reports.md +240 -0
- package/src/skills/lv-aggregators-api/SKILL.md +113 -0
- package/src/skills/lv-aggregators-api/references/integration-guide.md +368 -0
- package/src/skills/lv-aggregators-api/references/kurpirkt.md +103 -0
- package/src/skills/lv-aggregators-api/references/salidzini.md +122 -0
- package/src/skills/nest-best-practices/SKILL.md +251 -0
- package/src/skills/nest-best-practices/references/best-practices-request-lifecycle.md +158 -0
- package/src/skills/nest-best-practices/references/cli-monorepo.md +106 -0
- package/src/skills/nest-best-practices/references/cli-overview.md +157 -0
- package/src/skills/nest-best-practices/references/core-controllers.md +165 -0
- package/src/skills/nest-best-practices/references/core-dependency-injection.md +179 -0
- package/src/skills/nest-best-practices/references/core-middleware.md +139 -0
- package/src/skills/nest-best-practices/references/core-modules.md +138 -0
- package/src/skills/nest-best-practices/references/core-providers.md +188 -0
- package/src/skills/nest-best-practices/references/faq-raw-body-hybrid.md +122 -0
- package/src/skills/nest-best-practices/references/fundamentals-circular-dependency.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-custom-decorators.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-dynamic-modules.md +125 -0
- package/src/skills/nest-best-practices/references/fundamentals-exception-filters.md +202 -0
- package/src/skills/nest-best-practices/references/fundamentals-execution-context.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-guards.md +136 -0
- package/src/skills/nest-best-practices/references/fundamentals-interceptors.md +187 -0
- package/src/skills/nest-best-practices/references/fundamentals-lazy-loading.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-lifecycle-events.md +87 -0
- package/src/skills/nest-best-practices/references/fundamentals-module-reference.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-pipes.md +197 -0
- package/src/skills/nest-best-practices/references/fundamentals-provider-scopes.md +92 -0
- package/src/skills/nest-best-practices/references/fundamentals-testing.md +142 -0
- package/src/skills/nest-best-practices/references/graphql-overview.md +233 -0
- package/src/skills/nest-best-practices/references/graphql-resolvers-mutations.md +199 -0
- package/src/skills/nest-best-practices/references/graphql-scalars-unions-enums.md +180 -0
- package/src/skills/nest-best-practices/references/graphql-subscriptions.md +228 -0
- package/src/skills/nest-best-practices/references/microservices-grpc.md +175 -0
- package/src/skills/nest-best-practices/references/microservices-overview.md +221 -0
- package/src/skills/nest-best-practices/references/microservices-transports.md +119 -0
- package/src/skills/nest-best-practices/references/openapi-swagger.md +207 -0
- package/src/skills/nest-best-practices/references/recipes-authentication.md +97 -0
- package/src/skills/nest-best-practices/references/recipes-cqrs.md +176 -0
- package/src/skills/nest-best-practices/references/recipes-crud-generator.md +87 -0
- package/src/skills/nest-best-practices/references/recipes-documentation.md +93 -0
- package/src/skills/nest-best-practices/references/recipes-mongoose.md +153 -0
- package/src/skills/nest-best-practices/references/recipes-prisma.md +98 -0
- package/src/skills/nest-best-practices/references/recipes-terminus.md +148 -0
- package/src/skills/nest-best-practices/references/recipes-typeorm.md +122 -0
- package/src/skills/nest-best-practices/references/security-authorization.md +196 -0
- package/src/skills/nest-best-practices/references/security-cors-helmet-rate-limiting.md +204 -0
- package/src/skills/nest-best-practices/references/security-encryption-hashing.md +93 -0
- package/src/skills/nest-best-practices/references/techniques-caching.md +142 -0
- package/src/skills/nest-best-practices/references/techniques-compression-streaming-sse.md +194 -0
- package/src/skills/nest-best-practices/references/techniques-configuration.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-database.md +153 -0
- package/src/skills/nest-best-practices/references/techniques-events.md +163 -0
- package/src/skills/nest-best-practices/references/techniques-fastify.md +137 -0
- package/src/skills/nest-best-practices/references/techniques-file-upload.md +140 -0
- package/src/skills/nest-best-practices/references/techniques-http-module.md +176 -0
- package/src/skills/nest-best-practices/references/techniques-logging.md +146 -0
- package/src/skills/nest-best-practices/references/techniques-mvc-serve-static.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-queues.md +162 -0
- package/src/skills/nest-best-practices/references/techniques-serialization.md +158 -0
- package/src/skills/nest-best-practices/references/techniques-sessions-cookies.md +167 -0
- package/src/skills/nest-best-practices/references/techniques-task-scheduling.md +166 -0
- package/src/skills/nest-best-practices/references/techniques-validation.md +126 -0
- package/src/skills/nest-best-practices/references/techniques-versioning.md +153 -0
- package/src/skills/nest-best-practices/references/websockets-advanced.md +96 -0
- package/src/skills/nest-best-practices/references/websockets-gateways.md +215 -0
- package/src/skills/tailwindcss-best-practices/SKILL.md +180 -0
- package/src/skills/tailwindcss-best-practices/references/best-practices-utility-patterns.md +87 -0
- package/src/skills/tailwindcss-best-practices/references/core-installation.md +109 -0
- package/src/skills/tailwindcss-best-practices/references/core-preflight.md +200 -0
- package/src/skills/tailwindcss-best-practices/references/core-responsive.md +163 -0
- package/src/skills/tailwindcss-best-practices/references/core-source-detection.md +114 -0
- package/src/skills/tailwindcss-best-practices/references/core-theme.md +108 -0
- package/src/skills/tailwindcss-best-practices/references/core-utility-classes.md +59 -0
- package/src/skills/tailwindcss-best-practices/references/core-variants.md +204 -0
- package/src/skills/tailwindcss-best-practices/references/effects-form-controls.md +76 -0
- package/src/skills/tailwindcss-best-practices/references/effects-mask.md +91 -0
- package/src/skills/tailwindcss-best-practices/references/effects-scroll-snap.md +59 -0
- package/src/skills/tailwindcss-best-practices/references/effects-text-shadow.md +78 -0
- package/src/skills/tailwindcss-best-practices/references/effects-transition-animation.md +80 -0
- package/src/skills/tailwindcss-best-practices/references/effects-visibility-interactivity.md +82 -0
- package/src/skills/tailwindcss-best-practices/references/features-content-detection.md +175 -0
- package/src/skills/tailwindcss-best-practices/references/features-custom-styles.md +203 -0
- package/src/skills/tailwindcss-best-practices/references/features-dark-mode.md +137 -0
- package/src/skills/tailwindcss-best-practices/references/features-functions-directives.md +241 -0
- package/src/skills/tailwindcss-best-practices/references/features-upgrade.md +160 -0
- package/src/skills/tailwindcss-best-practices/references/layout-aspect-ratio.md +39 -0
- package/src/skills/tailwindcss-best-practices/references/layout-columns.md +80 -0
- package/src/skills/tailwindcss-best-practices/references/layout-display.md +110 -0
- package/src/skills/tailwindcss-best-practices/references/layout-flexbox.md +112 -0
- package/src/skills/tailwindcss-best-practices/references/layout-grid.md +87 -0
- package/src/skills/tailwindcss-best-practices/references/layout-height.md +97 -0
- package/src/skills/tailwindcss-best-practices/references/layout-inset.md +103 -0
- package/src/skills/tailwindcss-best-practices/references/layout-logical-properties.md +92 -0
- package/src/skills/tailwindcss-best-practices/references/layout-margin.md +126 -0
- package/src/skills/tailwindcss-best-practices/references/layout-min-max-sizing.md +63 -0
- package/src/skills/tailwindcss-best-practices/references/layout-object-fit-position.md +64 -0
- package/src/skills/tailwindcss-best-practices/references/layout-overflow.md +57 -0
- package/src/skills/tailwindcss-best-practices/references/layout-padding.md +77 -0
- package/src/skills/tailwindcss-best-practices/references/layout-position.md +85 -0
- package/src/skills/tailwindcss-best-practices/references/layout-tables.md +67 -0
- package/src/skills/tailwindcss-best-practices/references/layout-width.md +102 -0
- package/src/skills/tailwindcss-best-practices/references/transform-base.md +68 -0
- package/src/skills/tailwindcss-best-practices/references/transform-rotate.md +70 -0
- package/src/skills/tailwindcss-best-practices/references/transform-scale.md +83 -0
- package/src/skills/tailwindcss-best-practices/references/transform-skew.md +62 -0
- package/src/skills/tailwindcss-best-practices/references/transform-translate.md +77 -0
- package/src/skills/tailwindcss-best-practices/references/typography-font-text.md +142 -0
- package/src/skills/tailwindcss-best-practices/references/typography-list-style.md +65 -0
- package/src/skills/tailwindcss-best-practices/references/typography-text-align.md +60 -0
- package/src/skills/tailwindcss-best-practices/references/visual-background.md +76 -0
- package/src/skills/tailwindcss-best-practices/references/visual-border.md +108 -0
- package/src/skills/tailwindcss-best-practices/references/visual-effects.md +111 -0
- package/src/skills/tailwindcss-best-practices/references/visual-svg.md +82 -0
- package/src/skills/test-mobile-app/SKILL.md +11 -6
- package/src/skills/test-mobile-app/scripts/analyze_apk.py +15 -4
- package/src/skills/test-mobile-app/scripts/check_environment.py +5 -5
- package/src/skills/test-mobile-app/scripts/run_tests.py +1 -1
- package/src/skills/test-web-ui/SKILL.md +264 -84
- package/src/skills/test-web-ui/scripts/discover.py +25 -12
- package/src/skills/test-web-ui/scripts/run_tests.py +3 -2
- package/src/skills/typescript-expert/SKILL.md +145 -0
- package/src/skills/typescript-expert/commands/typescript-fix.md +65 -0
- package/src/skills/typescript-expert/references/advanced-conditional-types.md +190 -0
- package/src/skills/typescript-expert/references/advanced-decorators.md +243 -0
- package/src/skills/typescript-expert/references/advanced-mapped-types.md +223 -0
- package/src/skills/typescript-expert/references/advanced-template-literals.md +209 -0
- package/src/skills/typescript-expert/references/advanced-type-guards.md +308 -0
- package/src/skills/typescript-expert/references/best-practices-patterns.md +313 -0
- package/src/skills/typescript-expert/references/best-practices-performance.md +185 -0
- package/src/skills/typescript-expert/references/best-practices-tsconfig.md +242 -0
- package/src/skills/typescript-expert/references/core-generics.md +246 -0
- package/src/skills/typescript-expert/references/core-interfaces-types.md +231 -0
- package/src/skills/typescript-expert/references/core-type-system.md +261 -0
- package/src/skills/typescript-expert/references/core-utility-types.md +235 -0
- package/src/skills/typescript-expert/references/features-ts5x.md +370 -0
- package/src/skills/vite-best-practices/SKILL.md +115 -0
- package/src/skills/vite-best-practices/references/build-and-ssr.md +255 -0
- package/src/skills/vite-best-practices/references/core-config.md +231 -0
- package/src/skills/vite-best-practices/references/core-features.md +222 -0
- package/src/skills/vite-best-practices/references/core-plugin-api.md +294 -0
- package/src/skills/vite-best-practices/references/environment-api.md +108 -0
- package/src/skills/vite-best-practices/references/rolldown-migration.md +242 -0
- package/codex-cli-workspace/iteration-1/benchmark.json +0 -122
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/eval_metadata.json +0 -13
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/with_skill/grading.json +0 -52
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/with_skill/outputs/response.md +0 -163
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/with_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/without_skill/grading.json +0 -58
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/without_skill/outputs/response.md +0 -151
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/without_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/eval_metadata.json +0 -13
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/grading.json +0 -52
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/outputs/response.md +0 -86
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/grading.json +0 -58
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/outputs/response.md +0 -164
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/eval_metadata.json +0 -13
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/with_skill/grading.json +0 -52
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/with_skill/outputs/response.md +0 -130
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/with_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/without_skill/grading.json +0 -64
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/without_skill/outputs/response.md +0 -209
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/without_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/review.html +0 -1325
- package/gemini-cli-workspace/iteration-1/benchmark.json +0 -86
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/eval_metadata.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/with_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/with_skill/outputs/response.md +0 -401
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/without_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/without_skill/outputs/response.md +0 -405
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/eval_metadata.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/outputs/response.md +0 -212
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/outputs/response.md +0 -427
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/eval_metadata.json +0 -32
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/with_skill/grading.json +0 -32
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/with_skill/outputs/response.md +0 -171
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/without_skill/grading.json +0 -32
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/without_skill/outputs/response.md +0 -199
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/review.html +0 -1325
- package/gemini-cli-workspace/iteration-2/benchmark.json +0 -173
- package/gemini-cli-workspace/iteration-2/benchmark.md +0 -28
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/eval_metadata.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/with_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/with_skill/outputs/response.md +0 -195
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/without_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/without_skill/outputs/response.md +0 -377
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/eval_metadata.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/with_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/with_skill/outputs/response.md +0 -127
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/without_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/without_skill/outputs/response.md +0 -164
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/eval_metadata.json +0 -32
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/with_skill/grading.json +0 -32
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/with_skill/outputs/response.md +0 -91
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/without_skill/grading.json +0 -32
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/without_skill/outputs/response.md +0 -112
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-viewer.html +0 -1325
- package/screen-recording-workspace/evals.json +0 -41
- package/screen-recording-workspace/iteration-1/benchmark.json +0 -102
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/eval_metadata.json +0 -31
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/with_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/with_skill/outputs/demo.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/with_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/without_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/without_skill/outputs/demo.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/without_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/eval_metadata.json +0 -31
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/with_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/with_skill/outputs/region_capture.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/with_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/without_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/without_skill/outputs/region_capture.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/without_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/eval_metadata.json +0 -31
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/with_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/with_skill/outputs/fallback_recording.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/with_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/outputs/fallback_recording.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/outputs/record_screen.py +0 -67
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/review.html +0 -1325
- package/src/skills/codex-cli/evals/evals.json +0 -47
- package/src/skills/gemini-cli/evals/evals.json +0 -46
- package/src/skills/tm-search/evals/evals.json +0 -23
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: microservices-transports
|
|
3
|
+
description: Redis, Kafka, NATS, RabbitMQ transport configuration
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Microservice Transports
|
|
7
|
+
|
|
8
|
+
## Redis
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm i ioredis
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
{
|
|
16
|
+
transport: Transport.REDIS,
|
|
17
|
+
options: {
|
|
18
|
+
host: 'localhost',
|
|
19
|
+
port: 6379,
|
|
20
|
+
password: 'secret',
|
|
21
|
+
retryAttempts: 3,
|
|
22
|
+
retryDelay: 1000,
|
|
23
|
+
wildcards: true, // psubscribe for pattern matching
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Client: `ClientsModule.register([{ name: 'MATH_SERVICE', transport: Transport.REDIS, options: {...} }])`
|
|
29
|
+
|
|
30
|
+
## Kafka
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm i kafkajs
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
{
|
|
38
|
+
transport: Transport.KAFKA,
|
|
39
|
+
options: {
|
|
40
|
+
client: {
|
|
41
|
+
clientId: 'my-app',
|
|
42
|
+
brokers: ['localhost:9092'],
|
|
43
|
+
},
|
|
44
|
+
consumer: {
|
|
45
|
+
groupId: 'my-consumer',
|
|
46
|
+
},
|
|
47
|
+
producer: {
|
|
48
|
+
allowAutoTopicCreation: true,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Use `@MessagePattern('topic')` for Kafka topics. Event-based (fire-and-forget) by default.
|
|
55
|
+
|
|
56
|
+
## NATS
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm i nats
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
{
|
|
64
|
+
transport: Transport.NATS,
|
|
65
|
+
options: {
|
|
66
|
+
servers: ['nats://localhost:4222'],
|
|
67
|
+
queue: 'my-queue', // queue group
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Supports wildcards: `@MessagePattern('time.us.*')` — `*` and `>` (multi-level).
|
|
73
|
+
|
|
74
|
+
## RabbitMQ
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm i amqplib
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
{
|
|
82
|
+
transport: Transport.RMQ,
|
|
83
|
+
options: {
|
|
84
|
+
urls: ['amqp://localhost:5672'],
|
|
85
|
+
queue: 'my_queue',
|
|
86
|
+
queueOptions: {
|
|
87
|
+
durable: true,
|
|
88
|
+
},
|
|
89
|
+
noAck: false,
|
|
90
|
+
prefetchCount: 1,
|
|
91
|
+
},
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Transport Comparison
|
|
96
|
+
|
|
97
|
+
| Transport | Pattern | Use Case |
|
|
98
|
+
|-----------|---------|----------|
|
|
99
|
+
| TCP | Request-Response | Internal RPC |
|
|
100
|
+
| Redis | Pub/Sub, Request-Response | Caching, queues |
|
|
101
|
+
| Kafka | Event-based | Event streaming |
|
|
102
|
+
| NATS | Pub/Sub, Request-Response | Lightweight messaging |
|
|
103
|
+
| RabbitMQ | Pub/Sub, Request-Response | Enterprise messaging |
|
|
104
|
+
| gRPC | Request-Response, Streaming | Performance, typed APIs |
|
|
105
|
+
|
|
106
|
+
## Key Points
|
|
107
|
+
|
|
108
|
+
- Redis: fire-and-forget, no delivery guarantee
|
|
109
|
+
- Kafka: persistent events, consumer groups
|
|
110
|
+
- NATS: wildcards (`*`, `>`), queue groups
|
|
111
|
+
- RabbitMQ: durable queues, ack required for reliability
|
|
112
|
+
|
|
113
|
+
<!--
|
|
114
|
+
Source references:
|
|
115
|
+
- https://docs.nestjs.com/microservices/redis
|
|
116
|
+
- https://docs.nestjs.com/microservices/kafka
|
|
117
|
+
- https://docs.nestjs.com/microservices/nats
|
|
118
|
+
- https://docs.nestjs.com/microservices/rabbitmq
|
|
119
|
+
-->
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openapi-swagger
|
|
3
|
+
description: OpenAPI/Swagger documentation generation
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# OpenAPI (Swagger)
|
|
7
|
+
|
|
8
|
+
Generate interactive API documentation using the OpenAPI specification.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @nestjs/swagger
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Basic Setup
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { NestFactory } from '@nestjs/core';
|
|
20
|
+
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
|
21
|
+
import { AppModule } from './app.module';
|
|
22
|
+
|
|
23
|
+
async function bootstrap() {
|
|
24
|
+
const app = await NestFactory.create(AppModule);
|
|
25
|
+
|
|
26
|
+
const config = new DocumentBuilder()
|
|
27
|
+
.setTitle('Cats API')
|
|
28
|
+
.setDescription('The cats API description')
|
|
29
|
+
.setVersion('1.0')
|
|
30
|
+
.addTag('cats')
|
|
31
|
+
.addBearerAuth()
|
|
32
|
+
.build();
|
|
33
|
+
|
|
34
|
+
const documentFactory = () => SwaggerModule.createDocument(app, config);
|
|
35
|
+
SwaggerModule.setup('api', app, documentFactory);
|
|
36
|
+
|
|
37
|
+
await app.listen(3000);
|
|
38
|
+
}
|
|
39
|
+
bootstrap();
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Access Swagger UI at `http://localhost:3000/api`
|
|
43
|
+
|
|
44
|
+
## DTO Documentation
|
|
45
|
+
|
|
46
|
+
Use `@ApiProperty()` to document DTO properties:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
50
|
+
|
|
51
|
+
export class CreateCatDto {
|
|
52
|
+
@ApiProperty({ description: 'The name of the cat' })
|
|
53
|
+
name: string;
|
|
54
|
+
|
|
55
|
+
@ApiProperty({ minimum: 0, maximum: 30, default: 1 })
|
|
56
|
+
age: number;
|
|
57
|
+
|
|
58
|
+
@ApiPropertyOptional({ example: 'Persian' })
|
|
59
|
+
breed?: string;
|
|
60
|
+
|
|
61
|
+
@ApiProperty({ enum: ['male', 'female'] })
|
|
62
|
+
gender: string;
|
|
63
|
+
|
|
64
|
+
@ApiProperty({ type: [String] })
|
|
65
|
+
tags: string[];
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Common Decorators
|
|
70
|
+
|
|
71
|
+
| Decorator | Level | Purpose |
|
|
72
|
+
|-----------|-------|---------|
|
|
73
|
+
| `@ApiTags()` | Controller/Method | Group endpoints |
|
|
74
|
+
| `@ApiOperation()` | Method | Describe operation |
|
|
75
|
+
| `@ApiResponse()` | Method/Controller | Document responses |
|
|
76
|
+
| `@ApiParam()` | Method | Document URL params |
|
|
77
|
+
| `@ApiQuery()` | Method | Document query params |
|
|
78
|
+
| `@ApiBody()` | Method | Document request body |
|
|
79
|
+
| `@ApiBearerAuth()` | Method/Controller | Mark as authenticated |
|
|
80
|
+
| `@ApiProperty()` | Model | Document property |
|
|
81
|
+
| `@ApiHideProperty()` | Model | Hide property |
|
|
82
|
+
| `@ApiExcludeEndpoint()` | Method | Exclude from docs |
|
|
83
|
+
|
|
84
|
+
## Controller Documentation
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import {
|
|
88
|
+
ApiTags,
|
|
89
|
+
ApiOperation,
|
|
90
|
+
ApiResponse,
|
|
91
|
+
ApiBearerAuth,
|
|
92
|
+
} from '@nestjs/swagger';
|
|
93
|
+
|
|
94
|
+
@ApiTags('cats')
|
|
95
|
+
@ApiBearerAuth()
|
|
96
|
+
@Controller('cats')
|
|
97
|
+
export class CatsController {
|
|
98
|
+
@Post()
|
|
99
|
+
@ApiOperation({ summary: 'Create a cat' })
|
|
100
|
+
@ApiResponse({ status: 201, description: 'Cat created successfully' })
|
|
101
|
+
@ApiResponse({ status: 400, description: 'Invalid input' })
|
|
102
|
+
create(@Body() dto: CreateCatDto) {
|
|
103
|
+
return this.catsService.create(dto);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@Get(':id')
|
|
107
|
+
@ApiOperation({ summary: 'Get a cat by ID' })
|
|
108
|
+
@ApiParam({ name: 'id', description: 'Cat ID' })
|
|
109
|
+
@ApiResponse({ status: 200, type: Cat })
|
|
110
|
+
@ApiResponse({ status: 404, description: 'Cat not found' })
|
|
111
|
+
findOne(@Param('id') id: string) {
|
|
112
|
+
return this.catsService.findOne(id);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Enums
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
export enum CatStatus {
|
|
121
|
+
Available = 'available',
|
|
122
|
+
Pending = 'pending',
|
|
123
|
+
Sold = 'sold',
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
@ApiProperty({
|
|
127
|
+
enum: CatStatus,
|
|
128
|
+
enumName: 'CatStatus'
|
|
129
|
+
})
|
|
130
|
+
status: CatStatus;
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Authentication
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
const config = new DocumentBuilder()
|
|
137
|
+
.addBearerAuth()
|
|
138
|
+
.addApiKey({ type: 'apiKey', name: 'X-API-Key', in: 'header' }, 'api-key')
|
|
139
|
+
.addOAuth2()
|
|
140
|
+
.build();
|
|
141
|
+
|
|
142
|
+
// Apply to endpoints
|
|
143
|
+
@ApiBearerAuth()
|
|
144
|
+
@UseGuards(AuthGuard('jwt'))
|
|
145
|
+
@Get('profile')
|
|
146
|
+
getProfile() {}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## CLI Plugin
|
|
150
|
+
|
|
151
|
+
Auto-document DTOs by adding to `nest-cli.json`:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"compilerOptions": {
|
|
156
|
+
"plugins": ["@nestjs/swagger"]
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
With options:
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"plugins": [
|
|
166
|
+
{
|
|
167
|
+
"name": "@nestjs/swagger",
|
|
168
|
+
"options": {
|
|
169
|
+
"classValidatorShim": true,
|
|
170
|
+
"introspectComments": true
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Document Options
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
const documentFactory = () => SwaggerModule.createDocument(app, config, {
|
|
181
|
+
include: [CatsModule], // Only include specific modules
|
|
182
|
+
extraModels: [ExtraModel], // Add extra models
|
|
183
|
+
ignoreGlobalPrefix: false, // Include global prefix
|
|
184
|
+
deepScanRoutes: true, // Scan imported modules
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Setup Options
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
SwaggerModule.setup('api', app, documentFactory, {
|
|
192
|
+
jsonDocumentUrl: '/api-json',
|
|
193
|
+
yamlDocumentUrl: '/api-yaml',
|
|
194
|
+
customSiteTitle: 'My API Docs',
|
|
195
|
+
customCss: '.swagger-ui .topbar { display: none }',
|
|
196
|
+
swaggerOptions: {
|
|
197
|
+
persistAuthorization: true,
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
<!--
|
|
203
|
+
Source references:
|
|
204
|
+
- https://docs.nestjs.com/openapi/introduction
|
|
205
|
+
- https://docs.nestjs.com/openapi/types-and-parameters
|
|
206
|
+
- https://docs.nestjs.com/openapi/decorators
|
|
207
|
+
-->
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: recipes-authentication
|
|
3
|
+
description: Authentication with Passport in NestJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Authentication
|
|
7
|
+
|
|
8
|
+
NestJS integrates with Passport for authentication strategies.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install --save @nestjs/passport passport passport-local
|
|
14
|
+
npm install --save-dev @types/passport-local
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Local Strategy
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
|
21
|
+
import { PassportStrategy } from '@nestjs/passport';
|
|
22
|
+
import { Strategy } from 'passport-local';
|
|
23
|
+
import { AuthService } from './auth.service';
|
|
24
|
+
|
|
25
|
+
@Injectable()
|
|
26
|
+
export class LocalStrategy extends PassportStrategy(Strategy) {
|
|
27
|
+
constructor(private authService: AuthService) {
|
|
28
|
+
super();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async validate(username: string, password: string): Promise<any> {
|
|
32
|
+
const user = await this.authService.validateUser(username, password);
|
|
33
|
+
if (!user) {
|
|
34
|
+
throw new UnauthorizedException();
|
|
35
|
+
}
|
|
36
|
+
return user;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## JWT Strategy
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install --save @nestjs/jwt passport-jwt
|
|
45
|
+
npm install --save-dev @types/passport-jwt
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { Injectable } from '@nestjs/common';
|
|
50
|
+
import { PassportStrategy } from '@nestjs/passport';
|
|
51
|
+
import { ExtractJwt, Strategy } from 'passport-jwt';
|
|
52
|
+
|
|
53
|
+
@Injectable()
|
|
54
|
+
export class JwtStrategy extends PassportStrategy(Strategy) {
|
|
55
|
+
constructor() {
|
|
56
|
+
super({
|
|
57
|
+
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
58
|
+
ignoreExpiration: false,
|
|
59
|
+
secretOrKey: 'secret',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async validate(payload: any) {
|
|
64
|
+
return { userId: payload.sub, username: payload.username };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Using Guards
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
@UseGuards(AuthGuard('local'))
|
|
73
|
+
@Post('auth/login')
|
|
74
|
+
async login(@Request() req) {
|
|
75
|
+
return req.user;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@UseGuards(AuthGuard('jwt'))
|
|
79
|
+
@Get('profile')
|
|
80
|
+
getProfile(@Request() req) {
|
|
81
|
+
return req.user;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Key Points
|
|
86
|
+
|
|
87
|
+
- Use `@nestjs/passport` for Passport integration
|
|
88
|
+
- Create strategies extending `PassportStrategy`
|
|
89
|
+
- Use `AuthGuard` with strategy name
|
|
90
|
+
- JWT tokens for stateless authentication
|
|
91
|
+
- Local strategy for username/password
|
|
92
|
+
- User object available in `request.user`
|
|
93
|
+
|
|
94
|
+
<!--
|
|
95
|
+
Source references:
|
|
96
|
+
- https://docs.nestjs.com/security/authentication
|
|
97
|
+
-->
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cqrs
|
|
3
|
+
description: Command Query Responsibility Segregation pattern for complex applications
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CQRS
|
|
7
|
+
|
|
8
|
+
Separate read and write operations for scalability and flexibility.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @nestjs/cqrs
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
@Module({
|
|
18
|
+
imports: [CqrsModule.forRoot()],
|
|
19
|
+
})
|
|
20
|
+
export class AppModule {}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Commands
|
|
24
|
+
|
|
25
|
+
Commands change application state. Use `CommandBus` to dispatch.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
// kill-dragon.command.ts
|
|
29
|
+
export class KillDragonCommand extends Command<{ actionId: string }> {
|
|
30
|
+
constructor(
|
|
31
|
+
public readonly heroId: string,
|
|
32
|
+
public readonly dragonId: string,
|
|
33
|
+
) {
|
|
34
|
+
super();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// kill-dragon.handler.ts
|
|
39
|
+
@CommandHandler(KillDragonCommand)
|
|
40
|
+
export class KillDragonHandler implements ICommandHandler<KillDragonCommand> {
|
|
41
|
+
constructor(private repository: HeroesRepository) {}
|
|
42
|
+
|
|
43
|
+
async execute(command: KillDragonCommand) {
|
|
44
|
+
const { heroId, dragonId } = command;
|
|
45
|
+
const hero = await this.repository.findOneById(+heroId);
|
|
46
|
+
hero.killEnemy(dragonId);
|
|
47
|
+
await this.repository.persist(hero);
|
|
48
|
+
return { actionId: crypto.randomUUID() };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// Usage
|
|
55
|
+
await this.commandBus.execute(
|
|
56
|
+
new KillDragonCommand(heroId, killDragonDto.dragonId)
|
|
57
|
+
);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Queries
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
export class GetHeroQuery extends Query<Hero> {
|
|
64
|
+
constructor(public readonly heroId: string) {
|
|
65
|
+
super();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@QueryHandler(GetHeroQuery)
|
|
70
|
+
export class GetHeroHandler implements IQueryHandler<GetHeroQuery> {
|
|
71
|
+
constructor(private repository: HeroesRepository) {}
|
|
72
|
+
|
|
73
|
+
async execute(query: GetHeroQuery) {
|
|
74
|
+
return this.repository.findOneById(query.heroId);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
const hero = await this.queryBus.execute(new GetHeroQuery(heroId));
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Events
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
export class HeroKilledDragonEvent {
|
|
87
|
+
constructor(
|
|
88
|
+
public readonly heroId: string,
|
|
89
|
+
public readonly dragonId: string,
|
|
90
|
+
) {}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@EventsHandler(HeroKilledDragonEvent)
|
|
94
|
+
export class HeroKilledDragonHandler implements IEventHandler<HeroKilledDragonEvent> {
|
|
95
|
+
handle(event: HeroKilledDragonEvent) {
|
|
96
|
+
// Update read model, send notifications, etc.
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Publish from model with `AggregateRoot`:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
export class Hero extends AggregateRoot {
|
|
105
|
+
killEnemy(enemyId: string) {
|
|
106
|
+
this.apply(new HeroKilledDragonEvent(this.id, enemyId));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Requires `EventPublisher.mergeObjectContext()` and `hero.commit()`.
|
|
112
|
+
|
|
113
|
+
Or publish manually:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
this.eventBus.publish(new HeroKilledDragonEvent(heroId, dragonId));
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Sagas
|
|
120
|
+
|
|
121
|
+
Long-running processes that listen to events and dispatch commands.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
@Injectable()
|
|
125
|
+
export class HeroesGameSagas {
|
|
126
|
+
@Saga()
|
|
127
|
+
dragonKilled = (events$: Observable<any>): Observable<ICommand> => {
|
|
128
|
+
return events$.pipe(
|
|
129
|
+
ofType(HeroKilledDragonEvent),
|
|
130
|
+
map((event) => new DropAncientItemCommand(event.heroId, fakeItemID)),
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Register saga as provider. `ofType` filters events; return command to dispatch.
|
|
137
|
+
|
|
138
|
+
## Request-Scoped Handlers
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
@CommandHandler(KillDragonCommand, { scope: Scope.REQUEST })
|
|
142
|
+
export class KillDragonHandler {
|
|
143
|
+
constructor(@Inject(REQUEST) private request: MyRequest) {}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Pass `AsyncContext` when executing:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const myRequest = new MyRequest(user);
|
|
151
|
+
await this.commandBus.execute(command, myRequest);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Unhandled Exceptions
|
|
155
|
+
|
|
156
|
+
Event handler errors don't reach Exception filters. Subscribe to `UnhandledExceptionBus`:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
this.unhandledExceptionsBus
|
|
160
|
+
.pipe(takeUntil(this.destroy$))
|
|
161
|
+
.subscribe((exceptionInfo) => {
|
|
162
|
+
// Handle exception
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Key Points
|
|
167
|
+
|
|
168
|
+
- Commands: task-based, change state; Queries: data-centric, read state
|
|
169
|
+
- Register all handlers/sagas as providers
|
|
170
|
+
- Event handlers run asynchronously—no HTTP response
|
|
171
|
+
- Use Redis-backed event store for production sagas
|
|
172
|
+
|
|
173
|
+
<!--
|
|
174
|
+
Source references:
|
|
175
|
+
- https://docs.nestjs.com/recipes/cqrs
|
|
176
|
+
-->
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: recipes-crud-generator
|
|
3
|
+
description: Using Nest CLI to generate CRUD resources
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CRUD Generator
|
|
7
|
+
|
|
8
|
+
Nest CLI provides a resource generator that automatically creates all boilerplate code for CRUD operations.
|
|
9
|
+
|
|
10
|
+
## Generate Resource
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
nest g resource
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The generator will prompt for:
|
|
17
|
+
- Resource name
|
|
18
|
+
- Transport layer (REST API, GraphQL, Microservice, WebSocket)
|
|
19
|
+
- Whether to generate CRUD entry points
|
|
20
|
+
|
|
21
|
+
## Generated Files
|
|
22
|
+
|
|
23
|
+
For REST API, generates:
|
|
24
|
+
- Module file (`users.module.ts`)
|
|
25
|
+
- Controller file (`users.controller.ts`)
|
|
26
|
+
- Service file (`users.service.ts`)
|
|
27
|
+
- DTO files (`create-user.dto.ts`, `update-user.dto.ts`)
|
|
28
|
+
- Entity file (`user.entity.ts`)
|
|
29
|
+
- Test files (`.spec.ts`)
|
|
30
|
+
|
|
31
|
+
## Generated Controller
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
@Controller('users')
|
|
35
|
+
export class UsersController {
|
|
36
|
+
constructor(private readonly usersService: UsersService) {}
|
|
37
|
+
|
|
38
|
+
@Post()
|
|
39
|
+
create(@Body() createUserDto: CreateUserDto) {
|
|
40
|
+
return this.usersService.create(createUserDto);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Get()
|
|
44
|
+
findAll() {
|
|
45
|
+
return this.usersService.findAll();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Get(':id')
|
|
49
|
+
findOne(@Param('id') id: string) {
|
|
50
|
+
return this.usersService.findOne(+id);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@Patch(':id')
|
|
54
|
+
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
|
|
55
|
+
return this.usersService.update(+id, updateUserDto);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@Delete(':id')
|
|
59
|
+
remove(@Param('id') id: string) {
|
|
60
|
+
return this.usersService.remove(+id);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## GraphQL Support
|
|
66
|
+
|
|
67
|
+
For GraphQL applications, generates resolvers instead of controllers:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
nest g resource users
|
|
71
|
+
# Select: GraphQL (code first)
|
|
72
|
+
# Select: Yes for CRUD entry points
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Key Points
|
|
76
|
+
|
|
77
|
+
- Generates all CRUD boilerplate automatically
|
|
78
|
+
- Supports REST, GraphQL, Microservices, and WebSockets
|
|
79
|
+
- Service methods contain placeholders for implementation
|
|
80
|
+
- Not tied to any specific ORM
|
|
81
|
+
- Includes test files
|
|
82
|
+
- Saves significant development time
|
|
83
|
+
|
|
84
|
+
<!--
|
|
85
|
+
Source references:
|
|
86
|
+
- https://docs.nestjs.com/recipes/crud-generator
|
|
87
|
+
-->
|