@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,194 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: compression-streaming-sse
|
|
3
|
+
description: Response compression, file streaming, and Server-Sent Events
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Compression, Streaming & SSE
|
|
7
|
+
|
|
8
|
+
## Compression
|
|
9
|
+
|
|
10
|
+
For high-traffic production sites, offload compression to a reverse proxy (Nginx).
|
|
11
|
+
|
|
12
|
+
### Express
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install compression
|
|
16
|
+
npm install -D @types/compression
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import * as compression from 'compression';
|
|
21
|
+
|
|
22
|
+
app.use(compression());
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Fastify
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @fastify/compress
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import compression from '@fastify/compress';
|
|
33
|
+
|
|
34
|
+
const app = await NestFactory.create<NestFastifyApplication>(
|
|
35
|
+
AppModule,
|
|
36
|
+
new FastifyAdapter(),
|
|
37
|
+
);
|
|
38
|
+
await app.register(compression);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Configure compression quality:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { constants } from 'node:zlib';
|
|
45
|
+
|
|
46
|
+
await app.register(compression, {
|
|
47
|
+
brotliOptions: {
|
|
48
|
+
params: { [constants.BROTLI_PARAM_QUALITY]: 4 },
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Or prefer faster encodings
|
|
53
|
+
await app.register(compression, {
|
|
54
|
+
encodings: ['gzip', 'deflate'],
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## File Streaming
|
|
59
|
+
|
|
60
|
+
Use `StreamableFile` to return file streams while keeping interceptor support:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { Controller, Get, StreamableFile } from '@nestjs/common';
|
|
64
|
+
import { createReadStream } from 'node:fs';
|
|
65
|
+
import { join } from 'node:path';
|
|
66
|
+
|
|
67
|
+
@Controller('files')
|
|
68
|
+
export class FilesController {
|
|
69
|
+
@Get()
|
|
70
|
+
getFile(): StreamableFile {
|
|
71
|
+
const file = createReadStream(join(process.cwd(), 'package.json'));
|
|
72
|
+
return new StreamableFile(file);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
With custom headers:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
@Get()
|
|
81
|
+
getFile(): StreamableFile {
|
|
82
|
+
const file = createReadStream(join(process.cwd(), 'report.pdf'));
|
|
83
|
+
return new StreamableFile(file, {
|
|
84
|
+
type: 'application/pdf',
|
|
85
|
+
disposition: 'attachment; filename="report.pdf"',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Or using response object:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
@Get()
|
|
94
|
+
getFile(@Res({ passthrough: true }) res: Response): StreamableFile {
|
|
95
|
+
const file = createReadStream(join(process.cwd(), 'image.png'));
|
|
96
|
+
res.set({
|
|
97
|
+
'Content-Type': 'image/png',
|
|
98
|
+
'Content-Disposition': 'inline; filename="image.png"',
|
|
99
|
+
});
|
|
100
|
+
return new StreamableFile(file);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Using `@Header()` decorator:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
@Get()
|
|
108
|
+
@Header('Content-Type', 'application/pdf')
|
|
109
|
+
@Header('Content-Disposition', 'attachment; filename="report.pdf"')
|
|
110
|
+
getFile(): StreamableFile {
|
|
111
|
+
const file = createReadStream(join(process.cwd(), 'report.pdf'));
|
|
112
|
+
return new StreamableFile(file);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Server-Sent Events (SSE)
|
|
117
|
+
|
|
118
|
+
SSE enables server-to-client push over HTTP.
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { Controller, Sse, MessageEvent } from '@nestjs/common';
|
|
122
|
+
import { Observable, interval, map } from 'rxjs';
|
|
123
|
+
|
|
124
|
+
@Controller()
|
|
125
|
+
export class EventsController {
|
|
126
|
+
@Sse('sse')
|
|
127
|
+
sse(): Observable<MessageEvent> {
|
|
128
|
+
return interval(1000).pipe(
|
|
129
|
+
map(() => ({
|
|
130
|
+
data: { timestamp: new Date().toISOString() },
|
|
131
|
+
})),
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
MessageEvent interface:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
interface MessageEvent {
|
|
141
|
+
data: string | object; // Event data
|
|
142
|
+
id?: string; // Event ID for reconnection
|
|
143
|
+
type?: string; // Event type
|
|
144
|
+
retry?: number; // Reconnection interval (ms)
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Client-side usage:
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
const eventSource = new EventSource('/sse');
|
|
152
|
+
|
|
153
|
+
eventSource.onmessage = ({ data }) => {
|
|
154
|
+
console.log('New message:', JSON.parse(data));
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Named events
|
|
158
|
+
eventSource.addEventListener('update', (event) => {
|
|
159
|
+
console.log('Update:', JSON.parse(event.data));
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Close connection
|
|
163
|
+
eventSource.close();
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
SSE with typed events:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
@Sse('notifications')
|
|
170
|
+
notifications(): Observable<MessageEvent> {
|
|
171
|
+
return this.notificationsService.getStream().pipe(
|
|
172
|
+
map((notification) => ({
|
|
173
|
+
data: notification,
|
|
174
|
+
type: 'notification',
|
|
175
|
+
id: notification.id,
|
|
176
|
+
})),
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Key Points
|
|
182
|
+
|
|
183
|
+
- SSE routes must return an `Observable` stream
|
|
184
|
+
- `StreamableFile` works with both Express and Fastify
|
|
185
|
+
- Default content type for StreamableFile is `application/octet-stream`
|
|
186
|
+
- SSE maintains persistent HTTP connection
|
|
187
|
+
- Compression should be disabled for SSE endpoints
|
|
188
|
+
|
|
189
|
+
<!--
|
|
190
|
+
Source references:
|
|
191
|
+
- https://docs.nestjs.com/techniques/compression
|
|
192
|
+
- https://docs.nestjs.com/techniques/streaming-files
|
|
193
|
+
- https://docs.nestjs.com/techniques/server-sent-events
|
|
194
|
+
-->
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: techniques-configuration
|
|
3
|
+
description: Configuration management with ConfigModule in NestJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Configuration
|
|
7
|
+
|
|
8
|
+
NestJS provides `@nestjs/config` package for managing application configuration across different environments.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm i --save @nestjs/config
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Basic Setup
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { Module } from '@nestjs/common';
|
|
20
|
+
import { ConfigModule } from '@nestjs/config';
|
|
21
|
+
|
|
22
|
+
@Module({
|
|
23
|
+
imports: [ConfigModule.forRoot()],
|
|
24
|
+
})
|
|
25
|
+
export class AppModule {}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Custom .env Path
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
ConfigModule.forRoot({
|
|
32
|
+
envFilePath: '.development.env',
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Multiple .env Files
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
ConfigModule.forRoot({
|
|
40
|
+
envFilePath: ['.env.development.local', '.env.development'],
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Global ConfigModule
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
ConfigModule.forRoot({
|
|
48
|
+
isGlobal: true,
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Using ConfigService
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { Injectable } from '@nestjs/common';
|
|
56
|
+
import { ConfigService } from '@nestjs/config';
|
|
57
|
+
|
|
58
|
+
@Injectable()
|
|
59
|
+
export class AppService {
|
|
60
|
+
constructor(private configService: ConfigService) {}
|
|
61
|
+
|
|
62
|
+
getDatabaseUrl() {
|
|
63
|
+
return this.configService.get<string>('DATABASE_URL');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getPort() {
|
|
67
|
+
return this.configService.get<number>('PORT', 3000);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Custom Configuration Files
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
export default () => ({
|
|
76
|
+
port: parseInt(process.env.PORT, 10) || 3000,
|
|
77
|
+
database: {
|
|
78
|
+
host: process.env.DATABASE_HOST,
|
|
79
|
+
port: parseInt(process.env.DATABASE_PORT, 10) || 5432,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Register:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
ConfigModule.forRoot({
|
|
88
|
+
load: [configuration],
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Schema Validation
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import * as Joi from 'joi';
|
|
96
|
+
|
|
97
|
+
ConfigModule.forRoot({
|
|
98
|
+
validationSchema: Joi.object({
|
|
99
|
+
NODE_ENV: Joi.string()
|
|
100
|
+
.valid('development', 'production', 'test')
|
|
101
|
+
.default('development'),
|
|
102
|
+
PORT: Joi.number().default(3000),
|
|
103
|
+
}),
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Async Configuration
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
ConfigModule.forRootAsync({
|
|
111
|
+
imports: [HttpModule],
|
|
112
|
+
useFactory: async (httpService: HttpService) => {
|
|
113
|
+
const response = await httpService.get('/config').toPromise();
|
|
114
|
+
return response.data;
|
|
115
|
+
},
|
|
116
|
+
inject: [HttpService],
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Key Points
|
|
121
|
+
|
|
122
|
+
- Use `ConfigModule.forRoot()` for basic setup
|
|
123
|
+
- `ConfigService` provides typed access to configuration
|
|
124
|
+
- Use custom configuration files for complex setups
|
|
125
|
+
- Validate configuration with Joi schemas
|
|
126
|
+
- Make ConfigModule global to avoid repeated imports
|
|
127
|
+
- Environment variables take precedence over .env files
|
|
128
|
+
|
|
129
|
+
<!--
|
|
130
|
+
Source references:
|
|
131
|
+
- https://docs.nestjs.com/techniques/configuration
|
|
132
|
+
-->
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: techniques-database
|
|
3
|
+
description: Database integration with TypeORM, Prisma, and MongoDB in NestJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Database Integration
|
|
7
|
+
|
|
8
|
+
NestJS supports multiple database solutions including TypeORM, Prisma, Sequelize, and MongoDB.
|
|
9
|
+
|
|
10
|
+
## TypeORM
|
|
11
|
+
|
|
12
|
+
### Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install --save @nestjs/typeorm typeorm mysql2
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Basic Setup
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
22
|
+
|
|
23
|
+
@Module({
|
|
24
|
+
imports: [
|
|
25
|
+
TypeOrmModule.forRoot({
|
|
26
|
+
type: 'mysql',
|
|
27
|
+
host: 'localhost',
|
|
28
|
+
port: 3306,
|
|
29
|
+
username: 'root',
|
|
30
|
+
password: 'root',
|
|
31
|
+
database: 'test',
|
|
32
|
+
entities: [User],
|
|
33
|
+
synchronize: true,
|
|
34
|
+
}),
|
|
35
|
+
],
|
|
36
|
+
})
|
|
37
|
+
export class AppModule {}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Feature Module
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
@Module({
|
|
44
|
+
imports: [TypeOrmModule.forFeature([User])],
|
|
45
|
+
providers: [UsersService],
|
|
46
|
+
controllers: [UsersController],
|
|
47
|
+
})
|
|
48
|
+
export class UsersModule {}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Using Repository
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
@Injectable()
|
|
55
|
+
export class UsersService {
|
|
56
|
+
constructor(
|
|
57
|
+
@InjectRepository(User)
|
|
58
|
+
private usersRepository: Repository<User>,
|
|
59
|
+
) {}
|
|
60
|
+
|
|
61
|
+
async findAll(): Promise<User[]> {
|
|
62
|
+
return this.usersRepository.find();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Prisma
|
|
68
|
+
|
|
69
|
+
### Installation
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm install --save @prisma/client
|
|
73
|
+
npm install --save-dev prisma
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Setup
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { PrismaService } from './prisma.service';
|
|
80
|
+
|
|
81
|
+
@Module({
|
|
82
|
+
providers: [PrismaService],
|
|
83
|
+
exports: [PrismaService],
|
|
84
|
+
})
|
|
85
|
+
export class PrismaModule {}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Using Prisma Service
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
@Injectable()
|
|
92
|
+
export class UsersService {
|
|
93
|
+
constructor(private prisma: PrismaService) {}
|
|
94
|
+
|
|
95
|
+
async findAll() {
|
|
96
|
+
return this.prisma.user.findMany();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## MongoDB
|
|
102
|
+
|
|
103
|
+
### Installation
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npm install --save @nestjs/mongoose mongoose
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Setup
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { MongooseModule } from '@nestjs/mongoose';
|
|
113
|
+
|
|
114
|
+
@Module({
|
|
115
|
+
imports: [
|
|
116
|
+
MongooseModule.forRoot('mongodb://localhost/nest'),
|
|
117
|
+
],
|
|
118
|
+
})
|
|
119
|
+
export class AppModule {}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Schema Definition
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
|
126
|
+
|
|
127
|
+
@Schema()
|
|
128
|
+
export class Cat {
|
|
129
|
+
@Prop()
|
|
130
|
+
name: string;
|
|
131
|
+
|
|
132
|
+
@Prop()
|
|
133
|
+
age: number;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export const CatSchema = SchemaFactory.createForClass(Cat);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Key Points
|
|
140
|
+
|
|
141
|
+
- TypeORM provides repository pattern
|
|
142
|
+
- Prisma offers type-safe database access
|
|
143
|
+
- Mongoose for MongoDB integration
|
|
144
|
+
- Use feature modules to organize database code
|
|
145
|
+
- Configure connection in root module
|
|
146
|
+
- Use repositories/services for data access
|
|
147
|
+
|
|
148
|
+
<!--
|
|
149
|
+
Source references:
|
|
150
|
+
- https://docs.nestjs.com/techniques/database
|
|
151
|
+
- https://docs.nestjs.com/recipes/prisma
|
|
152
|
+
- https://docs.nestjs.com/techniques/mongodb
|
|
153
|
+
-->
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: events
|
|
3
|
+
description: Event-driven architecture with @nestjs/event-emitter
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Events
|
|
7
|
+
|
|
8
|
+
The `@nestjs/event-emitter` package provides event-driven architecture for decoupled application design.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @nestjs/event-emitter
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Setup
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { Module } from '@nestjs/common';
|
|
20
|
+
import { EventEmitterModule } from '@nestjs/event-emitter';
|
|
21
|
+
|
|
22
|
+
@Module({
|
|
23
|
+
imports: [EventEmitterModule.forRoot()],
|
|
24
|
+
})
|
|
25
|
+
export class AppModule {}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Dispatching Events
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { Injectable } from '@nestjs/common';
|
|
32
|
+
import { EventEmitter2 } from '@nestjs/event-emitter';
|
|
33
|
+
|
|
34
|
+
@Injectable()
|
|
35
|
+
export class OrdersService {
|
|
36
|
+
constructor(private eventEmitter: EventEmitter2) {}
|
|
37
|
+
|
|
38
|
+
createOrder(data: CreateOrderDto) {
|
|
39
|
+
const order = this.ordersRepository.create(data);
|
|
40
|
+
|
|
41
|
+
this.eventEmitter.emit('order.created', new OrderCreatedEvent({
|
|
42
|
+
orderId: order.id,
|
|
43
|
+
userId: data.userId,
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
return order;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Listening to Events
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { Injectable } from '@nestjs/common';
|
|
55
|
+
import { OnEvent } from '@nestjs/event-emitter';
|
|
56
|
+
|
|
57
|
+
@Injectable()
|
|
58
|
+
export class NotificationsListener {
|
|
59
|
+
@OnEvent('order.created')
|
|
60
|
+
handleOrderCreated(event: OrderCreatedEvent) {
|
|
61
|
+
// Send notification to user
|
|
62
|
+
console.log(`Order ${event.orderId} created`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@OnEvent('order.created', { async: true })
|
|
66
|
+
async sendEmailNotification(event: OrderCreatedEvent) {
|
|
67
|
+
await this.emailService.send(event);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Wildcard Listeners
|
|
73
|
+
|
|
74
|
+
Enable wildcards in configuration:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
EventEmitterModule.forRoot({
|
|
78
|
+
wildcard: true,
|
|
79
|
+
delimiter: '.',
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Use wildcards:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
@OnEvent('order.*')
|
|
87
|
+
handleAllOrderEvents(event: any) {
|
|
88
|
+
// Handles order.created, order.updated, order.shipped, etc.
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@OnEvent('**')
|
|
92
|
+
handleAllEvents(event: any) {
|
|
93
|
+
// Handles all events
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Configuration Options
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
EventEmitterModule.forRoot({
|
|
101
|
+
wildcard: false, // Enable wildcard patterns
|
|
102
|
+
delimiter: '.', // Namespace delimiter
|
|
103
|
+
newListener: false, // Emit newListener event
|
|
104
|
+
removeListener: false, // Emit removeListener event
|
|
105
|
+
maxListeners: 10, // Max listeners per event
|
|
106
|
+
verboseMemoryLeak: false, // Show event name in leak warning
|
|
107
|
+
ignoreErrors: false, // Don't throw on unhandled errors
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Listener Options
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
@OnEvent('order.created', {
|
|
115
|
+
async: true, // Handle asynchronously
|
|
116
|
+
prependListener: true, // Add to beginning of listener array
|
|
117
|
+
suppressErrors: true, // Don't throw errors
|
|
118
|
+
})
|
|
119
|
+
handleOrderCreated(event: OrderCreatedEvent) {}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Event Class Pattern
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
export class OrderCreatedEvent {
|
|
126
|
+
constructor(
|
|
127
|
+
public readonly orderId: string,
|
|
128
|
+
public readonly userId: string,
|
|
129
|
+
public readonly createdAt: Date = new Date(),
|
|
130
|
+
) {}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Preventing Event Loss
|
|
135
|
+
|
|
136
|
+
Events emitted before `onApplicationBootstrap` may be missed:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
@Injectable()
|
|
140
|
+
export class MyService implements OnApplicationBootstrap {
|
|
141
|
+
constructor(
|
|
142
|
+
private eventEmitter: EventEmitter2,
|
|
143
|
+
private eventEmitterReadinessWatcher: EventEmitterReadinessWatcher,
|
|
144
|
+
) {}
|
|
145
|
+
|
|
146
|
+
async onApplicationBootstrap() {
|
|
147
|
+
await this.eventEmitterReadinessWatcher.waitUntilReady();
|
|
148
|
+
this.eventEmitter.emit('app.ready', {});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Key Points
|
|
154
|
+
|
|
155
|
+
- Event subscribers cannot be request-scoped
|
|
156
|
+
- Multiple listeners can subscribe to the same event
|
|
157
|
+
- Events are great for decoupling modules
|
|
158
|
+
- Use async: true for non-blocking event handling
|
|
159
|
+
|
|
160
|
+
<!--
|
|
161
|
+
Source references:
|
|
162
|
+
- https://docs.nestjs.com/techniques/events
|
|
163
|
+
-->
|