@flusys/nestjs-shared 0.1.0-beta.2 → 1.0.0-beta
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 +51 -29
- package/cjs/classes/api-controller.class.js +0 -21
- package/cjs/classes/api-service.class.js +4 -41
- package/cjs/classes/request-scoped-api.service.js +4 -53
- package/cjs/classes/winston.logger.class.js +5 -15
- package/cjs/constants/index.js +2 -11
- package/cjs/dtos/response-payload.dto.js +40 -85
- package/cjs/interfaces/logged-user-info.interface.js +1 -2
- package/cjs/interfaces/permission.interface.js +1 -10
- package/cjs/middlewares/logger.middleware.js +2 -6
- package/cjs/modules/datasource/multi-tenant-datasource.service.js +9 -9
- package/fesm/classes/api-controller.class.js +1 -69
- package/fesm/classes/api-service.class.js +5 -46
- package/fesm/classes/request-scoped-api.service.js +4 -53
- package/fesm/classes/winston.logger.class.js +6 -18
- package/fesm/constants/index.js +14 -29
- package/fesm/dtos/response-payload.dto.js +44 -109
- package/fesm/interfaces/logged-user-info.interface.js +1 -2
- package/fesm/interfaces/permission.interface.js +0 -12
- package/fesm/middlewares/logger.middleware.js +2 -6
- package/fesm/modules/datasource/multi-tenant-datasource.service.js +9 -9
- package/package.json +2 -2
|
@@ -21,12 +21,7 @@ function _ts_metadata(k, v) {
|
|
|
21
21
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
22
|
}
|
|
23
23
|
import { ApiExtraModels, ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
24
|
-
|
|
25
|
-
// REQUEST METADATA (for tracking)
|
|
26
|
-
// =============================================================================
|
|
27
|
-
/**
|
|
28
|
-
* Request metadata - automatically added by interceptor
|
|
29
|
-
*/ export class RequestMetaDto {
|
|
24
|
+
export class RequestMetaDto {
|
|
30
25
|
constructor(){
|
|
31
26
|
_define_property(this, "requestId", void 0);
|
|
32
27
|
_define_property(this, "timestamp", void 0);
|
|
@@ -35,22 +30,19 @@ import { ApiExtraModels, ApiProperty, ApiPropertyOptional } from '@nestjs/swagge
|
|
|
35
30
|
}
|
|
36
31
|
_ts_decorate([
|
|
37
32
|
ApiPropertyOptional({
|
|
38
|
-
example: 'req_abc123'
|
|
39
|
-
description: 'Unique request ID'
|
|
33
|
+
example: 'req_abc123'
|
|
40
34
|
}),
|
|
41
35
|
_ts_metadata("design:type", String)
|
|
42
36
|
], RequestMetaDto.prototype, "requestId", void 0);
|
|
43
37
|
_ts_decorate([
|
|
44
38
|
ApiPropertyOptional({
|
|
45
|
-
example: '2024-12-19T10:30:00.000Z'
|
|
46
|
-
description: 'Request timestamp'
|
|
39
|
+
example: '2024-12-19T10:30:00.000Z'
|
|
47
40
|
}),
|
|
48
41
|
_ts_metadata("design:type", String)
|
|
49
42
|
], RequestMetaDto.prototype, "timestamp", void 0);
|
|
50
43
|
_ts_decorate([
|
|
51
44
|
ApiPropertyOptional({
|
|
52
|
-
example: 45
|
|
53
|
-
description: 'Response time in milliseconds'
|
|
45
|
+
example: 45
|
|
54
46
|
}),
|
|
55
47
|
_ts_metadata("design:type", Number)
|
|
56
48
|
], RequestMetaDto.prototype, "responseTime", void 0);
|
|
@@ -64,40 +56,30 @@ export class SingleResponseDto {
|
|
|
64
56
|
}
|
|
65
57
|
_ts_decorate([
|
|
66
58
|
ApiProperty({
|
|
67
|
-
example: true
|
|
68
|
-
description: 'Whether the operation was successful'
|
|
59
|
+
example: true
|
|
69
60
|
}),
|
|
70
61
|
_ts_metadata("design:type", Boolean)
|
|
71
62
|
], SingleResponseDto.prototype, "success", void 0);
|
|
72
63
|
_ts_decorate([
|
|
73
64
|
ApiProperty({
|
|
74
|
-
example: 'Operation successful'
|
|
75
|
-
description: 'Response message'
|
|
65
|
+
example: 'Operation successful'
|
|
76
66
|
}),
|
|
77
67
|
_ts_metadata("design:type", String)
|
|
78
68
|
], SingleResponseDto.prototype, "message", void 0);
|
|
79
69
|
_ts_decorate([
|
|
80
|
-
ApiPropertyOptional(
|
|
81
|
-
description: 'Response data (single item)'
|
|
82
|
-
}),
|
|
70
|
+
ApiPropertyOptional(),
|
|
83
71
|
_ts_metadata("design:type", typeof T === "undefined" ? Object : T)
|
|
84
72
|
], SingleResponseDto.prototype, "data", void 0);
|
|
85
73
|
_ts_decorate([
|
|
86
74
|
ApiPropertyOptional({
|
|
87
|
-
type: RequestMetaDto
|
|
88
|
-
description: 'Request metadata'
|
|
75
|
+
type: RequestMetaDto
|
|
89
76
|
}),
|
|
90
77
|
_ts_metadata("design:type", typeof RequestMetaDto === "undefined" ? Object : RequestMetaDto)
|
|
91
78
|
], SingleResponseDto.prototype, "_meta", void 0);
|
|
92
79
|
SingleResponseDto = _ts_decorate([
|
|
93
80
|
ApiExtraModels()
|
|
94
81
|
], SingleResponseDto);
|
|
95
|
-
|
|
96
|
-
// LIST RESPONSE WITH PAGINATION (get-all)
|
|
97
|
-
// =============================================================================
|
|
98
|
-
/**
|
|
99
|
-
* Pagination metadata for list responses
|
|
100
|
-
*/ export class PaginationMetaDto {
|
|
82
|
+
export class PaginationMetaDto {
|
|
101
83
|
constructor(){
|
|
102
84
|
_define_property(this, "total", void 0);
|
|
103
85
|
_define_property(this, "page", void 0);
|
|
@@ -109,43 +91,37 @@ SingleResponseDto = _ts_decorate([
|
|
|
109
91
|
}
|
|
110
92
|
_ts_decorate([
|
|
111
93
|
ApiProperty({
|
|
112
|
-
example: 100
|
|
113
|
-
description: 'Total records in database'
|
|
94
|
+
example: 100
|
|
114
95
|
}),
|
|
115
96
|
_ts_metadata("design:type", Number)
|
|
116
97
|
], PaginationMetaDto.prototype, "total", void 0);
|
|
117
98
|
_ts_decorate([
|
|
118
99
|
ApiProperty({
|
|
119
|
-
example: 0
|
|
120
|
-
description: 'Current page number (0-based)'
|
|
100
|
+
example: 0
|
|
121
101
|
}),
|
|
122
102
|
_ts_metadata("design:type", Number)
|
|
123
103
|
], PaginationMetaDto.prototype, "page", void 0);
|
|
124
104
|
_ts_decorate([
|
|
125
105
|
ApiProperty({
|
|
126
|
-
example: 10
|
|
127
|
-
description: 'Items per page'
|
|
106
|
+
example: 10
|
|
128
107
|
}),
|
|
129
108
|
_ts_metadata("design:type", Number)
|
|
130
109
|
], PaginationMetaDto.prototype, "pageSize", void 0);
|
|
131
110
|
_ts_decorate([
|
|
132
111
|
ApiProperty({
|
|
133
|
-
example: 10
|
|
134
|
-
description: 'Number of items in current response'
|
|
112
|
+
example: 10
|
|
135
113
|
}),
|
|
136
114
|
_ts_metadata("design:type", Number)
|
|
137
115
|
], PaginationMetaDto.prototype, "count", void 0);
|
|
138
116
|
_ts_decorate([
|
|
139
117
|
ApiPropertyOptional({
|
|
140
|
-
example: true
|
|
141
|
-
description: 'Whether there are more pages'
|
|
118
|
+
example: true
|
|
142
119
|
}),
|
|
143
120
|
_ts_metadata("design:type", Boolean)
|
|
144
121
|
], PaginationMetaDto.prototype, "hasMore", void 0);
|
|
145
122
|
_ts_decorate([
|
|
146
123
|
ApiPropertyOptional({
|
|
147
|
-
example: 10
|
|
148
|
-
description: 'Total number of pages'
|
|
124
|
+
example: 10
|
|
149
125
|
}),
|
|
150
126
|
_ts_metadata("design:type", Number)
|
|
151
127
|
], PaginationMetaDto.prototype, "totalPages", void 0);
|
|
@@ -160,48 +136,38 @@ export class ListResponseDto {
|
|
|
160
136
|
}
|
|
161
137
|
_ts_decorate([
|
|
162
138
|
ApiProperty({
|
|
163
|
-
example: true
|
|
164
|
-
description: 'Whether the operation was successful'
|
|
139
|
+
example: true
|
|
165
140
|
}),
|
|
166
141
|
_ts_metadata("design:type", Boolean)
|
|
167
142
|
], ListResponseDto.prototype, "success", void 0);
|
|
168
143
|
_ts_decorate([
|
|
169
144
|
ApiProperty({
|
|
170
|
-
example: 'Data retrieved successfully'
|
|
171
|
-
description: 'Response message'
|
|
145
|
+
example: 'Data retrieved successfully'
|
|
172
146
|
}),
|
|
173
147
|
_ts_metadata("design:type", String)
|
|
174
148
|
], ListResponseDto.prototype, "message", void 0);
|
|
175
149
|
_ts_decorate([
|
|
176
150
|
ApiPropertyOptional({
|
|
177
|
-
description: 'Response data (array of items)',
|
|
178
151
|
isArray: true
|
|
179
152
|
}),
|
|
180
153
|
_ts_metadata("design:type", Array)
|
|
181
154
|
], ListResponseDto.prototype, "data", void 0);
|
|
182
155
|
_ts_decorate([
|
|
183
156
|
ApiProperty({
|
|
184
|
-
type: PaginationMetaDto
|
|
185
|
-
description: 'Pagination metadata'
|
|
157
|
+
type: PaginationMetaDto
|
|
186
158
|
}),
|
|
187
159
|
_ts_metadata("design:type", typeof PaginationMetaDto === "undefined" ? Object : PaginationMetaDto)
|
|
188
160
|
], ListResponseDto.prototype, "meta", void 0);
|
|
189
161
|
_ts_decorate([
|
|
190
162
|
ApiPropertyOptional({
|
|
191
|
-
type: RequestMetaDto
|
|
192
|
-
description: 'Request metadata'
|
|
163
|
+
type: RequestMetaDto
|
|
193
164
|
}),
|
|
194
165
|
_ts_metadata("design:type", typeof RequestMetaDto === "undefined" ? Object : RequestMetaDto)
|
|
195
166
|
], ListResponseDto.prototype, "_meta", void 0);
|
|
196
167
|
ListResponseDto = _ts_decorate([
|
|
197
168
|
ApiExtraModels()
|
|
198
169
|
], ListResponseDto);
|
|
199
|
-
|
|
200
|
-
// BULK OPERATION RESPONSE (insert-many, update-many)
|
|
201
|
-
// =============================================================================
|
|
202
|
-
/**
|
|
203
|
-
* Metadata for bulk operations
|
|
204
|
-
*/ export class BulkMetaDto {
|
|
170
|
+
export class BulkMetaDto {
|
|
205
171
|
constructor(){
|
|
206
172
|
_define_property(this, "count", void 0);
|
|
207
173
|
_define_property(this, "failed", void 0);
|
|
@@ -210,22 +176,19 @@ ListResponseDto = _ts_decorate([
|
|
|
210
176
|
}
|
|
211
177
|
_ts_decorate([
|
|
212
178
|
ApiProperty({
|
|
213
|
-
example: 5
|
|
214
|
-
description: 'Number of items successfully processed'
|
|
179
|
+
example: 5
|
|
215
180
|
}),
|
|
216
181
|
_ts_metadata("design:type", Number)
|
|
217
182
|
], BulkMetaDto.prototype, "count", void 0);
|
|
218
183
|
_ts_decorate([
|
|
219
184
|
ApiPropertyOptional({
|
|
220
|
-
example: 0
|
|
221
|
-
description: 'Number of items that failed'
|
|
185
|
+
example: 0
|
|
222
186
|
}),
|
|
223
187
|
_ts_metadata("design:type", Number)
|
|
224
188
|
], BulkMetaDto.prototype, "failed", void 0);
|
|
225
189
|
_ts_decorate([
|
|
226
190
|
ApiPropertyOptional({
|
|
227
|
-
example: 5
|
|
228
|
-
description: 'Total items in request'
|
|
191
|
+
example: 5
|
|
229
192
|
}),
|
|
230
193
|
_ts_metadata("design:type", Number)
|
|
231
194
|
], BulkMetaDto.prototype, "total", void 0);
|
|
@@ -240,36 +203,31 @@ export class BulkResponseDto {
|
|
|
240
203
|
}
|
|
241
204
|
_ts_decorate([
|
|
242
205
|
ApiProperty({
|
|
243
|
-
example: true
|
|
244
|
-
description: 'Whether the operation was successful'
|
|
206
|
+
example: true
|
|
245
207
|
}),
|
|
246
208
|
_ts_metadata("design:type", Boolean)
|
|
247
209
|
], BulkResponseDto.prototype, "success", void 0);
|
|
248
210
|
_ts_decorate([
|
|
249
211
|
ApiProperty({
|
|
250
|
-
example: 'Items processed successfully'
|
|
251
|
-
description: 'Response message'
|
|
212
|
+
example: 'Items processed successfully'
|
|
252
213
|
}),
|
|
253
214
|
_ts_metadata("design:type", String)
|
|
254
215
|
], BulkResponseDto.prototype, "message", void 0);
|
|
255
216
|
_ts_decorate([
|
|
256
217
|
ApiPropertyOptional({
|
|
257
|
-
description: 'Response data (array of items)',
|
|
258
218
|
isArray: true
|
|
259
219
|
}),
|
|
260
220
|
_ts_metadata("design:type", Array)
|
|
261
221
|
], BulkResponseDto.prototype, "data", void 0);
|
|
262
222
|
_ts_decorate([
|
|
263
223
|
ApiProperty({
|
|
264
|
-
type: BulkMetaDto
|
|
265
|
-
description: 'Bulk operation metadata'
|
|
224
|
+
type: BulkMetaDto
|
|
266
225
|
}),
|
|
267
226
|
_ts_metadata("design:type", typeof BulkMetaDto === "undefined" ? Object : BulkMetaDto)
|
|
268
227
|
], BulkResponseDto.prototype, "meta", void 0);
|
|
269
228
|
_ts_decorate([
|
|
270
229
|
ApiPropertyOptional({
|
|
271
|
-
type: RequestMetaDto
|
|
272
|
-
description: 'Request metadata'
|
|
230
|
+
type: RequestMetaDto
|
|
273
231
|
}),
|
|
274
232
|
_ts_metadata("design:type", typeof RequestMetaDto === "undefined" ? Object : RequestMetaDto)
|
|
275
233
|
], BulkResponseDto.prototype, "_meta", void 0);
|
|
@@ -285,34 +243,26 @@ export class MessageResponseDto {
|
|
|
285
243
|
}
|
|
286
244
|
_ts_decorate([
|
|
287
245
|
ApiProperty({
|
|
288
|
-
example: true
|
|
289
|
-
description: 'Whether the operation was successful'
|
|
246
|
+
example: true
|
|
290
247
|
}),
|
|
291
248
|
_ts_metadata("design:type", Boolean)
|
|
292
249
|
], MessageResponseDto.prototype, "success", void 0);
|
|
293
250
|
_ts_decorate([
|
|
294
251
|
ApiProperty({
|
|
295
|
-
example: 'Operation completed successfully'
|
|
296
|
-
description: 'Response message'
|
|
252
|
+
example: 'Operation completed successfully'
|
|
297
253
|
}),
|
|
298
254
|
_ts_metadata("design:type", String)
|
|
299
255
|
], MessageResponseDto.prototype, "message", void 0);
|
|
300
256
|
_ts_decorate([
|
|
301
257
|
ApiPropertyOptional({
|
|
302
|
-
type: RequestMetaDto
|
|
303
|
-
description: 'Request metadata'
|
|
258
|
+
type: RequestMetaDto
|
|
304
259
|
}),
|
|
305
260
|
_ts_metadata("design:type", typeof RequestMetaDto === "undefined" ? Object : RequestMetaDto)
|
|
306
261
|
], MessageResponseDto.prototype, "_meta", void 0);
|
|
307
262
|
MessageResponseDto = _ts_decorate([
|
|
308
263
|
ApiExtraModels()
|
|
309
264
|
], MessageResponseDto);
|
|
310
|
-
|
|
311
|
-
// ERROR RESPONSE (for consistent error handling)
|
|
312
|
-
// =============================================================================
|
|
313
|
-
/**
|
|
314
|
-
* Error detail for validation errors
|
|
315
|
-
*/ export class ValidationErrorDto {
|
|
265
|
+
export class ValidationErrorDto {
|
|
316
266
|
constructor(){
|
|
317
267
|
_define_property(this, "field", void 0);
|
|
318
268
|
_define_property(this, "message", void 0);
|
|
@@ -321,22 +271,19 @@ MessageResponseDto = _ts_decorate([
|
|
|
321
271
|
}
|
|
322
272
|
_ts_decorate([
|
|
323
273
|
ApiProperty({
|
|
324
|
-
example: 'email'
|
|
325
|
-
description: 'Field that failed validation'
|
|
274
|
+
example: 'email'
|
|
326
275
|
}),
|
|
327
276
|
_ts_metadata("design:type", String)
|
|
328
277
|
], ValidationErrorDto.prototype, "field", void 0);
|
|
329
278
|
_ts_decorate([
|
|
330
279
|
ApiProperty({
|
|
331
|
-
example: 'Invalid email format'
|
|
332
|
-
description: 'Error message'
|
|
280
|
+
example: 'Invalid email format'
|
|
333
281
|
}),
|
|
334
282
|
_ts_metadata("design:type", String)
|
|
335
283
|
], ValidationErrorDto.prototype, "message", void 0);
|
|
336
284
|
_ts_decorate([
|
|
337
285
|
ApiPropertyOptional({
|
|
338
|
-
example: 'isEmail'
|
|
339
|
-
description: 'Validation constraint that failed'
|
|
286
|
+
example: 'isEmail'
|
|
340
287
|
}),
|
|
341
288
|
_ts_metadata("design:type", String)
|
|
342
289
|
], ValidationErrorDto.prototype, "constraint", void 0);
|
|
@@ -351,22 +298,19 @@ export class ErrorResponseDto {
|
|
|
351
298
|
}
|
|
352
299
|
_ts_decorate([
|
|
353
300
|
ApiProperty({
|
|
354
|
-
example: false
|
|
355
|
-
description: 'Always false for errors'
|
|
301
|
+
example: false
|
|
356
302
|
}),
|
|
357
303
|
_ts_metadata("design:type", Boolean)
|
|
358
304
|
], ErrorResponseDto.prototype, "success", void 0);
|
|
359
305
|
_ts_decorate([
|
|
360
306
|
ApiProperty({
|
|
361
|
-
example: 'Validation failed'
|
|
362
|
-
description: 'Error message'
|
|
307
|
+
example: 'Validation failed'
|
|
363
308
|
}),
|
|
364
309
|
_ts_metadata("design:type", String)
|
|
365
310
|
], ErrorResponseDto.prototype, "message", void 0);
|
|
366
311
|
_ts_decorate([
|
|
367
312
|
ApiPropertyOptional({
|
|
368
|
-
example: 'VALIDATION_ERROR'
|
|
369
|
-
description: 'Error code'
|
|
313
|
+
example: 'VALIDATION_ERROR'
|
|
370
314
|
}),
|
|
371
315
|
_ts_metadata("design:type", String)
|
|
372
316
|
], ErrorResponseDto.prototype, "code", void 0);
|
|
@@ -374,15 +318,13 @@ _ts_decorate([
|
|
|
374
318
|
ApiPropertyOptional({
|
|
375
319
|
type: [
|
|
376
320
|
ValidationErrorDto
|
|
377
|
-
]
|
|
378
|
-
description: 'Validation errors (for 400 responses)'
|
|
321
|
+
]
|
|
379
322
|
}),
|
|
380
323
|
_ts_metadata("design:type", Array)
|
|
381
324
|
], ErrorResponseDto.prototype, "errors", void 0);
|
|
382
325
|
_ts_decorate([
|
|
383
326
|
ApiPropertyOptional({
|
|
384
|
-
type: RequestMetaDto
|
|
385
|
-
description: 'Request metadata'
|
|
327
|
+
type: RequestMetaDto
|
|
386
328
|
}),
|
|
387
329
|
_ts_metadata("design:type", typeof RequestMetaDto === "undefined" ? Object : RequestMetaDto)
|
|
388
330
|
], ErrorResponseDto.prototype, "_meta", void 0);
|
|
@@ -400,34 +342,27 @@ export class ResponsePayloadDto {
|
|
|
400
342
|
}
|
|
401
343
|
_ts_decorate([
|
|
402
344
|
ApiProperty({
|
|
403
|
-
example: true
|
|
404
|
-
description: 'Whether the operation was successful'
|
|
345
|
+
example: true
|
|
405
346
|
}),
|
|
406
347
|
_ts_metadata("design:type", Boolean)
|
|
407
348
|
], ResponsePayloadDto.prototype, "success", void 0);
|
|
408
349
|
_ts_decorate([
|
|
409
350
|
ApiProperty({
|
|
410
|
-
example: 'Operation successful'
|
|
411
|
-
description: 'Response message'
|
|
351
|
+
example: 'Operation successful'
|
|
412
352
|
}),
|
|
413
353
|
_ts_metadata("design:type", String)
|
|
414
354
|
], ResponsePayloadDto.prototype, "message", void 0);
|
|
415
355
|
_ts_decorate([
|
|
416
|
-
ApiPropertyOptional(
|
|
417
|
-
description: 'Response data'
|
|
418
|
-
}),
|
|
356
|
+
ApiPropertyOptional(),
|
|
419
357
|
_ts_metadata("design:type", typeof T === "undefined" ? Object : T)
|
|
420
358
|
], ResponsePayloadDto.prototype, "data", void 0);
|
|
421
359
|
_ts_decorate([
|
|
422
|
-
ApiPropertyOptional(
|
|
423
|
-
description: 'Response metadata'
|
|
424
|
-
}),
|
|
360
|
+
ApiPropertyOptional(),
|
|
425
361
|
_ts_metadata("design:type", Object)
|
|
426
362
|
], ResponsePayloadDto.prototype, "meta", void 0);
|
|
427
363
|
_ts_decorate([
|
|
428
364
|
ApiPropertyOptional({
|
|
429
|
-
type: RequestMetaDto
|
|
430
|
-
description: 'Request metadata'
|
|
365
|
+
type: RequestMetaDto
|
|
431
366
|
}),
|
|
432
367
|
_ts_metadata("design:type", typeof RequestMetaDto === "undefined" ? Object : RequestMetaDto)
|
|
433
368
|
], ResponsePayloadDto.prototype, "_meta", void 0);
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Permission-related interfaces and types
|
|
3
|
-
*/ // =============================================================================
|
|
4
|
-
// PERMISSION OPERATORS
|
|
5
|
-
// =============================================================================
|
|
6
|
-
/**
|
|
7
|
-
* Permission operator type
|
|
8
|
-
* - 'and': User must have ALL permissions
|
|
9
|
-
* - 'or': User must have at least ONE permission
|
|
10
|
-
*/ // =============================================================================
|
|
11
|
-
// PERMISSION GUARD CONFIG
|
|
12
|
-
// =============================================================================
|
|
13
1
|
/**
|
|
14
2
|
* Configuration for the permission guard
|
|
15
3
|
*/ export { };
|
|
@@ -23,9 +23,7 @@ import { AsyncLocalStorage } from 'async_hooks';
|
|
|
23
23
|
import { v4 as uuidv4 } from 'uuid';
|
|
24
24
|
import { instance as winstonLogger } from '../classes/winston.logger.class';
|
|
25
25
|
import { REQUEST_ID_HEADER } from '../constants';
|
|
26
|
-
//
|
|
27
|
-
// CONFIGURATION
|
|
28
|
-
// =============================================================================
|
|
26
|
+
// Configuration
|
|
29
27
|
const IS_DEBUG = envConfig.getLogConfig().level === 'debug';
|
|
30
28
|
const TENANT_ID_HEADER = 'x-tenant-id';
|
|
31
29
|
const EXCLUDED_PATHS = [
|
|
@@ -53,9 +51,7 @@ export const setCompanyId = (companyId)=>{
|
|
|
53
51
|
const store = requestContext.getStore();
|
|
54
52
|
if (store) store.companyId = companyId;
|
|
55
53
|
};
|
|
56
|
-
//
|
|
57
|
-
// HELPER FUNCTIONS
|
|
58
|
-
// =============================================================================
|
|
54
|
+
// Helper Functions
|
|
59
55
|
function sanitizeHeaders(headers) {
|
|
60
56
|
const sanitized = {};
|
|
61
57
|
for (const [key, value] of Object.entries(headers)){
|
|
@@ -32,7 +32,7 @@ import { Request } from 'express';
|
|
|
32
32
|
import { DataSource } from 'typeorm';
|
|
33
33
|
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
|
|
34
34
|
export class MultiTenantDataSourceService {
|
|
35
|
-
//
|
|
35
|
+
// Initialization
|
|
36
36
|
initializeFromOptions() {
|
|
37
37
|
if (!this.options) return;
|
|
38
38
|
if (!MultiTenantDataSourceService.initialized) {
|
|
@@ -45,7 +45,7 @@ export class MultiTenantDataSourceService {
|
|
|
45
45
|
MultiTenantDataSourceService.tenantsRegistry.set(tenant.id, tenant);
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
|
-
//
|
|
48
|
+
// Public API
|
|
49
49
|
/**
|
|
50
50
|
* Set custom tenant header name
|
|
51
51
|
*/ setTenantHeader(header) {
|
|
@@ -61,7 +61,7 @@ export class MultiTenantDataSourceService {
|
|
|
61
61
|
*/ isMultiTenant() {
|
|
62
62
|
return this.getDatabaseMode() === 'multi-tenant';
|
|
63
63
|
}
|
|
64
|
-
//
|
|
64
|
+
// Tenant Resolution
|
|
65
65
|
/**
|
|
66
66
|
* Get current tenant ID from request header
|
|
67
67
|
* Validates tenant ID format for security (alphanumeric, hyphens, underscores only)
|
|
@@ -96,7 +96,7 @@ export class MultiTenantDataSourceService {
|
|
|
96
96
|
*/ getActiveTenants() {
|
|
97
97
|
return this.getAllTenants();
|
|
98
98
|
}
|
|
99
|
-
//
|
|
99
|
+
// DataSource Access
|
|
100
100
|
/**
|
|
101
101
|
* Get DataSource for current context (tenant or single)
|
|
102
102
|
*/ async getDataSource() {
|
|
@@ -116,7 +116,7 @@ export class MultiTenantDataSourceService {
|
|
|
116
116
|
*/ setDataSource(dataSource) {
|
|
117
117
|
MultiTenantDataSourceService.singleDataSource = dataSource;
|
|
118
118
|
}
|
|
119
|
-
//
|
|
119
|
+
// Repository Access
|
|
120
120
|
/**
|
|
121
121
|
* Get repository for entity in current context
|
|
122
122
|
*/ async getRepository(entity) {
|
|
@@ -129,7 +129,7 @@ export class MultiTenantDataSourceService {
|
|
|
129
129
|
const dataSource = await this.getDataSourceForTenant(tenantId);
|
|
130
130
|
return dataSource.getRepository(entity);
|
|
131
131
|
}
|
|
132
|
-
//
|
|
132
|
+
// Multi-Tenant Operations
|
|
133
133
|
/**
|
|
134
134
|
* Execute callback with specific tenant's DataSource
|
|
135
135
|
*/ async withTenant(tenantId, callback) {
|
|
@@ -150,7 +150,7 @@ export class MultiTenantDataSourceService {
|
|
|
150
150
|
}
|
|
151
151
|
return results;
|
|
152
152
|
}
|
|
153
|
-
//
|
|
153
|
+
// Tenant Management
|
|
154
154
|
/**
|
|
155
155
|
* Register a new tenant at runtime
|
|
156
156
|
*/ registerTenant(tenant) {
|
|
@@ -162,7 +162,7 @@ export class MultiTenantDataSourceService {
|
|
|
162
162
|
await this.closeTenantConnection(tenantId);
|
|
163
163
|
MultiTenantDataSourceService.tenantsRegistry.delete(tenantId);
|
|
164
164
|
}
|
|
165
|
-
//
|
|
165
|
+
// Connection Lifecycle
|
|
166
166
|
/**
|
|
167
167
|
* Close specific tenant connection
|
|
168
168
|
*/ async closeTenantConnection(tenantId) {
|
|
@@ -190,7 +190,7 @@ export class MultiTenantDataSourceService {
|
|
|
190
190
|
MultiTenantDataSourceService.tenantsRegistry.clear();
|
|
191
191
|
MultiTenantDataSourceService.connectionLocks.clear();
|
|
192
192
|
}
|
|
193
|
-
//
|
|
193
|
+
// Protected Methods (for subclasses)
|
|
194
194
|
/**
|
|
195
195
|
* Get single database DataSource with connection locking to prevent race conditions
|
|
196
196
|
*/ async getSingleDataSource() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-shared",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0-beta",
|
|
4
4
|
"description": "Common shared utilities for Flusys NestJS applications",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "fesm/index.js",
|
|
@@ -105,6 +105,6 @@
|
|
|
105
105
|
"winston-daily-rotate-file": "^5.0.0"
|
|
106
106
|
},
|
|
107
107
|
"dependencies": {
|
|
108
|
-
"@flusys/nestjs-core": "
|
|
108
|
+
"@flusys/nestjs-core": "1.0.0-beta"
|
|
109
109
|
}
|
|
110
110
|
}
|