@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.
- package/.turbo/turbo-build.log +15 -0
- package/CHANGELOG.md +7 -0
- package/dist/index.d.ts +1400 -0
- package/dist/index.js +2171 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
- package/src/abstracts/index.ts +3 -0
- package/src/abstracts/nestjs-resource-service.ts +154 -0
- package/src/abstracts/nestjs-service.ts +25 -0
- package/src/configs/app.config.ts +185 -0
- package/src/configs/db.config.ts +122 -0
- package/src/configs/index.ts +4 -0
- package/src/configs/logger.config.ts +62 -0
- package/src/context/action-context.ts +34 -0
- package/src/context/current-user.ts +49 -0
- package/src/context/index.ts +5 -0
- package/src/context/platform-method-context.ts +5 -0
- package/src/context/service-method-context.ts +47 -0
- package/src/db/snake-naming.strategy.ts +277 -0
- package/src/enums/app-env.enum.ts +36 -0
- package/src/enums/app-mode.enum.ts +5 -0
- package/src/enums/app-server.enum.ts +39 -0
- package/src/enums/index.ts +4 -0
- package/src/enums/worker-mode.enum.ts +11 -0
- package/src/errors/access-denied.error.ts +18 -0
- package/src/errors/bad-request.error.ts +9 -0
- package/src/errors/forbidden.error.ts +9 -0
- package/src/errors/index.ts +8 -0
- package/src/errors/input-validation.error.ts +16 -0
- package/src/errors/nest-error.filter.ts +70 -0
- package/src/errors/nest-error.ts +63 -0
- package/src/errors/not-found.error.ts +9 -0
- package/src/errors/unauthorized.error.ts +9 -0
- package/src/exceptions/http-exception-response.ts +34 -0
- package/src/exceptions/http-exceptions.filter.ts +95 -0
- package/src/index.ts +32 -0
- package/src/jwt/extractors.ts +80 -0
- package/src/jwt/types.ts +209 -0
- package/src/logger/classes/logger-factory.ts +54 -0
- package/src/logger/classes/logger.ts +340 -0
- package/src/logger/classes/nest-system-logger.ts +63 -0
- package/src/logger/classes/typeorm-logger.ts +83 -0
- package/src/logger/index.ts +20 -0
- package/src/logger/logger.constants.ts +24 -0
- package/src/logger/logger.interfaces.ts +98 -0
- package/src/logger/logger.module.ts +45 -0
- package/src/logger/logger.providers.ts +140 -0
- package/src/logger/winston.tools.ts +241 -0
- package/src/middlewares/app.middleware.ts +26 -0
- package/src/middlewares/index.ts +1 -0
- package/src/modules/hooks/base-hook.ts +64 -0
- package/src/modules/hooks/decorators/on-hook.decorator.ts +19 -0
- package/src/modules/hooks/hooks.module.ts +10 -0
- package/src/modules/hooks/hooks.service.ts +28 -0
- package/src/modules/hooks/index.ts +11 -0
- package/src/modules/id/id.module.ts +26 -0
- package/src/modules/id/id.service.ts +57 -0
- package/src/modules/id/index.ts +2 -0
- package/src/modules/postgres-pubsub/index.ts +3 -0
- package/src/modules/postgres-pubsub/postgres-pubsub.module.ts +14 -0
- package/src/modules/postgres-pubsub/postgres-pubsub.ts +461 -0
- package/src/pagination/constants.ts +9 -0
- package/src/pagination/cursor/cursor-pagination.exception.ts +16 -0
- package/src/pagination/cursor/cursor-pagination.helpers.ts +145 -0
- package/src/pagination/cursor/cursor-pagination.input.ts +96 -0
- package/src/pagination/cursor/cursor-pagination.types.ts +127 -0
- package/src/pagination/index.ts +9 -0
- package/src/pagination/offset/offset-pagination.exception.ts +15 -0
- package/src/pagination/offset/offset-pagination.helpers.ts +122 -0
- package/src/pagination/offset/offset-pagination.input.ts +30 -0
- package/src/pagination/offset/offset-pagination.types.ts +82 -0
- package/src/pagination/tools.ts +53 -0
- package/src/tools/compose.ts +92 -0
- package/src/tools/convert-to-bigint.ts +27 -0
- package/src/tools/create-list-meta.ts +64 -0
- package/src/tools/define-statuses.ts +15 -0
- package/src/tools/env.ts +139 -0
- package/src/tools/fetch-total-with-query.ts +48 -0
- package/src/tools/generate-entity-id.ts +23 -0
- package/src/tools/get-request-language.ts +13 -0
- package/src/tools/is-object.ts +10 -0
- package/src/tools/postgres/locale-to-pg-collate.ts +21 -0
- package/src/tools/remove-undefined-properties.ts +20 -0
- package/src/tools/request-id.ts +25 -0
- package/src/tools/stringify-opts.ts +20 -0
- package/src/tools/typeorm/add-filter.ts +164 -0
- package/src/tools/typeorm/ensure-inner-join.ts +36 -0
- package/src/tools/typeorm/ensure-left-join.ts +36 -0
- package/src/tools/typeorm/is-alias-already-busy.ts +25 -0
- package/src/tools/wait.ts +26 -0
- package/src/types/express-request.ts +8 -0
- package/src/types/list-mehod-options.ts +32 -0
- package/src/types/list-meta.ts +16 -0
- package/src/types/maybe.ts +2 -0
- package/src/validation/index.ts +1 -0
- package/src/validation/validation-pipe.ts +14 -0
- package/tsconfig.lib.json +9 -0
- 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
|