@pcg/core 1.0.0-alpha.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.
Files changed (98) hide show
  1. package/.turbo/turbo-build.log +15 -0
  2. package/CHANGELOG.md +7 -0
  3. package/dist/index.d.ts +1400 -0
  4. package/dist/index.js +2171 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +55 -0
  7. package/src/abstracts/index.ts +3 -0
  8. package/src/abstracts/nestjs-resource-service.ts +154 -0
  9. package/src/abstracts/nestjs-service.ts +25 -0
  10. package/src/configs/app.config.ts +185 -0
  11. package/src/configs/db.config.ts +122 -0
  12. package/src/configs/index.ts +4 -0
  13. package/src/configs/logger.config.ts +62 -0
  14. package/src/context/action-context.ts +34 -0
  15. package/src/context/current-user.ts +49 -0
  16. package/src/context/index.ts +5 -0
  17. package/src/context/platform-method-context.ts +5 -0
  18. package/src/context/service-method-context.ts +47 -0
  19. package/src/db/snake-naming.strategy.ts +277 -0
  20. package/src/enums/app-env.enum.ts +36 -0
  21. package/src/enums/app-mode.enum.ts +5 -0
  22. package/src/enums/app-server.enum.ts +39 -0
  23. package/src/enums/index.ts +4 -0
  24. package/src/enums/worker-mode.enum.ts +11 -0
  25. package/src/errors/access-denied.error.ts +18 -0
  26. package/src/errors/bad-request.error.ts +9 -0
  27. package/src/errors/forbidden.error.ts +9 -0
  28. package/src/errors/index.ts +8 -0
  29. package/src/errors/input-validation.error.ts +16 -0
  30. package/src/errors/nest-error.filter.ts +70 -0
  31. package/src/errors/nest-error.ts +63 -0
  32. package/src/errors/not-found.error.ts +9 -0
  33. package/src/errors/unauthorized.error.ts +9 -0
  34. package/src/exceptions/http-exception-response.ts +34 -0
  35. package/src/exceptions/http-exceptions.filter.ts +95 -0
  36. package/src/index.ts +32 -0
  37. package/src/jwt/extractors.ts +80 -0
  38. package/src/jwt/types.ts +209 -0
  39. package/src/logger/classes/logger-factory.ts +54 -0
  40. package/src/logger/classes/logger.ts +340 -0
  41. package/src/logger/classes/nest-system-logger.ts +63 -0
  42. package/src/logger/classes/typeorm-logger.ts +83 -0
  43. package/src/logger/index.ts +20 -0
  44. package/src/logger/logger.constants.ts +24 -0
  45. package/src/logger/logger.interfaces.ts +98 -0
  46. package/src/logger/logger.module.ts +45 -0
  47. package/src/logger/logger.providers.ts +140 -0
  48. package/src/logger/winston.tools.ts +241 -0
  49. package/src/middlewares/app.middleware.ts +26 -0
  50. package/src/middlewares/index.ts +1 -0
  51. package/src/modules/hooks/base-hook.ts +64 -0
  52. package/src/modules/hooks/decorators/on-hook.decorator.ts +19 -0
  53. package/src/modules/hooks/hooks.module.ts +10 -0
  54. package/src/modules/hooks/hooks.service.ts +28 -0
  55. package/src/modules/hooks/index.ts +11 -0
  56. package/src/modules/id/id.module.ts +26 -0
  57. package/src/modules/id/id.service.ts +57 -0
  58. package/src/modules/id/index.ts +2 -0
  59. package/src/modules/postgres-pubsub/index.ts +3 -0
  60. package/src/modules/postgres-pubsub/postgres-pubsub.module.ts +14 -0
  61. package/src/modules/postgres-pubsub/postgres-pubsub.ts +461 -0
  62. package/src/pagination/constants.ts +9 -0
  63. package/src/pagination/cursor/cursor-pagination.exception.ts +16 -0
  64. package/src/pagination/cursor/cursor-pagination.helpers.ts +145 -0
  65. package/src/pagination/cursor/cursor-pagination.input.ts +96 -0
  66. package/src/pagination/cursor/cursor-pagination.types.ts +127 -0
  67. package/src/pagination/index.ts +9 -0
  68. package/src/pagination/offset/offset-pagination.exception.ts +15 -0
  69. package/src/pagination/offset/offset-pagination.helpers.ts +122 -0
  70. package/src/pagination/offset/offset-pagination.input.ts +30 -0
  71. package/src/pagination/offset/offset-pagination.types.ts +82 -0
  72. package/src/pagination/tools.ts +53 -0
  73. package/src/tools/compose.ts +92 -0
  74. package/src/tools/convert-to-bigint.ts +27 -0
  75. package/src/tools/create-list-meta.ts +64 -0
  76. package/src/tools/define-statuses.ts +15 -0
  77. package/src/tools/env.ts +139 -0
  78. package/src/tools/fetch-total-with-query.ts +48 -0
  79. package/src/tools/generate-entity-id.ts +23 -0
  80. package/src/tools/get-request-language.ts +13 -0
  81. package/src/tools/is-object.ts +10 -0
  82. package/src/tools/postgres/locale-to-pg-collate.ts +21 -0
  83. package/src/tools/remove-undefined-properties.ts +20 -0
  84. package/src/tools/request-id.ts +25 -0
  85. package/src/tools/stringify-opts.ts +20 -0
  86. package/src/tools/typeorm/add-filter.ts +164 -0
  87. package/src/tools/typeorm/ensure-inner-join.ts +36 -0
  88. package/src/tools/typeorm/ensure-left-join.ts +36 -0
  89. package/src/tools/typeorm/is-alias-already-busy.ts +25 -0
  90. package/src/tools/wait.ts +26 -0
  91. package/src/types/express-request.ts +8 -0
  92. package/src/types/list-mehod-options.ts +32 -0
  93. package/src/types/list-meta.ts +16 -0
  94. package/src/types/maybe.ts +2 -0
  95. package/src/validation/index.ts +1 -0
  96. package/src/validation/validation-pipe.ts +14 -0
  97. package/tsconfig.lib.json +9 -0
  98. package/tsdown.config.ts +15 -0
