@furkanogutcu/nest-common 0.0.3 → 1.0.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.
Files changed (50) hide show
  1. package/README.md +180 -12
  2. package/dist/decorators/index.d.ts +3 -0
  3. package/dist/decorators/index.js +20 -0
  4. package/dist/decorators/index.js.map +1 -0
  5. package/dist/decorators/order-by.decorator.d.ts +3 -0
  6. package/dist/decorators/order-by.decorator.js +12 -0
  7. package/dist/decorators/order-by.decorator.js.map +1 -0
  8. package/dist/decorators/pagination.decorator.d.ts +1 -0
  9. package/dist/decorators/pagination.decorator.js +10 -0
  10. package/dist/decorators/pagination.decorator.js.map +1 -0
  11. package/dist/decorators/search.decorator.d.ts +3 -0
  12. package/dist/decorators/search.decorator.js +17 -0
  13. package/dist/decorators/search.decorator.js.map +1 -0
  14. package/dist/index.d.ts +5 -0
  15. package/dist/index.js +5 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/pipes/app-zod-validation.pipe.d.ts +5 -0
  18. package/dist/pipes/app-zod-validation.pipe.js +28 -0
  19. package/dist/pipes/app-zod-validation.pipe.js.map +1 -0
  20. package/dist/pipes/index.d.ts +1 -0
  21. package/dist/pipes/index.js +18 -0
  22. package/dist/pipes/index.js.map +1 -0
  23. package/dist/responses/api-response.type.d.ts +17 -0
  24. package/dist/responses/api-response.type.js +3 -0
  25. package/dist/responses/api-response.type.js.map +1 -0
  26. package/dist/responses/index.d.ts +1 -0
  27. package/dist/responses/index.js +18 -0
  28. package/dist/responses/index.js.map +1 -0
  29. package/dist/utils/exponential-retry.util.d.ts +5 -0
  30. package/dist/utils/exponential-retry.util.js +23 -0
  31. package/dist/utils/exponential-retry.util.js.map +1 -0
  32. package/dist/utils/index.d.ts +2 -0
  33. package/dist/utils/index.js +19 -0
  34. package/dist/utils/index.js.map +1 -0
  35. package/dist/utils/sleep.util.d.ts +1 -0
  36. package/dist/utils/sleep.util.js +8 -0
  37. package/dist/utils/sleep.util.js.map +1 -0
  38. package/dist/validations/index.d.ts +3 -0
  39. package/dist/validations/index.js +20 -0
  40. package/dist/validations/index.js.map +1 -0
  41. package/dist/validations/order-by.validation.d.ts +14 -0
  42. package/dist/validations/order-by.validation.js +18 -0
  43. package/dist/validations/order-by.validation.js.map +1 -0
  44. package/dist/validations/pagination.validation.d.ts +18 -0
  45. package/dist/validations/pagination.validation.js +16 -0
  46. package/dist/validations/pagination.validation.js.map +1 -0
  47. package/dist/validations/search.validation.d.ts +8 -0
  48. package/dist/validations/search.validation.js +8 -0
  49. package/dist/validations/search.validation.js.map +1 -0
  50. package/package.json +3 -2
