@valentine-efagene/qshelter-common 1.0.1 → 1.0.3

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 (154) hide show
  1. package/dist/OpenApiHelper.d.ts +9 -0
  2. package/dist/OpenApiHelper.js +118 -0
  3. package/dist/OpenApiHelper.js.map +1 -0
  4. package/dist/decorator/index.d.ts +2 -0
  5. package/dist/decorator/index.js +19 -0
  6. package/dist/decorator/index.js.map +1 -0
  7. package/dist/decorator/permission.decorator.d.ts +2 -0
  8. package/dist/decorator/permission.decorator.js +6 -0
  9. package/dist/decorator/permission.decorator.js.map +1 -0
  10. package/dist/decorator/tenant.decorator.d.ts +2 -0
  11. package/dist/decorator/tenant.decorator.js +13 -0
  12. package/dist/decorator/tenant.decorator.js.map +1 -0
  13. package/dist/entities/common.entity.js +1 -1
  14. package/dist/entities/common.entity.js.map +1 -1
  15. package/dist/entities/common.pure.entity.js +3 -2
  16. package/dist/entities/common.pure.entity.js.map +1 -1
  17. package/dist/entities/mortgage.entity.js +13 -13
  18. package/dist/entities/mortgage.entity.js.map +1 -1
  19. package/dist/entities/property.entity.d.ts +1 -2
  20. package/dist/entities/property.entity.js +6 -12
  21. package/dist/entities/property.entity.js.map +1 -1
  22. package/dist/entities/tenant.entity.d.ts +1 -1
  23. package/dist/entities/tenant.entity.js +3 -3
  24. package/dist/entities/tenant.entity.js.map +1 -1
  25. package/dist/entities/user.entity.d.ts +1 -1
  26. package/dist/entities/user.entity.js +7 -7
  27. package/dist/entities/user.entity.js.map +1 -1
  28. package/dist/entities/wallet.entity.js +9 -9
  29. package/dist/entities/wallet.entity.js.map +1 -1
  30. package/dist/guard/index.d.ts +2 -0
  31. package/dist/guard/index.js +19 -0
  32. package/dist/guard/index.js.map +1 -0
  33. package/dist/guard/permission.guard.d.ts +10 -0
  34. package/dist/guard/permission.guard.js +47 -0
  35. package/dist/guard/permission.guard.js.map +1 -0
  36. package/dist/guard/swagger-auth.guard.d.ts +1 -0
  37. package/dist/guard/swagger-auth.guard.js +9 -0
  38. package/dist/guard/swagger-auth.guard.js.map +1 -0
  39. package/dist/helpers/ArrayHelper.d.ts +2 -0
  40. package/dist/helpers/ArrayHelper.js +6 -0
  41. package/dist/helpers/ArrayHelper.js.map +1 -0
  42. package/dist/helpers/ConstantHelper.d.ts +36 -0
  43. package/{helpers/ConstantHelper.ts → dist/helpers/ConstantHelper.js} +36 -47
  44. package/dist/helpers/ConstantHelper.js.map +1 -0
  45. package/dist/helpers/CustomNamingStrategy.d.ts +7 -0
  46. package/dist/helpers/CustomNamingStrategy.js +22 -0
  47. package/dist/helpers/CustomNamingStrategy.js.map +1 -0
  48. package/dist/helpers/DateHelper.d.ts +3 -0
  49. package/dist/helpers/DateHelper.js +20 -0
  50. package/dist/helpers/DateHelper.js.map +1 -0
  51. package/dist/helpers/EmailHelper.d.ts +4 -0
  52. package/dist/helpers/EmailHelper.js +65 -0
  53. package/dist/helpers/EmailHelper.js.map +1 -0
  54. package/dist/helpers/FileSystemHelper.d.ts +15 -0
  55. package/dist/helpers/FileSystemHelper.js +112 -0
  56. package/dist/helpers/FileSystemHelper.js.map +1 -0
  57. package/dist/helpers/index.d.ts +5 -0
  58. package/dist/helpers/index.js +22 -0
  59. package/dist/helpers/index.js.map +1 -0
  60. package/dist/index.d.ts +6 -0
  61. package/dist/index.js +6 -0
  62. package/dist/index.js.map +1 -1
  63. package/dist/middleware/AccessLoggerMiddleware.d.ts +6 -0
  64. package/dist/middleware/AccessLoggerMiddleware.js +64 -0
  65. package/dist/middleware/AccessLoggerMiddleware.js.map +1 -0
  66. package/dist/middleware/AuthenticationMiddleware.d.ts +5 -0
  67. package/dist/middleware/AuthenticationMiddleware.js +19 -0
  68. package/dist/middleware/AuthenticationMiddleware.js.map +1 -0
  69. package/dist/middleware/TenantMiddleware.d.ts +14 -0
  70. package/dist/middleware/TenantMiddleware.js +49 -0
  71. package/dist/middleware/TenantMiddleware.js.map +1 -0
  72. package/dist/middleware/index.d.ts +3 -0
  73. package/dist/middleware/index.js +20 -0
  74. package/dist/middleware/index.js.map +1 -0
  75. package/dist/tsconfig.tsbuildinfo +1 -1
  76. package/dist/types/common.type.d.ts +15 -0
  77. package/dist/types/common.type.js +18 -1
  78. package/dist/types/common.type.js.map +1 -1
  79. package/dist/types/index.d.ts +8 -0
  80. package/dist/types/index.js +25 -0
  81. package/dist/types/index.js.map +1 -0
  82. package/dist/types/mortgage-fsm.type.d.ts +180 -0
  83. package/dist/types/mortgage-fsm.type.js +130 -0
  84. package/dist/types/mortgage-fsm.type.js.map +1 -0
  85. package/dist/types/permission.enums.d.ts +42 -0
  86. package/dist/types/permission.enums.js +47 -0
  87. package/dist/types/permission.enums.js.map +1 -0
  88. package/dist/types/permission.type.d.ts +42 -0
  89. package/dist/types/permission.type.js +47 -0
  90. package/dist/types/permission.type.js.map +1 -0
  91. package/{types/policy.types.ts → dist/types/policy.type.d.ts} +0 -3
  92. package/dist/types/policy.type.js +3 -0
  93. package/dist/types/policy.type.js.map +1 -0
  94. package/dist/types/tenant.type.d.ts +13 -0
  95. package/dist/types/tenant.type.js +19 -0
  96. package/dist/types/tenant.type.js.map +1 -0
  97. package/dist/types/user.type.d.ts +10 -0
  98. package/dist/types/user.type.js +16 -0
  99. package/dist/types/user.type.js.map +1 -0
  100. package/package.json +51 -3
  101. package/OpenApiHelper.ts +0 -121
  102. package/decorator/permission.decorator.ts +0 -4
  103. package/decorator/tenant.decorator.ts +0 -16
  104. package/entities/BaseEntity.ts +0 -34
  105. package/entities/TenantAwareEntity.ts +0 -34
  106. package/entities/TenantAwareRepository.ts +0 -100
  107. package/entities/amenity.entity.ts +0 -10
  108. package/entities/common.entity.ts +0 -46
  109. package/entities/common.pure.entity.ts +0 -36
  110. package/entities/index.ts +0 -27
  111. package/entities/mortgage-document.entity.ts +0 -37
  112. package/entities/mortgage-downpayment-installment.entity.ts +0 -40
  113. package/entities/mortgage-downpayment-payment.entity.ts +0 -61
  114. package/entities/mortgage-downpayment.entity.ts +0 -43
  115. package/entities/mortgage-step.entity.ts +0 -33
  116. package/entities/mortgage-type.entity.ts +0 -31
  117. package/entities/mortgage.entity.ts +0 -89
  118. package/entities/password_reset_tokens.entity.ts +0 -25
  119. package/entities/permission.entity.ts +0 -12
  120. package/entities/property-document.entity.ts +0 -21
  121. package/entities/property-media.entity.ts +0 -23
  122. package/entities/property.entity.ts +0 -147
  123. package/entities/refresh_token.entity.ts +0 -16
  124. package/entities/role.entity.ts +0 -20
  125. package/entities/settings.entity.ts +0 -56
  126. package/entities/social.entity.ts +0 -27
  127. package/entities/tenant.entity.ts +0 -65
  128. package/entities/transaction.entity.ts +0 -56
  129. package/entities/user.entity.ts +0 -89
  130. package/entities/user_suspensions.entity.ts +0 -24
  131. package/entities/wallet.entity.ts +0 -54
  132. package/guard/permission.guard.ts +0 -42
  133. package/guard/swagger-auth.guard.ts +0 -9
  134. package/helpers/ArrayHelper.ts +0 -1
  135. package/helpers/CustomNamingStrategy.ts +0 -27
  136. package/helpers/DateHelper.ts +0 -21
  137. package/helpers/EmailHelper.ts +0 -38
  138. package/helpers/FileSystemHelper.ts +0 -101
  139. package/index.ts +0 -9
  140. package/middleware/AccessLoggerMiddleware.ts +0 -58
  141. package/middleware/AuthenticationMiddleware.ts +0 -13
  142. package/middleware/TenantMiddleware.ts +0 -52
  143. package/pagination/index.ts +0 -2
  144. package/pagination/pagination.helper.ts +0 -57
  145. package/pagination/pagination.types.ts +0 -21
  146. package/standard-response.ts +0 -16
  147. package/tsconfig.json +0 -33
  148. package/types/common.type.ts +0 -32
  149. package/types/mortgage-fsm.types.ts +0 -279
  150. package/types/property.type.ts +0 -10
  151. package/types/social.enums.ts +0 -17
  152. package/types/tenant.enums.ts +0 -14
  153. package/types/transaction.type.ts +0 -9
  154. package/types/user.enums.ts +0 -11
