@russ-b/nestjs-common-tools 2.0.2 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -0
- package/dist/class-transformer/index.d.ts +2 -0
- package/dist/class-transformer/index.js +2 -0
- package/dist/class-transformer/index.js.map +1 -1
- package/dist/class-transformer/to-optional-number.decorator.d.ts +3 -0
- package/dist/class-transformer/to-optional-number.decorator.js +27 -0
- package/dist/class-transformer/to-optional-number.decorator.js.map +1 -0
- package/dist/class-transformer/to-optional-string.decorator.d.ts +3 -0
- package/dist/class-transformer/to-optional-string.decorator.js +17 -0
- package/dist/class-transformer/to-optional-string.decorator.js.map +1 -0
- package/dist/common/util/mask-string.util.d.ts +14 -0
- package/dist/common/util/mask-string.util.js +15 -0
- package/dist/common/util/mask-string.util.js.map +1 -1
- package/dist/logger/logger.d.ts +13 -0
- package/dist/logger/logger.js +13 -0
- package/dist/logger/logger.js.map +1 -1
- package/dist/modules/s3/s3.interface.d.ts +3 -0
- package/dist/pagination/dto/paginated-response.dto.d.ts +6 -0
- package/dist/pagination/dto/paginated-response.dto.js +6 -0
- package/dist/pagination/dto/paginated-response.dto.js.map +1 -1
- package/dist/pagination/pagination.d.ts +6 -0
- package/dist/pagination/pagination.js +6 -0
- package/dist/pagination/pagination.js.map +1 -1
- package/dist/typeorm/config/index.d.ts +3 -0
- package/dist/typeorm/config/index.js +20 -0
- package/dist/typeorm/config/index.js.map +1 -0
- package/dist/typeorm/config/mysql-typeorm-options.factory.d.ts +13 -0
- package/dist/typeorm/config/mysql-typeorm-options.factory.js +32 -0
- package/dist/typeorm/config/mysql-typeorm-options.factory.js.map +1 -0
- package/dist/typeorm/config/postgres-typeorm-options.factory.d.ts +19 -0
- package/dist/typeorm/config/postgres-typeorm-options.factory.js +71 -0
- package/dist/typeorm/config/postgres-typeorm-options.factory.js.map +1 -0
- package/dist/typeorm/config/typeorm-options.factory.d.ts +9 -0
- package/dist/typeorm/config/typeorm-options.factory.js +14 -0
- package/dist/typeorm/config/typeorm-options.factory.js.map +1 -0
- package/dist/typeorm/config/typeorm-options.util.d.ts +13 -0
- package/dist/typeorm/config/typeorm-options.util.js +29 -0
- package/dist/typeorm/config/typeorm-options.util.js.map +1 -0
- package/dist/typeorm/index.d.ts +1 -0
- package/dist/typeorm/index.js +1 -0
- package/dist/typeorm/index.js.map +1 -1
- package/dist/validators/entity/entity.decorator.d.ts +5 -0
- package/dist/validators/entity/entity.decorator.js +5 -0
- package/dist/validators/entity/entity.decorator.js.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -14,6 +14,14 @@ npm install @russ-b/nestjs-common-tools
|
|
|
14
14
|
|
|
15
15
|
Depending on which features you use, make sure the relevant peer dependencies are also installed in your project.
|
|
16
16
|
|
|
17
|
+
For TypeORM helpers that integrate with Nest's `TypeOrmModule`, install `@nestjs/typeorm` together with TypeORM and your database driver:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @nestjs/typeorm typeorm pg
|
|
21
|
+
# or, for MySQL
|
|
22
|
+
npm install @nestjs/typeorm typeorm mysql2
|
|
23
|
+
```
|
|
24
|
+
|
|
17
25
|
## Public entrypoints
|
|
18
26
|
|
|
19
27
|
This package uses subpath exports for most features.
|
|
@@ -211,6 +219,28 @@ It will:
|
|
|
211
219
|
- trim extra spaces and ignore case
|
|
212
220
|
- leave unsupported values unchanged
|
|
213
221
|
|
|
222
|
+
### `ToOptionalNumber`
|
|
223
|
+
|
|
224
|
+
`ToOptionalNumber()` is useful for DTO fields that may arrive as strings such as `'42'`, blank strings, or already parsed numbers.
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
import { ToOptionalNumber } from '@russ-b/nestjs-common-tools/class-transformer';
|
|
228
|
+
|
|
229
|
+
export class SearchDto {
|
|
230
|
+
@ToOptionalNumber()
|
|
231
|
+
page?: number;
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
It will:
|
|
236
|
+
|
|
237
|
+
- convert numeric strings to numbers
|
|
238
|
+
- trim extra spaces before parsing
|
|
239
|
+
- convert empty or blank strings to `undefined`
|
|
240
|
+
- keep `null` as `null`
|
|
241
|
+
- keep `undefined` as `undefined`
|
|
242
|
+
- return `NaN` for unsupported non-string values
|
|
243
|
+
|
|
214
244
|
## S3 Module
|
|
215
245
|
|
|
216
246
|
`S3Module` is a small NestJS wrapper around the AWS SDK v3 S3 client. It gives you a reusable `S3Service` with a simple Nest-friendly setup for uploads, downloads, deletes, and signed URLs.
|
|
@@ -483,6 +513,9 @@ export class AppModule {}
|
|
|
483
513
|
|
|
484
514
|
## Usage
|
|
485
515
|
|
|
516
|
+
> Deprecated: `IsEntity` couples DTO validation to persistence/service concerns.
|
|
517
|
+
> Keep entity existence checks in the service/application layer instead.
|
|
518
|
+
|
|
486
519
|
```typescript
|
|
487
520
|
import { IsEntity } from '@russ-b/nestjs-common-tools/validators';
|
|
488
521
|
|
|
@@ -528,6 +561,89 @@ export class AssignRolesDto {
|
|
|
528
561
|
}
|
|
529
562
|
```
|
|
530
563
|
|
|
564
|
+
## TypeORM Options Factories
|
|
565
|
+
|
|
566
|
+
`createTypeOrmOptions` creates Nest `TypeOrmModuleOptions` using driver-specific defaults. It currently supports PostgreSQL and MySQL.
|
|
567
|
+
|
|
568
|
+
```typescript
|
|
569
|
+
// app.module.ts
|
|
570
|
+
import { Module } from '@nestjs/common';
|
|
571
|
+
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
572
|
+
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
573
|
+
import { createTypeOrmOptions } from '@russ-b/nestjs-common-tools/typeorm';
|
|
574
|
+
|
|
575
|
+
@Module({
|
|
576
|
+
imports: [
|
|
577
|
+
ConfigModule.forRoot({
|
|
578
|
+
isGlobal: true,
|
|
579
|
+
}),
|
|
580
|
+
TypeOrmModule.forRootAsync({
|
|
581
|
+
imports: [ConfigModule],
|
|
582
|
+
inject: [ConfigService],
|
|
583
|
+
useFactory: (config: ConfigService) =>
|
|
584
|
+
createTypeOrmOptions({
|
|
585
|
+
type: 'postgres',
|
|
586
|
+
appName: 'parking-api',
|
|
587
|
+
databaseUrl: config.getOrThrow<string>('DATABASE_URL'),
|
|
588
|
+
schema: config.get<string>('DATABASE_SCHEMA'),
|
|
589
|
+
sync: config.get<string>('TYPEORM_SYNC'),
|
|
590
|
+
logging: config.get<string>('TYPEORM_LOGGING'),
|
|
591
|
+
isProduction: config.get<string>('NODE_ENV') === 'production',
|
|
592
|
+
}),
|
|
593
|
+
}),
|
|
594
|
+
],
|
|
595
|
+
})
|
|
596
|
+
export class AppModule {}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
PostgreSQL support is also exposed directly as `createPostgresTypeormOptions`. Its `schema` option is applied both as TypeORM's schema and as `search_path`, and pool options are passed through the `pg` driver via TypeORM's `extra` config.
|
|
600
|
+
|
|
601
|
+
For managed PostgreSQL providers that require SSL with a CA certificate, you can pass atomic connection fields and `sslCa`. This avoids `pg` overwriting the explicit `ssl` object when `sslmode` or `sslrootcert` exists in the connection string.
|
|
602
|
+
|
|
603
|
+
```typescript
|
|
604
|
+
TypeOrmModule.forRootAsync({
|
|
605
|
+
imports: [ConfigModule],
|
|
606
|
+
inject: [ConfigService],
|
|
607
|
+
useFactory: (config: ConfigService) =>
|
|
608
|
+
createTypeOrmOptions({
|
|
609
|
+
type: 'postgres',
|
|
610
|
+
database: {
|
|
611
|
+
host: config.getOrThrow<string>('DB_HOST'),
|
|
612
|
+
port: config.get<number>('DB_PORT'),
|
|
613
|
+
username: config.getOrThrow<string>('DB_USER'),
|
|
614
|
+
password: config.getOrThrow<string>('DB_PASSWORD'),
|
|
615
|
+
database: config.getOrThrow<string>('DB_NAME'),
|
|
616
|
+
},
|
|
617
|
+
sslCa: config.get<string>('DB_CA_CERT'),
|
|
618
|
+
sync: config.get<string>('TYPEORM_SYNC'),
|
|
619
|
+
logging: config.get<string>('TYPEORM_LOGGING'),
|
|
620
|
+
isProduction: config.get<string>('NODE_ENV') === 'production',
|
|
621
|
+
}),
|
|
622
|
+
});
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
When `sslCa` is used together with `databaseUrl`, SSL-related query params such as `sslmode` and `sslrootcert` are removed from the URL before TypeORM passes the config to `pg`.
|
|
626
|
+
|
|
627
|
+
For MySQL, use `type: 'mysql'` or call `createMysqlTypeormOptions` directly:
|
|
628
|
+
|
|
629
|
+
```typescript
|
|
630
|
+
TypeOrmModule.forRootAsync({
|
|
631
|
+
imports: [ConfigModule],
|
|
632
|
+
inject: [ConfigService],
|
|
633
|
+
useFactory: (config: ConfigService) =>
|
|
634
|
+
createTypeOrmOptions({
|
|
635
|
+
type: 'mysql',
|
|
636
|
+
databaseUrl: config.getOrThrow<string>('DATABASE_URL'),
|
|
637
|
+
sync: config.get<string>('TYPEORM_SYNC'),
|
|
638
|
+
logging: config.get<string>('TYPEORM_LOGGING'),
|
|
639
|
+
isProduction: config.get<string>('NODE_ENV') === 'production',
|
|
640
|
+
connectorPackage: 'mysql2',
|
|
641
|
+
}),
|
|
642
|
+
});
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
The MySQL factory uses TypeORM's `poolSize`, `connectTimeout`, and `acquireTimeout` options instead of PostgreSQL-only `search_path`, `application_name`, or `query_timeout` settings.
|
|
646
|
+
|
|
531
647
|
## TypeORM Exception Filter
|
|
532
648
|
|
|
533
649
|
When you want to convert low-level database errors into meaningful HTTP responses, a TypeORM exception filter helps keep that logic out of controllers and services. You can register it once and optionally override specific constraints with your own domain-friendly messages.
|
|
@@ -16,4 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./to-string-array.decorator"), exports);
|
|
18
18
|
__exportStar(require("./to-boolean-from-string.decorator"), exports);
|
|
19
|
+
__exportStar(require("./to-optional-string.decorator"), exports);
|
|
20
|
+
__exportStar(require("./to-optional-number.decorator"), exports);
|
|
19
21
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/class-transformer/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8DAA4C;AAC5C,qEAAmD"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/class-transformer/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8DAA4C;AAC5C,qEAAmD;AACnD,iEAA+C;AAC/C,iEAA+C"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseOptionalNumberTransformer = void 0;
|
|
4
|
+
exports.ToOptionalNumber = ToOptionalNumber;
|
|
5
|
+
const class_transformer_1 = require("class-transformer");
|
|
6
|
+
function ToOptionalNumber() {
|
|
7
|
+
return (0, class_transformer_1.Transform)(exports.parseOptionalNumberTransformer);
|
|
8
|
+
}
|
|
9
|
+
const parseOptionalNumberTransformer = ({ value, }) => normalizeOptionalNumber(value);
|
|
10
|
+
exports.parseOptionalNumberTransformer = parseOptionalNumberTransformer;
|
|
11
|
+
function normalizeOptionalNumber(value) {
|
|
12
|
+
if (value === null) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
if (value === undefined) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
if (typeof value === 'string') {
|
|
19
|
+
const trimmedValue = value.trim();
|
|
20
|
+
return trimmedValue === '' ? undefined : Number(trimmedValue);
|
|
21
|
+
}
|
|
22
|
+
if (typeof value === 'number') {
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
return Number.NaN;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=to-optional-number.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-optional-number.decorator.js","sourceRoot":"","sources":["../../src/class-transformer/to-optional-number.decorator.ts"],"names":[],"mappings":";;;AAEA,4CAEC;AAJD,yDAAiE;AAEjE,SAAgB,gBAAgB;IAC9B,OAAO,IAAA,6BAAS,EAAC,sCAA8B,CAAC,CAAC;AACnD,CAAC;AAEM,MAAM,8BAA8B,GAAG,CAAC,EAC7C,KAAK,GACa,EAAW,EAAE,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;AAFpD,QAAA,8BAA8B,kCAEsB;AAEjE,SAAS,uBAAuB,CAAC,KAAc;IAC7C,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAElC,OAAO,YAAY,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,MAAM,CAAC,GAAG,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeOptionalStringTransformer = void 0;
|
|
4
|
+
exports.ToOptionalString = ToOptionalString;
|
|
5
|
+
const class_transformer_1 = require("class-transformer");
|
|
6
|
+
function ToOptionalString() {
|
|
7
|
+
return (0, class_transformer_1.Transform)(exports.normalizeOptionalStringTransformer);
|
|
8
|
+
}
|
|
9
|
+
const normalizeOptionalStringTransformer = ({ value, }) => {
|
|
10
|
+
if (typeof value !== 'string') {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
const trimmedValue = value.trim();
|
|
14
|
+
return trimmedValue === '' ? undefined : trimmedValue;
|
|
15
|
+
};
|
|
16
|
+
exports.normalizeOptionalStringTransformer = normalizeOptionalStringTransformer;
|
|
17
|
+
//# sourceMappingURL=to-optional-string.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-optional-string.decorator.js","sourceRoot":"","sources":["../../src/class-transformer/to-optional-string.decorator.ts"],"names":[],"mappings":";;;AAEA,4CAEC;AAJD,yDAAiE;AAEjE,SAAgB,gBAAgB;IAC9B,OAAO,IAAA,6BAAS,EAAC,0CAAkC,CAAC,CAAC;AACvD,CAAC;AAEM,MAAM,kCAAkC,GAAG,CAAC,EACjD,KAAK,GACa,EAAW,EAAE;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAElC,OAAO,YAAY,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC;AACxD,CAAC,CAAC;AAVW,QAAA,kCAAkC,sCAU7C"}
|
|
@@ -1 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Masks a string, leaving only the last N characters visible
|
|
3
|
+
*
|
|
4
|
+
* @param value - The string to mask
|
|
5
|
+
* @param visibleChars - Number of characters to leave visible at the end (default: 4)
|
|
6
|
+
* @param maskChar - Character to use for masking (default: '*')
|
|
7
|
+
* @param preservePrefix - Number of characters to preserve at the start (optional)
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* maskString('+37369313123', 4) // '+373*****3123'
|
|
11
|
+
* maskString('+37369313123', 4, '*', 4) // '+373*****3123'
|
|
12
|
+
* maskString('user@example.com', 4) // '***********.com'
|
|
13
|
+
* maskString('1234567890', 4) // '******7890'
|
|
14
|
+
*/
|
|
1
15
|
export declare function maskString(value: string, visibleChars?: number, maskChar?: string, preservePrefix?: number): string;
|
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.maskString = maskString;
|
|
4
|
+
/**
|
|
5
|
+
* Masks a string, leaving only the last N characters visible
|
|
6
|
+
*
|
|
7
|
+
* @param value - The string to mask
|
|
8
|
+
* @param visibleChars - Number of characters to leave visible at the end (default: 4)
|
|
9
|
+
* @param maskChar - Character to use for masking (default: '*')
|
|
10
|
+
* @param preservePrefix - Number of characters to preserve at the start (optional)
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* maskString('+37369313123', 4) // '+373*****3123'
|
|
14
|
+
* maskString('+37369313123', 4, '*', 4) // '+373*****3123'
|
|
15
|
+
* maskString('user@example.com', 4) // '***********.com'
|
|
16
|
+
* maskString('1234567890', 4) // '******7890'
|
|
17
|
+
*/
|
|
4
18
|
function maskString(value, visibleChars = 4, maskChar = '*', preservePrefix) {
|
|
5
19
|
if (!value || value.length === 0) {
|
|
6
20
|
return '';
|
|
7
21
|
}
|
|
22
|
+
// If string is too short to mask meaningfully
|
|
8
23
|
if (value.length <= visibleChars) {
|
|
9
24
|
return maskChar.repeat(value.length);
|
|
10
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mask-string.util.js","sourceRoot":"","sources":["../../../src/common/util/mask-string.util.ts"],"names":[],"mappings":";;AAcA,gCA6BC;
|
|
1
|
+
{"version":3,"file":"mask-string.util.js","sourceRoot":"","sources":["../../../src/common/util/mask-string.util.ts"],"names":[],"mappings":";;AAcA,gCA6BC;AA3CD;;;;;;;;;;;;;GAaG;AACH,SAAgB,UAAU,CACxB,KAAa,EACb,eAAuB,CAAC,EACxB,WAAmB,GAAG,EACtB,cAAuB;IAEvB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,8CAA8C;IAC9C,IAAI,KAAK,CAAC,MAAM,IAAI,YAAY,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;IAE7C,IAAI,cAAc,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;QAC9C,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,GAAG,cAAc,GAAG,YAAY,CAAC;QAClE,MAAM,MAAM,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAErE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,EAAE,CAAC;IAC1C,CAAC;IAED,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,GAAG,YAAY,CAAC;IACjD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAE7C,OAAO,GAAG,MAAM,GAAG,SAAS,EAAE,CAAC;AACjC,CAAC"}
|
package/dist/logger/logger.d.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { LogLevelType, TransportOptions, TransportType } from './types';
|
|
2
2
|
import { LoggerBuilder } from './logger-builder';
|
|
3
3
|
export declare class Logger {
|
|
4
|
+
/**
|
|
5
|
+
* Creates a fluent logger builder
|
|
6
|
+
* @param appName - Application name (default: 'NestApp')
|
|
7
|
+
* @param level - Log level (default: 'debug')
|
|
8
|
+
* @returns LoggerBuilder instance
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const logger = Logger.builder('MyApp', 'info')
|
|
12
|
+
* .addTransport('json')
|
|
13
|
+
* .addTransport('loki', { lokiUrl: 'http://...' })
|
|
14
|
+
* .build();
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
4
17
|
static builder(appName?: string, level?: LogLevelType): LoggerBuilder;
|
|
5
18
|
private static normalizeFormats;
|
|
6
19
|
static create(appName: string, level: LogLevelType, formats?: TransportType[] | TransportType, options?: TransportOptions): import("@nestjs/common").LoggerService;
|
package/dist/logger/logger.js
CHANGED
|
@@ -3,6 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Logger = void 0;
|
|
4
4
|
const logger_builder_1 = require("./logger-builder");
|
|
5
5
|
class Logger {
|
|
6
|
+
/**
|
|
7
|
+
* Creates a fluent logger builder
|
|
8
|
+
* @param appName - Application name (default: 'NestApp')
|
|
9
|
+
* @param level - Log level (default: 'debug')
|
|
10
|
+
* @returns LoggerBuilder instance
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const logger = Logger.builder('MyApp', 'info')
|
|
14
|
+
* .addTransport('json')
|
|
15
|
+
* .addTransport('loki', { lokiUrl: 'http://...' })
|
|
16
|
+
* .build();
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
6
19
|
static builder(appName, level) {
|
|
7
20
|
return new logger_builder_1.LoggerBuilder(appName, level);
|
|
8
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/logger/logger.ts"],"names":[],"mappings":";;;AACA,qDAAiD;AAEjD,MAAa,MAAM;
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/logger/logger.ts"],"names":[],"mappings":";;;AACA,qDAAiD;AAEjD,MAAa,MAAM;IACjB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,OAAO,CAAC,OAAgB,EAAE,KAAoB;QACnD,OAAO,IAAI,8BAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAEO,MAAM,CAAC,gBAAgB,CAC7B,OAAyC;QAEzC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,CAAC,MAAM,CACX,OAAe,EACf,KAAmB,EACnB,OAAyC,EACzC,OAA0B;QAE1B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAE/C,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAE7C,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QAE5E,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;IAEO,MAAM,CAAC,qBAAqB,CAClC,OAAsB,EACtB,IAAmB,EACnB,OAA0B;QAE1B,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,MAAM;gBACT,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;oBACnB,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;gBACzE,CAAC;gBACD,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;gBACzC,MAAM;YACR,KAAK,MAAM;gBACT,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;gBAC1C,MAAM;YACR,KAAK,MAAM;gBACT,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;gBAC1C,MAAM;QACV,CAAC;IACH,CAAC;CACF;AA/DD,wBA+DC"}
|
|
@@ -10,6 +10,9 @@ export interface S3ModuleOptions {
|
|
|
10
10
|
requestChecksumCalculation?: S3ClientConfig['requestChecksumCalculation'];
|
|
11
11
|
responseChecksumValidation?: S3ClientConfig['responseChecksumValidation'];
|
|
12
12
|
defaultBucket?: string;
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated Use defaultBucket instead.
|
|
15
|
+
*/
|
|
13
16
|
bucket?: string;
|
|
14
17
|
logger?: boolean | S3ModuleLogger;
|
|
15
18
|
}
|
|
@@ -19,6 +19,12 @@ export declare class LegacyPaginatedResponseDto<T> implements LegacyPaginatedRes
|
|
|
19
19
|
pagination: LegacyPaginationMetaDto;
|
|
20
20
|
data: T[];
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* @deprecated This DTO preserves the legacy pagination shape
|
|
24
|
+
* (`totalItems` / `totalPages`).
|
|
25
|
+
* Use PaginationResponseDto for the standard contract or
|
|
26
|
+
* LegacyPaginatedResponseDto when you explicitly need the legacy contract.
|
|
27
|
+
*/
|
|
22
28
|
export declare class PaginatedResponseDto<T> extends LegacyPaginatedResponseDto<T> {
|
|
23
29
|
}
|
|
24
30
|
export {};
|
|
@@ -83,6 +83,12 @@ __decorate([
|
|
|
83
83
|
exports.LegacyPaginatedResponseDto = LegacyPaginatedResponseDto = __decorate([
|
|
84
84
|
(0, class_transformer_1.Exclude)()
|
|
85
85
|
], LegacyPaginatedResponseDto);
|
|
86
|
+
/**
|
|
87
|
+
* @deprecated This DTO preserves the legacy pagination shape
|
|
88
|
+
* (`totalItems` / `totalPages`).
|
|
89
|
+
* Use PaginationResponseDto for the standard contract or
|
|
90
|
+
* LegacyPaginatedResponseDto when you explicitly need the legacy contract.
|
|
91
|
+
*/
|
|
86
92
|
class PaginatedResponseDto extends LegacyPaginatedResponseDto {
|
|
87
93
|
}
|
|
88
94
|
exports.PaginatedResponseDto = PaginatedResponseDto;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paginated-response.dto.js","sourceRoot":"","sources":["../../../src/pagination/dto/paginated-response.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,yDAA0D;AAS1D,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;CAYtB,CAAA;AAVC;IADC,IAAA,0BAAM,GAAE;;gDACK;AAGd;IADC,IAAA,0BAAM,GAAE;;gDACK;AAGd;IADC,IAAA,0BAAM,GAAE;;+CACI;AAGb;IADC,IAAA,0BAAM,GAAE;;kDACO;AAXZ,iBAAiB;IADtB,IAAA,2BAAO,GAAE;GACJ,iBAAiB,CAYtB;AAGD,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;CAY5B,CAAA;AAVC;IADC,IAAA,0BAAM,GAAE;;2DACU;AAGnB;IADC,IAAA,0BAAM,GAAE;;2DACU;AAGnB;IADC,IAAA,0BAAM,GAAE;;qDACI;AAGb;IADC,IAAA,0BAAM,GAAE;;wDACO;AAXZ,uBAAuB;IAD5B,IAAA,2BAAO,GAAE;GACJ,uBAAuB,CAY5B;AAGM,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;CAOjC,CAAA;AAPY,sDAAqB;AAGhC;IAFC,IAAA,0BAAM,GAAE;IACR,IAAA,wBAAI,EAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC;8BAClB,iBAAiB;yDAAC;AAG9B;IADC,IAAA,0BAAM,GAAE;;mDACC;gCANC,qBAAqB;IADjC,IAAA,2BAAO,GAAE;GACG,qBAAqB,CAOjC;AAGM,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;CAStC,CAAA;AATY,gEAA0B;AAKrC;IAFC,IAAA,0BAAM,GAAE;IACR,IAAA,wBAAI,EAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC;8BACxB,uBAAuB;8DAAC;AAGpC;IADC,IAAA,0BAAM,GAAE;;wDACC;qCARC,0BAA0B;IADtC,IAAA,2BAAO,GAAE;GACG,0BAA0B,CAStC;
|
|
1
|
+
{"version":3,"file":"paginated-response.dto.js","sourceRoot":"","sources":["../../../src/pagination/dto/paginated-response.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,yDAA0D;AAS1D,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;CAYtB,CAAA;AAVC;IADC,IAAA,0BAAM,GAAE;;gDACK;AAGd;IADC,IAAA,0BAAM,GAAE;;gDACK;AAGd;IADC,IAAA,0BAAM,GAAE;;+CACI;AAGb;IADC,IAAA,0BAAM,GAAE;;kDACO;AAXZ,iBAAiB;IADtB,IAAA,2BAAO,GAAE;GACJ,iBAAiB,CAYtB;AAGD,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;CAY5B,CAAA;AAVC;IADC,IAAA,0BAAM,GAAE;;2DACU;AAGnB;IADC,IAAA,0BAAM,GAAE;;2DACU;AAGnB;IADC,IAAA,0BAAM,GAAE;;qDACI;AAGb;IADC,IAAA,0BAAM,GAAE;;wDACO;AAXZ,uBAAuB;IAD5B,IAAA,2BAAO,GAAE;GACJ,uBAAuB,CAY5B;AAGM,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;CAOjC,CAAA;AAPY,sDAAqB;AAGhC;IAFC,IAAA,0BAAM,GAAE;IACR,IAAA,wBAAI,EAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC;8BAClB,iBAAiB;yDAAC;AAG9B;IADC,IAAA,0BAAM,GAAE;;mDACC;gCANC,qBAAqB;IADjC,IAAA,2BAAO,GAAE;GACG,qBAAqB,CAOjC;AAGM,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;CAStC,CAAA;AATY,gEAA0B;AAKrC;IAFC,IAAA,0BAAM,GAAE;IACR,IAAA,wBAAI,EAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC;8BACxB,uBAAuB;8DAAC;AAGpC;IADC,IAAA,0BAAM,GAAE;;wDACC;qCARC,0BAA0B;IADtC,IAAA,2BAAO,GAAE;GACG,0BAA0B,CAStC;AAED;;;;;GAKG;AACH,MAAa,oBAAwB,SAAQ,0BAA6B;CAAG;AAA7E,oDAA6E"}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { CountableResponse, LegacyPaginatedResponse, PaginatedResponse, PaginationParams, PaginationRequest } from './interfaces/pagination.interface';
|
|
2
2
|
export declare abstract class Pagination {
|
|
3
3
|
static params(page: number, perPage: number): PaginationParams;
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated Use params instead.
|
|
6
|
+
*/
|
|
4
7
|
static paginationParams(page: number, perPage: number): PaginationParams;
|
|
5
8
|
static offset(page: number, perPage: number): number;
|
|
6
9
|
static createResponse<T>({ page, perPage }: PaginationRequest, [data, total]: CountableResponse<T>): PaginatedResponse<T>;
|
|
7
10
|
static createLegacyResponse<T>({ page, perPage }: PaginationRequest, [data, total]: CountableResponse<T>): LegacyPaginatedResponse<T>;
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Use createLegacyResponse instead.
|
|
13
|
+
*/
|
|
8
14
|
static response<T>(pagination: PaginationRequest, result: CountableResponse<T>): LegacyPaginatedResponse<T>;
|
|
9
15
|
private static createMeta;
|
|
10
16
|
private static createLegacyMeta;
|
|
@@ -7,6 +7,9 @@ class Pagination {
|
|
|
7
7
|
static params(page, perPage) {
|
|
8
8
|
return { perPage, offset: Pagination.offset(page, perPage) };
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* @deprecated Use params instead.
|
|
12
|
+
*/
|
|
10
13
|
static paginationParams(page, perPage) {
|
|
11
14
|
return Pagination.params(page, perPage);
|
|
12
15
|
}
|
|
@@ -25,6 +28,9 @@ class Pagination {
|
|
|
25
28
|
pagination: Pagination.createLegacyMeta(Pagination.createMeta(page, perPage, total)),
|
|
26
29
|
};
|
|
27
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* @deprecated Use createLegacyResponse instead.
|
|
33
|
+
*/
|
|
28
34
|
static response(pagination, result) {
|
|
29
35
|
try {
|
|
30
36
|
return Pagination.createLegacyResponse(pagination, result);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/pagination/pagination.ts"],"names":[],"mappings":";;;AAAA,2CAAqD;AAUrD,6CAA8E;AAE9E,MAAsB,UAAU;IAC9B,MAAM,CAAC,MAAM,CAAC,IAAY,EAAE,OAAe;QACzC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;IAC/D,CAAC;
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/pagination/pagination.ts"],"names":[],"mappings":";;;AAAA,2CAAqD;AAUrD,6CAA8E;AAE9E,MAAsB,UAAU;IAC9B,MAAM,CAAC,MAAM,CAAC,IAAY,EAAE,OAAe;QACzC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;IAC/D,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,IAAY,EAAE,OAAe;QACnD,OAAO,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,IAAY,EAAE,OAAe;QACzC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC;IAC9B,CAAC;IAED,MAAM,CAAC,cAAc,CACnB,EAAE,IAAI,EAAE,OAAO,EAAqB,EACpC,CAAC,IAAI,EAAE,KAAK,CAAuB;QAEnC,OAAO;YACL,IAAI;YACJ,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC;SACxD,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,oBAAoB,CACzB,EAAE,IAAI,EAAE,OAAO,EAAqB,EACpC,CAAC,IAAI,EAAE,KAAK,CAAuB;QAEnC,OAAO;YACL,IAAI;YACJ,UAAU,EAAE,UAAU,CAAC,gBAAgB,CACrC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAC5C;SACF,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,QAAQ,CACb,UAA6B,EAC7B,MAA4B;QAE5B,IAAI,CAAC;YACH,OAAO,UAAU,CAAC,oBAAoB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,sCAAyB,EAAE,CAAC;gBAC/C,MAAM,IAAI,4BAAmB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC/C,CAAC;YAED,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,UAAU,CACvB,IAAY,EACZ,OAAe,EACf,KAAa;QAEb,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC;QAEzC,IAAI,IAAI,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,gCAAmB,EAAE,CAAC;QAClC,CAAC;QAED,OAAO;YACL,KAAK;YACL,KAAK;YACL,OAAO;YACP,IAAI;SACL,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,gBAAgB,CAAC,EAC9B,KAAK,EACL,KAAK,EACL,IAAI,EACJ,OAAO,GACQ;QACf,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,UAAU,EAAE,KAAK;YACjB,OAAO;YACP,IAAI;SACL,CAAC;IACJ,CAAC;CACF;AAxFD,gCAwFC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./postgres-typeorm-options.factory"), exports);
|
|
18
|
+
__exportStar(require("./mysql-typeorm-options.factory"), exports);
|
|
19
|
+
__exportStar(require("./typeorm-options.factory"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/typeorm/config/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qEAAmD;AACnD,kEAAgD;AAChD,4DAA0C"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
|
2
|
+
import { CommonTypeormConfigOptions } from './typeorm-options.util';
|
|
3
|
+
export interface MysqlTypeormConfigOptions extends CommonTypeormConfigOptions {
|
|
4
|
+
type?: 'mysql';
|
|
5
|
+
connectTimeout?: number;
|
|
6
|
+
acquireTimeout?: number;
|
|
7
|
+
charset?: string;
|
|
8
|
+
timezone?: string;
|
|
9
|
+
connectorPackage?: 'mysql' | 'mysql2';
|
|
10
|
+
supportBigNumbers?: boolean;
|
|
11
|
+
bigNumberStrings?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function createMysqlTypeormOptions(options: MysqlTypeormConfigOptions): TypeOrmModuleOptions;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMysqlTypeormOptions = createMysqlTypeormOptions;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const typeorm_options_util_1 = require("./typeorm-options.util");
|
|
6
|
+
const logger = new common_1.Logger('MysqlTypeormConfig');
|
|
7
|
+
function createMysqlTypeormOptions(options) {
|
|
8
|
+
const resolvedOptions = {
|
|
9
|
+
...typeorm_options_util_1.TYPEORM_CONFIG_DEFAULTS,
|
|
10
|
+
connectTimeout: 5000,
|
|
11
|
+
acquireTimeout: 30_000,
|
|
12
|
+
...options,
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
type: 'mysql',
|
|
16
|
+
url: encodeURI(resolvedOptions.databaseUrl),
|
|
17
|
+
autoLoadEntities: true,
|
|
18
|
+
maxQueryExecutionTime: resolvedOptions.maxQueryExecutionTime,
|
|
19
|
+
synchronize: (0, typeorm_options_util_1.useSynchronize)(resolvedOptions, logger),
|
|
20
|
+
logging: (0, typeorm_options_util_1.useLogging)(resolvedOptions.logging),
|
|
21
|
+
retryAttempts: 5,
|
|
22
|
+
poolSize: resolvedOptions.maxConnections,
|
|
23
|
+
connectTimeout: resolvedOptions.connectTimeout,
|
|
24
|
+
acquireTimeout: resolvedOptions.acquireTimeout,
|
|
25
|
+
charset: resolvedOptions.charset,
|
|
26
|
+
timezone: resolvedOptions.timezone,
|
|
27
|
+
connectorPackage: resolvedOptions.connectorPackage,
|
|
28
|
+
supportBigNumbers: resolvedOptions.supportBigNumbers,
|
|
29
|
+
bigNumberStrings: resolvedOptions.bigNumberStrings,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=mysql-typeorm-options.factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mysql-typeorm-options.factory.js","sourceRoot":"","sources":["../../../src/typeorm/config/mysql-typeorm-options.factory.ts"],"names":[],"mappings":";;AAoCA,8DA2BC;AA/DD,2CAAwC;AAExC,iEAMgC;AA0BhC,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,oBAAoB,CAAC,CAAC;AAEhD,SAAgB,yBAAyB,CACvC,OAAkC;IAElC,MAAM,eAAe,GAAsC;QACzD,GAAG,8CAAuB;QAC1B,cAAc,EAAE,IAAI;QACpB,cAAc,EAAE,MAAM;QACtB,GAAG,OAAO;KACX,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,OAAO;QACb,GAAG,EAAE,SAAS,CAAC,eAAe,CAAC,WAAW,CAAC;QAC3C,gBAAgB,EAAE,IAAI;QACtB,qBAAqB,EAAE,eAAe,CAAC,qBAAqB;QAC5D,WAAW,EAAE,IAAA,qCAAc,EAAC,eAAe,EAAE,MAAM,CAAC;QACpD,OAAO,EAAE,IAAA,iCAAU,EAAC,eAAe,CAAC,OAAO,CAAC;QAC5C,aAAa,EAAE,CAAC;QAChB,QAAQ,EAAE,eAAe,CAAC,cAAc;QACxC,cAAc,EAAE,eAAe,CAAC,cAAc;QAC9C,cAAc,EAAE,eAAe,CAAC,cAAc;QAC9C,OAAO,EAAE,eAAe,CAAC,OAAO;QAChC,QAAQ,EAAE,eAAe,CAAC,QAAQ;QAClC,gBAAgB,EAAE,eAAe,CAAC,gBAAgB;QAClD,iBAAiB,EAAE,eAAe,CAAC,iBAAiB;QACpD,gBAAgB,EAAE,eAAe,CAAC,gBAAgB;KACnD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
|
2
|
+
import { CommonTypeormConfigOptions } from './typeorm-options.util';
|
|
3
|
+
export interface PostgresTypeormDatabaseConnectionOptions {
|
|
4
|
+
host: string;
|
|
5
|
+
port?: number;
|
|
6
|
+
username: string;
|
|
7
|
+
password: string;
|
|
8
|
+
database: string;
|
|
9
|
+
}
|
|
10
|
+
export interface PostgresTypeormConfigOptions extends Omit<CommonTypeormConfigOptions, 'databaseUrl'> {
|
|
11
|
+
type?: 'postgres';
|
|
12
|
+
databaseUrl?: string;
|
|
13
|
+
database?: PostgresTypeormDatabaseConnectionOptions;
|
|
14
|
+
appName?: string;
|
|
15
|
+
schema?: string;
|
|
16
|
+
sslCa?: string;
|
|
17
|
+
queryTimeout?: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function createPostgresTypeormOptions(options: PostgresTypeormConfigOptions): TypeOrmModuleOptions;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createPostgresTypeormOptions = createPostgresTypeormOptions;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const typeorm_options_util_1 = require("./typeorm-options.util");
|
|
6
|
+
const logger = new common_1.Logger('PostgresTypeormConfig');
|
|
7
|
+
function createPostgresTypeormOptions(options) {
|
|
8
|
+
const resolvedOptions = {
|
|
9
|
+
...typeorm_options_util_1.TYPEORM_CONFIG_DEFAULTS,
|
|
10
|
+
queryTimeout: 30_000,
|
|
11
|
+
...options,
|
|
12
|
+
};
|
|
13
|
+
const connectionOptions = createConnectionOptions(resolvedOptions);
|
|
14
|
+
const ssl = createSslOptions(resolvedOptions.sslCa);
|
|
15
|
+
return {
|
|
16
|
+
type: 'postgres',
|
|
17
|
+
...connectionOptions,
|
|
18
|
+
...(ssl ? { ssl } : {}),
|
|
19
|
+
autoLoadEntities: true,
|
|
20
|
+
schema: resolvedOptions.schema,
|
|
21
|
+
maxQueryExecutionTime: resolvedOptions.maxQueryExecutionTime,
|
|
22
|
+
synchronize: (0, typeorm_options_util_1.useSynchronize)(resolvedOptions, logger),
|
|
23
|
+
logging: (0, typeorm_options_util_1.useLogging)(resolvedOptions.logging),
|
|
24
|
+
retryAttempts: 5,
|
|
25
|
+
extra: {
|
|
26
|
+
options: resolvedOptions.schema
|
|
27
|
+
? `-c search_path=${resolvedOptions.schema},public`
|
|
28
|
+
: undefined,
|
|
29
|
+
max: resolvedOptions.maxConnections,
|
|
30
|
+
idleTimeoutMillis: 10000,
|
|
31
|
+
connectionTimeoutMillis: 5000,
|
|
32
|
+
maxUses: 10000,
|
|
33
|
+
keepAlive: true,
|
|
34
|
+
...(resolvedOptions.appName
|
|
35
|
+
? { application_name: resolvedOptions.appName }
|
|
36
|
+
: {}),
|
|
37
|
+
query_timeout: resolvedOptions.queryTimeout,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function createConnectionOptions(options) {
|
|
42
|
+
if (options.database) {
|
|
43
|
+
return options.database;
|
|
44
|
+
}
|
|
45
|
+
if (!options.databaseUrl) {
|
|
46
|
+
throw new Error('databaseUrl or database connection options must be configured.');
|
|
47
|
+
}
|
|
48
|
+
const databaseUrl = encodeURI(options.databaseUrl);
|
|
49
|
+
return {
|
|
50
|
+
url: options.sslCa
|
|
51
|
+
? removeConnectionStringSslParams(databaseUrl)
|
|
52
|
+
: databaseUrl,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function createSslOptions(sslCa) {
|
|
56
|
+
if (!sslCa) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
ca: sslCa.replace(/\\n/g, '\n'),
|
|
61
|
+
rejectUnauthorized: true,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function removeConnectionStringSslParams(databaseUrl) {
|
|
65
|
+
const parsedUrl = new URL(databaseUrl);
|
|
66
|
+
for (const param of ['ssl', 'sslcert', 'sslkey', 'sslmode', 'sslrootcert']) {
|
|
67
|
+
parsedUrl.searchParams.delete(param);
|
|
68
|
+
}
|
|
69
|
+
return parsedUrl.toString();
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=postgres-typeorm-options.factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-typeorm-options.factory.js","sourceRoot":"","sources":["../../../src/typeorm/config/postgres-typeorm-options.factory.ts"],"names":[],"mappings":";;AAuDA,oEAoCC;AA3FD,2CAAwC;AAGxC,iEAKgC;AA6ChC,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,uBAAuB,CAAC,CAAC;AAEnD,SAAgB,4BAA4B,CAC1C,OAAqC;IAErC,MAAM,eAAe,GAAyC;QAC5D,GAAG,8CAAuB;QAC1B,YAAY,EAAE,MAAM;QACpB,GAAG,OAAO;KACX,CAAC;IACF,MAAM,iBAAiB,GAAG,uBAAuB,CAAC,eAAe,CAAC,CAAC;IACnE,MAAM,GAAG,GAAG,gBAAgB,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAEpD,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,GAAG,iBAAiB;QACpB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvB,gBAAgB,EAAE,IAAI;QACtB,MAAM,EAAE,eAAe,CAAC,MAAM;QAC9B,qBAAqB,EAAE,eAAe,CAAC,qBAAqB;QAC5D,WAAW,EAAE,IAAA,qCAAc,EAAC,eAAe,EAAE,MAAM,CAAC;QACpD,OAAO,EAAE,IAAA,iCAAU,EAAC,eAAe,CAAC,OAAO,CAAC;QAC5C,aAAa,EAAE,CAAC;QAChB,KAAK,EAAE;YACL,OAAO,EAAE,eAAe,CAAC,MAAM;gBAC7B,CAAC,CAAC,kBAAkB,eAAe,CAAC,MAAM,SAAS;gBACnD,CAAC,CAAC,SAAS;YACb,GAAG,EAAE,eAAe,CAAC,cAAc;YACnC,iBAAiB,EAAE,KAAK;YACxB,uBAAuB,EAAE,IAAI;YAC7B,OAAO,EAAE,KAAK;YACd,SAAS,EAAE,IAAI;YACf,GAAG,CAAC,eAAe,CAAC,OAAO;gBACzB,CAAC,CAAC,EAAE,gBAAgB,EAAE,eAAe,CAAC,OAAO,EAAE;gBAC/C,CAAC,CAAC,EAAE,CAAC;YACP,aAAa,EAAE,eAAe,CAAC,YAAY;SAC5C;KACF,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAC9B,OAGC;IAED,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,OAAO,OAAO,CAAC,QAAQ,CAAC;IAC1B,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAEnD,OAAO;QACL,GAAG,EAAE,OAAO,CAAC,KAAK;YAChB,CAAC,CAAC,+BAA+B,CAAC,WAAW,CAAC;YAC9C,CAAC,CAAC,WAAW;KAChB,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;QAC/B,kBAAkB,EAAE,IAAI;KACzB,CAAC;AACJ,CAAC;AAED,SAAS,+BAA+B,CAAC,WAAmB;IAC1D,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IAEvC,KAAK,MAAM,KAAK,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE,CAAC;QAC3E,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,SAAS,CAAC,QAAQ,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
|
2
|
+
import { MysqlTypeormConfigOptions } from './mysql-typeorm-options.factory';
|
|
3
|
+
import { PostgresTypeormConfigOptions } from './postgres-typeorm-options.factory';
|
|
4
|
+
export type TypeOrmConfigOptions = (PostgresTypeormConfigOptions & {
|
|
5
|
+
type: 'postgres';
|
|
6
|
+
}) | (MysqlTypeormConfigOptions & {
|
|
7
|
+
type: 'mysql';
|
|
8
|
+
});
|
|
9
|
+
export declare function createTypeOrmOptions(options: TypeOrmConfigOptions): TypeOrmModuleOptions;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTypeOrmOptions = createTypeOrmOptions;
|
|
4
|
+
const mysql_typeorm_options_factory_1 = require("./mysql-typeorm-options.factory");
|
|
5
|
+
const postgres_typeorm_options_factory_1 = require("./postgres-typeorm-options.factory");
|
|
6
|
+
function createTypeOrmOptions(options) {
|
|
7
|
+
switch (options.type) {
|
|
8
|
+
case 'postgres':
|
|
9
|
+
return (0, postgres_typeorm_options_factory_1.createPostgresTypeormOptions)(options);
|
|
10
|
+
case 'mysql':
|
|
11
|
+
return (0, mysql_typeorm_options_factory_1.createMysqlTypeormOptions)(options);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=typeorm-options.factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeorm-options.factory.js","sourceRoot":"","sources":["../../../src/typeorm/config/typeorm-options.factory.ts"],"names":[],"mappings":";;AAcA,oDASC;AAtBD,mFAGyC;AACzC,yFAG4C;AAM5C,SAAgB,oBAAoB,CAClC,OAA6B;IAE7B,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,UAAU;YACb,OAAO,IAAA,+DAA4B,EAAC,OAAO,CAAC,CAAC;QAC/C,KAAK,OAAO;YACV,OAAO,IAAA,yDAAyB,EAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Logger } from '@nestjs/common';
|
|
2
|
+
export interface CommonTypeormConfigOptions {
|
|
3
|
+
databaseUrl: string;
|
|
4
|
+
sync?: boolean | string;
|
|
5
|
+
logging?: boolean | string;
|
|
6
|
+
isProduction: boolean;
|
|
7
|
+
maxConnections?: number;
|
|
8
|
+
maxQueryExecutionTime?: number;
|
|
9
|
+
}
|
|
10
|
+
export type ResolvedCommonTypeormConfigOptions = Required<CommonTypeormConfigOptions>;
|
|
11
|
+
export declare const TYPEORM_CONFIG_DEFAULTS: Pick<ResolvedCommonTypeormConfigOptions, 'sync' | 'logging' | 'maxConnections' | 'maxQueryExecutionTime'>;
|
|
12
|
+
export declare function useSynchronize(options: Pick<ResolvedCommonTypeormConfigOptions, 'isProduction' | 'sync'>, logger: Logger): boolean;
|
|
13
|
+
export declare function useLogging(logging: boolean | string): boolean;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TYPEORM_CONFIG_DEFAULTS = void 0;
|
|
4
|
+
exports.useSynchronize = useSynchronize;
|
|
5
|
+
exports.useLogging = useLogging;
|
|
6
|
+
exports.TYPEORM_CONFIG_DEFAULTS = {
|
|
7
|
+
sync: false,
|
|
8
|
+
logging: false,
|
|
9
|
+
maxConnections: 20,
|
|
10
|
+
maxQueryExecutionTime: 500,
|
|
11
|
+
};
|
|
12
|
+
function useSynchronize(options, logger) {
|
|
13
|
+
const doSync = coerceBoolean(options.sync);
|
|
14
|
+
if (options.isProduction && doSync) {
|
|
15
|
+
logger.warn("Your sync is on! But due security reasons it's not allowed to perform in production!");
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return doSync;
|
|
19
|
+
}
|
|
20
|
+
function useLogging(logging) {
|
|
21
|
+
return coerceBoolean(logging);
|
|
22
|
+
}
|
|
23
|
+
function coerceBoolean(value) {
|
|
24
|
+
if (typeof value === 'boolean') {
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
return !!Number(value);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=typeorm-options.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeorm-options.util.js","sourceRoot":"","sources":["../../../src/typeorm/config/typeorm-options.util.ts"],"names":[],"mappings":";;;AAwBA,wCAeC;AAED,gCAEC;AA7BY,QAAA,uBAAuB,GAGhC;IACF,IAAI,EAAE,KAAK;IACX,OAAO,EAAE,KAAK;IACd,cAAc,EAAE,EAAE;IAClB,qBAAqB,EAAE,GAAG;CAC3B,CAAC;AAEF,SAAgB,cAAc,CAC5B,OAA0E,EAC1E,MAAc;IAEd,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3C,IAAI,OAAO,CAAC,YAAY,IAAI,MAAM,EAAE,CAAC;QACnC,MAAM,CAAC,IAAI,CACT,sFAAsF,CACvF,CAAC;QAEF,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,UAAU,CAAC,OAAyB;IAClD,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,aAAa,CAAC,KAAuB;IAC5C,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzB,CAAC"}
|
package/dist/typeorm/index.d.ts
CHANGED
package/dist/typeorm/index.js
CHANGED
|
@@ -19,4 +19,5 @@ __exportStar(require("./errors"), exports);
|
|
|
19
19
|
__exportStar(require("./transformers"), exports);
|
|
20
20
|
__exportStar(require("./types"), exports);
|
|
21
21
|
__exportStar(require("./utils"), exports);
|
|
22
|
+
__exportStar(require("./config"), exports);
|
|
22
23
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/typeorm/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,2CAAyB;AACzB,iDAA+B;AAC/B,0CAAwB;AACxB,0CAAwB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/typeorm/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,2CAAyB;AACzB,iDAA+B;AAC/B,0CAAwB;AACxB,0CAAwB;AACxB,2CAAyB"}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import { ValidationOptions } from 'class-validator';
|
|
2
2
|
import { EntityValidationOptions } from './entity.interface';
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated Entity existence checks are not the responsibility of DTO
|
|
5
|
+
* validation. This validator leaks persistence/service concerns into DTOs; keep
|
|
6
|
+
* that logic in the service/application layer instead.
|
|
7
|
+
*/
|
|
3
8
|
export declare function IsEntity(entityType: Function, options?: EntityValidationOptions & ValidationOptions): (object: any, propertyName: string) => void;
|
|
@@ -4,6 +4,11 @@ exports.IsEntity = IsEntity;
|
|
|
4
4
|
const class_validator_1 = require("class-validator");
|
|
5
5
|
const entity_constant_1 = require("./entity.constant");
|
|
6
6
|
const entity_constraint_1 = require("./entity.constraint");
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Entity existence checks are not the responsibility of DTO
|
|
9
|
+
* validation. This validator leaks persistence/service concerns into DTOs; keep
|
|
10
|
+
* that logic in the service/application layer instead.
|
|
11
|
+
*/
|
|
7
12
|
function IsEntity(entityType, options) {
|
|
8
13
|
const { isUuid, each, property, ...validationOptions } = options || {};
|
|
9
14
|
return function (object, propertyName) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.decorator.js","sourceRoot":"","sources":["../../../src/validators/entity/entity.decorator.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"entity.decorator.js","sourceRoot":"","sources":["../../../src/validators/entity/entity.decorator.ts"],"names":[],"mappings":";;AAUA,4BAgBC;AA1BD,qDAAuE;AAEvE,uDAA8C;AAC9C,2DAAuD;AAEvD;;;;GAIG;AACH,SAAgB,QAAQ,CACtB,UAAoB,EACpB,OAAqD;IAErD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,iBAAiB,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IAEvE,OAAO,UAAU,MAAW,EAAE,YAAoB;QAChD,IAAA,mCAAiB,EAAC;YAChB,IAAI,EAAE,2BAAS;YACf,MAAM,EAAE,MAAM,CAAC,WAAW;YAC1B,YAAY;YACZ,OAAO,EAAE,iBAAiB;YAC1B,WAAW,EAAE,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;YACrD,SAAS,EAAE,oCAAgB;SAC5B,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@russ-b/nestjs-common-tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "NestJS utility tools",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -109,6 +109,7 @@
|
|
|
109
109
|
"@aws-sdk/s3-request-presigner": "^3.1019.0",
|
|
110
110
|
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
111
111
|
"@nestjs/config": "^3.0.0 || ^4.0.0",
|
|
112
|
+
"@nestjs/typeorm": "^10.0.0 || ^11.0.0",
|
|
112
113
|
"nest-winston": "^1.10.2",
|
|
113
114
|
"typeorm": "^0.3.20",
|
|
114
115
|
"winston": "^3.17.0",
|
|
@@ -119,6 +120,7 @@
|
|
|
119
120
|
"@eslint/eslintrc": "^3.2.0",
|
|
120
121
|
"@eslint/js": "^9.18.0",
|
|
121
122
|
"@nestjs/testing": "^11.0.7",
|
|
123
|
+
"@nestjs/typeorm": "^11.0.0",
|
|
122
124
|
"@types/express": "^5.0.0",
|
|
123
125
|
"@types/jest": "^29.5.14",
|
|
124
126
|
"eslint": "^9.18.0",
|