@biggora/claude-plugins 1.2.2 → 1.3.1
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 +5 -1
- package/package.json +1 -1
- package/registry/registry.json +15 -0
- package/specs/coding.md +11 -0
- package/src/commands/skills/add.js +115 -31
- package/src/commands/skills/list.js +25 -52
- package/src/commands/skills/remove.js +45 -27
- package/src/commands/skills/resolve.js +104 -0
- package/src/commands/skills/update.js +58 -74
- package/src/config.js +5 -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/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,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: encryption-hashing
|
|
3
|
+
description: Encryption and password hashing (bcrypt, argon2) for NestJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Encryption and Hashing
|
|
7
|
+
|
|
8
|
+
Nest uses Node.js built-in `crypto` for encryption. For password hashing, use bcrypt or argon2.
|
|
9
|
+
|
|
10
|
+
## Encryption (crypto)
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
import { createCipheriv, createDecipheriv, randomBytes, scrypt } from 'node:crypto';
|
|
14
|
+
import { promisify } from 'node:util';
|
|
15
|
+
|
|
16
|
+
const iv = randomBytes(16);
|
|
17
|
+
const key = (await promisify(scrypt)(password, 'salt', 32)) as Buffer;
|
|
18
|
+
|
|
19
|
+
// Encrypt
|
|
20
|
+
const cipher = createCipheriv('aes-256-ctr', key, iv);
|
|
21
|
+
const encrypted = Buffer.concat([
|
|
22
|
+
cipher.update(textToEncrypt),
|
|
23
|
+
cipher.final(),
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
// Decrypt
|
|
27
|
+
const decipher = createDecipheriv('aes-256-ctr', key, iv);
|
|
28
|
+
const decrypted = Buffer.concat([
|
|
29
|
+
decipher.update(encrypted),
|
|
30
|
+
decipher.final(),
|
|
31
|
+
]);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Hashing (bcrypt)
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm i bcrypt
|
|
38
|
+
npm i -D @types/bcrypt
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import * as bcrypt from 'bcrypt';
|
|
43
|
+
|
|
44
|
+
// Hash password
|
|
45
|
+
const saltOrRounds = 10;
|
|
46
|
+
const hash = await bcrypt.hash(password, saltOrRounds);
|
|
47
|
+
|
|
48
|
+
// Generate salt
|
|
49
|
+
const salt = await bcrypt.genSalt();
|
|
50
|
+
|
|
51
|
+
// Verify
|
|
52
|
+
const isMatch = await bcrypt.compare(password, hash);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Hashing (argon2)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm i argon2
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import * as argon2 from 'argon2';
|
|
63
|
+
|
|
64
|
+
const hash = await argon2.hash(password);
|
|
65
|
+
const isMatch = await argon2.verify(hash, password);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Injectable Hashing Service
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
@Injectable()
|
|
72
|
+
export class HashingService {
|
|
73
|
+
async hash(password: string): Promise<string> {
|
|
74
|
+
return bcrypt.hash(password, 10);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async compare(password: string, hash: string): Promise<boolean> {
|
|
78
|
+
return bcrypt.compare(password, hash);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Key Points
|
|
84
|
+
|
|
85
|
+
- Use bcrypt or argon2 for passwords (argon2 preferred for new apps)
|
|
86
|
+
- Node.js `crypto` for encryption/decryption
|
|
87
|
+
- Never store plain passwords
|
|
88
|
+
- Use strong salts; bcrypt handles salt internally
|
|
89
|
+
|
|
90
|
+
<!--
|
|
91
|
+
Source references:
|
|
92
|
+
- https://docs.nestjs.com/security/encryption-and-hashing
|
|
93
|
+
-->
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: caching
|
|
3
|
+
description: Caching with @nestjs/cache-manager and Redis integration
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Caching
|
|
7
|
+
|
|
8
|
+
Caching improves performance by storing frequently accessed data for quick retrieval.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @nestjs/cache-manager cache-manager
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Basic Setup
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { Module } from '@nestjs/common';
|
|
20
|
+
import { CacheModule } from '@nestjs/cache-manager';
|
|
21
|
+
|
|
22
|
+
@Module({
|
|
23
|
+
imports: [CacheModule.register()],
|
|
24
|
+
})
|
|
25
|
+
export class AppModule {}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Interacting with Cache
|
|
29
|
+
|
|
30
|
+
Inject the cache manager:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { Injectable, Inject } from '@nestjs/common';
|
|
34
|
+
import { CACHE_MANAGER, Cache } from '@nestjs/cache-manager';
|
|
35
|
+
|
|
36
|
+
@Injectable()
|
|
37
|
+
export class CatsService {
|
|
38
|
+
constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
|
|
39
|
+
|
|
40
|
+
async getCats() {
|
|
41
|
+
// Get from cache
|
|
42
|
+
const cached = await this.cacheManager.get('cats');
|
|
43
|
+
if (cached) return cached;
|
|
44
|
+
|
|
45
|
+
const cats = await this.fetchCats();
|
|
46
|
+
|
|
47
|
+
// Set with TTL (milliseconds)
|
|
48
|
+
await this.cacheManager.set('cats', cats, 60000);
|
|
49
|
+
return cats;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async clearCache() {
|
|
53
|
+
await this.cacheManager.del('cats');
|
|
54
|
+
// Or clear all
|
|
55
|
+
await this.cacheManager.clear();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Auto-caching Responses
|
|
61
|
+
|
|
62
|
+
Use `CacheInterceptor` for automatic GET endpoint caching:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { Controller, Get, UseInterceptors } from '@nestjs/common';
|
|
66
|
+
import { CacheInterceptor, CacheKey, CacheTTL } from '@nestjs/cache-manager';
|
|
67
|
+
|
|
68
|
+
@Controller('cats')
|
|
69
|
+
@UseInterceptors(CacheInterceptor)
|
|
70
|
+
export class CatsController {
|
|
71
|
+
@Get()
|
|
72
|
+
@CacheKey('all-cats')
|
|
73
|
+
@CacheTTL(30000)
|
|
74
|
+
findAll() {
|
|
75
|
+
return this.catsService.findAll();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Global cache interceptor:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
@Module({
|
|
84
|
+
providers: [
|
|
85
|
+
{ provide: APP_INTERCEPTOR, useClass: CacheInterceptor },
|
|
86
|
+
],
|
|
87
|
+
})
|
|
88
|
+
export class AppModule {}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Configuration
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
CacheModule.register({
|
|
95
|
+
ttl: 5000, // Default TTL in milliseconds
|
|
96
|
+
isGlobal: true, // Available everywhere without importing
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Redis Integration
|
|
101
|
+
|
|
102
|
+
Install Redis adapter:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npm install @keyv/redis
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Configure multiple stores:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { CacheModule } from '@nestjs/cache-manager';
|
|
112
|
+
import KeyvRedis from '@keyv/redis';
|
|
113
|
+
import { Keyv } from 'keyv';
|
|
114
|
+
import { CacheableMemory } from 'cacheable';
|
|
115
|
+
|
|
116
|
+
@Module({
|
|
117
|
+
imports: [
|
|
118
|
+
CacheModule.registerAsync({
|
|
119
|
+
useFactory: async () => ({
|
|
120
|
+
stores: [
|
|
121
|
+
new Keyv({ store: new CacheableMemory({ ttl: 60000 }) }),
|
|
122
|
+
new KeyvRedis('redis://localhost:6379'),
|
|
123
|
+
],
|
|
124
|
+
}),
|
|
125
|
+
}),
|
|
126
|
+
],
|
|
127
|
+
})
|
|
128
|
+
export class AppModule {}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Key Points
|
|
132
|
+
|
|
133
|
+
- Only GET endpoints are auto-cached
|
|
134
|
+
- `CacheInterceptor` doesn't work with GraphQL field resolvers
|
|
135
|
+
- Use `@CacheKey()` for custom cache keys
|
|
136
|
+
- Set `ttl: 0` for no expiration
|
|
137
|
+
- Works with WebSockets and Microservices
|
|
138
|
+
|
|
139
|
+
<!--
|
|
140
|
+
Source references:
|
|
141
|
+
- https://docs.nestjs.com/techniques/caching
|
|
142
|
+
-->
|
|
@@ -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
|
+
-->
|