package/dist/index.js ADDED
@@ -0,0 +1,2171 @@
1
+ import { Catch, ConsoleLogger, Global, HttpException, HttpServer, HttpStatus, Inject, Injectable, Module, ValidationPipe } from "@nestjs/common";
2
+ import { InjectDataSource } from "@nestjs/typeorm";
3
+ import { Brackets, DataSource, DefaultNamingStrategy, In, IsNull } from "typeorm";
4
+ import { getConfigToken, registerAs } from "@nestjs/config";
5
+ import { createRandomString, pluralToSingular, singularToPlural, snakeCase } from "@pcg/text-kit";
6
+ import { Type as Type$1, plainToInstance } from "class-transformer";
7
+ import { IsBoolean, IsEnum, IsNumber, IsOptional, IsString, Min, validateSync } from "class-validator";
8
+ import { ArgsType, Field, Int, ObjectType } from "@nestjs/graphql";
9
+ import { isFunction, isObject as isObject$1, isPlainObject } from "@nestjs/common/utils/shared.utils";
10
+ import { GraphQLError } from "graphql";
11
+ import { AbstractLogger } from "typeorm/logger/AbstractLogger.js";
12
+ import * as winston from "winston";
13
+ import { Logger as Logger$1, createLogger, format } from "winston";
14
+ import clc from "cli-color";
15
+ import fg from "fast-glob";
16
+ import { parse } from "accept-language-parser";
17
+ import { GqlArgumentsHost } from "@nestjs/graphql/dist/services/gql-arguments-host";
18
+
19
+ //#region src/enums/app-env.enum.ts
20
+ /**
21
+ * Application environment enum
22
+ */
23
+ let AppEnv = /* @__PURE__ */ function(AppEnv$1) {
24
+ /**
25
+ * Local environment.
26
+ * Used for local development on your machine.
27
+ */
28
+ AppEnv$1["LOCAL"] = "local";
29
+ /**
30
+ * Test environment.
31
+ * Used when running tests.
32
+ */
33
+ AppEnv$1["TEST"] = "test";
34
+ /**
35
+ * Development environment.
36
+ * Used when deploying to a development server.
37
+ * Development server provide early access to new features.
38
+ */
39
+ AppEnv$1["DEVELOPMENT"] = "development";
40
+ /**
41
+ * Stage environment.
42
+ * Used when deploying to a stage server.
43
+ * Stage is a pre-production environment.
44
+ */
45
+ AppEnv$1["STAGE"] = "stage";
46
+ /**
47
+ * Production environment.
48
+ * Used when deploying to a production server.
49
+ */
50
+ AppEnv$1["PRODUCTION"] = "production";
51
+ return AppEnv$1;
52
+ }({});
53
+
54
+ //#endregion
55
+ //#region src/enums/app-mode.enum.ts
56
+ let AppMode = /* @__PURE__ */ function(AppMode$1) {
57
+ AppMode$1["STANDALONE"] = "standalone";
58
+ AppMode$1["PARENT"] = "parent";
59
+ AppMode$1["CHILD"] = "child";
60
+ return AppMode$1;
61
+ }({});
62
+
63
+ //#endregion
64
+ //#region src/tools/env.ts
65
+ /**
66
+ * Validate environment variables using class-validator
67
+ *
68
+ * @param cls - class with environment variables
69
+ * @throws Error if validation fails
70
+ * @returns validated config as typed object
71
+ * @example
72
+ * ```ts
73
+ * export class AppConfigEnvironmentVariables {
74
+ * @Type(() => Number)
75
+ * @IsNumber()
76
+ * PORT = 3000;
77
+ * }
78
+ *
79
+ * const env = validateEnv(AppConfigEnvironmentVariables); // typed object
80
+ * // env.PORT is now a number
81
+ * ```
82
+ */
83
+ const validateEnv = (cls) => {
84
+ const validatedConfig = plainToInstance(cls, process.env, { enableImplicitConversion: true });
85
+ const errors = validateSync(validatedConfig, { skipMissingProperties: false });
86
+ if (errors.length > 0) throw new Error(errors.toString());
87
+ return validatedConfig;
88
+ };
89
+ /**
90
+ * Returns a string with a dash prefix based on the current environment.
91
+ * If the environment is development or local, returns '-dev'.
92
+ * If the environment is stage, returns '-stage'.
93
+ * Otherwise, returns an empty string.
94
+ *
95
+ * @returns a string with a dash prefix based on the current environment
96
+ * @example
97
+ * ```typescript
98
+ * const name = `my-app${withDashEnv()}`;
99
+ * ```
100
+ */
101
+ const withDashEnv = () => {
102
+ if (process.env.APP_ENV === AppEnv.DEVELOPMENT || process.env.APP_ENV === AppEnv.LOCAL || process.env.APP_ENV === AppEnv.TEST) return "-dev";
103
+ if (process.env.APP_ENV === AppEnv.STAGE) return "-stage";
104
+ return "";
105
+ };
106
+ /**
107
+ * Returns a string with a dash prefix based on the current environment.
108
+ * If the environment is development or local, returns '.dev'.
109
+ * If the environment is stage, returns '.stage'.
110
+ * Otherwise, returns an empty string.
111
+ *
112
+ * @returns a string with a dot prefix based on the current environment
113
+ * @example
114
+ * ```typescript
115
+ * const name = `config${withDotEnv()}`;
116
+ * ```
117
+ */
118
+ const withDotEnv = () => {
119
+ if (process.env.APP_ENV === AppEnv.DEVELOPMENT || process.env.APP_ENV === AppEnv.LOCAL || process.env.APP_ENV === AppEnv.TEST) return ".dev";
120
+ if (process.env.APP_ENV === AppEnv.STAGE) return ".stage";
121
+ return "";
122
+ };
123
+ /**
124
+ * Returns a string with a colon prefix based on the current environment.
125
+ * If the environment is development or local, returns ':dev'.
126
+ * If the environment is stage, returns ':stage'.
127
+ * Otherwise, returns an empty string.
128
+ *
129
+ * @returns a string with a colon prefix based on the current environment
130
+ * @example
131
+ * ```typescript
132
+ * const name = `my:app${withColonEnv()}`;
133
+ * ```
134
+ */
135
+ const withColonEnv = () => {
136
+ if (process.env.APP_ENV === AppEnv.DEVELOPMENT || process.env.APP_ENV === AppEnv.LOCAL || process.env.APP_ENV === AppEnv.TEST) return ":dev";
137
+ if (process.env.APP_ENV === AppEnv.STAGE) return ":stage";
138
+ return "";
139
+ };
140
+ /**
141
+ * Returns a string with an underscore prefix based on the current environment.
142
+ * If the environment is development or local, returns '_dev'.
143
+ * If the environment is stage, returns '_stage'.
144
+ * Otherwise, returns an empty string.
145
+ *
146
+ * @returns a string with an underscore prefix based on the current environment
147
+ * @example
148
+ * ```typescript
149
+ * const name = `my_app${withUnderscoreEnv()}`;
150
+ * ```
151
+ */
152
+ const withUnderscoreEnv = () => {
153
+ if (process.env.APP_ENV === AppEnv.DEVELOPMENT || process.env.APP_ENV === AppEnv.LOCAL || process.env.APP_ENV === AppEnv.TEST) return "_dev";
154
+ if (process.env.APP_ENV === AppEnv.STAGE) return "_stage";
155
+ return "";
156
+ };
157
+
158
+ //#endregion
159
+ //#region \0@oxc-project+runtime@0.95.0/helpers/decorateMetadata.js
160
+ function __decorateMetadata(k, v) {
161
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
162
+ }
163
+
164
+ //#endregion
165
+ //#region \0@oxc-project+runtime@0.95.0/helpers/decorate.js
166
+ function __decorate(decorators, target, key, desc) {
167
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
168
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
169
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
170
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
171
+ }
172
+
173
+ //#endregion
174
+ //#region src/configs/app.config.ts
175
+ var _ref$4;
176
+ /**
177
+ * NestJS injection token for app config
178
+ */
179
+ const APP_CONFIG_TOKEN = "APP_CONFIG_TOKEN";
180
+ const InjectAppConfig = () => Inject(getConfigToken(APP_CONFIG_TOKEN));
181
+ /**
182
+ * Application config environment variables
183
+ */
184
+ var AppConfigEnvironmentVariables = class {
185
+ /**
186
+ * Application port
187
+ * @example
188
+ * ```yaml
189
+ * PORT: 3000
190
+ * ```
191
+ */
192
+ PORT = 3e3;
193
+ /**
194
+ * Application host
195
+ * @example
196
+ * ```yaml
197
+ * APP_HOST: 'https://app-api.example.com'
198
+ * # or
199
+ * APP_HOST: 'http://localhost:3000'
200
+ * ```
201
+ */
202
+ APP_HOST;
203
+ /**
204
+ * Application UI host
205
+ * @example
206
+ * ```yaml
207
+ * APP_UI_HOST: 'https://app.example.com'
208
+ * # or
209
+ * APP_UI_HOST: 'http://localhost:4200'
210
+ * ```
211
+ */
212
+ APP_UI_HOST;
213
+ /**
214
+ * Application environment. Can be 'local', 'development', 'stage', 'production'
215
+ * @example
216
+ * ```yaml
217
+ * APP_ENV: 'local'
218
+ * ```
219
+ */
220
+ APP_ENV;
221
+ /**
222
+ * Application service account id (user with type SA in users table)
223
+ * @example
224
+ * ```yaml
225
+ * APP_SERVICE_ACCOUNT_ID: 'hcu:xxxxxxxxxxx'
226
+ * ```
227
+ */
228
+ APP_SERVICE_ACCOUNT_ID;
229
+ /**
230
+ * Application fallback language
231
+ * @example
232
+ * ```yaml
233
+ * FALLBACK_LANGUAGE: 'es'
234
+ * ```
235
+ */
236
+ FALLBACK_LANGUAGE = "en";
237
+ };
238
+ __decorate([
239
+ Type$1(() => Number),
240
+ IsNumber(),
241
+ __decorateMetadata("design:type", Object)
242
+ ], AppConfigEnvironmentVariables.prototype, "PORT", void 0);
243
+ __decorate([
244
+ IsOptional(),
245
+ IsString(),
246
+ __decorateMetadata("design:type", String)
247
+ ], AppConfigEnvironmentVariables.prototype, "APP_HOST", void 0);
248
+ __decorate([
249
+ IsOptional(),
250
+ IsString(),
251
+ __decorateMetadata("design:type", String)
252
+ ], AppConfigEnvironmentVariables.prototype, "APP_UI_HOST", void 0);
253
+ __decorate([IsEnum(AppEnv), __decorateMetadata("design:type", typeof (_ref$4 = typeof AppEnv !== "undefined" && AppEnv) === "function" ? _ref$4 : Object)], AppConfigEnvironmentVariables.prototype, "APP_ENV", void 0);
254
+ __decorate([
255
+ IsOptional(),
256
+ IsString(),
257
+ __decorateMetadata("design:type", String)
258
+ ], AppConfigEnvironmentVariables.prototype, "APP_SERVICE_ACCOUNT_ID", void 0);
259
+ __decorate([
260
+ IsOptional(),
261
+ IsString(),
262
+ __decorateMetadata("design:type", Object)
263
+ ], AppConfigEnvironmentVariables.prototype, "FALLBACK_LANGUAGE", void 0);
264
+ /**
265
+ * Create Main Application Config
266
+ * @example
267
+ * ```ts
268
+ * // src/config/index.ts
269
+ *
270
+ * import { createAppConfig } from '#/dist/configs';
271
+ *
272
+ * export const appConfig = createAppConfig({
273
+ * name: 'Jetstream',
274
+ * shortname: 'js',
275
+ * });
276
+ * ```
277
+ */
278
+ const createAppConfig = (opts) => {
279
+ return registerAs(APP_CONFIG_TOKEN, () => {
280
+ const env = validateEnv(AppConfigEnvironmentVariables);
281
+ return {
282
+ env: env.APP_ENV,
283
+ name: opts.name,
284
+ shortname: opts.shortname,
285
+ port: env.PORT,
286
+ host: env.APP_HOST,
287
+ mode: opts.mode || AppMode.STANDALONE,
288
+ uiHost: env.APP_UI_HOST,
289
+ appServiceAccountId: env.APP_SERVICE_ACCOUNT_ID,
290
+ fallbackLanguage: env.FALLBACK_LANGUAGE
291
+ };
292
+ });
293
+ };
294
+
295
+ //#endregion
296
+ //#region src/enums/app-server.enum.ts
297
+ /**
298
+ * Enum for the NestJS server mode
299
+ */
300
+ let AppServer = /* @__PURE__ */ function(AppServer$1) {
301
+ /**
302
+ * NestJS HTTP server with GraphQL
303
+ */
304
+ AppServer$1["HTTP"] = "http";
305
+ /**
306
+ * NestJS gRPC server
307
+ */
308
+ AppServer$1["GRPC"] = "grpc";
309
+ /**
310
+ * NestJS WebSocket server
311
+ */
312
+ AppServer$1["WS"] = "ws";
313
+ /**
314
+ * Run as a worker
315
+ */
316
+ AppServer$1["WORKER"] = "worker";
317
+ /**
318
+ * Run as an agent
319
+ */
320
+ AppServer$1["AGENT"] = "agent";
321
+ /**
322
+ * Run as an bot (e.g. Slack bot)
323
+ */
324
+ AppServer$1["BOT"] = "bot";
325
+ /**
326
+ * Run as Cloud Run job
327
+ */
328
+ AppServer$1["CLOUDRUN_JOB"] = "cloudrun-job";
329
+ return AppServer$1;
330
+ }({});
331
+
332
+ //#endregion
333
+ //#region src/enums/worker-mode.enum.ts
334
+ let WorkerMode = /* @__PURE__ */ function(WorkerMode$1) {
335
+ /**
336
+ * Run jobs in loop
337
+ */
338
+ WorkerMode$1["LOOP"] = "loop";
339
+ /**
340
+ * Run one job and exit
341
+ */
342
+ WorkerMode$1["ONE_JOB"] = "one-job";
343
+ return WorkerMode$1;
344
+ }({});
345
+
346
+ //#endregion
347
+ //#region src/tools/generate-entity-id.ts
348
+ /**
349
+ * Generates a unique entity identifier by combining product name, entity prefix, delimiter, and random string.
350
+ *
351
+ * @param product - The product short name to include in the entity ID (e.g., 'fwd' for Forward)
352
+ * @param prefix - The entity type prefix to include in the entity ID (e.g., 'u' for user, 'org' for organization)
353
+ * @param delimiter - The delimiter to separate components (default: ':')
354
+ * @param size - The length of the random string component (default: 11)
355
+ * @returns A formatted entity ID string in the format: `${product}${prefix}${delimiter}${randomString}`
356
+ *
357
+ * @example
358
+ * ```typescript
359
+ * generateEntityId('fwd', 'org')
360
+ * // Returns: 'fwdorg:A1b2C3d4E5f'
361
+ *
362
+ * generateEntityId('myapp', 'u', '_', 8)
363
+ * // Returns: 'myappuser_A1b2C3d4'
364
+ * ```
365
+ */
366
+ const generateEntityId = (product, prefix, delimiter = ":", size = 11) => {
367
+ return `${product}${prefix}${delimiter}${createRandomString(size)}`;
368
+ };
369
+
370
+ //#endregion
371
+ //#region \0@oxc-project+runtime@0.95.0/helpers/decorateParam.js
372
+ function __decorateParam(paramIndex, decorator) {
373
+ return function(target, key) {
374
+ decorator(target, key, paramIndex);
375
+ };
376
+ }
377
+
378
+ //#endregion
379
+ //#region src/modules/id/id.service.ts
380
+ let IdService = class IdService$1 {
381
+ constructor(appConfig) {
382
+ this.appConfig = appConfig;
383
+ }
384
+ /**
385
+ * Returns a delimiter string based on the current environment.
386
+ * This delimiter is used in constructing the entity IDs.
387
+ * The delimiter is ':dev:' for development environments,
388
+ * :stage:' for staging environments and ':' for other environments.
389
+ *
390
+ * This allows for better differentiation and traceability of entities across various environments.
391
+ */
392
+ get delimiter() {
393
+ switch (this.appConfig.env) {
394
+ case AppEnv.TEST: return ":test:";
395
+ case AppEnv.DEVELOPMENT: return ":dev:";
396
+ case AppEnv.STAGE: return ":stage:";
397
+ default: return ":";
398
+ }
399
+ }
400
+ /**
401
+ * Generates unique id for entity
402
+ * @param prefix - entity id prefix in database (e.g. 'u' for users)
403
+ * @param app - app shortname (e.g. 'js')
404
+ * @returns id in format 'jsu:xxxxxxxxxxx' or 'jsu:stage:xxxxxxxxxxx' for staging environment
405
+ */
406
+ generateEntityId(prefix, app) {
407
+ return generateEntityId(app ?? this.appConfig.shortname, prefix, this.delimiter, 11);
408
+ }
409
+ /**
410
+ * Generates unique id with length 11
411
+ * @returns id in format 'xxxxxxxxxxx'
412
+ */
413
+ generateId(size) {
414
+ return createRandomString(size);
415
+ }
416
+ };
417
+ IdService = __decorate([
418
+ Injectable(),
419
+ __decorateParam(0, Inject(getConfigToken(APP_CONFIG_TOKEN))),
420
+ __decorateMetadata("design:paramtypes", [Object])
421
+ ], IdService);
422
+
423
+ //#endregion
424
+ //#region src/modules/id/id.module.ts
425
+ let IdModule = class IdModule$1 {};
426
+ IdModule = __decorate([Global(), Module({
427
+ providers: [IdService],
428
+ exports: [IdService]
429
+ })], IdModule);
430
+
431
+ //#endregion
432
+ //#region src/errors/nest-error.ts
433
+ /**
434
+ * Custom error class for NestJS applications that extends the native Error class.
435
+ *
436
+ * This error class provides additional context and structured error handling
437
+ * capabilities beyond the standard Error object.
438
+ *
439
+ * @example
440
+ * ```typescript
441
+ * throw new NestError({
442
+ * key: 'AUTH_USER_NOT_FOUND',
443
+ * message: 'User with the specified ID was not found',
444
+ * context: { userId: '123' },
445
+ * cause: originalError
446
+ * });
447
+ * ```
448
+ */
449
+ var NestError = class extends Error {
450
+ key;
451
+ context;
452
+ httpStatusCode = HttpStatus.INTERNAL_SERVER_ERROR;
453
+ silent;
454
+ constructor(opts) {
455
+ super(opts.message, opts.cause instanceof Error ? { cause: opts.cause } : void 0);
456
+ this.name = "NestError";
457
+ this.key = opts.key;
458
+ this.context = opts.context;
459
+ this.silent = opts.silent ?? false;
460
+ }
461
+ };
462
+
463
+ //#endregion
464
+ //#region src/errors/bad-request.error.ts
465
+ var BadRequestError = class extends NestError {
466
+ constructor(opts) {
467
+ super(opts);
468
+ this.name = "BadRequestError";
469
+ this.httpStatusCode = 400;
470
+ }
471
+ };
472
+
473
+ //#endregion
474
+ //#region src/errors/not-found.error.ts
475
+ var NotFoundError = class extends NestError {
476
+ constructor(opts) {
477
+ super(opts);
478
+ this.name = "NotFoundError";
479
+ this.httpStatusCode = 404;
480
+ }
481
+ };
482
+
483
+ //#endregion
484
+ //#region src/pagination/constants.ts
485
+ /**
486
+ * Pagination default limit value
487
+ */
488
+ const PAGINATION_DEFAULT_LIMIT = 20;
489
+
490
+ //#endregion
491
+ //#region src/errors/forbidden.error.ts
492
+ var ForbiddenError = class extends NestError {
493
+ constructor(opts) {
494
+ super(opts);
495
+ this.name = "ForbiddenError";
496
+ this.httpStatusCode = 403;
497
+ }
498
+ };
499
+
500
+ //#endregion
501
+ //#region src/errors/access-denied.error.ts
502
+ var AccessDeniedError = class extends ForbiddenError {
503
+ constructor(opts) {
504
+ super({
505
+ key: "AUTH_ACCESS_DENIED",
506
+ message: opts.message || `Access denied: you don't have permission to perform "${opts.action}" action`,
507
+ context: opts.context
508
+ });
509
+ this.name = "AccessDeniedError";
510
+ }
511
+ };
512
+
513
+ //#endregion
514
+ //#region src/errors/input-validation.error.ts
515
+ var InputValidationError = class extends NestError {
516
+ constructor(errors) {
517
+ super({
518
+ message: "Input validation failed",
519
+ key: "NST_INPUT_VALIDATION_ERROR",
520
+ context: errors ? { errors } : void 0
521
+ });
522
+ this.name = "InputValidationError";
523
+ this.httpStatusCode = 400;
524
+ }
525
+ };
526
+
527
+ //#endregion
528
+ //#region src/errors/unauthorized.error.ts
529
+ var UnauthorizedError = class extends NestError {
530
+ constructor(opts) {
531
+ super(opts);
532
+ this.name = "UnauthorizedError";
533
+ this.httpStatusCode = 401;
534
+ }
535
+ };
536
+
537
+ //#endregion
538
+ //#region src/pagination/cursor/cursor-pagination.types.ts
539
+ let CursorPaginationPageInfo = class CursorPaginationPageInfo$1 {
540
+ /**
541
+ * The cursor to the first item in the list
542
+ */
543
+ startCursor;
544
+ /**
545
+ * The cursor to the last item in the list
546
+ */
547
+ endCursor;
548
+ /**
549
+ * Whether there are more items in the list before the start cursor
550
+ */
551
+ hasPreviousPage;
552
+ /**
553
+ * Whether there are more items in the list after the end cursor
554
+ */
555
+ hasNextPage;
556
+ };
557
+ __decorate([Field(() => String, { nullable: true }), __decorateMetadata("design:type", Object)], CursorPaginationPageInfo.prototype, "startCursor", void 0);
558
+ __decorate([Field(() => String, { nullable: true }), __decorateMetadata("design:type", Object)], CursorPaginationPageInfo.prototype, "endCursor", void 0);
559
+ __decorate([Field(() => Boolean, { nullable: true }), __decorateMetadata("design:type", Boolean)], CursorPaginationPageInfo.prototype, "hasPreviousPage", void 0);
560
+ __decorate([Field(() => Boolean, { nullable: true }), __decorateMetadata("design:type", Boolean)], CursorPaginationPageInfo.prototype, "hasNextPage", void 0);
561
+ CursorPaginationPageInfo = __decorate([ObjectType()], CursorPaginationPageInfo);
562
+
563
+ //#endregion
564
+ //#region src/pagination/cursor/cursor-pagination.input.ts
565
+ let CursorPaginationInput = class CursorPaginationInput$1 {
566
+ /**
567
+ * The amount of items to be requested per page from the start
568
+ * @example
569
+ * ```graphql
570
+ * query {
571
+ * messages(first: 3) {
572
+ * edges {
573
+ * cursor
574
+ * node {
575
+ * id
576
+ * }
577
+ * }
578
+ * }
579
+ * }
580
+ * ```
581
+ */
582
+ first;
583
+ /**
584
+ * The cursor to start the pagination
585
+ * @example
586
+ * ```graphql
587
+ * query {
588
+ * messages(first: 3, after: "xxx") {
589
+ * edges {
590
+ * cursor
591
+ * node {
592
+ * id
593
+ * }
594
+ * }
595
+ * }
596
+ * }
597
+ * ```
598
+ */
599
+ after;
600
+ /**
601
+ * The amount of items to be requested per page from the end
602
+ * @example
603
+ * ```graphql
604
+ * query {
605
+ * messages(last: 2) {
606
+ * edges {
607
+ * cursor
608
+ * node {
609
+ * id
610
+ * }
611
+ * }
612
+ * }
613
+ * }
614
+ * ```
615
+ */
616
+ last;
617
+ /**
618
+ * The cursor to end the pagination
619
+ * @example
620
+ * ```graphql
621
+ * query {
622
+ * messages(last: 2, before: "xxx") {
623
+ * edges {
624
+ * cursor
625
+ * node {
626
+ * id
627
+ * }
628
+ * }
629
+ * }
630
+ * }
631
+ * ```
632
+ */
633
+ before;
634
+ };
635
+ __decorate([
636
+ Field(() => Int, { nullable: true }),
637
+ Min(1),
638
+ IsOptional(),
639
+ __decorateMetadata("design:type", Number)
640
+ ], CursorPaginationInput.prototype, "first", void 0);
641
+ __decorate([Field(() => String, { nullable: true }), __decorateMetadata("design:type", String)], CursorPaginationInput.prototype, "after", void 0);
642
+ __decorate([
643
+ Field(() => Int, { nullable: true }),
644
+ Min(1),
645
+ IsOptional(),
646
+ __decorateMetadata("design:type", Number)
647
+ ], CursorPaginationInput.prototype, "last", void 0);
648
+ __decorate([Field(() => String, { nullable: true }), __decorateMetadata("design:type", String)], CursorPaginationInput.prototype, "before", void 0);
649
+ CursorPaginationInput = __decorate([ArgsType()], CursorPaginationInput);
650
+
651
+ //#endregion
652
+ //#region src/pagination/offset/offset-pagination.helpers.ts
653
+ /**
654
+ * Extract sort field name and sort direction from orderBy string.
655
+ * @example
656
+ * const orderBy = 'createdAt_ASC';
657
+ *
658
+ * // sort.fieldName = 'createdAt', sort.direction = 'ASC'; sort.columnName = 'created_at';
659
+ * const sort = extractSortParams(orderBy);
660
+ */
661
+ const extractSortParams = (orderBy) => {
662
+ const slices = orderBy.split("_");
663
+ if (slices.length !== 2) throw new Error("Invalid orderBy argument");
664
+ return {
665
+ fieldName: slices[0],
666
+ direction: slices[1],
667
+ columnName: snakeCase(slices[0])
668
+ };
669
+ };
670
+
671
+ //#endregion
672
+ //#region src/pagination/offset/offset-pagination.input.ts
673
+ let OffsetPaginationInput = class OffsetPaginationInput$1 {
674
+ /**
675
+ * the amount of items to be requested per page
676
+ */
677
+ limit;
678
+ /**
679
+ * @default 1
680
+ * the page that is requested
681
+ */
682
+ page = 1;
683
+ };
684
+ __decorate([Field(() => Int, {
685
+ description: "the amount of items to be requested per page",
686
+ defaultValue: PAGINATION_DEFAULT_LIMIT,
687
+ nullable: true
688
+ }), __decorateMetadata("design:type", Number)], OffsetPaginationInput.prototype, "limit", void 0);
689
+ __decorate([Field(() => Int, {
690
+ defaultValue: 1,
691
+ description: "the page that is requested"
692
+ }), __decorateMetadata("design:type", Number)], OffsetPaginationInput.prototype, "page", void 0);
693
+ OffsetPaginationInput = __decorate([ArgsType()], OffsetPaginationInput);
694
+
695
+ //#endregion
696
+ //#region src/pagination/offset/offset-pagination.types.ts
697
+ let OffsetPaginationPageInfo = class OffsetPaginationPageInfo$1 {
698
+ /**
699
+ * The total amount of pages
700
+ * (total items / limit)
701
+ */
702
+ totalPages;
703
+ /**
704
+ * The total amount of items
705
+ */
706
+ totalItems;
707
+ /**
708
+ * The current page
709
+ */
710
+ page;
711
+ /**
712
+ * The amount of items to be requested per page
713
+ */
714
+ limit;
715
+ };
716
+ __decorate([Field(() => Int, { description: "The total amount of pages (total items / limit)" }), __decorateMetadata("design:type", Number)], OffsetPaginationPageInfo.prototype, "totalPages", void 0);
717
+ __decorate([Field(() => Int, { description: "The total amount of items" }), __decorateMetadata("design:type", Number)], OffsetPaginationPageInfo.prototype, "totalItems", void 0);
718
+ __decorate([Field(() => Int, { description: "The current page" }), __decorateMetadata("design:type", Number)], OffsetPaginationPageInfo.prototype, "page", void 0);
719
+ __decorate([Field(() => Int, { description: "The amount of items to be requested per page" }), __decorateMetadata("design:type", Number)], OffsetPaginationPageInfo.prototype, "limit", void 0);
720
+ OffsetPaginationPageInfo = __decorate([ObjectType()], OffsetPaginationPageInfo);
721
+
722
+ //#endregion
723
+ //#region src/tools/stringify-opts.ts
724
+ /**
725
+ * Converts an object into a human-readable string representation.
726
+ *
727
+ * Takes an object and transforms it into a string where each key-value pair
728
+ * is formatted as "key JSON-value" and all pairs are joined with " and ".
729
+ *
730
+ * @param opts - The object to stringify
731
+ * @returns A string representation of the object with entries joined by " and "
732
+ *
733
+ * @example
734
+ * ```ts
735
+ * stringifyOpts({ name: 'John', age: 30 })
736
+ * // Returns: 'name "John" and age 30'
737
+ * ```
738
+ */
739
+ const stringifyOpts = (opts) => {
740
+ return Object.entries(opts).map(([key, value]) => `${key} ${JSON.stringify(value)}`).join(" and ");
741
+ };
742
+
743
+ //#endregion
744
+ //#region src/logger/logger.constants.ts
745
+ /**
746
+ * Injection token for Winston logger module configuration options
747
+ */
748
+ const NESTKIT_LOGGER_MODULE_OPTIONS = "NestKitLoggerModuleOptions";
749
+ /**
750
+ * Injection token for the Winston logger instance provider
751
+ */
752
+ const NESTKIT_WINSTON_LOGGER_PROVIDER = "NestKitLogger";
753
+ /**
754
+ * Injection token for the main NestKit logger provider
755
+ */
756
+ const NESTKIT_LOGGER_PROVIDER = "NestKitLogger";
757
+ /**
758
+ * Injection token for the NestJS system logger provider
759
+ */
760
+ const NESTKIT_SYSTEM_LOGGER_PROVIDER = "NestKitSystemLogger";
761
+ /**
762
+ * Injection token for the logger factory provider
763
+ */
764
+ const NESTKIT_LOGGER_FACTORY_PROVIDER = "NestKitLoggerFactory";
765
+
766
+ //#endregion
767
+ //#region src/tools/is-object.ts
768
+ /**
769
+ * Checks if the given value is an object (not an array).
770
+ * @param {unknown} obj - The value to check.
771
+ * @returns {boolean} Returns true if `obj` is an object, false otherwise.
772
+ * @example
773
+ * isObject({ a: 1 }); // Returns true
774
+ * isObject([1, 2, 3]); // Returns false
775
+ */
776
+ const isObject = (obj) => obj !== null && !!obj && typeof obj === "object" && !Array.isArray(obj);
777
+
778
+ //#endregion
779
+ //#region src/logger/classes/logger.ts
780
+ /**
781
+ * Logger with context for NestJS (from NestKit)
782
+ */
783
+ var Logger = class Logger {
784
+ constructor(winstonLogger, context = {}) {
785
+ this.winstonLogger = winstonLogger;
786
+ this.context = context;
787
+ }
788
+ /**
789
+ * Created child logger with specific context
790
+ * @param context - object with scope, action and other data
791
+ * @returns - new logger with context
792
+ * @example
793
+ * ```ts
794
+ * class SomeService {
795
+ * logger: Logger;
796
+ *
797
+ * constructor(
798
+ * @InjectLoggerFactory() private readonly loggerFactory: LoggerFactory,
799
+ * ) {
800
+ * // Create logger for this service
801
+ * this.winstonLogger = this.winstonLoggerFactory.create({
802
+ * scope: SomeService.name,
803
+ * })
804
+ * }
805
+ *
806
+ * // Create child logger for some method
807
+ * getOne(id: string) {
808
+ * const logger = this.winstonLogger.child({
809
+ * action: this.someMethod.name,
810
+ * id,
811
+ * });
812
+ * }
813
+ * ```
814
+ */
815
+ child(context) {
816
+ return new Logger(this.winstonLogger, {
817
+ ...this.context,
818
+ ...context
819
+ });
820
+ }
821
+ /**
822
+ * Created child logger for nest service method
823
+ * Automatically parse service method context and add it to logger context
824
+ * @param name - service method name
825
+ * @param ctx - service method context
826
+ * @param other - custom logger context
827
+ * @returns - new logger with context
828
+ */
829
+ forMethod(name, ctx, other) {
830
+ const context = { action: name };
831
+ if (ctx) {
832
+ Object.assign(context, { requestId: ctx.requestId });
833
+ if (!ctx.user) throw new Error("User is required for strict method context. Use guards: @UseGuards(JwtAuthGuard) or @UseGuards(GraphQLJwtAuthGuard)");
834
+ Object.assign(context, {
835
+ requestId: ctx.requestId,
836
+ userId: ctx.user.id
837
+ });
838
+ }
839
+ if (other) Object.assign(context, other);
840
+ return this.child(context);
841
+ }
842
+ setContext(...args) {
843
+ if (args.length === 2 && typeof args[0] === "string" && typeof args[1] !== "undefined") {
844
+ const key = args[0];
845
+ const value = args[1];
846
+ this.context[key] = value;
847
+ } else this.context = {
848
+ ...this.context,
849
+ ...args[0]
850
+ };
851
+ }
852
+ /**
853
+ * Get logger context data
854
+ * @returns - logger context
855
+ */
856
+ getContext() {
857
+ return structuredClone(this.context);
858
+ }
859
+ log(...args) {
860
+ if (isObject(args[0])) this.winstonLogger.log({
861
+ ...this.context,
862
+ ...args[0]
863
+ });
864
+ else this.winstonLogger.log({
865
+ level: args[0],
866
+ message: args[1],
867
+ ...this.context,
868
+ ...args[2]
869
+ });
870
+ }
871
+ info(...args) {
872
+ if (typeof args[0] === "string") this.winstonLogger.info({
873
+ message: args[0],
874
+ ...this.context,
875
+ ...args[1]
876
+ });
877
+ else this.winstonLogger.info({
878
+ ...this.context,
879
+ ...args[0]
880
+ });
881
+ }
882
+ error(...args) {
883
+ if (args[0] instanceof NestError) {
884
+ const err = args[0];
885
+ this.winstonLogger.error({
886
+ ...this.context,
887
+ ...args[1],
888
+ ...this.destructureError(err)
889
+ });
890
+ } else if (args[0] instanceof Error) {
891
+ const err = args[0];
892
+ this.winstonLogger.error({
893
+ ...this.context,
894
+ ...args[1],
895
+ ...this.destructureError(err)
896
+ });
897
+ } else if (typeof args[0] === "string" && args[1] instanceof Error) {
898
+ const message = args[0];
899
+ const err = args[1];
900
+ this.winstonLogger.error({
901
+ message,
902
+ ...this.context,
903
+ ...args[2],
904
+ error: this.destructureError(err)
905
+ });
906
+ } else if (typeof args[0] === "string") {
907
+ const message = args[0];
908
+ this.winstonLogger.error({
909
+ message,
910
+ ...this.context,
911
+ ...args[1]
912
+ });
913
+ }
914
+ }
915
+ /**
916
+ * Creates plain object from error
917
+ * @see {@link DestructuredError}
918
+ */
919
+ destructureError(error) {
920
+ const errorObject = {};
921
+ if (error instanceof NestError) {
922
+ errorObject.message = error.message;
923
+ errorObject.stack = error.stack;
924
+ errorObject.context = error.context;
925
+ errorObject.statusCode = error.httpStatusCode;
926
+ errorObject.errorKey = error.key;
927
+ if (error.cause instanceof Error) errorObject.cause = this.destructureError(error.cause);
928
+ } else if (error instanceof Error) {
929
+ errorObject.message = error.message;
930
+ errorObject.stack = error.stack;
931
+ }
932
+ if (error instanceof HttpException) {
933
+ errorObject.statusCode = error.getStatus();
934
+ const response = error.getResponse();
935
+ if (isObject(response)) {
936
+ if (response.key) errorObject.errorKey = response.key;
937
+ if (response.context) {
938
+ if (!errorObject.context) errorObject.context = {};
939
+ errorObject.context = {
940
+ ...errorObject.context,
941
+ ...response.context
942
+ };
943
+ }
944
+ if (response.error) errorObject.cause = this.destructureError(response.error);
945
+ }
946
+ return errorObject;
947
+ } else if (error instanceof GraphQLError) {
948
+ const ctx = JSON.parse(JSON.stringify({
949
+ locations: error.locations,
950
+ positions: error.positions,
951
+ source: error.source
952
+ }));
953
+ errorObject.context = {
954
+ ...errorObject.context,
955
+ ...ctx
956
+ };
957
+ }
958
+ return errorObject;
959
+ }
960
+ warn(...args) {
961
+ if (typeof args[0] === "string") this.winstonLogger.warn({
962
+ message: args[0],
963
+ ...this.context,
964
+ ...args[1]
965
+ });
966
+ else this.winstonLogger.warn({
967
+ ...this.context,
968
+ ...args[0]
969
+ });
970
+ }
971
+ debug(...args) {
972
+ if (typeof args[0] === "string") this.winstonLogger.debug({
973
+ message: args[0],
974
+ ...this.context,
975
+ ...args[1]
976
+ });
977
+ else this.winstonLogger.debug({
978
+ ...this.context,
979
+ ...args[0]
980
+ });
981
+ }
982
+ verbose(...args) {
983
+ if (typeof args[0] === "string") this.winstonLogger.verbose({
984
+ message: args[0],
985
+ ...this.context,
986
+ ...args[1]
987
+ });
988
+ else this.winstonLogger.verbose({
989
+ ...this.context,
990
+ ...args[0]
991
+ });
992
+ }
993
+ };
994
+
995
+ //#endregion
996
+ //#region src/logger/classes/nest-system-logger.ts
997
+ var _ref$3;
998
+ let NestSystemLogger = class NestSystemLogger$1 extends ConsoleLogger {
999
+ logger;
1000
+ printMessages(messages, context, logLevel) {
1001
+ for (const message of messages) this.logger.log(this.getWinstonLogLevel(logLevel), this.stringifyMessage(message), { scope: context });
1002
+ }
1003
+ stringifyMessage(message) {
1004
+ if (isFunction(message)) return this.stringifyMessage(message());
1005
+ if (isPlainObject(message) || Array.isArray(message)) return JSON.stringify(message, (key, value) => typeof value === "bigint" ? value.toString() : value, 2);
1006
+ return String(message);
1007
+ }
1008
+ getWinstonLogLevel(level) {
1009
+ switch (level) {
1010
+ case "log": return "info";
1011
+ case "verbose": return "verbose";
1012
+ case "debug": return "debug";
1013
+ case "warn": return "warn";
1014
+ case "error": return "error";
1015
+ default: return "info";
1016
+ }
1017
+ }
1018
+ };
1019
+ __decorate([Inject(NESTKIT_LOGGER_PROVIDER), __decorateMetadata("design:type", typeof (_ref$3 = typeof Logger !== "undefined" && Logger) === "function" ? _ref$3 : Object)], NestSystemLogger.prototype, "logger", void 0);
1020
+ NestSystemLogger = __decorate([Injectable()], NestSystemLogger);
1021
+
1022
+ //#endregion
1023
+ //#region src/logger/classes/typeorm-logger.ts
1024
+ var TypeOrmLoggerOptions = class {
1025
+ enabled;
1026
+ logger;
1027
+ levels;
1028
+ };
1029
+ var TypeOrmLogger = class extends AbstractLogger {
1030
+ logger;
1031
+ constructor(opts) {
1032
+ super(opts.enabled && opts.levels ? opts.levels : false);
1033
+ this.logger = opts.logger;
1034
+ }
1035
+ /**
1036
+ * Write log to specific output.
1037
+ */
1038
+ writeLog(level, logMessage) {
1039
+ const messages = this.prepareLogMessages(logMessage, { highlightSql: false });
1040
+ for (const message of messages) switch (message.type ?? level) {
1041
+ case "log":
1042
+ case "query":
1043
+ case "schema-build":
1044
+ this.logger.debug(String(message.message), this.getCtx(message));
1045
+ break;
1046
+ case "migration":
1047
+ case "info":
1048
+ if (message.prefix) this.logger.info(`${message.prefix} ${message.message}`, this.getCtx(message));
1049
+ else this.logger.info(String(message.message), this.getCtx(message));
1050
+ break;
1051
+ case "warn":
1052
+ case "query-slow":
1053
+ if (message.prefix) this.logger.warn(`${message.prefix} ${message.message}`, this.getCtx(message));
1054
+ else this.logger.warn(String(message.message), this.getCtx(message));
1055
+ break;
1056
+ case "error":
1057
+ case "query-error":
1058
+ if (message.prefix) this.logger.error(`[${message.prefix}] ${message.message}`, this.getCtx(message));
1059
+ else this.logger.error(String(message.message), this.getCtx(message));
1060
+ break;
1061
+ }
1062
+ }
1063
+ getCtx(message) {
1064
+ const ctx = { ...message.additionalInfo };
1065
+ if (Array.isArray(ctx.parameters)) ctx.parameters = message.parameters;
1066
+ return ctx;
1067
+ }
1068
+ };
1069
+
1070
+ //#endregion
1071
+ //#region src/logger/classes/logger-factory.ts
1072
+ /**
1073
+ * Logger factory for creating loggers with predefined context
1074
+ * Factory is singleton, so it keep original winston `Logger` instance
1075
+ * and is can be injected to any service
1076
+ */
1077
+ var LoggerFactory = class {
1078
+ constructor(winstonLogger, context = {}) {
1079
+ this.winstonLogger = winstonLogger;
1080
+ this.context = context;
1081
+ }
1082
+ /**
1083
+ * Created new logger with specific context merge it with global context
1084
+ * @param context - specific action with scope, and other data
1085
+ * @returns - new logger with context
1086
+ * @example
1087
+ * ```ts
1088
+ * class SomeService {
1089
+ * logger: Logger;
1090
+ *
1091
+ * constructor(
1092
+ * @InjectLoggerFactory() private readonly loggerFactory: LoggerFactory,
1093
+ * ) {
1094
+ * // Create logger for this service
1095
+ * this.logger = this.loggerFactory.create({
1096
+ * scope: SomeService.name,
1097
+ * })
1098
+ * }
1099
+ * ```
1100
+ */
1101
+ create(context = {}) {
1102
+ return new Logger(this.winstonLogger, {
1103
+ ...this.context,
1104
+ ...context
1105
+ });
1106
+ }
1107
+ createTypeOrmLogger(opts) {
1108
+ return new TypeOrmLogger({
1109
+ logger: this.create({ scope: "TypeORM" }),
1110
+ ...opts
1111
+ });
1112
+ }
1113
+ };
1114
+
1115
+ //#endregion
1116
+ //#region src/logger/logger.providers.ts
1117
+ /**
1118
+ * Syntax sugar. Injects logger via NESTKIT_LOGGER_PROVIDER token
1119
+ * @example
1120
+ * ```ts
1121
+ * class SomeService {
1122
+ * constructor(
1123
+ * @InjectLogger() private readonly logger: Logger
1124
+ * ) {}
1125
+ * ```
1126
+ */
1127
+ const InjectLogger = () => Inject(NESTKIT_LOGGER_PROVIDER);
1128
+ /**
1129
+ * Syntax sugar. Injects winston logger factory by WINSTON_MODULE_FACTORY_PROVIDER token
1130
+ * @example
1131
+ * ```ts
1132
+ * class SomeService {
1133
+ * constructor(
1134
+ * @InjectLoggerFactory() private readonly loggerFactory: LoggerFactory
1135
+ * ) {}
1136
+ * ```
1137
+ */
1138
+ const InjectLoggerFactory = () => Inject(NESTKIT_LOGGER_FACTORY_PROVIDER);
1139
+ const createNestLogger = (loggerOpts) => {
1140
+ return new Logger$1(createLogger(loggerOpts));
1141
+ };
1142
+ const createLoggerProviders = (loggerOpts) => {
1143
+ return [
1144
+ {
1145
+ provide: NESTKIT_WINSTON_LOGGER_PROVIDER,
1146
+ useFactory: () => createLogger(loggerOpts)
1147
+ },
1148
+ {
1149
+ provide: NESTKIT_LOGGER_PROVIDER,
1150
+ useFactory: (logger) => {
1151
+ return new Logger$1(logger);
1152
+ },
1153
+ inject: [NESTKIT_WINSTON_LOGGER_PROVIDER]
1154
+ },
1155
+ {
1156
+ provide: NESTKIT_SYSTEM_LOGGER_PROVIDER,
1157
+ useClass: NestSystemLogger
1158
+ },
1159
+ {
1160
+ provide: NESTKIT_LOGGER_FACTORY_PROVIDER,
1161
+ useFactory: (logger) => {
1162
+ return new LoggerFactory(logger);
1163
+ },
1164
+ inject: [NESTKIT_WINSTON_LOGGER_PROVIDER]
1165
+ }
1166
+ ];
1167
+ };
1168
+ const createLoggerAsyncProviders = (options) => {
1169
+ const providers = [
1170
+ {
1171
+ provide: NESTKIT_WINSTON_LOGGER_PROVIDER,
1172
+ useFactory: (loggerOpts) => createLogger(loggerOpts),
1173
+ inject: [NESTKIT_LOGGER_MODULE_OPTIONS]
1174
+ },
1175
+ {
1176
+ provide: NESTKIT_LOGGER_PROVIDER,
1177
+ useFactory: (logger) => {
1178
+ return new Logger$1(logger);
1179
+ },
1180
+ inject: [NESTKIT_WINSTON_LOGGER_PROVIDER]
1181
+ },
1182
+ {
1183
+ provide: NESTKIT_SYSTEM_LOGGER_PROVIDER,
1184
+ useClass: NestSystemLogger
1185
+ },
1186
+ {
1187
+ provide: NESTKIT_LOGGER_FACTORY_PROVIDER,
1188
+ useFactory: (logger) => {
1189
+ return new LoggerFactory(logger);
1190
+ },
1191
+ inject: [NESTKIT_WINSTON_LOGGER_PROVIDER]
1192
+ }
1193
+ ];
1194
+ if (options.useClass) {
1195
+ const useClass = options.useClass;
1196
+ providers.push(...[{
1197
+ provide: NESTKIT_LOGGER_MODULE_OPTIONS,
1198
+ useFactory: async (optionsFactory) => await optionsFactory.createLoggerModuleOptions(),
1199
+ inject: [useClass]
1200
+ }, {
1201
+ provide: useClass,
1202
+ useClass
1203
+ }]);
1204
+ }
1205
+ if (options.useFactory) providers.push({
1206
+ provide: NESTKIT_LOGGER_MODULE_OPTIONS,
1207
+ useFactory: options.useFactory,
1208
+ inject: options.inject || []
1209
+ });
1210
+ return providers;
1211
+ };
1212
+
1213
+ //#endregion
1214
+ //#region src/logger/logger.module.ts
1215
+ var _LoggerModule;
1216
+ let LoggerModule = _LoggerModule = class LoggerModule$1 {
1217
+ static forRoot(options) {
1218
+ const providers = createLoggerProviders(options);
1219
+ return {
1220
+ module: _LoggerModule,
1221
+ providers,
1222
+ exports: providers
1223
+ };
1224
+ }
1225
+ static forRootAsync(options) {
1226
+ const providers = createLoggerAsyncProviders(options);
1227
+ return {
1228
+ module: _LoggerModule,
1229
+ imports: options.imports,
1230
+ providers,
1231
+ exports: providers
1232
+ };
1233
+ }
1234
+ static createLogger(options) {
1235
+ return createNestLogger(options);
1236
+ }
1237
+ };
1238
+ LoggerModule = _LoggerModule = __decorate([Global(), Module({})], LoggerModule);
1239
+
1240
+ //#endregion
1241
+ //#region src/logger/winston.tools.ts
1242
+ const nestLikeColorScheme = {
1243
+ log: clc.greenBright,
1244
+ info: clc.greenBright,
1245
+ error: clc.red,
1246
+ warn: clc.yellow,
1247
+ debug: clc.magentaBright,
1248
+ verbose: clc.cyanBright
1249
+ };
1250
+ /**
1251
+ * Create a pretty message for the logger with nest-like formatting
1252
+ * Use recursion to print child errors
1253
+ * @param vars - message variables
1254
+ * @returns - formatted message
1255
+ * @example
1256
+ * [Jetstream] - 6/10/2022, 4:33:42 PM ERROR [VideoService.createOutput] Failed to create cloudlfare output
1257
+ */
1258
+ const createPrettyMessage = ({ appName, action, level, timestamp, message, scope, stack, errorKey, context, parentPath, cause, deep = 0 }) => {
1259
+ if ("undefined" !== typeof timestamp) try {
1260
+ if (timestamp === new Date(timestamp).toISOString()) timestamp = new Date(timestamp).toLocaleString();
1261
+ } catch {}
1262
+ const color = nestLikeColorScheme[level] || ((text) => text);
1263
+ if (errorKey) message += ` [${errorKey}]`;
1264
+ const sAppName = color(`[${appName}]`);
1265
+ const sTimestamp = timestamp ? `${timestamp} ` : "";
1266
+ const sLevel = color(level.toUpperCase());
1267
+ let path = "";
1268
+ let sPath = "";
1269
+ if ("undefined" !== typeof scope && "undefined" !== typeof action) path = `${scope}.${action}`;
1270
+ else if ("undefined" !== typeof scope) path = scope;
1271
+ else if ("undefined" !== typeof action) path = action;
1272
+ if (path && parentPath) path = `${parentPath} --> ${path}`;
1273
+ else if (parentPath) path = parentPath;
1274
+ if (path) sPath = clc.yellow(` [${path}]`);
1275
+ const sMessage = color(` ${message}`);
1276
+ const sStack = "undefined" !== typeof stack ? color(`\n ${stack}`) : "";
1277
+ let sRecursion = "";
1278
+ if (cause) {
1279
+ const { action: action$1, scope: scope$1,...context$1 } = cause?.context || {};
1280
+ /**
1281
+ * Print child errors recursively
1282
+ */
1283
+ sRecursion = cause ? `\n${createPrettyMessage({
1284
+ appName,
1285
+ action: action$1,
1286
+ level,
1287
+ timestamp,
1288
+ message: cause.message ?? message,
1289
+ scope: scope$1,
1290
+ stack: cause.stack,
1291
+ errorKey: cause.errorKey,
1292
+ context: context$1,
1293
+ parentPath: path,
1294
+ cause: cause.cause,
1295
+ deep: deep + 1
1296
+ })}` : "";
1297
+ }
1298
+ const sContext = context && Object.keys(context).length > 0 ? color(` -- ${JSON.stringify(context, null, 2)}`) : "";
1299
+ return `${sAppName} - ${sTimestamp} ${sLevel}${sPath}${sMessage}${sStack}${sContext}${sRecursion}`;
1300
+ };
1301
+ /**
1302
+ * Create a nest-like console format
1303
+ * @param appName - App name (Jetstream, WHATSBIBLE, etc.)
1304
+ * @returns Winston format
1305
+ */
1306
+ const nestLikeConsoleFormat = (appName = "Nest") => format.printf(({ level, timestamp, message, scope, action, stack, errorKey, statusCode, error: cause,...context }) => {
1307
+ return createPrettyMessage({
1308
+ appName,
1309
+ action,
1310
+ level,
1311
+ timestamp,
1312
+ message,
1313
+ stack,
1314
+ context,
1315
+ scope,
1316
+ errorKey,
1317
+ statusCode,
1318
+ cause,
1319
+ deep: 0
1320
+ });
1321
+ });
1322
+
1323
+ //#endregion
1324
+ //#region src/configs/logger.config.ts
1325
+ /**
1326
+ * NestJS injection token for Logger config
1327
+ */
1328
+ const LOGGER_CONFIG_TOKEN = "LOGGER_CONFIG_TOKEN";
1329
+ const InjectLoggerConfig = () => Inject(getConfigToken(LOGGER_CONFIG_TOKEN));
1330
+ /**
1331
+ * Create NestJS Logger config
1332
+ * @example
1333
+ * ```ts
1334
+ * // src/config/index.ts
1335
+ *
1336
+ * import { createLoggerConfig } from '#/dist/configs';
1337
+ *
1338
+ * export const LoggerConfig = createLoggerConfig();
1339
+ * ```
1340
+ */
1341
+ const createLoggerConfig = (opts) => {
1342
+ return registerAs(LOGGER_CONFIG_TOKEN, () => {
1343
+ const format$1 = [
1344
+ winston.format.splat(),
1345
+ winston.format.timestamp(),
1346
+ nestLikeConsoleFormat(opts.appName)
1347
+ ];
1348
+ const winstonOptions = { transports: [] };
1349
+ if (!Array.isArray(winstonOptions.transports)) return winstonOptions;
1350
+ if (opts.useConsole) winstonOptions.transports.push(new winston.transports.Console({
1351
+ level: opts.consoleLevel ?? "debug",
1352
+ format: winston.format.combine(...format$1)
1353
+ }));
1354
+ if (opts.transports) winstonOptions.transports.push(...opts.transports);
1355
+ return winstonOptions;
1356
+ });
1357
+ };
1358
+
1359
+ //#endregion
1360
+ //#region src/abstracts/nestjs-service.ts
1361
+ var _ref$2;
1362
+ /**
1363
+ * Abstract service class for NestJS services
1364
+ * Automatically initializes logger with the constructor name as scope
1365
+ */
1366
+ var NestJsService = class {
1367
+ loggerFactory;
1368
+ logger;
1369
+ /**
1370
+ * Initialize logger using the constructor name as scope
1371
+ */
1372
+ onModuleInit() {
1373
+ this.logger = this.loggerFactory.create({ scope: this.constructor.name });
1374
+ }
1375
+ };
1376
+ __decorate([InjectLoggerFactory(), __decorateMetadata("design:type", typeof (_ref$2 = typeof LoggerFactory !== "undefined" && LoggerFactory) === "function" ? _ref$2 : Object)], NestJsService.prototype, "loggerFactory", void 0);
1377
+
1378
+ //#endregion
1379
+ //#region src/abstracts/nestjs-resource-service.ts
1380
+ var _ref$1, _ref2$1;
1381
+ var NestJsResourceService = class extends NestJsService {
1382
+ constructor(params) {
1383
+ super();
1384
+ this.params = params;
1385
+ }
1386
+ idService;
1387
+ dataSource;
1388
+ get repository() {
1389
+ return this.dataSource.getRepository(this.params.entity.type);
1390
+ }
1391
+ generateEntityId() {
1392
+ return this.idService.generateEntityId(this.params.entity.idPrefix);
1393
+ }
1394
+ get entityName() {
1395
+ return this.params.entity.type.name;
1396
+ }
1397
+ get alias() {
1398
+ return this.params.entity.alias;
1399
+ }
1400
+ async getOneBy(opts) {
1401
+ const logger = this.logger.child({
1402
+ action: this.getOneBy.name,
1403
+ ...opts
1404
+ });
1405
+ if (Object.values(opts).filter((v) => v).length === 0) throw new BadRequestError({
1406
+ message: "Empty options",
1407
+ key: "NST_GET_ONE_BY_EMPTY_OPTIONS",
1408
+ context: logger.getContext()
1409
+ });
1410
+ return await this.repository.findOneBy({ ...opts });
1411
+ }
1412
+ async getOne(id) {
1413
+ return await this.getOneBy({ id });
1414
+ }
1415
+ async getOneByOrFail(opts, ctx) {
1416
+ const logger = this.logger.forMethod(this.getOneByOrFail.name, ctx, { ...opts });
1417
+ const item = await this.getOneBy(opts);
1418
+ if (!item) throw new NotFoundError({
1419
+ message: `${this.entityName} with ${stringifyOpts(opts)} not found`,
1420
+ key: "NST_CHANNELS_NOT_FOUND",
1421
+ context: logger.getContext()
1422
+ });
1423
+ return item;
1424
+ }
1425
+ async getOneOrFail(id, ctx) {
1426
+ return await this.getOneByOrFail({ id }, ctx);
1427
+ }
1428
+ applyFilterToQuery(query, filter) {
1429
+ if (!filter) return;
1430
+ if (filter.search) query.andWhere(`${this.alias}.title LIKE :search`, { search: `%${filter.search}%` });
1431
+ }
1432
+ applySearchToQuery(query, search) {
1433
+ if (!search) return;
1434
+ query.andWhere(`${this.alias}.title LIKE :search`, { search: `%${search}%` });
1435
+ }
1436
+ applyOrderByToQuery(query, orderBy) {
1437
+ const sort = extractSortParams(orderBy);
1438
+ query.addOrderBy(`${this.alias}.${sort.columnName}`, sort.direction);
1439
+ }
1440
+ };
1441
+ __decorate([Inject(IdService), __decorateMetadata("design:type", typeof (_ref$1 = typeof IdService !== "undefined" && IdService) === "function" ? _ref$1 : Object)], NestJsResourceService.prototype, "idService", void 0);
1442
+ __decorate([InjectDataSource(), __decorateMetadata("design:type", typeof (_ref2$1 = typeof DataSource !== "undefined" && DataSource) === "function" ? _ref2$1 : Object)], NestJsResourceService.prototype, "dataSource", void 0);
1443
+
1444
+ //#endregion
1445
+ //#region src/db/snake-naming.strategy.ts
1446
+ /**
1447
+ * Snake case naming strategy for typeorm.
1448
+ * Determines table and column names from class and property names.
1449
+ */
1450
+ var SnakeNamingStrategy = class extends DefaultNamingStrategy {
1451
+ /**
1452
+ * Create a table name from a class name.
1453
+ * @param className - The class name of the entity
1454
+ * @param customName - The custom table name
1455
+ * @returns The table name
1456
+ * @example Create table name from class name
1457
+ * ```ts
1458
+ * @Entity()
1459
+ * class User {}
1460
+ * // returns 'users'
1461
+ *
1462
+ * @Entity('custom_table_name')
1463
+ * class User {}
1464
+ * // returns 'custom_table_name'
1465
+ *
1466
+ *```
1467
+ */
1468
+ tableName(className, customName) {
1469
+ if (customName) return customName;
1470
+ const snakeClassName = snakeCase(className);
1471
+ if (snakeClassName.includes("_to_")) return snakeClassName;
1472
+ const parts = snakeClassName.split("_");
1473
+ if (parts.length === 1) return singularToPlural(snakeClassName);
1474
+ return parts.map((name, i) => i === 0 ? name : singularToPlural(name)).join("_");
1475
+ }
1476
+ /**
1477
+ * Create a column name from a property name.
1478
+ * @param propertyName - The property name of the entity
1479
+ * @param customName - The custom column name
1480
+ * @param embeddedPrefixes - The embedded prefixes
1481
+ * @returns The table column name
1482
+ * @example Create column name from property name
1483
+ * ```ts
1484
+ * @Entity()
1485
+ * class User {
1486
+ * @Column()
1487
+ * firstName: string; // returns 'first_name'
1488
+ *
1489
+ * @Column('custom_last_name')
1490
+ * lastName: string; // returns 'custom_last_name'
1491
+ * }
1492
+ * ```
1493
+ */
1494
+ columnName(propertyName, customName, embeddedPrefixes = []) {
1495
+ return snakeCase(embeddedPrefixes.concat("").join("_")) + (customName ? customName : snakeCase(propertyName));
1496
+ }
1497
+ relationName(propertyName) {
1498
+ return snakeCase(propertyName);
1499
+ }
1500
+ joinColumnName(relationName, referencedColumnName) {
1501
+ return snakeCase(relationName + "_" + referencedColumnName);
1502
+ }
1503
+ /**
1504
+ * Create join table name for many-to-many relations.
1505
+ * @returns join table name
1506
+ * @example
1507
+ * ```ts
1508
+ * @Entity()
1509
+ * class Post {
1510
+ * @ManyToMany(() => Theme) // post_to_theme
1511
+ * themes: Theme[];
1512
+ * }
1513
+ *
1514
+ */
1515
+ joinTableName(firstTableName, secondTableName) {
1516
+ return snakeCase(pluralToSingular(firstTableName) + "_to_" + pluralToSingular(secondTableName));
1517
+ }
1518
+ joinTableColumnName(tableName, propertyName, columnName) {
1519
+ return snakeCase(pluralToSingular(tableName) + "_" + (columnName ? columnName : propertyName));
1520
+ }
1521
+ eagerJoinRelationAlias(alias, propertyPath) {
1522
+ return alias + "__" + propertyPath.replace(".", "_");
1523
+ }
1524
+ /**
1525
+ * Create a primary key name.
1526
+ * @param tableOrName - The table or table name
1527
+ * @param columnNames - The column names
1528
+ * @returns The primary key name
1529
+ * @example
1530
+ * ```ts
1531
+ * @Entity()
1532
+ * class User {
1533
+ * @PrimaryColumn()
1534
+ * id: string;
1535
+ * }
1536
+ *
1537
+ * // returns 'pk_users__id'
1538
+ */
1539
+ primaryKeyName(tableOrName, columnNames) {
1540
+ tableOrName = typeof tableOrName === "string" ? tableOrName : tableOrName.name;
1541
+ let name = tableOrName;
1542
+ for (const column of columnNames) name += `__${column}`;
1543
+ name = this.simplifyName(name);
1544
+ return `pk_${name}`;
1545
+ }
1546
+ /**
1547
+ * Create a foreign key name.
1548
+ * @param tableOrName - The table or table name
1549
+ * @param columnNames - The column names
1550
+ * @returns The foreign key name
1551
+ * @example
1552
+ * ```ts
1553
+ * @Entity()
1554
+ * class User {
1555
+ * @PrimaryColumn()
1556
+ * id: string;
1557
+ * }
1558
+ * @Entity()
1559
+ * class Post {
1560
+ * @PrimaryColumn()
1561
+ * id: string;
1562
+ *
1563
+ * @ManyToOne(() => User, user => user.posts)
1564
+ * user: User;
1565
+ * }
1566
+ *
1567
+ * // returns 'fk_posts__user_id__users__id'
1568
+ * ```
1569
+ */
1570
+ foreignKeyName(tableOrName, columnNames) {
1571
+ tableOrName = typeof tableOrName === "string" ? tableOrName : tableOrName.name;
1572
+ let name = tableOrName;
1573
+ for (const column of columnNames) name += `__${column}`;
1574
+ name = this.simplifyName(name);
1575
+ return `fk_${name}`;
1576
+ }
1577
+ /**
1578
+ * Create an index name.
1579
+ * @param tableOrName - The table or table name
1580
+ * @param columnNames - The column names
1581
+ * @returns The index name
1582
+ * @example
1583
+ * ```ts
1584
+ * @Entity()
1585
+ * class User {
1586
+ * @Index()
1587
+ * @Column()
1588
+ * email: string;
1589
+ * }
1590
+ * // returns 'idx_users__email'
1591
+ * ```
1592
+ */
1593
+ indexName(tableOrName, columnNames) {
1594
+ tableOrName = typeof tableOrName === "string" ? tableOrName : tableOrName.name;
1595
+ let name = tableOrName;
1596
+ for (const column of columnNames) name += `__${column}`;
1597
+ name = this.simplifyName(name);
1598
+ return `idx_${name}`;
1599
+ }
1600
+ /**
1601
+ * Create a unique constraint name.
1602
+ * @param tableOrName - The table or table name
1603
+ * @param columnNames - The column names
1604
+ * @returns The unique constraint name
1605
+ * @example
1606
+ * ```ts
1607
+ * @Entity()
1608
+ * class User {
1609
+ * @Unique()
1610
+ * @Column()
1611
+ * email: string;
1612
+ * }
1613
+ * // returns 'uq_users__email'
1614
+ * ```
1615
+ */
1616
+ uniqueConstraintName(tableOrName, columnNames) {
1617
+ tableOrName = typeof tableOrName === "string" ? tableOrName : tableOrName.name;
1618
+ let name = tableOrName;
1619
+ for (const column of columnNames) name += `__${column}`;
1620
+ name = this.simplifyName(name);
1621
+ return `uq_${name}`;
1622
+ }
1623
+ simplifyName(name) {
1624
+ if (name.length > 50) return name.split("__").map((piece) => {
1625
+ if (piece.includes("_to_")) return piece.split("_").map((p) => p[0]).join("");
1626
+ return piece;
1627
+ }).join("__");
1628
+ return name;
1629
+ }
1630
+ };
1631
+
1632
+ //#endregion
1633
+ //#region src/configs/db.config.ts
1634
+ /**
1635
+ * NestJS injection token for postgres db config
1636
+ */
1637
+ const DB_CONFIG_TOKEN = "DB_CONFIG_TOKEN";
1638
+ const InjectDbConfig = () => Inject(getConfigToken(DB_CONFIG_TOKEN));
1639
+ /**
1640
+ * Postgres db config environment variables
1641
+ */
1642
+ var DbConfigEnvironmentVariables = class {
1643
+ /**
1644
+ * Postgres host
1645
+ * @example
1646
+ * ```yaml
1647
+ * POSTGRES_HOST: 'localhost'
1648
+ * ```
1649
+ */
1650
+ POSTGRES_HOST;
1651
+ /**
1652
+ * Postgres port
1653
+ * @example
1654
+ * ```yaml
1655
+ * POSTGRES_PORT: 5432
1656
+ * ```
1657
+ */
1658
+ POSTGRES_PORT;
1659
+ /**
1660
+ * Postgres user
1661
+ * @example
1662
+ * ```yaml
1663
+ * POSTGRES_USER: 'app'
1664
+ * ```
1665
+ */
1666
+ POSTGRES_USER;
1667
+ /**
1668
+ * Postgres password
1669
+ * @example
1670
+ * ```yaml
1671
+ * POSTGRES_PASS: 'qwerty'
1672
+ * ```
1673
+ */
1674
+ POSTGRES_PASS;
1675
+ /**
1676
+ * Postgres database name
1677
+ * @example
1678
+ * ```yaml
1679
+ * POSTGRES_DB: 'jetstream'
1680
+ * ```
1681
+ */
1682
+ POSTGRES_DB;
1683
+ /**
1684
+ * Enable postgres logging
1685
+ * @example
1686
+ * ```yaml
1687
+ * POSTGRES_IS_LOGGING_ENABLED: "true"
1688
+ * ```
1689
+ */
1690
+ POSTGRES_IS_LOGGING_ENABLED;
1691
+ };
1692
+ __decorate([IsString(), __decorateMetadata("design:type", String)], DbConfigEnvironmentVariables.prototype, "POSTGRES_HOST", void 0);
1693
+ __decorate([
1694
+ Type$1(() => Number),
1695
+ IsNumber(),
1696
+ __decorateMetadata("design:type", Number)
1697
+ ], DbConfigEnvironmentVariables.prototype, "POSTGRES_PORT", void 0);
1698
+ __decorate([IsString(), __decorateMetadata("design:type", String)], DbConfigEnvironmentVariables.prototype, "POSTGRES_USER", void 0);
1699
+ __decorate([IsString(), __decorateMetadata("design:type", String)], DbConfigEnvironmentVariables.prototype, "POSTGRES_PASS", void 0);
1700
+ __decorate([IsString(), __decorateMetadata("design:type", String)], DbConfigEnvironmentVariables.prototype, "POSTGRES_DB", void 0);
1701
+ __decorate([
1702
+ Type$1(() => Boolean),
1703
+ IsOptional(),
1704
+ IsBoolean(),
1705
+ __decorateMetadata("design:type", Boolean)
1706
+ ], DbConfigEnvironmentVariables.prototype, "POSTGRES_IS_LOGGING_ENABLED", void 0);
1707
+ /**
1708
+ * Postgres Database Config
1709
+ */
1710
+ const createDbConfig = (opts) => {
1711
+ return registerAs(DB_CONFIG_TOKEN, () => {
1712
+ const env = validateEnv(DbConfigEnvironmentVariables);
1713
+ const entities = [...opts?.entities ?? ["dist/**/*.entity.js", "node_modules/@deep/nest-kit/dist/modules/**/*.entity.js"]];
1714
+ return {
1715
+ type: "postgres",
1716
+ logging: env.POSTGRES_IS_LOGGING_ENABLED,
1717
+ host: env.POSTGRES_HOST,
1718
+ port: env.POSTGRES_PORT,
1719
+ username: env.POSTGRES_USER,
1720
+ password: env.POSTGRES_PASS,
1721
+ database: env.POSTGRES_DB,
1722
+ synchronize: false,
1723
+ migrations: ["dist/migrations/*.js"],
1724
+ subscribers: ["dist/**/*.entity-subscriber.js"],
1725
+ migrationsRun: true,
1726
+ namingStrategy: new SnakeNamingStrategy(),
1727
+ ...opts,
1728
+ entities: fg.sync(entities)
1729
+ };
1730
+ });
1731
+ };
1732
+
1733
+ //#endregion
1734
+ //#region src/tools/compose.ts
1735
+ function compose(baseClass, ...mixins) {
1736
+ return mixins.reduce((currentClass, mixin) => mixin(currentClass), baseClass);
1737
+ }
1738
+
1739
+ //#endregion
1740
+ //#region src/tools/convert-to-bigint.ts
1741
+ /**
1742
+ * Converts a number or string value to a BigInt, preserving null and undefined values.
1743
+ *
1744
+ * @param value - The value to convert. Can be a number, string, undefined, or null.
1745
+ * @returns The converted BigInt value, or the original value if it was null or undefined.
1746
+ *
1747
+ * @example
1748
+ * ```typescript
1749
+ * convertToBigInt(123) // returns 123n
1750
+ * convertToBigInt("456") // returns 456n
1751
+ * convertToBigInt(null) // returns null
1752
+ * convertToBigInt(undefined) // returns undefined
1753
+ * ```
1754
+ *
1755
+ * @throws {RangeError} Throws when the input cannot be converted to a valid BigInt.
1756
+ */
1757
+ const convertToBigInt = (value) => {
1758
+ if (value === null) return value;
1759
+ if (typeof value === "undefined") return value;
1760
+ return BigInt(value);
1761
+ };
1762
+
1763
+ //#endregion
1764
+ //#region src/tools/fetch-total-with-query.ts
1765
+ /**
1766
+ * Returns total count of items with typeorm query
1767
+ * @param query - typeorm query builder
1768
+ * @returns total count of items
1769
+ */
1770
+ /**
1771
+ * Returns total count of items with typeorm query
1772
+ * @param query - typeorm query builder
1773
+ * @returns total count of items
1774
+ */
1775
+ const fetchTotalWithQuery = async (query) => {
1776
+ const totalQueryBuilder = query.clone();
1777
+ totalQueryBuilder.offset(void 0).limit(void 0).skip(void 0).take(void 0).orderBy();
1778
+ const hasDistinctOn = totalQueryBuilder.expressionMap.selectDistinctOn && totalQueryBuilder.expressionMap.selectDistinctOn.length > 0;
1779
+ const isGrouped = totalQueryBuilder.expressionMap.groupBys && totalQueryBuilder.expressionMap.groupBys.length > 0;
1780
+ if (hasDistinctOn || isGrouped) {
1781
+ const subQuery = totalQueryBuilder.getQuery();
1782
+ return (await query.connection.createQueryBuilder().select("COUNT(*)", "rowsCount").from(`(${subQuery})`, "subQuery").setParameters(totalQueryBuilder.getParameters()).getRawOne())?.rowsCount ?? 0;
1783
+ }
1784
+ return await totalQueryBuilder.getCount();
1785
+ };
1786
+
1787
+ //#endregion
1788
+ //#region src/tools/create-list-meta.ts
1789
+ /**
1790
+ * Create list meta object
1791
+ * @returns list meta object
1792
+ * @example
1793
+ * class UsersService {
1794
+ * async getMany(opts: GetManyUsersOptions): Promise<[User[], ListMeta]> {
1795
+ * ...
1796
+ * return Promise.all([
1797
+ * query.getMany(),
1798
+ * createListMeta<User>({
1799
+ * query,
1800
+ * needCountTotal,
1801
+ * limit,
1802
+ * offset,
1803
+ * }),
1804
+ * ]);
1805
+ * }
1806
+ */
1807
+ const createListMeta = async ({ query, needCountTotal = false, limit, offset }) => {
1808
+ const meta = {
1809
+ limit,
1810
+ offset
1811
+ };
1812
+ if (needCountTotal) meta.total = await fetchTotalWithQuery(query);
1813
+ return meta;
1814
+ };
1815
+
1816
+ //#endregion
1817
+ //#region src/tools/define-statuses.ts
1818
+ /**
1819
+ * Define statuses. Returns array of statuses from filter or default statuses
1820
+ * @param statuses - array of statuses from filter. Can be undefined
1821
+ * @param defaultStatuses - array of default statuses
1822
+ * @returns final array of statuses
1823
+ * @example
1824
+ * const statuses = defineStatuses(['active', 'pending'], ['active']);
1825
+ * // statuses = ['active', 'pending']
1826
+ *
1827
+ * const statuses = defineStatuses(undefined, ['active']);
1828
+ * // statuses = ['active']
1829
+ */
1830
+ const defineStatuses = (statuses, defaultStatuses) => {
1831
+ return Array.isArray(statuses) ? statuses : defaultStatuses;
1832
+ };
1833
+
1834
+ //#endregion
1835
+ //#region src/tools/get-request-language.ts
1836
+ const getRequestLanguage = (req, fallbackLanguage) => {
1837
+ const headers = req?.headers;
1838
+ return parse(headers["accept-language"])?.[0]?.code ?? fallbackLanguage;
1839
+ };
1840
+
1841
+ //#endregion
1842
+ //#region src/tools/postgres/locale-to-pg-collate.ts
1843
+ /**
1844
+ * Converts a locale string to a PostgreSQL collation identifier.
1845
+ *
1846
+ * @param locale - The locale string to convert (e.g., 'uk', 'en')
1847
+ * @returns The PostgreSQL collation identifier (e.g., 'uk_UA', 'en_US')
1848
+ *
1849
+ * @example
1850
+ * ```typescript
1851
+ * localeToPgCollate('uk') // returns 'uk_UA'
1852
+ * localeToPgCollate('en') // returns 'en_US'
1853
+ * ```
1854
+ */
1855
+ const localeToPgCollate = (locale) => {
1856
+ let collate = "en_US";
1857
+ if (locale === "uk") collate = "uk_UA";
1858
+ return collate;
1859
+ };
1860
+
1861
+ //#endregion
1862
+ //#region src/tools/remove-undefined-properties.ts
1863
+ const removeUndefinedProperties = (obj) => {
1864
+ const result = {};
1865
+ for (const key in obj) if (Object.prototype.hasOwnProperty.call(obj, key) && obj[key] !== void 0) result[key] = obj[key];
1866
+ return result;
1867
+ };
1868
+
1869
+ //#endregion
1870
+ //#region src/tools/request-id.ts
1871
+ const generateRequestId = (appShortName) => {
1872
+ return `${appShortName}req:${createRandomString()}`;
1873
+ };
1874
+ const extractRequestId = (req) => {
1875
+ const headers = req?.headers;
1876
+ if (headers?.["x-request-id"]) return headers["x-request-id"];
1877
+ if (headers["x-cloud-trace-context"]) return req.appShortname + `req:${headers["x-cloud-trace-context"]}`;
1878
+ return generateRequestId(req.appShortname);
1879
+ };
1880
+
1881
+ //#endregion
1882
+ //#region src/tools/wait.ts
1883
+ /**
1884
+ * Pauses execution for a specified amount of time using a Promise.
1885
+ * @param ms - The amount of time to pause in milliseconds.
1886
+ * @returns A Promise that resolves after the specified amount of time has elapsed.
1887
+ * @deprecated use wait instead
1888
+ */
1889
+ const pauseWithPromise = async (ms) => {
1890
+ return await new Promise((resolve) => {
1891
+ setTimeout(() => {
1892
+ resolve();
1893
+ }, ms);
1894
+ });
1895
+ };
1896
+ /**
1897
+ * Pauses execution for a specified amount of time using a Promise.
1898
+ * @param ms - The amount of time to pause in milliseconds.
1899
+ * @returns A Promise that resolves after the specified amount of time has elapsed.
1900
+ */
1901
+ const wait = async (ms) => {
1902
+ return await new Promise((resolve) => {
1903
+ setTimeout(() => {
1904
+ resolve();
1905
+ }, ms);
1906
+ });
1907
+ };
1908
+
1909
+ //#endregion
1910
+ //#region src/tools/typeorm/add-filter.ts
1911
+ /**
1912
+ * Adds a filter condition to a TypeORM SelectQueryBuilder based on the provided field and value(s).
1913
+ *
1914
+ * Handles three types of filtering:
1915
+ * - Single value filtering: when a single non-null value is provided
1916
+ * - Multiple value filtering: when an array of values is provided
1917
+ * - Null value filtering: when null is explicitly provided as the filter value
1918
+ *
1919
+ * @template T - The entity type that extends ObjectLiteral
1920
+ * @template K - The field name key type that must be a string key of T
1921
+ *
1922
+ * @param query - The TypeORM SelectQueryBuilder instance to add the filter to
1923
+ * @param fieldName - The name of the field to filter by, must be a valid key of entity T
1924
+ * @param valueOrValues - The filter value(s). Can be:
1925
+ * - A single value of type T[K]
1926
+ * - An array of values of type T[K]
1927
+ * - null to filter for null values
1928
+ * - An array containing null values
1929
+ * @example
1930
+ * ```typescript
1931
+ * // Single value filter
1932
+ * addFilterByField(queryBuilder, 'status', 'active');
1933
+ * // Multiple values filter
1934
+ * addFilterByField(queryBuilder, 'id', [1, 2, 3]);
1935
+ * // Null value filter
1936
+ * addFilterByField(queryBuilder, 'deletedAt', null);
1937
+ * ```
1938
+ *
1939
+ * @returns void - Modifies the query builder in place
1940
+ */
1941
+ const addFilterByField = (query, fieldName, valueOrValues) => {
1942
+ if (Array.isArray(valueOrValues)) addMultipleFilter(query, fieldName, valueOrValues);
1943
+ else if (valueOrValues === null) addNullableFilter(query, fieldName);
1944
+ else addSingleFilter(query, fieldName, valueOrValues);
1945
+ };
1946
+ /**
1947
+ * Adds a filter to a TypeORM query that matches multiple values for a given column,
1948
+ * including support for null values.
1949
+ *
1950
+ * @template T - The entity type that extends ObjectLiteral
1951
+ * @template K - The key type that must be both a key of T and a string
1952
+ * @param query - The TypeORM SelectQueryBuilder instance to add the filter to
1953
+ * @param columnName - The name of the column to filter on
1954
+ * @param values - An array of values to match, which may include null
1955
+ *
1956
+ * @remarks
1957
+ * This function creates an OR condition that matches any of the provided values.
1958
+ * If the values array includes null, a separate null check is added to the filter.
1959
+ * Non-null values are handled using TypeORM's `In` operator.
1960
+ *
1961
+ * @example
1962
+ * ```typescript
1963
+ * const query = repository.createQueryBuilder('user');
1964
+ * addMultipleFilter(query, 'status', ['active', 'pending', null]);
1965
+ * // Generates: WHERE (status IS NULL OR status IN ('active', 'pending'))
1966
+ * ```
1967
+ */
1968
+ const addMultipleFilter = (query, columnName, values) => {
1969
+ query.andWhere(new Brackets((subQuery) => {
1970
+ if (values.includes(null)) addNullValueToMultipleFilter(subQuery, columnName);
1971
+ const notNullValues = values.filter((v) => v !== null);
1972
+ subQuery.orWhere({ [columnName]: In(notNullValues) });
1973
+ }));
1974
+ };
1975
+ /**
1976
+ * Adds a single filter condition to a TypeORM SelectQueryBuilder.
1977
+ *
1978
+ * @template T - The entity type that extends ObjectLiteral
1979
+ * @template K - The column name type, constrained to string keys of T
1980
+ *
1981
+ * @param query - The SelectQueryBuilder instance to add the filter to
1982
+ * @param columnName - The name of the column to filter on
1983
+ * @param value - The value to filter by, must match the type of the column
1984
+ *
1985
+ * @returns void
1986
+ *
1987
+ * @example
1988
+ * ```typescript
1989
+ * const query = repository.createQueryBuilder('user');
1990
+ * addSingleFilter(query, 'email', 'user@example.com');
1991
+ * // Results in: WHERE user.email = 'user@example.com'
1992
+ * ```
1993
+ */
1994
+ const addSingleFilter = (query, columnName, value) => {
1995
+ query.andWhere({ [columnName]: value });
1996
+ };
1997
+ /**
1998
+ * Adds a nullable filter to a TypeORM query builder.
1999
+ *
2000
+ * This function applies a WHERE clause that filters for NULL values in the specified column.
2001
+ * The filter is combined with existing conditions using AND logic.
2002
+ *
2003
+ * @template T - The entity type that extends ObjectLiteral
2004
+ * @param query - The TypeORM SelectQueryBuilder instance to add the filter to
2005
+ * @param columnName - The name of the column to check for NULL values
2006
+ * @returns void
2007
+ *
2008
+ * @example
2009
+ * ```typescript
2010
+ * const query = repository.createQueryBuilder('user');
2011
+ * addNullableFilter(query, 'deletedAt');
2012
+ * // Results in: WHERE deletedAt IS NULL
2013
+ * ```
2014
+ */
2015
+ const addNullableFilter = (query, columnName) => {
2016
+ query.andWhere({ [columnName]: IsNull() });
2017
+ };
2018
+ /**
2019
+ * Adds an OR condition to the query to check if the specified column is NULL.
2020
+ *
2021
+ * This function is used to extend filtering logic by adding a null value check
2022
+ * as an alternative condition in a WHERE clause.
2023
+ *
2024
+ * @param query - The TypeORM WhereExpressionBuilder instance to which the null condition will be added
2025
+ * @param columnName - The name of the database column to check for NULL values
2026
+ *
2027
+ * @returns void
2028
+ *
2029
+ * @example
2030
+ * ```typescript
2031
+ * const queryBuilder = repository.createQueryBuilder('user');
2032
+ * addNullValueToMultipleFilter(queryBuilder, 'deletedAt');
2033
+ * // Results in: WHERE ... OR deletedAt IS NULL
2034
+ * ```
2035
+ */
2036
+ const addNullValueToMultipleFilter = (query, columnName) => {
2037
+ query.orWhere({ [columnName]: IsNull() });
2038
+ };
2039
+
2040
+ //#endregion
2041
+ //#region src/tools/typeorm/is-alias-already-busy.ts
2042
+ /**
2043
+ * Checks if a given alias is already used in the query builder's join attributes.
2044
+ *
2045
+ * This utility function inspects the query builder's expression map to determine
2046
+ * whether a specific alias name has already been assigned to any join attribute.
2047
+ * This is useful to avoid alias conflicts when building complex TypeORM queries.
2048
+ *
2049
+ * @template T - The entity type that extends ObjectLiteral
2050
+ * @param {SelectQueryBuilder<T>} query - The TypeORM SelectQueryBuilder instance to check
2051
+ * @param {string} alias - The alias name to search for in the join attributes
2052
+ * @returns {boolean} True if the alias is already used in any join attribute, false otherwise
2053
+ *
2054
+ * @example
2055
+ * ```typescript
2056
+ * const query = repository.createQueryBuilder('user');
2057
+ * const isBusy = isAliasAlreadyBusy(query, 'profile');
2058
+ * if (!isBusy) {
2059
+ * query.leftJoinAndSelect('user.profile', 'profile');
2060
+ * }
2061
+ * ```
2062
+ */
2063
+ const isAliasAlreadyBusy = (query, alias) => query.expressionMap.joinAttributes.some((a) => a.alias.name === alias);
2064
+
2065
+ //#endregion
2066
+ //#region src/tools/typeorm/ensure-inner-join.ts
2067
+ /**
2068
+ * Ensures an inner join is added to the TypeORM query builder only if the alias is not already in use.
2069
+ *
2070
+ * This function checks if the specified alias is already being used in the query builder.
2071
+ * If the alias is available, it adds an inner join with the provided entity, alias, and optional condition.
2072
+ * If the alias is already busy, the function returns without making any changes to the query.
2073
+ *
2074
+ * @template T - The entity type that extends ObjectLiteral
2075
+ * @param query - The TypeORM SelectQueryBuilder instance to add the inner join to
2076
+ * @param entity - The entity class (Function) or entity name (string) to join
2077
+ * @param alias - The alias to use for the joined entity
2078
+ * @param condition - Optional join condition as a string
2079
+ * @returns void
2080
+ *
2081
+ * @example
2082
+ * ```typescript
2083
+ * const query = repository.createQueryBuilder('user');
2084
+ * ensureInnerJoin(query, Profile, 'profile', 'profile.userId = user.id');
2085
+ * ```
2086
+ */
2087
+ const ensureInnerJoin = (query, entity, alias, condition) => {
2088
+ if (isAliasAlreadyBusy(query, alias)) return;
2089
+ query.innerJoin(entity, alias, condition);
2090
+ };
2091
+
2092
+ //#endregion
2093
+ //#region src/tools/typeorm/ensure-left-join.ts
2094
+ /**
2095
+ * Ensures a left join is added to a TypeORM query builder if the alias is not already in use.
2096
+ *
2097
+ * This function checks if the specified alias is already being used in the query.
2098
+ * If the alias is available, it performs a left join with the provided entity, alias, and optional condition.
2099
+ * If the alias is already busy, the function returns early without modifying the query.
2100
+ *
2101
+ * @template T - The entity type that extends ObjectLiteral
2102
+ * @param query - The TypeORM SelectQueryBuilder instance to add the left join to
2103
+ * @param entity - The entity class (Function) or table name (string) to join
2104
+ * @param alias - The alias name to use for the joined entity
2105
+ * @param condition - Optional join condition as a string (e.g., "alias.id = entity.foreignId")
2106
+ * @returns void
2107
+ *
2108
+ * @example
2109
+ * ```typescript
2110
+ * ensureLeftJoin(queryBuilder, User, 'user', 'user.id = post.userId');
2111
+ * ```
2112
+ */
2113
+ const ensureLeftJoin = (query, entity, alias, condition) => {
2114
+ if (isAliasAlreadyBusy(query, alias)) return;
2115
+ query.leftJoin(entity, alias, condition);
2116
+ };
2117
+
2118
+ //#endregion
2119
+ //#region src/validation/validation-pipe.ts
2120
+ var NestKitValidationPipe = class extends ValidationPipe {
2121
+ createExceptionFactory() {
2122
+ return (validationErrors = []) => {
2123
+ if (!this.isDetailedOutputDisabled) return new InputValidationError(validationErrors);
2124
+ return new InputValidationError();
2125
+ };
2126
+ }
2127
+ };
2128
+
2129
+ //#endregion
2130
+ //#region src/exceptions/http-exceptions.filter.ts
2131
+ var _ref, _ref2, _HttpExceptionFilter;
2132
+ let HttpExceptionFilter = _HttpExceptionFilter = class HttpExceptionFilter$1 {
2133
+ logger;
2134
+ constructor(applicationRef, loggerFactory) {
2135
+ this.applicationRef = applicationRef;
2136
+ this.loggerFactory = loggerFactory;
2137
+ this.logger = this.loggerFactory.create({ scope: _HttpExceptionFilter.name });
2138
+ }
2139
+ catch(exception, host) {
2140
+ const type = GqlArgumentsHost.create(host).getType();
2141
+ const response = exception.getResponse();
2142
+ if (!response?.silent) if (isObject$1(response)) {
2143
+ const logger = this.loggerFactory.create(response.context);
2144
+ if (response.error instanceof Error) logger.error(response.message, response.error);
2145
+ else logger.error(exception);
2146
+ } else this.logger.error(exception);
2147
+ if (type !== "http") return exception;
2148
+ /**
2149
+ * If request is http, then we need to send response to client
2150
+ */
2151
+ let body;
2152
+ if (isObject$1(response)) {
2153
+ body = {
2154
+ key: response.key,
2155
+ message: response.message,
2156
+ context: response.context,
2157
+ statusCode: exception.getStatus()
2158
+ };
2159
+ if (response.error instanceof Error && process.env.NODE_ENV !== AppEnv.PRODUCTION) body.stack = response.error.stack;
2160
+ } else body = {
2161
+ statusCode: exception.getStatus(),
2162
+ message: response
2163
+ };
2164
+ this.applicationRef.reply(host.getArgByIndex(1), body, exception.getStatus());
2165
+ }
2166
+ };
2167
+ HttpExceptionFilter = _HttpExceptionFilter = __decorate([Catch(HttpException), __decorateMetadata("design:paramtypes", [typeof (_ref = typeof HttpServer !== "undefined" && HttpServer) === "function" ? _ref : Object, typeof (_ref2 = typeof LoggerFactory !== "undefined" && LoggerFactory) === "function" ? _ref2 : Object])], HttpExceptionFilter);
2168
+
2169
+ //#endregion
2170
+ export { APP_CONFIG_TOKEN, AccessDeniedError, AppConfigEnvironmentVariables, AppEnv, AppMode, AppServer, BadRequestError, DB_CONFIG_TOKEN, ForbiddenError, HttpExceptionFilter, InjectAppConfig, InjectDbConfig, InjectLogger, InjectLoggerConfig, InjectLoggerFactory, InputValidationError, LOGGER_CONFIG_TOKEN, Logger, LoggerFactory, LoggerModule, NESTKIT_LOGGER_FACTORY_PROVIDER, NESTKIT_LOGGER_MODULE_OPTIONS, NESTKIT_LOGGER_PROVIDER, NESTKIT_SYSTEM_LOGGER_PROVIDER, NESTKIT_WINSTON_LOGGER_PROVIDER, NestError, NestJsResourceService, NestJsService, NestKitValidationPipe, NestSystemLogger, NotFoundError, TypeOrmLogger, TypeOrmLoggerOptions, UnauthorizedError, WorkerMode, addFilterByField, compose, convertToBigInt, createAppConfig, createDbConfig, createListMeta, createLoggerAsyncProviders, createLoggerConfig, createLoggerProviders, createNestLogger, createPrettyMessage, defineStatuses, ensureInnerJoin, ensureLeftJoin, extractRequestId, fetchTotalWithQuery, generateEntityId, generateRequestId, getRequestLanguage, isAliasAlreadyBusy, isObject, localeToPgCollate, nestLikeConsoleFormat, pauseWithPromise, removeUndefinedProperties, stringifyOpts, validateEnv, wait, withColonEnv, withDashEnv, withDotEnv, withUnderscoreEnv };
2171
+ //# sourceMappingURL=index.js.map