@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,202 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fundamentals-exception-filters
|
|
3
|
+
description: NestJS exception filters for error handling
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Exception Filters
|
|
7
|
+
|
|
8
|
+
Exception filters give you full control over the exceptions layer and the response sent back to the client.
|
|
9
|
+
|
|
10
|
+
## Throwing Exceptions
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
@Get()
|
|
14
|
+
async findAll() {
|
|
15
|
+
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Response:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"statusCode": 403,
|
|
24
|
+
"message": "Forbidden"
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Custom Response Body
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
throw new HttpException({
|
|
32
|
+
status: HttpStatus.FORBIDDEN,
|
|
33
|
+
error: 'This is a custom message',
|
|
34
|
+
}, HttpStatus.FORBIDDEN);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Built-in HTTP Exceptions
|
|
38
|
+
|
|
39
|
+
- `BadRequestException`
|
|
40
|
+
- `UnauthorizedException`
|
|
41
|
+
- `NotFoundException`
|
|
42
|
+
- `ForbiddenException`
|
|
43
|
+
- `NotAcceptableException`
|
|
44
|
+
- `RequestTimeoutException`
|
|
45
|
+
- `ConflictException`
|
|
46
|
+
- `GoneException`
|
|
47
|
+
- `HttpVersionNotSupportedException`
|
|
48
|
+
- `PayloadTooLargeException`
|
|
49
|
+
- `UnsupportedMediaTypeException`
|
|
50
|
+
- `UnprocessableEntityException`
|
|
51
|
+
- `InternalServerErrorException`
|
|
52
|
+
- `NotImplementedException`
|
|
53
|
+
- `ImATeapotException`
|
|
54
|
+
- `MethodNotAllowedException`
|
|
55
|
+
- `BadGatewayException`
|
|
56
|
+
- `ServiceUnavailableException`
|
|
57
|
+
- `GatewayTimeoutException`
|
|
58
|
+
- `PreconditionFailedException`
|
|
59
|
+
|
|
60
|
+
## Custom Exception Filter
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
|
|
64
|
+
import { Request, Response } from 'express';
|
|
65
|
+
|
|
66
|
+
@Catch(HttpException)
|
|
67
|
+
export class HttpExceptionFilter implements ExceptionFilter {
|
|
68
|
+
catch(exception: HttpException, host: ArgumentsHost) {
|
|
69
|
+
const ctx = host.switchToHttp();
|
|
70
|
+
const response = ctx.getResponse<Response>();
|
|
71
|
+
const request = ctx.getRequest<Request>();
|
|
72
|
+
const status = exception.getStatus();
|
|
73
|
+
|
|
74
|
+
response
|
|
75
|
+
.status(status)
|
|
76
|
+
.json({
|
|
77
|
+
statusCode: status,
|
|
78
|
+
timestamp: new Date().toISOString(),
|
|
79
|
+
path: request.url,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Binding Filters
|
|
86
|
+
|
|
87
|
+
### Method-scoped
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
@Post()
|
|
91
|
+
@UseFilters(new HttpExceptionFilter())
|
|
92
|
+
async create(@Body() createCatDto: CreateCatDto) {
|
|
93
|
+
throw new ForbiddenException();
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Controller-scoped
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
@Controller()
|
|
101
|
+
@UseFilters(new HttpExceptionFilter())
|
|
102
|
+
export class CatsController {}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Global Filters
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const app = await NestFactory.create(AppModule);
|
|
109
|
+
app.useGlobalFilters(new HttpExceptionFilter());
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Or via module:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { Module } from '@nestjs/common';
|
|
116
|
+
import { APP_FILTER } from '@nestjs/core';
|
|
117
|
+
|
|
118
|
+
@Module({
|
|
119
|
+
providers: [
|
|
120
|
+
{
|
|
121
|
+
provide: APP_FILTER,
|
|
122
|
+
useClass: HttpExceptionFilter,
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
})
|
|
126
|
+
export class AppModule {}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Catching Everything
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
@Catch()
|
|
133
|
+
export class AllExceptionsFilter implements ExceptionFilter {
|
|
134
|
+
catch(exception: unknown, host: ArgumentsHost) {
|
|
135
|
+
// Handle all exceptions
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Platform-agnostic Filter
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
import {
|
|
144
|
+
ExceptionFilter,
|
|
145
|
+
Catch,
|
|
146
|
+
ArgumentsHost,
|
|
147
|
+
HttpException,
|
|
148
|
+
HttpStatus,
|
|
149
|
+
} from '@nestjs/common';
|
|
150
|
+
import { HttpAdapterHost } from '@nestjs/core';
|
|
151
|
+
|
|
152
|
+
@Catch()
|
|
153
|
+
export class CatchEverythingFilter implements ExceptionFilter {
|
|
154
|
+
constructor(private readonly httpAdapterHost: HttpAdapterHost) {}
|
|
155
|
+
|
|
156
|
+
catch(exception: unknown, host: ArgumentsHost): void {
|
|
157
|
+
const { httpAdapter } = this.httpAdapterHost;
|
|
158
|
+
const ctx = host.switchToHttp();
|
|
159
|
+
|
|
160
|
+
const httpStatus =
|
|
161
|
+
exception instanceof HttpException
|
|
162
|
+
? exception.getStatus()
|
|
163
|
+
: HttpStatus.INTERNAL_SERVER_ERROR;
|
|
164
|
+
|
|
165
|
+
const responseBody = {
|
|
166
|
+
statusCode: httpStatus,
|
|
167
|
+
timestamp: new Date().toISOString(),
|
|
168
|
+
path: httpAdapter.getRequestUrl(ctx.getRequest()),
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
httpAdapter.reply(ctx.getResponse(), responseBody, httpStatus);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Extending Base Filter
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { Catch, ArgumentsHost } from '@nestjs/common';
|
|
180
|
+
import { BaseExceptionFilter } from '@nestjs/core';
|
|
181
|
+
|
|
182
|
+
@Catch()
|
|
183
|
+
export class AllExceptionsFilter extends BaseExceptionFilter {
|
|
184
|
+
catch(exception: unknown, host: ArgumentsHost) {
|
|
185
|
+
super.catch(exception, host);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Key Points
|
|
191
|
+
|
|
192
|
+
- Filters catch exceptions and format responses
|
|
193
|
+
- Use `@Catch()` to specify exception types
|
|
194
|
+
- Filters can be method, controller, or global scoped
|
|
195
|
+
- Use `HttpAdapterHost` for platform-agnostic code
|
|
196
|
+
- Extend `BaseExceptionFilter` to reuse default behavior
|
|
197
|
+
- Multiple filters can be chained
|
|
198
|
+
|
|
199
|
+
<!--
|
|
200
|
+
Source references:
|
|
201
|
+
- https://docs.nestjs.com/exception-filters
|
|
202
|
+
-->
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fundamentals-execution-context
|
|
3
|
+
description: Accessing execution context in NestJS guards, filters, and interceptors
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Execution Context
|
|
7
|
+
|
|
8
|
+
`ExecutionContext` provides information about the current execution context, useful for building generic guards, filters, and interceptors.
|
|
9
|
+
|
|
10
|
+
## ArgumentsHost
|
|
11
|
+
|
|
12
|
+
`ArgumentsHost` provides methods to retrieve handler arguments:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
const ctx = host.switchToHttp();
|
|
16
|
+
const request = ctx.getRequest<Request>();
|
|
17
|
+
const response = ctx.getResponse<Response>();
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Application Context Types
|
|
21
|
+
|
|
22
|
+
Determine application type:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
if (host.getType() === 'http') {
|
|
26
|
+
// HTTP context
|
|
27
|
+
} else if (host.getType() === 'rpc') {
|
|
28
|
+
// Microservice context
|
|
29
|
+
} else if (host.getType<GqlContextType>() === 'graphql') {
|
|
30
|
+
// GraphQL context
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Switching Contexts
|
|
35
|
+
|
|
36
|
+
### HTTP Context
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const ctx = host.switchToHttp();
|
|
40
|
+
const request = ctx.getRequest<Request>();
|
|
41
|
+
const response = ctx.getResponse<Response>();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### WebSocket Context
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
const ctx = host.switchToWs();
|
|
48
|
+
const client = ctx.getClient<Socket>();
|
|
49
|
+
const data = ctx.getData();
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### RPC Context
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
const ctx = host.switchToRpc();
|
|
56
|
+
const data = ctx.getData();
|
|
57
|
+
const context = ctx.getContext();
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## ExecutionContext
|
|
61
|
+
|
|
62
|
+
`ExecutionContext` extends `ArgumentsHost` with additional methods:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
export interface ExecutionContext extends ArgumentsHost {
|
|
66
|
+
getClass<T = any>(): Type<T>;
|
|
67
|
+
getHandler(): Function;
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Using in Guards
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
@Injectable()
|
|
75
|
+
export class RolesGuard implements CanActivate {
|
|
76
|
+
constructor(private reflector: Reflector) {}
|
|
77
|
+
|
|
78
|
+
canActivate(context: ExecutionContext): boolean {
|
|
79
|
+
const roles = this.reflector.get(Roles, context.getHandler());
|
|
80
|
+
const request = context.switchToHttp().getRequest();
|
|
81
|
+
return matchRoles(roles, request.user.roles);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Reflection and Metadata
|
|
87
|
+
|
|
88
|
+
Access route metadata:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
const roles = this.reflector.get(Roles, context.getHandler());
|
|
92
|
+
const roles = this.reflector.get(Roles, context.getClass());
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Key Points
|
|
96
|
+
|
|
97
|
+
- `ArgumentsHost` provides access to handler arguments
|
|
98
|
+
- `ExecutionContext` adds class and handler information
|
|
99
|
+
- Use `switchToHttp()`, `switchToWs()`, `switchToRpc()` for context-specific access
|
|
100
|
+
- Use `getType()` to determine application context
|
|
101
|
+
- `Reflector` provides access to route metadata
|
|
102
|
+
- Execution context is available in guards, filters, and interceptors
|
|
103
|
+
|
|
104
|
+
<!--
|
|
105
|
+
Source references:
|
|
106
|
+
- https://docs.nestjs.com/fundamentals/execution-context
|
|
107
|
+
-->
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fundamentals-guards
|
|
3
|
+
description: NestJS guards for authorization and access control
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Guards
|
|
7
|
+
|
|
8
|
+
Guards determine whether a request should be handled by a route handler. They have access to `ExecutionContext` and know what will be executed next.
|
|
9
|
+
|
|
10
|
+
## Basic Guard
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
|
14
|
+
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class AuthGuard implements CanActivate {
|
|
17
|
+
canActivate(
|
|
18
|
+
context: ExecutionContext,
|
|
19
|
+
): boolean | Promise<boolean> | Observable<boolean> {
|
|
20
|
+
const request = context.switchToHttp().getRequest();
|
|
21
|
+
return validateRequest(request);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Role-based Guard
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
|
30
|
+
import { Reflector } from '@nestjs/core';
|
|
31
|
+
import { Roles } from './roles.decorator';
|
|
32
|
+
|
|
33
|
+
@Injectable()
|
|
34
|
+
export class RolesGuard implements CanActivate {
|
|
35
|
+
constructor(private reflector: Reflector) {}
|
|
36
|
+
|
|
37
|
+
canActivate(context: ExecutionContext): boolean {
|
|
38
|
+
const roles = this.reflector.get(Roles, context.getHandler());
|
|
39
|
+
if (!roles) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
const request = context.switchToHttp().getRequest();
|
|
43
|
+
const user = request.user;
|
|
44
|
+
return matchRoles(roles, user.roles);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Custom Decorator
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { Reflector } from '@nestjs/core';
|
|
53
|
+
|
|
54
|
+
export const Roles = Reflector.createDecorator<string[]>();
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Usage:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
@Post()
|
|
61
|
+
@Roles(['admin'])
|
|
62
|
+
async create(@Body() createCatDto: CreateCatDto) {
|
|
63
|
+
this.catsService.create(createCatDto);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Binding Guards
|
|
68
|
+
|
|
69
|
+
### Controller-scoped
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
@Controller('cats')
|
|
73
|
+
@UseGuards(RolesGuard)
|
|
74
|
+
export class CatsController {}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Method-scoped
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
@Post()
|
|
81
|
+
@UseGuards(RolesGuard)
|
|
82
|
+
async create(@Body() createCatDto: CreateCatDto) {
|
|
83
|
+
this.catsService.create(createCatDto);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Global Guards
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
const app = await NestFactory.create(AppModule);
|
|
91
|
+
app.useGlobalGuards(new RolesGuard());
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Or via module:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { Module } from '@nestjs/common';
|
|
98
|
+
import { APP_GUARD } from '@nestjs/core';
|
|
99
|
+
|
|
100
|
+
@Module({
|
|
101
|
+
providers: [
|
|
102
|
+
{
|
|
103
|
+
provide: APP_GUARD,
|
|
104
|
+
useClass: RolesGuard,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
})
|
|
108
|
+
export class AppModule {}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Multiple Guards
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
@UseGuards(AuthGuard, RolesGuard)
|
|
115
|
+
export class CatsController {}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Execution Order
|
|
119
|
+
|
|
120
|
+
Guards are executed:
|
|
121
|
+
- After middleware
|
|
122
|
+
- Before interceptors and pipes
|
|
123
|
+
|
|
124
|
+
## Key Points
|
|
125
|
+
|
|
126
|
+
- Guards return `true` to allow, `false` to deny
|
|
127
|
+
- Guards can be async (return `Promise<boolean>`)
|
|
128
|
+
- Use `Reflector` to access route metadata
|
|
129
|
+
- Guards throw exceptions to deny access
|
|
130
|
+
- Use `@SetMetadata()` or `Reflector.createDecorator()` for custom metadata
|
|
131
|
+
- Guards have access to `ExecutionContext`
|
|
132
|
+
|
|
133
|
+
<!--
|
|
134
|
+
Source references:
|
|
135
|
+
- https://docs.nestjs.com/guards
|
|
136
|
+
-->
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fundamentals-interceptors
|
|
3
|
+
description: NestJS interceptors for aspect-oriented programming
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Interceptors
|
|
7
|
+
|
|
8
|
+
Interceptors implement aspect-oriented programming (AOP). They can bind extra logic before/after method execution, transform results, handle exceptions, and extend function behavior.
|
|
9
|
+
|
|
10
|
+
## Basic Interceptor
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
14
|
+
import { Observable } from 'rxjs';
|
|
15
|
+
import { tap } from 'rxjs/operators';
|
|
16
|
+
|
|
17
|
+
@Injectable()
|
|
18
|
+
export class LoggingInterceptor implements NestInterceptor {
|
|
19
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
20
|
+
console.log('Before...');
|
|
21
|
+
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
return next
|
|
24
|
+
.handle()
|
|
25
|
+
.pipe(
|
|
26
|
+
tap(() => console.log(`After... ${Date.now() - now}ms`)),
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Response Transformation
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
36
|
+
import { Observable } from 'rxjs';
|
|
37
|
+
import { map } from 'rxjs/operators';
|
|
38
|
+
|
|
39
|
+
export interface Response<T> {
|
|
40
|
+
data: T;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Injectable()
|
|
44
|
+
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
|
|
45
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
|
|
46
|
+
return next.handle().pipe(map(data => ({ data })));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Exception Mapping
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import {
|
|
55
|
+
Injectable,
|
|
56
|
+
NestInterceptor,
|
|
57
|
+
ExecutionContext,
|
|
58
|
+
BadGatewayException,
|
|
59
|
+
CallHandler,
|
|
60
|
+
} from '@nestjs/common';
|
|
61
|
+
import { Observable, throwError } from 'rxjs';
|
|
62
|
+
import { catchError } from 'rxjs/operators';
|
|
63
|
+
|
|
64
|
+
@Injectable()
|
|
65
|
+
export class ErrorsInterceptor implements NestInterceptor {
|
|
66
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
67
|
+
return next
|
|
68
|
+
.handle()
|
|
69
|
+
.pipe(
|
|
70
|
+
catchError(err => throwError(() => new BadGatewayException())),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Caching Interceptor
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
80
|
+
import { Observable, of } from 'rxjs';
|
|
81
|
+
|
|
82
|
+
@Injectable()
|
|
83
|
+
export class CacheInterceptor implements NestInterceptor {
|
|
84
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
85
|
+
const isCached = true;
|
|
86
|
+
if (isCached) {
|
|
87
|
+
return of([]);
|
|
88
|
+
}
|
|
89
|
+
return next.handle();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Timeout Interceptor
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, RequestTimeoutException } from '@nestjs/common';
|
|
98
|
+
import { Observable, throwError, TimeoutError } from 'rxjs';
|
|
99
|
+
import { catchError, timeout } from 'rxjs/operators';
|
|
100
|
+
|
|
101
|
+
@Injectable()
|
|
102
|
+
export class TimeoutInterceptor implements NestInterceptor {
|
|
103
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
104
|
+
return next.handle().pipe(
|
|
105
|
+
timeout(5000),
|
|
106
|
+
catchError(err => {
|
|
107
|
+
if (err instanceof TimeoutError) {
|
|
108
|
+
return throwError(() => new RequestTimeoutException());
|
|
109
|
+
}
|
|
110
|
+
return throwError(() => err);
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Binding Interceptors
|
|
118
|
+
|
|
119
|
+
### Controller-scoped
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
@Controller('cats')
|
|
123
|
+
@UseInterceptors(LoggingInterceptor)
|
|
124
|
+
export class CatsController {}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Method-scoped
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
@Get()
|
|
131
|
+
@UseInterceptors(LoggingInterceptor)
|
|
132
|
+
async findAll() {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Global Interceptors
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
const app = await NestFactory.create(AppModule);
|
|
141
|
+
app.useGlobalInterceptors(new LoggingInterceptor());
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Or via module:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { Module } from '@nestjs/common';
|
|
148
|
+
import { APP_INTERCEPTOR } from '@nestjs/core';
|
|
149
|
+
|
|
150
|
+
@Module({
|
|
151
|
+
providers: [
|
|
152
|
+
{
|
|
153
|
+
provide: APP_INTERCEPTOR,
|
|
154
|
+
useClass: LoggingInterceptor,
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
})
|
|
158
|
+
export class AppModule {}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Null Transformation
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
@Injectable()
|
|
165
|
+
export class ExcludeNullInterceptor implements NestInterceptor {
|
|
166
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
167
|
+
return next
|
|
168
|
+
.handle()
|
|
169
|
+
.pipe(map(value => value === null ? '' : value));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Key Points
|
|
175
|
+
|
|
176
|
+
- Interceptors wrap request/response stream
|
|
177
|
+
- Use RxJS operators to manipulate streams
|
|
178
|
+
- Must call `next.handle()` to continue execution
|
|
179
|
+
- Can transform responses using `map()`
|
|
180
|
+
- Can handle errors using `catchError()`
|
|
181
|
+
- Can override stream completely (caching)
|
|
182
|
+
- Interceptors support dependency injection
|
|
183
|
+
|
|
184
|
+
<!--
|
|
185
|
+
Source references:
|
|
186
|
+
- https://docs.nestjs.com/interceptors
|
|
187
|
+
-->
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lazy-loading
|
|
3
|
+
description: Lazy loading modules for serverless and performance optimization
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Lazy Loading Modules
|
|
7
|
+
|
|
8
|
+
Lazy loading helps decrease bootstrap time by loading modules only when needed, particularly useful for serverless environments where cold start latency matters.
|
|
9
|
+
|
|
10
|
+
## Basic Usage
|
|
11
|
+
|
|
12
|
+
Inject `LazyModuleLoader` to load modules on-demand:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { Injectable } from '@nestjs/common';
|
|
16
|
+
import { LazyModuleLoader } from '@nestjs/core';
|
|
17
|
+
|
|
18
|
+
@Injectable()
|
|
19
|
+
export class CatsService {
|
|
20
|
+
constructor(private lazyModuleLoader: LazyModuleLoader) {}
|
|
21
|
+
|
|
22
|
+
async loadFeature() {
|
|
23
|
+
const { LazyModule } = await import('./lazy.module');
|
|
24
|
+
const moduleRef = await this.lazyModuleLoader.load(() => LazyModule);
|
|
25
|
+
|
|
26
|
+
const { LazyService } = await import('./lazy.service');
|
|
27
|
+
const lazyService = moduleRef.get(LazyService);
|
|
28
|
+
return lazyService.doSomething();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Module Definition
|
|
34
|
+
|
|
35
|
+
Lazy loaded modules are standard Nest modules:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
@Module({
|
|
39
|
+
providers: [LazyService],
|
|
40
|
+
exports: [LazyService],
|
|
41
|
+
})
|
|
42
|
+
export class LazyModule {}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Caching Behavior
|
|
46
|
+
|
|
47
|
+
Lazy loaded modules are cached after the first load:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
Load "LazyModule" attempt: 1 - time: 2.379ms
|
|
51
|
+
Load "LazyModule" attempt: 2 - time: 0.294ms // Cached
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Limitations
|
|
55
|
+
|
|
56
|
+
**Cannot lazy load:**
|
|
57
|
+
- Controllers (routes must be registered at startup)
|
|
58
|
+
- Resolvers (GraphQL schema generated at startup)
|
|
59
|
+
- Gateways (WebSocket routes registered at startup)
|
|
60
|
+
|
|
61
|
+
**Other restrictions:**
|
|
62
|
+
- Cannot register as global modules
|
|
63
|
+
- Global enhancers (guards/interceptors) won't work
|
|
64
|
+
- Lifecycle hooks are not invoked in lazy loaded modules
|
|
65
|
+
|
|
66
|
+
## Webpack Configuration
|
|
67
|
+
|
|
68
|
+
For Webpack, update `tsconfig.json`:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"compilerOptions": {
|
|
73
|
+
"module": "esnext",
|
|
74
|
+
"moduleResolution": "node"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Use Cases
|
|
80
|
+
|
|
81
|
+
Best suited for:
|
|
82
|
+
- Serverless functions (Lambda, Cloud Functions)
|
|
83
|
+
- Worker/cron jobs with conditional logic
|
|
84
|
+
- Feature modules loaded based on runtime conditions
|
|
85
|
+
|
|
86
|
+
<!--
|
|
87
|
+
Source references:
|
|
88
|
+
- https://docs.nestjs.com/fundamentals/lazy-loading-modules
|
|
89
|
+
-->
|