@@ -1,56 +0,0 @@
1
- import { Column, CreateDateColumn, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
2
- import { Provider, TransactionType } from '../types/transaction.type';
3
- import { Wallet } from './wallet.entity';
4
- import { User } from './user.entity';
5
-
6
- @Entity({ name: 'prod_transactions' })
7
- export class Transaction {
8
- @PrimaryGeneratedColumn()
9
- id: number;
10
-
11
- @Column({
12
- type: 'enum',
13
- enum: TransactionType
14
- })
15
- type: TransactionType
16
-
17
- @ManyToOne(() => Wallet, wallet => wallet.transactions, {
18
- onDelete: 'CASCADE',
19
- onUpdate: 'CASCADE',
20
- })
21
- @JoinColumn({ name: 'wallet_id' })
22
- wallet: Wallet;
23
-
24
- @Column()
25
- walletId: number
26
-
27
- @ManyToOne(() => User, (user) => user.transactions)
28
- @JoinColumn({ name: 'user_id' })
29
- user: User;
30
-
31
- @Column()
32
- userId: number
33
-
34
- @Column({
35
- type: 'enum',
36
- enum: Provider
37
- })
38
- provider: Provider
39
-
40
- @Column()
41
- ref: string
42
-
43
- @Column({
44
- type: 'text'
45
- })
46
- metadata: string
47
-
48
- @Column({ type: 'decimal', precision: 65, scale: 2, nullable: true })
49
- amount: number;
50
-
51
- @CreateDateColumn()
52
- createdAt: Date;
53
-
54
- @UpdateDateColumn()
55
- updatedAt: Date;
56
- }
@@ -1,89 +0,0 @@
1
- import { Column, Entity, JoinTable, ManyToMany, OneToMany } from 'typeorm';
2
- import { TenantAwareBaseEntity } from './BaseEntity';
3
- import { UserStatus } from '../types/user.enums';
4
- import { Role } from './role.entity';
5
- import { RefreshToken } from './refresh_token.entity';
6
- import { Property } from './property.entity';
7
- import { Transaction } from './transaction.entity';
8
- import { Wallet } from './wallet.entity';
9
-
10
- @Entity({ name: 'users' })
11
- export class User extends TenantAwareBaseEntity {
12
- @Column({ nullable: true })
13
- firstName?: string;
14
-
15
- @Column({ nullable: true })
16
- lastName?: string;
17
-
18
- @Column({ nullable: true })
19
- phone?: string;
20
-
21
- @Column({ nullable: true, type: 'text' })
22
- bio?: string;
23
-
24
- @Column({ nullable: true })
25
- address?: string;
26
-
27
- @Column({ nullable: true })
28
- email: string;
29
-
30
- @Column({ nullable: true })
31
- password: string;
32
-
33
- @Column({ type: 'text', nullable: true })
34
- avatar?: string;
35
-
36
- @Column({ nullable: true })
37
- gender: string;
38
-
39
- @ManyToMany(() => Role, (role) => role.users, {
40
- onDelete: 'CASCADE',
41
- eager: true
42
- })
43
- @JoinTable()
44
- roles?: Role[]
45
-
46
- @OneToMany(
47
- () => RefreshToken,
48
- (refreshToken) =>
49
- refreshToken.user,
50
- { eager: true },
51
- )
52
- refreshTokens: RefreshToken[];
53
-
54
- @OneToMany(
55
- () => Wallet,
56
- (wallet) =>
57
- wallet.user,
58
- { eager: true },
59
- )
60
- wallets: Wallet[];
61
-
62
- @OneToMany(
63
- () => Transaction,
64
- (transaction) =>
65
- transaction.user,
66
- { eager: true },
67
- )
68
- transactions: Transaction[];
69
-
70
- @OneToMany(
71
- () => Property,
72
- (property) =>
73
- property.user,
74
- )
75
- properties: Property[];
76
-
77
- @Column({
78
- type: 'enum',
79
- enum: UserStatus,
80
- default: UserStatus.PENDING
81
- })
82
- status: UserStatus
83
-
84
- @Column({ default: false })
85
- isEmailVerified?: boolean;
86
-
87
- @Column({ nullable: true })
88
- emailVerificationToken: string | null
89
- }
@@ -1,24 +0,0 @@
1
- import { Column, Entity, JoinColumn, OneToOne } from 'typeorm';
2
- import { BaseEntity } from './BaseEntity';
3
- import { User } from './user.entity';
4
-
5
- @Entity({ name: 'user_suspension' })
6
- export class UserSuspension extends BaseEntity {
7
- @OneToOne(() => User, {
8
- //eager: true,
9
- onDelete: 'CASCADE',
10
- onUpdate: 'CASCADE',
11
- })
12
- @JoinColumn({ name: 'user_id' })
13
- user: User;
14
-
15
- @Column({
16
- nullable: false
17
- })
18
- userId: number
19
-
20
- @Column({
21
- nullable: false
22
- })
23
- reason: string
24
- }
@@ -1,54 +0,0 @@
1
- import { Column, CreateDateColumn, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
2
- import { Transaction } from './transaction.entity';
3
- import { User } from './user.entity';
4
- import { Currency } from '../types/social.enums';
5
-
6
- @Entity({ name: 'wallets' })
7
- export class Wallet {
8
- @PrimaryGeneratedColumn()
9
- id: number;
10
-
11
- @ManyToOne(() => User, (user) => user.wallets)
12
- @JoinColumn({ name: 'user_id' })
13
- user: User;
14
-
15
- @Column()
16
- userId: number
17
-
18
- @Column({
19
- type: 'enum',
20
- enum: Currency
21
- })
22
- currency: number
23
-
24
- @Column({
25
- })
26
- customerId: string
27
-
28
- @Column({
29
- })
30
- bankName: string
31
-
32
- @Column({
33
- })
34
- accountNumber: string
35
-
36
- @Column({
37
- })
38
- accountName: string
39
-
40
- @Column({ type: 'decimal', precision: 65, scale: 2, nullable: true })
41
- balance: number;
42
-
43
- @Column()
44
- enabled: boolean
45
-
46
- @CreateDateColumn()
47
- createdAt: Date;
48
-
49
- @UpdateDateColumn()
50
- updatedAt: Date;
51
-
52
- @OneToMany(() => Transaction, transaction => transaction.wallet)
53
- transactions: Transaction[]
54
- }
@@ -1,42 +0,0 @@
1
- import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
2
- import { Reflector } from '@nestjs/core';
3
- import { RequirePermission } from '../decorator/permission.decorator';
4
- import { Observable } from 'rxjs';
5
- import { User } from '../../user/user.entity';
6
-
7
- @Injectable()
8
- export class PermissionGuard implements CanActivate {
9
- constructor(private reflector: Reflector) { }
10
-
11
- canActivate(
12
- context: ExecutionContext,
13
- ): boolean | Promise<boolean> | Observable<boolean> {
14
- const permission = this.reflector.get(RequirePermission, context.getHandler());
15
-
16
- if (!permission) {
17
- return true;
18
- }
19
-
20
- const request = context.switchToHttp().getRequest();
21
-
22
- const user: User = request.user;
23
-
24
- if (!user) {
25
- return false
26
- }
27
-
28
- return this.matchPermission(permission, user);
29
- }
30
-
31
- matchPermission(permission: string, user: User) {
32
- const roles = user.roles
33
-
34
- if (!roles || roles.length < 1) {
35
- return false
36
- }
37
-
38
- const permissions = roles.map(role => role.permissions).reduce((acc, curr) => [...acc, ...curr]) ?? []
39
- const permissionNames = permissions?.map(permission => permission.name)
40
- return permissionNames.includes(permission)
41
- }
42
- }
@@ -1,9 +0,0 @@
1
- import { applyDecorators, UseGuards } from '@nestjs/common';
2
- import { ApiBearerAuth } from '@nestjs/swagger';
3
-
4
- export function SwaggerAuth() {
5
- return applyDecorators(
6
- // UseGuards(AuthGuard),
7
- ApiBearerAuth()
8
- );
9
- }
@@ -1 +0,0 @@
1
- export default class ArrayHelper {}
@@ -1,27 +0,0 @@
1
- import { DefaultNamingStrategy, NamingStrategyInterface } from 'typeorm';
2
-
3
- export class CustomNamingStrategy
4
- extends DefaultNamingStrategy
5
- implements NamingStrategyInterface {
6
- tableName(className: string, customName: string): string {
7
- return customName ? customName : this.snakeCase(className);
8
- }
9
-
10
- columnName(
11
- propertyName: string,
12
- customName: string,
13
- //embeddedPrefixes: string[],
14
- ): string {
15
- return customName ? customName : this.snakeCase(propertyName);
16
- }
17
-
18
- relationName(propertyName: string): string {
19
- return this.snakeCase(propertyName);
20
- }
21
-
22
- private snakeCase(name: string): string {
23
- return name
24
- .replace(/([A-Z])/g, (match) => `_${match.toLowerCase()}`)
25
- .replace(/^_/, '');
26
- }
27
- }
@@ -1,21 +0,0 @@
1
- import { BadRequestException } from '@nestjs/common';
2
-
3
- export default class DateHelper {
4
- public static formatDateToYYYYMMDD(dateString: string) {
5
- try {
6
- const date = new Date(dateString);
7
-
8
- // Ensure the input is a valid Date object
9
- if (!(date instanceof Date)) {
10
- throw new BadRequestException('Invalid date');
11
- }
12
-
13
- // Format the date using the formatter
14
- const formattedDate = date.toISOString().split('T')[0];
15
-
16
- return formattedDate;
17
- } catch (error) {
18
- throw new BadRequestException('Invalid date');
19
- }
20
- }
21
- }
@@ -1,38 +0,0 @@
1
-
2
- import * as Handlebars from 'handlebars';
3
- import { FileSystemHelper } from "./FileSystemHelper";
4
-
5
- export default class EmailHelper {
6
- public static async compileStringTemplate(rawTemplate: string, variables: Record<string, any>): Promise<string> {
7
- try {
8
- // Compile it with Handlebars
9
- const compiled = Handlebars.compile(rawTemplate);
10
-
11
- const html = compiled(variables);
12
-
13
- return html;
14
- } catch (error) {
15
- throw new Error(`Failed to generate HTML: ${error.message}`);
16
- }
17
- }
18
-
19
- public static async compileTemplate(templatePath: string, variables: Record<string, any>): Promise<string> {
20
- try {
21
- // Load the raw template
22
- const rawTemplate = FileSystemHelper.loadFile(templatePath);
23
-
24
- // Compile it with Handlebars
25
- const compiled = Handlebars.compile(rawTemplate);
26
-
27
- if (templatePath.includes('layout')) {
28
- console.log({ compiled, variables })
29
- }
30
-
31
- const html = compiled(variables);
32
-
33
- return html;
34
- } catch (error) {
35
- throw new Error(`Failed to generate HTML: ${error.message}`);
36
- }
37
- }
38
- }
@@ -1,101 +0,0 @@
1
- import { readFileSync, readdirSync, statSync, promises, constants } from 'fs';
2
- import * as path from 'path';
3
-
4
- export class FileSystemHelper {
5
- private static root: string = path.join(__dirname, '../../mail/templates/');
6
-
7
- public static async getFilePath(fileName: string): Promise<string> {
8
- const filePath = path.join(this.root, fileName);
9
- return filePath
10
- }
11
-
12
- public static async checkFileExists(fileName: string): Promise<boolean> {
13
- const filePath = path.join(this.root, fileName);
14
-
15
- try {
16
- await promises.access(`${filePath}`, constants.F_OK)
17
- console.log({ filePath, found: true })
18
- return true
19
- } catch (error) {
20
- console.log({ filePath, found: false })
21
- return false
22
- }
23
- }
24
-
25
- public static loadFileWithFullPath(path: string): string {
26
- const fileContent = readFileSync(path, 'utf-8');
27
- return fileContent;
28
- }
29
-
30
- public static loadFile(fileName: string): string {
31
- const filePath = path.join(this.root, fileName);
32
-
33
- const fileContent = readFileSync(filePath, 'utf-8');
34
- return fileContent;
35
- }
36
-
37
- public static async splitFilePath(filePath: string) {
38
- // Normalize the file path to handle both Windows and Unix formats
39
- let normalizedPath = path.normalize(filePath)
40
- normalizedPath = normalizedPath.replaceAll('\\', '/')
41
-
42
- // Get the file name (last part of the path)
43
- const fileName = path.basename(normalizedPath);
44
-
45
- // Get the directory path
46
- const directoryPath = path.dirname(normalizedPath);
47
- const extension = path.extname(fileName)
48
-
49
- // Split the directory path into an array of folders
50
- const folderArray = directoryPath.split('/');
51
-
52
- // Reassemble the folder path as a string (optional, if you need it in this format)
53
- const folderPath = folderArray.join('/');
54
-
55
- return {
56
- folderArray,
57
- folderPath,
58
- fileName,
59
- extension
60
- };
61
- }
62
-
63
- public static loadTemplate(fileName: string): string {
64
- const filePath = path.join(this.root, `${fileName}`);
65
-
66
- const fileContent = readFileSync(filePath, 'utf-8');
67
- return fileContent;
68
- }
69
-
70
- // Method to list all .html files from the templates directory
71
- public static listHtmlFilesInTemplates(): string[] {
72
- const htmlFiles: string[] = [];
73
-
74
- const getFilesRecursively = (dir: string) => {
75
- try {
76
- const files = readdirSync(dir);
77
-
78
- files.forEach(file => {
79
- const fullPath = path.join(dir, file);
80
- const relativePath = path.relative(this.root, fullPath);
81
-
82
- if (statSync(fullPath).isDirectory()) {
83
- // If it's a directory, go deeper
84
- getFilesRecursively(fullPath);
85
- } else if (file.endsWith('.html')) {
86
- // If it's an HTML file, add to the list
87
- htmlFiles.push(relativePath);
88
- }
89
- });
90
- } catch (error) {
91
- console.log(error)
92
- throw error
93
- }
94
- };
95
-
96
- // Start the recursion from the templates folder
97
- getFilesRecursively(this.root);
98
-
99
- return htmlFiles;
100
- }
101
- }
package/index.ts DELETED
@@ -1,9 +0,0 @@
1
- // Pagination
2
- export * from './pagination';
3
-
4
- // Types
5
- export * from './standard-response';
6
-
7
- // Entities
8
- export * from './entities';
9
-
@@ -1,58 +0,0 @@
1
- import { Injectable, NestMiddleware, Logger } from '@nestjs/common';
2
- import { Request, Response, NextFunction } from 'express';
3
-
4
- @Injectable()
5
- export class AccessLoggerMiddleware implements NestMiddleware {
6
- private readonly logger = new Logger('HTTP');
7
-
8
- use = (request: Request, response: Response, next: NextFunction): void => {
9
- const { ip, method, originalUrl: url } = request;
10
- const userAgent = request.get('user-agent') || '';
11
- const startTime = Date.now();
12
-
13
- // 👇 capture body but don’t log yet
14
- const originalSend = response.send;
15
- let responseBody: any;
16
-
17
- response.send = function (body?: any): Response {
18
- responseBody = body;
19
- return originalSend.call(this, body);
20
- };
21
-
22
- response.on('finish', () => {
23
- const { statusCode } = response;
24
- const contentLength = response.get('content-length');
25
- const responseTime = Date.now() - startTime;
26
-
27
- const message = {
28
- method,
29
- url,
30
- statusCode,
31
- contentLength,
32
- responseTime: `${responseTime}ms`,
33
- userAgent,
34
- ip,
35
- timestamp: new Date().toISOString(),
36
- };
37
-
38
- if (statusCode >= 500) {
39
- this.logger.error(JSON.stringify(message));
40
-
41
- // 👇 only log the response body here
42
- try {
43
- if (typeof responseBody === 'object') {
44
- console.log('Response body:', JSON.stringify(responseBody, null, 2));
45
- } else {
46
- console.log('Response body:', responseBody);
47
- }
48
- } catch (err) {
49
- console.log('Response body (unserializable):', responseBody);
50
- }
51
- } else {
52
- this.logger.log(JSON.stringify(message));
53
- }
54
- });
55
-
56
- next();
57
- };
58
- }
@@ -1,13 +0,0 @@
1
- import { Injectable, NestMiddleware } from '@nestjs/common';
2
- import { Request, Response, NextFunction } from 'express';
3
-
4
- @Injectable()
5
- export default class AuthenticationMiddleware implements NestMiddleware {
6
- use(req: Request, _res: Response, next: NextFunction) {
7
- // No-op authentication middleware for now. Consumers should attach
8
- // a real implementation or use a guard. This prevents build-time errors
9
- // where the middleware is referenced.
10
- // It preserves any existing req.user if already set by upstream middleware.
11
- return next();
12
- }
13
- }
@@ -1,52 +0,0 @@
1
- import { Injectable, NestMiddleware } from '@nestjs/common';
2
- import { Request, Response, NextFunction } from 'express';
3
-
4
- // Extend Express Request to include tenantId
5
- declare global {
6
- namespace Express {
7
- interface Request {
8
- tenantId?: number;
9
- }
10
- }
11
- }
12
-
13
- @Injectable()
14
- export class TenantMiddleware implements NestMiddleware {
15
- async use(req: Request, _res: Response, next: NextFunction) {
16
- // Prefer explicit header `x-tenant-id`
17
- const tenantIdHeader = (req.headers['x-tenant-id'] as string) || (req.headers['X-Tenant-Id'] as string);
18
- if (tenantIdHeader) {
19
- const id = parseInt(tenantIdHeader, 10);
20
- if (!isNaN(id)) {
21
- req.tenantId = id;
22
- return next();
23
- }
24
- }
25
-
26
- // Fall back to subdomain extraction (subdomain.domain.tld)
27
- const host = (req.hostname || req.headers.host || '').toString();
28
- const subdomain = this.extractSubdomain(host);
29
- if (subdomain) {
30
- // If subdomain is numeric, treat as tenantId; otherwise leave undefined
31
- const id = parseInt(subdomain, 10);
32
- if (!isNaN(id)) {
33
- req.tenantId = id;
34
- }
35
- }
36
-
37
- next();
38
- }
39
-
40
- private extractSubdomain(host: string): string | null {
41
- if (!host) return null;
42
- const hostname = host.split(':')[0];
43
- const parts = hostname.split('.');
44
- if (hostname === 'localhost' || /^(\d{1,3}\.){3}\d{1,3}$/.test(hostname)) {
45
- return null;
46
- }
47
- if (parts.length >= 3) return parts[0];
48
- return null;
49
- }
50
- }
51
-
52
- export default TenantMiddleware;
@@ -1,2 +0,0 @@
1
- export * from './pagination.types';
2
- export * from './pagination.helper';
@@ -1,57 +0,0 @@
1
- import { PaginatedResponse, PaginationQuery } from './pagination.types';
2
-
3
- export class PaginationHelper {
4
- /**
5
- * Creates a paginated response object
6
- */
7
- static paginate<T>(
8
- items: T[],
9
- total: number,
10
- query: PaginationQuery
11
- ): PaginatedResponse<T> {
12
- const page = Math.max(1, query.page || 1);
13
- const limit = this.getLimit(query.limit);
14
- const totalPages = Math.ceil(total / limit);
15
-
16
- return {
17
- data: items,
18
- meta: {
19
- total,
20
- page,
21
- limit,
22
- totalPages,
23
- hasNext: page < totalPages,
24
- hasPrev: page > 1,
25
- },
26
- };
27
- }
28
-
29
- /**
30
- * Calculate the number of records to skip for pagination
31
- */
32
- static getSkip(page?: number, limit?: number): number {
33
- const actualPage = Math.max(1, page || 1);
34
- const actualLimit = this.getLimit(limit);
35
- return (actualPage - 1) * actualLimit;
36
- }
37
-
38
- /**
39
- * Get validated limit (min: 1, max: 100, default: 10)
40
- */
41
- static getLimit(limit?: number): number {
42
- return Math.min(100, Math.max(1, limit || 10));
43
- }
44
-
45
- /**
46
- * Parse and validate pagination query parameters
47
- */
48
- static parseQuery(query: any): PaginationQuery {
49
- return {
50
- page: query.page ? parseInt(query.page, 10) : 1,
51
- limit: query.limit ? parseInt(query.limit, 10) : 10,
52
- sortBy: query.sortBy || 'id',
53
- sortOrder: query.sortOrder?.toUpperCase() === 'ASC' ? 'ASC' : 'DESC',
54
- search: query.search || undefined,
55
- };
56
- }
57
- }
@@ -1,21 +0,0 @@
1
- export interface PaginationQuery {
2
- page?: number;
3
- limit?: number;
4
- sortBy?: string;
5
- sortOrder?: 'ASC' | 'DESC';
6
- search?: string;
7
- }
8
-
9
- export interface PaginationMeta {
10
- total: number;
11
- page: number;
12
- limit: number;
13
- totalPages: number;
14
- hasNext: boolean;
15
- hasPrev: boolean;
16
- }
17
-
18
- export interface PaginatedResponse<T> {
19
- data: T[];
20
- meta: PaginationMeta;
21
- }