package/README.md CHANGED
@@ -12,6 +12,10 @@ This package is designed to standardize structures you repeatedly use in your Ne
12
12
  - [Installation](#installation)
13
13
  - [Features](#features)
14
14
  - [Exceptions](#1-exceptions)
15
+ - [API Responses](#2-api-responses)
16
+ - [Validators and Pipes](#3-validators-and-pipes)
17
+ - [Decorators](#4-decorators)
18
+ - [Utilities](#5-utilities)
15
19
  - [Development](#development)
16
20
  - [License](#license)
17
21
 
@@ -39,25 +43,27 @@ No additional installation steps are needed beyond installing the package.
39
43
 
40
44
  - **Custom Exception Classes**: Comprehensive set of HTTP-based exception classes for consistent error responses.
41
45
 
42
- | Exception Class | HTTP Status | Description |
43
- |-----------------|-------------|-------------|
44
- | `AppException` | - | Base exception class for all custom exceptions |
45
- | `AppBadRequestException` | 400 | For invalid input, malformed requests |
46
- | `AppUnauthorizedException` | 401 | For authentication failures |
47
- | `AppForbiddenException` | 403 | For authorization failures |
48
- | `AppNotFoundException` | 404 | For resources that couldn't be found |
49
- | `AppConflictException` | 409 | For conflicting requests (e.g., duplicate entries) |
50
- | `AppUnprocessableEntityException` | 422 | For semantically incorrect requests |
51
- | `AppInternalException` | 500 | For server-side errors |
52
- | `AppTooManyRequestException` | 429 | For rate limiting scenarios |
53
- | `AppValidationException` | 400 | Specifically for input validation errors |
46
+ | Exception Class | HTTP Status | Description |
47
+ | --------------------------------- | ----------- | -------------------------------------------------- |
48
+ | `AppException` | - | Base exception class for all custom exceptions |
49
+ | `AppBadRequestException` | 400 | For invalid input, malformed requests |
50
+ | `AppUnauthorizedException` | 401 | For authentication failures |
51
+ | `AppForbiddenException` | 403 | For authorization failures |
52
+ | `AppNotFoundException` | 404 | For resources that couldn't be found |
53
+ | `AppConflictException` | 409 | For conflicting requests (e.g., duplicate entries) |
54
+ | `AppUnprocessableEntityException` | 422 | For semantically incorrect requests |
55
+ | `AppInternalException` | 500 | For server-side errors |
56
+ | `AppTooManyRequestException` | 429 | For rate limiting scenarios |
57
+ | `AppValidationException` | 400 | Specifically for input validation errors |
54
58
 
55
59
  - **Global Exception Filter**: Automatically catches and transforms exceptions throughout your application.
60
+
56
61
  - Centralized error handling logic
57
62
  - Consistent error response format
58
63
  - Easy to configure through NestJS's dependency injection
59
64
 
60
65
  - **Exception Transformers**: Converts various error types to standardized app exceptions.
66
+
61
67
  - NestJS built-in exception transformer
62
68
  - TypeORM exception transformer
63
69
 
@@ -155,6 +161,168 @@ The `type` field in validation error details can have the following values:
155
161
 
156
162
  For more detailed information about the filters, transformers, and interfaces included in the exceptions package, please check the source code.
157
163
 
164
+ ### 2. API Responses
165
+
166
+ #### Features
167
+
168
+ - **Standardized Response Types**: Comprehensive set of response interfaces for consistent API responses.
169
+ - `APIResponse`: Generic type for creating standardized responses
170
+ - `APIResponseOnlyMessage`: Simple message-only response
171
+ - `PaginatedAPIResponse`: Response format for paginated data with metadata
172
+
173
+ #### Usage
174
+
175
+ ```typescript
176
+ import { Controller, Get, Post, Body, Param, Query } from '@nestjs/common';
177
+ import {
178
+ APIResponse,
179
+ APIResponseOnlyMessage,
180
+ PaginatedAPIResponse,
181
+ Pagination,
182
+ PaginationParams,
183
+ } from '@furkanogutcu/nest-common';
184
+ import { User } from './user.entity';
185
+ import { CreateUserDto } from './dto/create-user.dto';
186
+
187
+ @Controller('users')
188
+ export class UsersController {
189
+ constructor(private readonly usersService: UsersService) {}
190
+
191
+ @Get()
192
+ async findAll(@Pagination() { skip, take }: PaginationParams): Promise<PaginatedAPIResponse<User>> {
193
+ const { items, metadata } = await this.usersService.findAll({ skip, take });
194
+
195
+ return {
196
+ data: items,
197
+ metadata,
198
+ };
199
+ }
200
+
201
+ @Get(':id')
202
+ async findOne(@Param('id') id: string): Promise<APIResponse<'user', User>> {
203
+ const user = await this.usersService.findOne(id);
204
+
205
+ return {
206
+ user,
207
+ };
208
+ }
209
+
210
+ @Post()
211
+ async create(@Body() createUserDto: CreateUserDto): Promise<APIResponseOnlyMessage> {
212
+ await this.usersService.create(createUserDto);
213
+
214
+ return {
215
+ message: 'User created successfully',
216
+ };
217
+ }
218
+ }
219
+ ```
220
+
221
+ ### 3. Validators and Pipes
222
+
223
+ #### Features
224
+
225
+ - **Zod Validation Pipe**: Extended validation pipe for NestJS using Zod schema validation.
226
+
227
+ - Seamless integration with NestJS validation pipeline
228
+ - Throws consistent `AppValidationException` on validation errors
229
+ - Compatible with Zod schemas
230
+
231
+ - **Common Validation Schemas**:
232
+ - `paginationSchema`: For standardizing pagination parameters
233
+ - `orderBySchema`: For standardizing sorting/ordering parameters
234
+ - `searchSchema`: For standardizing search parameters
235
+
236
+ #### Usage
237
+
238
+ ##### Setting up validation globally
239
+
240
+ ```typescript
241
+ import { Module } from '@nestjs/common';
242
+ import { APP_PIPE } from '@nestjs/core';
243
+ import { AppZodValidationPipe } from '@furkanogutcu/nest-common';
244
+
245
+ @Module({
246
+ imports: [
247
+ // Your other modules
248
+ ],
249
+ controllers: [
250
+ // Your controllers
251
+ ],
252
+ providers: [
253
+ // Your other providers
254
+ {
255
+ provide: APP_PIPE,
256
+ useClass: AppZodValidationPipe,
257
+ },
258
+ ],
259
+ })
260
+ export class AppModule {}
261
+ ```
262
+
263
+ ### 4. Decorators
264
+
265
+ #### Features
266
+
267
+ - **Parameter Decorators**: Decorators for common query parameter extraction and validation.
268
+ - `@Pagination()`: Extracts and validates pagination parameters
269
+ - `@OrderBy()`: Extracts and validates ordering parameters
270
+ - `@Search()`: Extracts and validates search parameters
271
+
272
+ #### Usage
273
+
274
+ ```typescript
275
+ import { Controller, Get } from '@nestjs/common';
276
+ import { Pagination, OrderBy, Search, PaginationParams, OrderByParam, SearchParams } from '@furkanogutcu/nest-common';
277
+
278
+ @Controller('users')
279
+ export class UsersController {
280
+ @Get()
281
+ findAll(
282
+ @Pagination() { skip, take }: PaginationParams,
283
+ @OrderBy<User>(['created_at']) orderBy: OrderByParam<User>,
284
+ @Search<User>(['email']) search: SearchParams<User>,
285
+ ) {
286
+ // Implement your service call with these validated parameters
287
+ return this.usersService.findAll({ skip, take, orderBy, where: search });
288
+ }
289
+ }
290
+ ```
291
+
292
+ ### 5. Utilities
293
+
294
+ #### Features
295
+
296
+ - **Asynchronous Utilities**:
297
+ - `exponentialRetry`: Retry a function with exponential backoff
298
+ - `sleep`: Simple promise-based delay utility
299
+
300
+ #### Usage
301
+
302
+ ```typescript
303
+ import { exponentialRetry, sleep } from '@furkanogutcu/nest-common';
304
+
305
+ // Retry a function with exponential backoff
306
+ async function fetchWithRetry() {
307
+ return exponentialRetry(
308
+ async () => {
309
+ // Potentially failing operation (e.g., API call)
310
+ return await externalApiCall();
311
+ },
312
+ {
313
+ maxAttempts: 5, // Maximum of 5 attempts
314
+ baseDelayMs: 1000, // Starting delay of 1000ms (will grow exponentially)
315
+ },
316
+ );
317
+ }
318
+
319
+ // Simple delay utility
320
+ async function processWithDelay() {
321
+ await sleep(2000); // Wait for 2 seconds
322
+ // Continue execution
323
+ }
324
+ ```
325
+
158
326
  ## Development
159
327
 
160
328
  ### Requirements
@@ -0,0 +1,3 @@
1
+ export * from './order-by.decorator';
2
+ export * from './pagination.decorator';
3
+ export * from './search.decorator';
@@ -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("./order-by.decorator"), exports);
18
+ __exportStar(require("./pagination.decorator"), exports);
19
+ __exportStar(require("./search.decorator"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAqC;AACrC,yDAAuC;AACvC,qDAAmC"}
@@ -0,0 +1,3 @@
1
+ import { FindOptionsOrder } from 'typeorm';
2
+ export type OrderByParam<Entity> = FindOptionsOrder<Entity> | undefined;
3
+ export declare const OrderBy: <Entity>(fields: (keyof Entity)[]) => ParameterDecorator;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OrderBy = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const order_by_validation_1 = require("../validations/order-by.validation");
6
+ const OrderBy = (fields) => (0, common_1.createParamDecorator)((data, ctx) => {
7
+ const request = ctx.switchToHttp().getRequest();
8
+ const orderBySchema = (0, order_by_validation_1.createOrderBySchema)(fields);
9
+ return orderBySchema.parse(request.query).order_by;
10
+ })();
11
+ exports.OrderBy = OrderBy;
12
+ //# sourceMappingURL=order-by.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order-by.decorator.js","sourceRoot":"","sources":["../../src/decorators/order-by.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAAwE;AAIxE,4EAAyE;AAIlE,MAAM,OAAO,GAAG,CAAS,MAAwB,EAAE,EAAE,CAC1D,IAAA,6BAAoB,EAAC,CAAC,IAAa,EAAE,GAAqB,EAAwB,EAAE;IAClF,MAAM,OAAO,GAAY,GAAG,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;IAEzD,MAAM,aAAa,GAAG,IAAA,yCAAmB,EAAC,MAAkB,CAAC,CAAC;IAE9D,OAAO,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAe,CAAC;AAC5D,CAAC,CAAC,EAAE,CAAC;AAPM,QAAA,OAAO,WAOb"}
@@ -0,0 +1 @@
1
+ export declare const Pagination: (...dataOrPipes: unknown[]) => ParameterDecorator;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Pagination = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const pagination_validation_1 = require("../validations/pagination.validation");
6
+ exports.Pagination = (0, common_1.createParamDecorator)((data, ctx) => {
7
+ const request = ctx.switchToHttp().getRequest();
8
+ return pagination_validation_1.paginationSchema.parse(request.query);
9
+ });
10
+ //# sourceMappingURL=pagination.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.decorator.js","sourceRoot":"","sources":["../../src/decorators/pagination.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAAwE;AAGxE,gFAAwE;AAE3D,QAAA,UAAU,GAAG,IAAA,6BAAoB,EAAC,CAAC,IAAa,EAAE,GAAqB,EAAE,EAAE;IACtF,MAAM,OAAO,GAAY,GAAG,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;IAEzD,OAAO,wCAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { FindOptionsWhere } from 'typeorm';
2
+ export type SearchParams<Entity> = FindOptionsWhere<Entity> | undefined;
3
+ export declare const Search: <Entity>(fields: (keyof Entity)[]) => ParameterDecorator;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Search = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const typeorm_1 = require("typeorm");
6
+ const search_validation_1 = require("../validations/search.validation");
7
+ const Search = (fields) => (0, common_1.createParamDecorator)((data, ctx) => {
8
+ const request = ctx.switchToHttp().getRequest();
9
+ const parsed = search_validation_1.searchSchema.parse(request.query);
10
+ if (!parsed.q)
11
+ return;
12
+ return fields.map((field) => ({
13
+ [field]: (0, typeorm_1.Raw)((alias) => `CAST(${alias} AS TEXT) ILIKE :searchTerm`, { searchTerm: `%${parsed.q}%` }),
14
+ }));
15
+ })();
16
+ exports.Search = Search;
17
+ //# sourceMappingURL=search.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.decorator.js","sourceRoot":"","sources":["../../src/decorators/search.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAAwE;AAExE,qCAAgD;AAEhD,wEAAgE;AAIzD,MAAM,MAAM,GAAG,CAAS,MAAwB,EAAE,EAAE,CACzD,IAAA,6BAAoB,EAAC,CAAC,IAAa,EAAE,GAAqB,EAAwB,EAAE;IAClF,MAAM,OAAO,GAAY,GAAG,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;IAEzD,MAAM,MAAM,GAAG,gCAAY,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAEjD,IAAI,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO;IAEtB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5B,CAAC,KAAK,CAAC,EAAE,IAAA,aAAG,EAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,KAAK,6BAA6B,EAAE,EAAE,UAAU,EAAE,IAAI,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC;KACrG,CAAC,CAAQ,CAAC;AACb,CAAC,CAAC,EAAE,CAAC;AAXM,QAAA,MAAM,UAWZ"}
package/dist/index.d.ts CHANGED
@@ -1 +1,6 @@
1
+ export * from './decorators';
1
2
  export * from './exceptions';
3
+ export * from './pipes';
4
+ export * from './responses';
5
+ export * from './utils';
6
+ export * from './validations';
package/dist/index.js CHANGED
@@ -14,5 +14,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./decorators"), exports);
17
18
  __exportStar(require("./exceptions"), exports);
19
+ __exportStar(require("./pipes"), exports);
20
+ __exportStar(require("./responses"), exports);
21
+ __exportStar(require("./utils"), exports);
22
+ __exportStar(require("./validations"), exports);
18
23
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,+CAA6B;AAC7B,0CAAwB;AACxB,8CAA4B;AAC5B,0CAAwB;AACxB,gDAA8B"}
@@ -0,0 +1,5 @@
1
+ import { ZodValidationPipe } from '@anatine/zod-nestjs';
2
+ import { ArgumentMetadata } from '@nestjs/common';
3
+ export declare class AppZodValidationPipe extends ZodValidationPipe {
4
+ transform(value: unknown, metadata: ArgumentMetadata): unknown;
5
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.AppZodValidationPipe = void 0;
10
+ const zod_nestjs_1 = require("@anatine/zod-nestjs");
11
+ const common_1 = require("@nestjs/common");
12
+ const exceptions_1 = require("../exceptions");
13
+ let AppZodValidationPipe = class AppZodValidationPipe extends zod_nestjs_1.ZodValidationPipe {
14
+ transform(value, metadata) {
15
+ const zodSchema = metadata?.metatype?.zodSchema;
16
+ if (!zodSchema)
17
+ return value;
18
+ const parseResult = zodSchema.safeParse(value);
19
+ if (!parseResult.success)
20
+ throw new exceptions_1.AppValidationException(parseResult.error);
21
+ return parseResult.data;
22
+ }
23
+ };
24
+ exports.AppZodValidationPipe = AppZodValidationPipe;
25
+ exports.AppZodValidationPipe = AppZodValidationPipe = __decorate([
26
+ (0, common_1.Injectable)()
27
+ ], AppZodValidationPipe);
28
+ //# sourceMappingURL=app-zod-validation.pipe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-zod-validation.pipe.js","sourceRoot":"","sources":["../../src/pipes/app-zod-validation.pipe.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oDAAsE;AACtE,2CAA8D;AAE9D,8CAAuD;AAGhD,IAAM,oBAAoB,GAA1B,MAAM,oBAAqB,SAAQ,8BAAiB;IACzD,SAAS,CAAC,KAAc,EAAE,QAA0B;QAClD,MAAM,SAAS,GAAI,QAAQ,EAAE,QAAyB,EAAE,SAAS,CAAC;QAElE,IAAI,CAAC,SAAS;YAAE,OAAO,KAAK,CAAC;QAE7B,MAAM,WAAW,GAAG,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAE/C,IAAI,CAAC,WAAW,CAAC,OAAO;YAAE,MAAM,IAAI,mCAAsB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAE9E,OAAO,WAAW,CAAC,IAAI,CAAC;IAC1B,CAAC;CACF,CAAA;AAZY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;GACA,oBAAoB,CAYhC"}
@@ -0,0 +1 @@
1
+ export * from './app-zod-validation.pipe';
@@ -0,0 +1,18 @@
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("./app-zod-validation.pipe"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pipes/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4DAA0C"}
@@ -0,0 +1,17 @@
1
+ type APIResponseValue = any[] | Record<string, any>;
2
+ export type APIResponse<T extends string[] | string, R = APIResponseValue> = {
3
+ [K in T extends string ? T : T[number]]: R;
4
+ };
5
+ export type APIResponseOnlyMessage = APIResponse<'message', string>;
6
+ export type APIResponseMetadata = {
7
+ metadata: {
8
+ pagination: {
9
+ page: number;
10
+ per_page: number;
11
+ total_pages: number;
12
+ total_items: number;
13
+ };
14
+ };
15
+ };
16
+ export type PaginatedAPIResponse<R = APIResponseValue> = APIResponse<'data', R[]> & APIResponseMetadata;
17
+ export {};
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=api-response.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-response.type.js","sourceRoot":"","sources":["../../src/responses/api-response.type.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ export * from './api-response.type';
@@ -0,0 +1,18 @@
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("./api-response.type"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/responses/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC"}
@@ -0,0 +1,5 @@
1
+ export interface ExponentialRetryOptions {
2
+ maxAttempts?: number;
3
+ baseDelayMs?: number;
4
+ }
5
+ export declare function exponentialRetry<T>(fn: () => Promise<T>, options?: ExponentialRetryOptions): Promise<T>;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exponentialRetry = exponentialRetry;
4
+ const sleep_util_1 = require("./sleep.util");
5
+ async function exponentialRetry(fn, options) {
6
+ const maxAttempts = options?.maxAttempts ?? 3;
7
+ const baseDelayMs = options?.baseDelayMs ?? 2000;
8
+ let lastError = null;
9
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
10
+ try {
11
+ return await fn();
12
+ }
13
+ catch (error) {
14
+ lastError = error instanceof Error ? error : new Error(String(error));
15
+ if (attempt === maxAttempts)
16
+ throw lastError;
17
+ const delay = Math.pow(2, attempt) * baseDelayMs;
18
+ await (0, sleep_util_1.sleep)(delay);
19
+ }
20
+ }
21
+ throw lastError || new Error('Unknown error');
22
+ }
23
+ //# sourceMappingURL=exponential-retry.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exponential-retry.util.js","sourceRoot":"","sources":["../../src/utils/exponential-retry.util.ts"],"names":[],"mappings":";;AAOA,4CAqBC;AA5BD,6CAAqC;AAO9B,KAAK,UAAU,gBAAgB,CAAI,EAAoB,EAAE,OAAiC;IAC/F,MAAM,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,IAAI,CAAC;IAEjD,IAAI,SAAS,GAAiB,IAAI,CAAC;IAEnC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACxD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAEtE,IAAI,OAAO,KAAK,WAAW;gBAAE,MAAM,SAAS,CAAC;YAE7C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,WAAW,CAAC;YAEjD,MAAM,IAAA,kBAAK,EAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './exponential-retry.util';
2
+ export * from './sleep.util';
@@ -0,0 +1,19 @@
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("./exponential-retry.util"), exports);
18
+ __exportStar(require("./sleep.util"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2DAAyC;AACzC,+CAA6B"}
@@ -0,0 +1 @@
1
+ export declare const sleep: (timeout: number) => Promise<void>;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sleep = void 0;
4
+ const sleep = async (timeout) => {
5
+ return await new Promise((resolve) => setTimeout(resolve, timeout));
6
+ };
7
+ exports.sleep = sleep;
8
+ //# sourceMappingURL=sleep.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleep.util.js","sourceRoot":"","sources":["../../src/utils/sleep.util.ts"],"names":[],"mappings":";;;AAAO,MAAM,KAAK,GAAG,KAAK,EAAE,OAAe,EAAE,EAAE;IAC7C,OAAO,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAC5E,CAAC,CAAC;AAFW,QAAA,KAAK,SAEhB"}
@@ -0,0 +1,3 @@
1
+ export * from './order-by.validation';
2
+ export * from './pagination.validation';
3
+ export * from './search.validation';
@@ -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("./order-by.validation"), exports);
18
+ __exportStar(require("./pagination.validation"), exports);
19
+ __exportStar(require("./search.validation"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/validations/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wDAAsC;AACtC,0DAAwC;AACxC,sDAAoC"}
@@ -0,0 +1,14 @@
1
+ import { z } from 'zod';
2
+ export declare const createOrderBySchema: (fields: string[]) => z.ZodObject<{
3
+ order_by: z.ZodOptional<z.ZodEffects<z.ZodEffects<z.ZodString, {
4
+ [x: string]: string;
5
+ }, string>, {
6
+ [x: string]: string;
7
+ }, string>>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ order_by?: {
10
+ [x: string]: string;
11
+ } | undefined;
12
+ }, {
13
+ order_by?: string | undefined;
14
+ }>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createOrderBySchema = void 0;
4
+ const zod_1 = require("zod");
5
+ const createOrderBySchema = (fields) => zod_1.z.object({
6
+ order_by: zod_1.z
7
+ .string()
8
+ .transform((val) => {
9
+ const [direction, field] = val.startsWith('-') ? ['desc', val.slice(1)] : ['asc', val];
10
+ return { [field]: direction };
11
+ })
12
+ .refine((val) => fields.includes(Object.keys(val)[0]), {
13
+ message: `Field must be one of: ${fields.join(', ')} `,
14
+ })
15
+ .optional(),
16
+ });
17
+ exports.createOrderBySchema = createOrderBySchema;
18
+ //# sourceMappingURL=order-by.validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order-by.validation.js","sourceRoot":"","sources":["../../src/validations/order-by.validation.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAEjB,MAAM,mBAAmB,GAAG,CAAC,MAAgB,EAAE,EAAE,CACtD,OAAC,CAAC,MAAM,CAAC;IACP,QAAQ,EAAE,OAAC;SACR,MAAM,EAAE;SACR,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE;QACjB,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAEvF,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;IAChC,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;QACrD,OAAO,EAAE,yBAAyB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;KACvD,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC;AAbQ,QAAA,mBAAmB,uBAa3B"}
@@ -0,0 +1,18 @@
1
+ import { z } from 'zod';
2
+ export declare const paginationSchema: z.ZodEffects<z.ZodObject<{
3
+ page: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
4
+ per_page: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
5
+ }, "strip", z.ZodTypeAny, {
6
+ page: number;
7
+ per_page: number;
8
+ }, {
9
+ page?: number | undefined;
10
+ per_page?: number | undefined;
11
+ }>, {
12
+ skip: number;
13
+ take: number;
14
+ }, {
15
+ page?: number | undefined;
16
+ per_page?: number | undefined;
17
+ }>;
18
+ export type PaginationParams = z.output<typeof paginationSchema>;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.paginationSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.paginationSchema = zod_1.z
6
+ .object({
7
+ page: zod_1.z.coerce.number().int().positive().optional().default(1),
8
+ per_page: zod_1.z.coerce.number().int().positive().optional().default(20),
9
+ })
10
+ .transform(({ page, per_page }) => {
11
+ return {
12
+ skip: (page - 1) * per_page,
13
+ take: per_page,
14
+ };
15
+ });
16
+ //# sourceMappingURL=pagination.validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.validation.js","sourceRoot":"","sources":["../../src/validations/pagination.validation.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAEX,QAAA,gBAAgB,GAAG,OAAC;KAC9B,MAAM,CAAC;IACN,IAAI,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9D,QAAQ,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;CACpE,CAAC;KACD,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;IAChC,OAAO;QACL,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ;QAC3B,IAAI,EAAE,QAAQ;KACf,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { z } from 'zod';
2
+ export declare const searchSchema: z.ZodObject<{
3
+ q: z.ZodOptional<z.ZodString>;
4
+ }, "strip", z.ZodTypeAny, {
5
+ q?: string | undefined;
6
+ }, {
7
+ q?: string | undefined;
8
+ }>;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.searchSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.searchSchema = zod_1.z.object({
6
+ q: zod_1.z.string().optional(),
7
+ });
8
+ //# sourceMappingURL=search.validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.validation.js","sourceRoot":"","sources":["../../src/validations/search.validation.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAEX,QAAA,YAAY,GAAG,OAAC,CAAC,MAAM,CAAC;IACnC,CAAC,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACzB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@furkanogutcu/nest-common",
3
- "version": "0.0.3",
3
+ "version": "1.0.1",
4
4
  "description": "Package of common structures for NestJS.",
5
5
  "author": "Furkan Ogutcu",
6
6
  "license": "MIT",
@@ -51,7 +51,8 @@
51
51
  "@nestjs/testing": "11.1.0",
52
52
  "@nestjs/platform-express": "^11.1.0",
53
53
  "zod": "^3.24.3",
54
- "typeorm": "^0.3.22"
54
+ "typeorm": "^0.3.22",
55
+ "@anatine/zod-nestjs": "^2.0.12"
55
56
  },
56
57
  "dependencies": {},
57
58
  "devDependencies": {