@biggora/claude-plugins 1.2.2 → 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 +2 -0
- package/package.json +1 -1
- package/registry/registry.json +15 -0
- package/specs/coding.md +6 -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/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/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
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: core-providers
|
|
3
|
+
description: NestJS providers and services for dependency injection
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Providers
|
|
7
|
+
|
|
8
|
+
Providers are classes that can be injected as dependencies. Services, repositories, factories, and helpers are all providers.
|
|
9
|
+
|
|
10
|
+
## Basic Service
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
import { Injectable } from '@nestjs/common';
|
|
14
|
+
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class CatsService {
|
|
17
|
+
private readonly cats: Cat[] = [];
|
|
18
|
+
|
|
19
|
+
create(cat: Cat) {
|
|
20
|
+
this.cats.push(cat);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
findAll(): Cat[] {
|
|
24
|
+
return this.cats;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Dependency Injection
|
|
30
|
+
|
|
31
|
+
Inject services in controllers:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
@Controller('cats')
|
|
35
|
+
export class CatsController {
|
|
36
|
+
constructor(private catsService: CatsService) {}
|
|
37
|
+
|
|
38
|
+
@Get()
|
|
39
|
+
async findAll(): Promise<Cat[]> {
|
|
40
|
+
return this.catsService.findAll();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Provider Registration
|
|
46
|
+
|
|
47
|
+
Register providers in modules:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
@Module({
|
|
51
|
+
controllers: [CatsController],
|
|
52
|
+
providers: [CatsService],
|
|
53
|
+
})
|
|
54
|
+
export class CatsModule {}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Optional Providers
|
|
58
|
+
|
|
59
|
+
Mark dependencies as optional:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { Injectable, Optional, Inject } from '@nestjs/common';
|
|
63
|
+
|
|
64
|
+
@Injectable()
|
|
65
|
+
export class HttpService<T> {
|
|
66
|
+
constructor(@Optional() @Inject('HTTP_OPTIONS') private httpClient: T) {}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Property-based Injection
|
|
71
|
+
|
|
72
|
+
Inject at property level:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
@Injectable()
|
|
76
|
+
export class HttpService<T> {
|
|
77
|
+
@Inject('HTTP_OPTIONS')
|
|
78
|
+
private readonly httpClient: T;
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Custom Providers
|
|
83
|
+
|
|
84
|
+
### Value Providers
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
const mockCatsService = {
|
|
88
|
+
findAll: () => ['test'],
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
@Module({
|
|
92
|
+
providers: [
|
|
93
|
+
{
|
|
94
|
+
provide: CatsService,
|
|
95
|
+
useValue: mockCatsService,
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
})
|
|
99
|
+
export class AppModule {}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Class Providers
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const configServiceProvider = {
|
|
106
|
+
provide: ConfigService,
|
|
107
|
+
useClass: process.env.NODE_ENV === 'development'
|
|
108
|
+
? DevelopmentConfigService
|
|
109
|
+
: ProductionConfigService,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
@Module({
|
|
113
|
+
providers: [configServiceProvider],
|
|
114
|
+
})
|
|
115
|
+
export class AppModule {}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Factory Providers
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
const connectionProvider = {
|
|
122
|
+
provide: 'CONNECTION',
|
|
123
|
+
useFactory: (optionsProvider: OptionsProvider) => {
|
|
124
|
+
const options = optionsProvider.get();
|
|
125
|
+
return new DatabaseConnection(options);
|
|
126
|
+
},
|
|
127
|
+
inject: [OptionsProvider],
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
@Module({
|
|
131
|
+
providers: [connectionProvider, OptionsProvider],
|
|
132
|
+
})
|
|
133
|
+
export class AppModule {}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Alias Providers
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const loggerAliasProvider = {
|
|
140
|
+
provide: 'AliasedLoggerService',
|
|
141
|
+
useExisting: LoggerService,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
@Module({
|
|
145
|
+
providers: [LoggerService, loggerAliasProvider],
|
|
146
|
+
})
|
|
147
|
+
export class AppModule {}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Non-class-based Tokens
|
|
151
|
+
|
|
152
|
+
Use strings or symbols as tokens:
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
@Module({
|
|
156
|
+
providers: [
|
|
157
|
+
{
|
|
158
|
+
provide: 'CONNECTION',
|
|
159
|
+
useValue: connection,
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
})
|
|
163
|
+
export class AppModule {}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Inject using `@Inject()`:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
@Injectable()
|
|
170
|
+
export class CatsRepository {
|
|
171
|
+
constructor(@Inject('CONNECTION') connection: Connection) {}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Key Points
|
|
176
|
+
|
|
177
|
+
- Use `@Injectable()` decorator to mark classes as providers
|
|
178
|
+
- Prefer constructor-based injection over property-based
|
|
179
|
+
- Providers are singletons by default
|
|
180
|
+
- Use custom providers for mocks, factories, and aliases
|
|
181
|
+
- Export providers to make them available to other modules
|
|
182
|
+
- Use string tokens for non-class providers
|
|
183
|
+
|
|
184
|
+
<!--
|
|
185
|
+
Source references:
|
|
186
|
+
- https://docs.nestjs.com/providers
|
|
187
|
+
- https://docs.nestjs.com/fundamentals/custom-providers
|
|
188
|
+
-->
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: raw-body-hybrid
|
|
3
|
+
description: Raw request body for webhooks and hybrid HTTP+microservice applications
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Raw Body and Hybrid Applications
|
|
7
|
+
|
|
8
|
+
## Raw Body (Webhook Signature Verification)
|
|
9
|
+
|
|
10
|
+
Required for Stripe, GitHub webhooks, etc. where you need the unparsed body to compute HMAC.
|
|
11
|
+
|
|
12
|
+
### Express
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
|
|
16
|
+
rawBody: true,
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { Controller, Post, RawBodyRequest, Req } from '@nestjs/common';
|
|
22
|
+
import { Request } from 'express';
|
|
23
|
+
|
|
24
|
+
@Controller('webhooks')
|
|
25
|
+
class WebhooksController {
|
|
26
|
+
@Post('stripe')
|
|
27
|
+
stripe(@Req() req: RawBodyRequest<Request>) {
|
|
28
|
+
const raw = req.rawBody; // Buffer
|
|
29
|
+
const signature = req.headers['stripe-signature'];
|
|
30
|
+
// Verify signature with raw body
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Fastify
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
const app = await NestFactory.create<NestFastifyApplication>(
|
|
39
|
+
AppModule,
|
|
40
|
+
new FastifyAdapter(),
|
|
41
|
+
{ rawBody: true },
|
|
42
|
+
);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Additional Parsers
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
app.useBodyParser('text');
|
|
49
|
+
app.useBodyParser('json', { limit: '10mb' });
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Hybrid Applications
|
|
53
|
+
|
|
54
|
+
Combine HTTP server with one or more microservice listeners.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const app = await NestFactory.create(AppModule);
|
|
58
|
+
|
|
59
|
+
// Connect microservices
|
|
60
|
+
app.connectMicroservice<MicroserviceOptions>({
|
|
61
|
+
transport: Transport.TCP,
|
|
62
|
+
options: { port: 3001 },
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
app.connectMicroservice<MicroserviceOptions>({
|
|
66
|
+
transport: Transport.REDIS,
|
|
67
|
+
options: { host: 'localhost', port: 6379 },
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
await app.startAllMicroservices();
|
|
71
|
+
await app.listen(3001);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Non-HTTP Applications
|
|
75
|
+
|
|
76
|
+
Use `app.init()` instead of `app.listen()` when not handling HTTP:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
await app.startAllMicroservices();
|
|
80
|
+
await app.init();
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Binding Patterns to Transport
|
|
84
|
+
|
|
85
|
+
When multiple transports exist, bind `@MessagePattern()` to specific transport:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
@MessagePattern('time.us.*', Transport.NATS)
|
|
89
|
+
getDate(@Payload() data: number[], @Ctx() context: NatsContext) {
|
|
90
|
+
return new Date().toLocaleTimeString();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@MessagePattern({ cmd: 'time.us' }, Transport.TCP)
|
|
94
|
+
getTCPDate(@Payload() data: number[]) {
|
|
95
|
+
return new Date().toLocaleTimeString();
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Inherit App Config
|
|
100
|
+
|
|
101
|
+
By default, microservices don't inherit global pipes/guards/interceptors. To inherit:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
app.connectMicroservice<MicroserviceOptions>(
|
|
105
|
+
{ transport: Transport.TCP },
|
|
106
|
+
{ inheritAppConfig: true },
|
|
107
|
+
);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Key Points
|
|
111
|
+
|
|
112
|
+
- `rawBody: true` must be set at app creation
|
|
113
|
+
- Don't use `bodyParser: false` with raw body
|
|
114
|
+
- `RawBodyRequest` interface adds `rawBody` to request
|
|
115
|
+
- Each `connectMicroservice()` adds one transport
|
|
116
|
+
- Call `startAllMicroservices()` before `listen()`
|
|
117
|
+
|
|
118
|
+
<!--
|
|
119
|
+
Source references:
|
|
120
|
+
- https://docs.nestjs.com/faq/raw-body
|
|
121
|
+
- https://docs.nestjs.com/faq/hybrid-application
|
|
122
|
+
-->
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: circular-dependency
|
|
3
|
+
description: Resolving circular dependencies between providers and modules
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Circular Dependency
|
|
7
|
+
|
|
8
|
+
Circular dependencies occur when two classes depend on each other. While they should be avoided, NestJS provides techniques to resolve them when necessary.
|
|
9
|
+
|
|
10
|
+
## Forward Reference for Providers
|
|
11
|
+
|
|
12
|
+
Use `forwardRef()` when two providers depend on each other:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// cats.service.ts
|
|
16
|
+
import { Injectable, Inject, forwardRef } from '@nestjs/common';
|
|
17
|
+
import { CommonService } from './common.service';
|
|
18
|
+
|
|
19
|
+
@Injectable()
|
|
20
|
+
export class CatsService {
|
|
21
|
+
constructor(
|
|
22
|
+
@Inject(forwardRef(() => CommonService))
|
|
23
|
+
private commonService: CommonService,
|
|
24
|
+
) {}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
// common.service.ts
|
|
30
|
+
@Injectable()
|
|
31
|
+
export class CommonService {
|
|
32
|
+
constructor(
|
|
33
|
+
@Inject(forwardRef(() => CatsService))
|
|
34
|
+
private catsService: CatsService,
|
|
35
|
+
) {}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Forward Reference for Modules
|
|
40
|
+
|
|
41
|
+
Apply `forwardRef()` on both sides of module imports:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// common.module.ts
|
|
45
|
+
@Module({
|
|
46
|
+
imports: [forwardRef(() => CatsModule)],
|
|
47
|
+
})
|
|
48
|
+
export class CommonModule {}
|
|
49
|
+
|
|
50
|
+
// cats.module.ts
|
|
51
|
+
@Module({
|
|
52
|
+
imports: [forwardRef(() => CommonModule)],
|
|
53
|
+
})
|
|
54
|
+
export class CatsModule {}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Using ModuleRef Alternative
|
|
58
|
+
|
|
59
|
+
Refactor to use `ModuleRef` to retrieve providers dynamically:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
@Injectable()
|
|
63
|
+
export class CatsService implements OnModuleInit {
|
|
64
|
+
private commonService: CommonService;
|
|
65
|
+
|
|
66
|
+
constructor(private moduleRef: ModuleRef) {}
|
|
67
|
+
|
|
68
|
+
onModuleInit() {
|
|
69
|
+
this.commonService = this.moduleRef.get(CommonService);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Common Causes
|
|
75
|
+
|
|
76
|
+
- Barrel files (index.ts) grouping imports - avoid when importing within same directory
|
|
77
|
+
- Over-coupled service design
|
|
78
|
+
|
|
79
|
+
## Key Points
|
|
80
|
+
|
|
81
|
+
- `forwardRef()` is imported from `@nestjs/common`
|
|
82
|
+
- Instantiation order is indeterminate with forward references
|
|
83
|
+
- Avoid circular dependencies with `Scope.REQUEST` providers (can cause undefined dependencies)
|
|
84
|
+
- Consider refactoring to eliminate circular dependencies when possible
|
|
85
|
+
|
|
86
|
+
<!--
|
|
87
|
+
Source references:
|
|
88
|
+
- https://docs.nestjs.com/fundamentals/circular-dependency
|
|
89
|
+
-->
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fundamentals-custom-decorators
|
|
3
|
+
description: Creating custom parameter decorators in NestJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Custom Decorators
|
|
7
|
+
|
|
8
|
+
Create custom parameter decorators to extract data from requests in a reusable way.
|
|
9
|
+
|
|
10
|
+
## Basic Custom Decorator
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
|
14
|
+
|
|
15
|
+
export const User = createParamDecorator(
|
|
16
|
+
(data: unknown, ctx: ExecutionContext) => {
|
|
17
|
+
const request = ctx.switchToHttp().getRequest();
|
|
18
|
+
return request.user;
|
|
19
|
+
},
|
|
20
|
+
);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
@Get()
|
|
27
|
+
async findOne(@User() user: UserEntity) {
|
|
28
|
+
console.log(user);
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Decorator with Data
|
|
33
|
+
|
|
34
|
+
Pass data to decorator:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
export const User = createParamDecorator(
|
|
38
|
+
(data: string, ctx: ExecutionContext) => {
|
|
39
|
+
const request = ctx.switchToHttp().getRequest();
|
|
40
|
+
const user = request.user;
|
|
41
|
+
|
|
42
|
+
return data ? user?.[data] : user;
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Usage:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
@Get()
|
|
51
|
+
async findOne(@User('firstName') firstName: string) {
|
|
52
|
+
console.log(`Hello ${firstName}`);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Working with Pipes
|
|
57
|
+
|
|
58
|
+
Apply pipes to custom decorators:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
@Get()
|
|
62
|
+
async findOne(
|
|
63
|
+
@User(new ValidationPipe({ validateCustomDecorators: true }))
|
|
64
|
+
user: UserEntity,
|
|
65
|
+
) {
|
|
66
|
+
console.log(user);
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Decorator Composition
|
|
71
|
+
|
|
72
|
+
Combine multiple decorators:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { applyDecorators } from '@nestjs/common';
|
|
76
|
+
|
|
77
|
+
export function Auth(...roles: Role[]) {
|
|
78
|
+
return applyDecorators(
|
|
79
|
+
SetMetadata('roles', roles),
|
|
80
|
+
UseGuards(AuthGuard, RolesGuard),
|
|
81
|
+
ApiBearerAuth(),
|
|
82
|
+
ApiUnauthorizedResponse({ description: 'Unauthorized' }),
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Usage:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
@Get('users')
|
|
91
|
+
@Auth('admin')
|
|
92
|
+
findAllUsers() {}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Key Points
|
|
96
|
+
|
|
97
|
+
- Use `createParamDecorator()` to create custom decorators
|
|
98
|
+
- Decorators receive `ExecutionContext` for accessing request/response
|
|
99
|
+
- Pass data as second parameter to decorator factory
|
|
100
|
+
- Custom decorators work with pipes
|
|
101
|
+
- Use `applyDecorators()` to compose multiple decorators
|
|
102
|
+
- TypeScript generics can enforce type safety
|
|
103
|
+
|
|
104
|
+
<!--
|
|
105
|
+
Source references:
|
|
106
|
+
- https://docs.nestjs.com/custom-decorators
|
|
107
|
+
-->
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fundamentals-dynamic-modules
|
|
3
|
+
description: Creating configurable dynamic modules in NestJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Dynamic Modules
|
|
7
|
+
|
|
8
|
+
Dynamic modules allow you to create modules that can be configured at runtime, providing flexible and customizable module APIs.
|
|
9
|
+
|
|
10
|
+
## Static vs Dynamic Modules
|
|
11
|
+
|
|
12
|
+
Static modules have fixed configuration:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
@Module({
|
|
16
|
+
imports: [ConfigModule],
|
|
17
|
+
})
|
|
18
|
+
export class AppModule {}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Dynamic modules accept configuration:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
@Module({
|
|
25
|
+
imports: [ConfigModule.forRoot({ envFilePath: '.env' })],
|
|
26
|
+
})
|
|
27
|
+
export class AppModule {}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Creating Dynamic Modules
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { Module, DynamicModule } from '@nestjs/common';
|
|
34
|
+
|
|
35
|
+
@Module({
|
|
36
|
+
providers: [Connection],
|
|
37
|
+
exports: [Connection],
|
|
38
|
+
})
|
|
39
|
+
export class DatabaseModule {
|
|
40
|
+
static forRoot(entities = [], options?): DynamicModule {
|
|
41
|
+
const providers = createDatabaseProviders(options, entities);
|
|
42
|
+
return {
|
|
43
|
+
module: DatabaseModule,
|
|
44
|
+
providers: providers,
|
|
45
|
+
exports: providers,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Using Dynamic Modules
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
@Module({
|
|
55
|
+
imports: [DatabaseModule.forRoot([User])],
|
|
56
|
+
})
|
|
57
|
+
export class AppModule {}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Global Dynamic Modules
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
{
|
|
64
|
+
global: true,
|
|
65
|
+
module: DatabaseModule,
|
|
66
|
+
providers: providers,
|
|
67
|
+
exports: providers,
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Re-exporting Dynamic Modules
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
@Module({
|
|
75
|
+
imports: [DatabaseModule.forRoot([User])],
|
|
76
|
+
exports: [DatabaseModule],
|
|
77
|
+
})
|
|
78
|
+
export class AppModule {}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Async Dynamic Modules
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
static forRootAsync(options: ConfigModuleAsyncOptions): DynamicModule {
|
|
85
|
+
return {
|
|
86
|
+
module: ConfigModule,
|
|
87
|
+
imports: options.imports || [],
|
|
88
|
+
providers: [
|
|
89
|
+
{
|
|
90
|
+
provide: CONFIG_OPTIONS,
|
|
91
|
+
useFactory: options.useFactory,
|
|
92
|
+
inject: options.inject || [],
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
exports: [ConfigService],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## ConfigurableModuleBuilder
|
|
101
|
+
|
|
102
|
+
Use `ConfigurableModuleBuilder` for advanced scenarios:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { ConfigurableModuleBuilder } from '@nestjs/common';
|
|
106
|
+
|
|
107
|
+
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
|
|
108
|
+
new ConfigurableModuleBuilder<ConfigModuleOptions>()
|
|
109
|
+
.setClassMethodName('forRoot')
|
|
110
|
+
.build();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Key Points
|
|
114
|
+
|
|
115
|
+
- Dynamic modules provide runtime configuration
|
|
116
|
+
- Use static `forRoot()` or `forRootAsync()` methods
|
|
117
|
+
- Return `DynamicModule` from factory methods
|
|
118
|
+
- Dynamic module properties extend base module metadata
|
|
119
|
+
- Use `ConfigurableModuleBuilder` for complex scenarios
|
|
120
|
+
- Dynamic modules can be global or scoped
|
|
121
|
+
|
|
122
|
+
<!--
|
|
123
|
+
Source references:
|
|
124
|
+
- https://docs.nestjs.com/fundamentals/dynamic-modules
|
|
125
|
+
-->
|