startx 0.0.1 → 0.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.
Files changed (155) hide show
  1. package/.prettierignore +0 -13
  2. package/.prettierrc.js +52 -52
  3. package/.vscode/launch.json +32 -0
  4. package/.vscode/settings.json +9 -3
  5. package/apps/core-server/.env.example +18 -24
  6. package/apps/core-server/Dockerfile +35 -61
  7. package/apps/core-server/eslint.config.ts +7 -0
  8. package/apps/core-server/package.json +41 -52
  9. package/apps/core-server/src/config/custom-type.ts +2 -40
  10. package/apps/core-server/src/events/index.ts +37 -37
  11. package/apps/core-server/src/index.ts +4 -13
  12. package/apps/core-server/src/middlewares/auth-middleware.ts +24 -7
  13. package/apps/core-server/src/middlewares/cors-middleware.ts +7 -6
  14. package/apps/core-server/src/middlewares/error-middleware.ts +7 -4
  15. package/apps/core-server/src/middlewares/logger-middleware.ts +81 -21
  16. package/apps/core-server/src/middlewares/notfound-middleware.ts +6 -14
  17. package/apps/core-server/src/middlewares/serve-static.ts +30 -24
  18. package/apps/core-server/src/routes/files/router.ts +9 -7
  19. package/apps/core-server/src/routes/server.ts +30 -36
  20. package/apps/core-server/tsdown.config.ts +4 -3
  21. package/biome.json +58 -60
  22. package/configs/eslint-config/package.json +16 -19
  23. package/configs/eslint-config/src/configs/base.ts +185 -225
  24. package/configs/eslint-config/src/configs/extend.ts +3 -0
  25. package/configs/eslint-config/src/configs/frontend.ts +81 -56
  26. package/configs/eslint-config/src/configs/node.ts +6 -6
  27. package/configs/eslint-config/src/plugin.ts +1 -0
  28. package/configs/eslint-config/src/rules/index.ts +8 -12
  29. package/configs/eslint-config/src/rules/no-json-parse-json-stringify.test.ts +30 -17
  30. package/configs/eslint-config/src/rules/no-json-parse-json-stringify.ts +52 -49
  31. package/configs/eslint-config/src/rules/no-uncaught-json-parse.ts +43 -45
  32. package/configs/tsdown-config/package.json +10 -3
  33. package/configs/typescript-config/package.json +10 -1
  34. package/configs/typescript-config/tsconfig.common.json +3 -3
  35. package/configs/vitest-config/dist/base.mjs +1 -0
  36. package/configs/vitest-config/dist/frontend.mjs +1 -0
  37. package/configs/vitest-config/dist/node.mjs +1 -0
  38. package/configs/vitest-config/package.json +12 -0
  39. package/configs/vitest-config/src/base.ts +17 -29
  40. package/configs/vitest-config/src/index.ts +1 -0
  41. package/package.json +15 -26
  42. package/packages/@repo/constants/eslint.config.ts +4 -0
  43. package/packages/@repo/constants/package.json +16 -0
  44. package/packages/@repo/constants/src/index.ts +8 -8
  45. package/packages/@repo/db/eslint.config.ts +4 -0
  46. package/packages/@repo/db/package.json +16 -8
  47. package/packages/@repo/db/src/index.ts +26 -20
  48. package/packages/@repo/db/src/schema/common.ts +45 -49
  49. package/packages/@repo/env/eslint.config.ts +4 -0
  50. package/packages/@repo/env/package.json +39 -0
  51. package/packages/@repo/env/src/default-env.ts +12 -0
  52. package/packages/@repo/env/src/define-env.ts +70 -0
  53. package/packages/@repo/env/src/index.ts +2 -0
  54. package/packages/@repo/env/src/utils.ts +52 -0
  55. package/packages/@repo/env/tsconfig.json +7 -0
  56. package/packages/@repo/lib/eslint.config.ts +4 -0
  57. package/packages/@repo/lib/package.json +34 -34
  58. package/packages/@repo/lib/src/bucket-module/file-storage.ts +50 -49
  59. package/packages/@repo/lib/src/bucket-module/index.ts +3 -0
  60. package/packages/@repo/lib/src/bucket-module/s3-storage.ts +120 -114
  61. package/packages/@repo/lib/src/bucket-module/utils.ts +10 -11
  62. package/packages/@repo/lib/src/{cookie-module.ts → cookie-module/cookie-module.ts} +48 -42
  63. package/packages/@repo/lib/src/cookie-module/index.ts +1 -0
  64. package/packages/@repo/lib/src/extra/index.ts +1 -0
  65. package/packages/@repo/lib/src/extra/pagination-module.ts +35 -0
  66. package/packages/@repo/lib/src/{token-module.ts → extra/token-module.ts} +12 -5
  67. package/packages/@repo/lib/src/file-system-module/index.ts +170 -0
  68. package/packages/@repo/lib/src/{hashing-module.ts → hashing-module/index.ts} +9 -9
  69. package/packages/@repo/lib/src/index.ts +0 -26
  70. package/packages/@repo/lib/src/mail-module/index.ts +2 -0
  71. package/packages/@repo/lib/src/mail-module/mock.ts +8 -8
  72. package/packages/@repo/lib/src/mail-module/nodemailer.ts +17 -7
  73. package/packages/@repo/lib/src/notification-module/index.ts +1 -172
  74. package/packages/@repo/lib/src/notification-module/push-notification.ts +97 -90
  75. package/packages/@repo/lib/src/{oauth2-client.ts → oauth2-module/index.ts} +107 -109
  76. package/packages/@repo/lib/src/otp-module/index.ts +91 -0
  77. package/packages/@repo/lib/src/session-module/index.ts +113 -0
  78. package/packages/@repo/lib/src/utils.ts +43 -42
  79. package/packages/@repo/lib/src/validation-module/index.ts +242 -0
  80. package/packages/@repo/logger/eslint.config.ts +4 -0
  81. package/packages/@repo/logger/package.json +40 -0
  82. package/packages/@repo/logger/src/index.ts +2 -0
  83. package/packages/@repo/logger/src/logger.ts +72 -0
  84. package/packages/@repo/{lib/src/logger-module → logger/src}/memory-profiler.ts +64 -65
  85. package/packages/@repo/logger/tsconfig.json +7 -0
  86. package/packages/@repo/mail/eslint.config.ts +4 -0
  87. package/packages/@repo/mail/package.json +10 -3
  88. package/packages/@repo/mail/src/emails/admin/OtpEmail.tsx +169 -168
  89. package/packages/@repo/mail/src/index.ts +1 -2
  90. package/packages/@repo/mail/tsconfig.json +3 -3
  91. package/packages/@repo/redis/dist/index.d.mts +3 -0
  92. package/packages/@repo/redis/dist/index.mjs +5 -0
  93. package/packages/@repo/redis/dist/lib/redis-client.d.mts +7 -0
  94. package/packages/@repo/redis/dist/lib/redis-client.mjs +25 -0
  95. package/packages/@repo/redis/dist/lib/redis-client.mjs.map +1 -0
  96. package/packages/@repo/redis/dist/lib/redis-module.d.mts +5 -0
  97. package/packages/@repo/redis/dist/lib/redis-module.mjs +6 -0
  98. package/packages/@repo/redis/dist/lib/redis-module.mjs.map +1 -0
  99. package/packages/@repo/redis/eslint.config.ts +4 -0
  100. package/packages/@repo/redis/package.json +13 -10
  101. package/packages/@repo/redis/src/index.ts +2 -2
  102. package/packages/@repo/redis/src/lib/redis-client.ts +36 -23
  103. package/packages/@repo/redis/src/lib/redis-module.ts +69 -3
  104. package/packages/cli/dist/index.mjs +203 -0
  105. package/packages/cli/eslint.config.ts +4 -0
  106. package/packages/cli/package.json +44 -0
  107. package/packages/cli/tsconfig.json +12 -0
  108. package/packages/cli/tsdown.config.ts +17 -0
  109. package/packages/ui/components.json +0 -1
  110. package/packages/ui/eslint.config.ts +4 -0
  111. package/packages/ui/package.json +16 -3
  112. package/packages/ui/postcss.config.mjs +9 -9
  113. package/packages/ui/src/components/lib/utils.ts +53 -53
  114. package/packages/ui/src/components/ui/alert-dialog.tsx +118 -116
  115. package/packages/ui/src/components/ui/avatar.tsx +52 -53
  116. package/packages/ui/src/components/ui/badge.tsx +45 -46
  117. package/packages/ui/src/components/ui/breadcrumb.tsx +108 -109
  118. package/packages/ui/src/components/ui/card.tsx +91 -92
  119. package/packages/ui/src/components/ui/carousel.tsx +243 -243
  120. package/packages/ui/src/components/ui/checkbox.tsx +32 -32
  121. package/packages/ui/src/components/ui/command.tsx +144 -155
  122. package/packages/ui/src/components/ui/dialog.tsx +124 -127
  123. package/packages/ui/src/components/ui/form.tsx +166 -165
  124. package/packages/ui/src/components/ui/input-otp.tsx +74 -76
  125. package/packages/ui/src/components/ui/input.tsx +19 -21
  126. package/packages/ui/src/components/ui/multiple-select.tsx +4 -4
  127. package/packages/ui/src/{components/lucide.tsx → lucide.ts} +3 -3
  128. package/packages/ui/tailwind.config.ts +94 -94
  129. package/packages/ui/tsconfig.json +7 -1
  130. package/pnpm-workspace.yaml +41 -1
  131. package/startx.json +22 -0
  132. package/turbo.json +20 -27
  133. package/apps/core-server/eslint.config.mjs +0 -47
  134. package/configs/eslint-config/src/rules/no-dynamic-import-template.ts +0 -32
  135. package/configs/eslint-config/src/rules/no-plain-errors.ts +0 -50
  136. package/configs/eslint-config/tsdown.config.ts +0 -11
  137. package/packages/@repo/constants/eslint.config.mjs +0 -21
  138. package/packages/@repo/db/eslint.config.mjs +0 -21
  139. package/packages/@repo/lib/eslint.config.mjs +0 -49
  140. package/packages/@repo/lib/src/command-module.ts +0 -77
  141. package/packages/@repo/lib/src/constants.ts +0 -3
  142. package/packages/@repo/lib/src/custom-type.ts +0 -54
  143. package/packages/@repo/lib/src/env.ts +0 -13
  144. package/packages/@repo/lib/src/file-system/index.ts +0 -90
  145. package/packages/@repo/lib/src/logger-module/log-config.ts +0 -16
  146. package/packages/@repo/lib/src/logger-module/logger.ts +0 -78
  147. package/packages/@repo/lib/src/mail-module/api.ts +0 -0
  148. package/packages/@repo/lib/src/otp-module.ts +0 -98
  149. package/packages/@repo/lib/src/pagination-module.ts +0 -49
  150. package/packages/@repo/lib/src/user-session.ts +0 -117
  151. package/packages/@repo/lib/src/validation-module.ts +0 -187
  152. package/packages/@repo/mail/tsconfig.build.json +0 -14
  153. package/packages/@repo/mail/tsdown.config.ts +0 -9
  154. package/packages/@repo/redis/eslint.config.mjs +0 -8
  155. package/packages/ui/eslint.config.mjs +0 -18
@@ -1,114 +1,120 @@
1
- /**
2
- * TODO: connect to bucket
3
- */
4
- import {
5
- DeleteObjectCommand,
6
- PutObjectCommand,
7
- type PutObjectCommandInput,
8
- S3Client,
9
- } from "@aws-sdk/client-s3";
10
-
11
- const s3Endpoint = process.env.S3_ENDPOINT;
12
-
13
- const credentials = {
14
- accessKeyId: process.env.AWS_ACCESS_KEY_ID,
15
- secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
16
- };
17
-
18
- // Create an S3 service client object.
19
- const s3Client = new S3Client({
20
- credentials,
21
- region: process.env.AWS_REGION,
22
- endpoint: s3Endpoint,
23
- });
24
-
25
- const bucket = process.env.AWS_BUCKET;
26
-
27
- export type UploadFile = {
28
- name: string;
29
- mimetype: string;
30
- data: Buffer;
31
- };
32
-
33
- export class S3Bucket {
34
- static async uploadFile(file: UploadFile, path: string) {
35
- let key = `${path}`;
36
- if (!key.includes(".")) {
37
- key += ".jpeg";
38
- }
39
- const params = {
40
- Bucket: bucket,
41
- Key: key,
42
- Body: file.data,
43
- ContentType: file.mimetype,
44
- } as PutObjectCommandInput;
45
- const command = new PutObjectCommand(params);
46
- await s3Client.send(command);
47
- const fileUrl = S3Bucket.getAwsUrl(key);
48
- return fileUrl;
49
- }
50
-
51
- static getAwsUrl(path: string) {
52
- return `https://${bucket}.s3.${process.env.AWS_REGION}.amazonaws.com/${path}`;
53
- }
54
-
55
- static getKeyFromUrl(url: string) {
56
- const key = url.split(`https://${bucket}.s3.${process.env.AWS_REGION}.amazonaws.com/`)[1];
57
- return key;
58
- }
59
-
60
- static async uploadFiles({ path, files }: { path: string; files: UploadFile[] }) {
61
- try {
62
- if (!path) throw new Error("Path must be provided.");
63
- if (!files) throw new Error("File must be provided.");
64
- // const buffers: UploadFile[] = [];
65
- // for (const key in file) {
66
- // const item = file[key];
67
- // if (Array.isArray(item)) item.forEach((e) => buffers.push(e));
68
- // else buffers.push(item!);
69
- // }
70
-
71
- // let upload = [] as { url: string; type: string; name: string }[];
72
- const upload = await Promise.all(
73
- files.map(async (file) => {
74
- const key = file.name;
75
- const params: PutObjectCommandInput = {
76
- Bucket: bucket,
77
- Key: `${path}/${key}`,
78
- Body: file.data,
79
- ContentType: file.mimetype,
80
- };
81
- const command = new PutObjectCommand(params);
82
- await s3Client.send(command);
83
- return {
84
- url: S3Bucket.getAwsUrl(`${path}/${key}`),
85
- type: file.mimetype,
86
- name: file.name,
87
- };
88
- }),
89
- );
90
- return upload;
91
- // if (upload.length > 0) return upload;
92
- // else throw new Error("Something went wrong.");
93
- } catch (error) {
94
- console.log(error);
95
- throw error;
96
- }
97
- }
98
-
99
- // ! don't use
100
- static async deleteFile(path: string) {
101
- try {
102
- const params = {
103
- Bucket: bucket,
104
- Key: path,
105
- };
106
-
107
- const command = new DeleteObjectCommand(params);
108
- await s3Client.send(command);
109
- } catch (error) {
110
- console.log(error);
111
- throw error;
112
- }
113
- }
114
- }
1
+ /**
2
+ * TODO: connect to bucket
3
+ */
4
+ import {
5
+ DeleteObjectCommand,
6
+ PutObjectCommand,
7
+ type PutObjectCommandInput,
8
+ S3Client,
9
+ } from "@aws-sdk/client-s3";
10
+ import { defineEnv } from "@repo/env";
11
+ import z from "zod";
12
+
13
+ const credentials = defineEnv({
14
+ AWS_ACCESS_KEY_ID: z.string(),
15
+ AWS_SECRET_ACCESS_KEY: z.string(),
16
+ AWS_REGION: z.string().default("us-east-1"),
17
+ AWS_BUCKET: z.string(),
18
+ S3_ENDPOINT: z.string().optional(),
19
+ });
20
+
21
+ const s3Endpoint = credentials.S3_ENDPOINT;
22
+ const s3Client = new S3Client({
23
+ credentials: {
24
+ accessKeyId: credentials.AWS_ACCESS_KEY_ID,
25
+ secretAccessKey: credentials.AWS_SECRET_ACCESS_KEY,
26
+ },
27
+ region: credentials.AWS_REGION,
28
+ endpoint: s3Endpoint,
29
+ });
30
+
31
+ const bucket = credentials.AWS_BUCKET;
32
+
33
+ export type UploadFile = {
34
+ name: string;
35
+ mimetype: string;
36
+ data: Buffer;
37
+ };
38
+
39
+ export class S3Bucket {
40
+ static async uploadFile(file: UploadFile, path: string) {
41
+ let key = `${path}`;
42
+ if (!key.includes(".")) {
43
+ key += ".jpeg";
44
+ }
45
+ const params = {
46
+ Bucket: bucket,
47
+ Key: key,
48
+ Body: file.data,
49
+ ContentType: file.mimetype,
50
+ } as PutObjectCommandInput;
51
+ const command = new PutObjectCommand(params);
52
+ await s3Client.send(command);
53
+ const fileUrl = S3Bucket.getAwsUrl(key);
54
+ return fileUrl;
55
+ }
56
+
57
+ static getAwsUrl(path: string) {
58
+ return `https://${bucket}.s3.${credentials.AWS_REGION}.amazonaws.com/${path}`;
59
+ }
60
+
61
+ static getKeyFromUrl(url: string) {
62
+ const key = url.split(`https://${bucket}.s3.${credentials.AWS_REGION}.amazonaws.com/`)[1];
63
+ return key;
64
+ }
65
+
66
+ static async uploadFiles({ path, files }: { path: string; files: UploadFile[] }) {
67
+ try {
68
+ if (!path) throw new Error("Path must be provided.");
69
+ if (!files) throw new Error("File must be provided.");
70
+ // const buffers: UploadFile[] = [];
71
+ // for (const key in file) {
72
+ // const item = file[key];
73
+ // if (Array.isArray(item)) item.forEach((e) => buffers.push(e));
74
+ // else buffers.push(item!);
75
+ // }
76
+
77
+ // let upload = [] as { url: string; type: string; name: string }[];
78
+ const upload = await Promise.all(
79
+ files.map(async file => {
80
+ const key = file.name;
81
+ const params: PutObjectCommandInput = {
82
+ Bucket: bucket,
83
+ Key: `${path}/${key}`,
84
+ Body: file.data,
85
+ ContentType: file.mimetype,
86
+ };
87
+ const command = new PutObjectCommand(params);
88
+ await s3Client.send(command);
89
+ return {
90
+ url: S3Bucket.getAwsUrl(`${path}/${key}`),
91
+ type: file.mimetype,
92
+ name: file.name,
93
+ };
94
+ })
95
+ );
96
+ return upload;
97
+ // if (upload.length > 0) return upload;
98
+ // else throw new Error("Something went wrong.");
99
+ } catch (error) {
100
+ console.log(error);
101
+ throw error;
102
+ }
103
+ }
104
+
105
+ // ! don't use
106
+ static async deleteFile(path: string) {
107
+ try {
108
+ const params = {
109
+ Bucket: bucket,
110
+ Key: path,
111
+ };
112
+
113
+ const command = new DeleteObjectCommand(params);
114
+ await s3Client.send(command);
115
+ } catch (error) {
116
+ console.log(error);
117
+ throw error;
118
+ }
119
+ }
120
+ }
@@ -1,11 +1,10 @@
1
- import { S3Bucket } from "./s3-storage.js";
2
-
3
- export const pathGenerator = {
4
- asset: {
5
- base: "image/assets",
6
- supportImage: "image/assets/bemyguest_support.png",
7
- },
8
- profile: (userId: string) => `user/${userId}/profile`,
9
- };
10
-
11
- export const defaultAvatarUrl = `${S3Bucket.getAwsUrl("image/assets/avatar_image.png")}`;
1
+ import { S3Bucket } from "./s3-storage.js";
2
+
3
+ export const pathGenerator = {
4
+ asset: {
5
+ base: "image/assets",
6
+ },
7
+ profile: (userId: string) => `user/${userId}/profile`,
8
+ };
9
+
10
+ export const defaultAvatarUrl = `${S3Bucket.getAwsUrl("image/assets/avatar_image.png")}`;
@@ -1,42 +1,48 @@
1
- import type { CookieOptions } from "express";
2
-
3
- const constants = {
4
- refreshToken: {
5
- cookie: "",
6
- cookieDomain: "",
7
- secureCookie: false,
8
- maxAge: 0,
9
- },
10
- initialize() {
11
- const prodMaxAge = 1000 * 60 * 60 * 24 * 30;
12
- const stagingMaxAge = 1000 * 60 * 60 * 24 * 365;
13
- const prodEnv = process.env.NODE_ENV === "production";
14
- const stagingEnv = process.env.NODE_ENV === "staging";
15
-
16
- if (prodEnv) {
17
- this.refreshToken.cookie = "refresh-token";
18
- this.refreshToken.cookieDomain = process.env.COOKIE_DOMAIN;
19
- this.refreshToken.secureCookie = true;
20
- this.refreshToken.maxAge = prodMaxAge;
21
- } else {
22
- this.refreshToken.cookie = "refresh-token-staging";
23
- this.refreshToken.cookieDomain = stagingEnv
24
- ? process.env.COOKIE_DOMAIN
25
- : process.env.COOKIE_DOMAIN || "localhost";
26
- this.refreshToken.secureCookie = stagingEnv ? true : false;
27
- this.refreshToken.maxAge = stagingMaxAge;
28
- }
29
- },
30
- };
31
- constants.initialize();
32
-
33
- export function getCookieOptions(refreshToken: string): [string, string, CookieOptions] {
34
- const cookieOptions: CookieOptions = {
35
- domain: constants.refreshToken.cookieDomain,
36
- maxAge: constants.refreshToken.maxAge,
37
- sameSite: "lax",
38
- httpOnly: true,
39
- secure: constants.refreshToken.secureCookie,
40
- };
41
- return [constants.refreshToken.cookie, refreshToken, cookieOptions];
42
- }
1
+ import { defineEnv, ENV } from "@repo/env";
2
+ import type { CookieOptions } from "express";
3
+ import z from "zod";
4
+
5
+ const credentials = defineEnv({
6
+ COOKIE_DOMAIN: z.string().optional().default(".localhost"),
7
+ });
8
+
9
+ const constants = {
10
+ refreshToken: {
11
+ cookie: "",
12
+ cookieDomain: "",
13
+ secureCookie: false,
14
+ maxAge: 0,
15
+ },
16
+ initialize() {
17
+ const prodMaxAge = 1000 * 60 * 60 * 24 * 30;
18
+ const stagingMaxAge = 1000 * 60 * 60 * 24 * 365;
19
+ const prodEnv = ENV.NODE_ENV === "production";
20
+ const stagingEnv = ENV.NODE_ENV === "staging";
21
+
22
+ if (prodEnv) {
23
+ this.refreshToken.cookie = "refresh-token";
24
+ this.refreshToken.cookieDomain = credentials.COOKIE_DOMAIN;
25
+ this.refreshToken.secureCookie = true;
26
+ this.refreshToken.maxAge = prodMaxAge;
27
+ } else {
28
+ this.refreshToken.cookie = "refresh-token-staging";
29
+ this.refreshToken.cookieDomain = stagingEnv
30
+ ? credentials.COOKIE_DOMAIN
31
+ : credentials.COOKIE_DOMAIN || "localhost";
32
+ this.refreshToken.secureCookie = stagingEnv ? true : false;
33
+ this.refreshToken.maxAge = stagingMaxAge;
34
+ }
35
+ },
36
+ };
37
+ constants.initialize();
38
+
39
+ export function getCookieOptions(refreshToken: string): [string, string, CookieOptions] {
40
+ const cookieOptions: CookieOptions = {
41
+ domain: constants.refreshToken.cookieDomain,
42
+ maxAge: constants.refreshToken.maxAge,
43
+ sameSite: "lax",
44
+ httpOnly: true,
45
+ secure: constants.refreshToken.secureCookie,
46
+ };
47
+ return [constants.refreshToken.cookie, refreshToken, cookieOptions];
48
+ }
@@ -0,0 +1 @@
1
+ export * from "./cookie-module.js";
@@ -0,0 +1 @@
1
+ export * from "./pagination-module.js";
@@ -0,0 +1,35 @@
1
+ type PageQuery = { page?: string; limit?: string };
2
+
3
+ export class Paginator {
4
+ static getPage(query: PageQuery = { page: "1", limit: "10" }) {
5
+ const page = parseInt(query.page ?? "1", 10);
6
+ const limit = parseInt(query.limit ?? "20", 10);
7
+ const offset = (page - 1) * limit;
8
+ return { page, limit, offset };
9
+ }
10
+
11
+ static async getTotalCount(
12
+ promise: Promise<
13
+ Array<{
14
+ count: number;
15
+ }>
16
+ >
17
+ ) {
18
+ const result = await promise;
19
+ return result[0]?.count || 0;
20
+ }
21
+
22
+ static paginate<T>(query: PageQuery = { page: "1", limit: "10" }, rows: T[], total: number) {
23
+ const { page, limit } = Paginator.getPage(query);
24
+ const totalPages = Math.ceil(total / limit);
25
+ return {
26
+ data: rows,
27
+ pagination: {
28
+ total,
29
+ totalPages,
30
+ currentPage: page,
31
+ pageSize: limit,
32
+ },
33
+ };
34
+ }
35
+ }
@@ -1,10 +1,17 @@
1
+ import { defineEnv, ENV } from "@repo/env";
1
2
  import * as jwt from "jsonwebtoken";
3
+ import z from "zod";
2
4
  export type AuthTokenPayload = {
3
5
  userID: string;
4
6
  email: string;
5
7
  };
6
- const accessTokenSecret = process.env.ACCESS_TOKEN_SECRET;
7
- const refreshTokenSecret = process.env.REFRESH_TOKEN_SECRET;
8
+
9
+ const credentials = defineEnv({
10
+ ACCESS_TOKEN_SECRET: z.string(),
11
+ REFRESH_TOKEN_SECRET: z.string(),
12
+ });
13
+ const accessTokenSecret = credentials.ACCESS_TOKEN_SECRET;
14
+ const refreshTokenSecret = credentials.REFRESH_TOKEN_SECRET;
8
15
 
9
16
  export class TokenModule {
10
17
  static signRefreshToken(payload: AuthTokenPayload) {
@@ -15,12 +22,12 @@ export class TokenModule {
15
22
  const payload = jwt.verify(refreshToken, refreshTokenSecret) as AuthTokenPayload;
16
23
  return payload;
17
24
  } catch (error) {
18
- console.error(error)
25
+ console.error(error);
19
26
  return null;
20
27
  }
21
28
  }
22
29
  static signAccessToken(payload: AuthTokenPayload) {
23
- const expiration = process.env.NODE_ENV === "development" ? "30d" : "1d";
30
+ const expiration = ENV.NODE_ENV === "development" ? "30d" : "1d";
24
31
  return jwt.sign(payload, accessTokenSecret, { expiresIn: expiration });
25
32
  }
26
33
  static verifyAccessToken(accessToken: string) {
@@ -28,7 +35,7 @@ export class TokenModule {
28
35
  const payload = jwt.verify(accessToken, accessTokenSecret) as AuthTokenPayload;
29
36
  return payload;
30
37
  } catch (error) {
31
- console.error(error)
38
+ console.error(error);
32
39
  return null;
33
40
  }
34
41
  }
@@ -0,0 +1,170 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import YAML from "yaml";
4
+
5
+ import { __dirname } from "../utils.js";
6
+
7
+ export class FStool {
8
+ root = __dirname();
9
+
10
+ private async pathExists(target: string) {
11
+ try {
12
+ await fs.access(target);
13
+ return true;
14
+ } catch {
15
+ return false;
16
+ }
17
+ }
18
+
19
+ async writeFile({ file, content }: { file: string; content: string }) {
20
+ await fs.writeFile(path.resolve(this.root, file), content);
21
+ }
22
+
23
+ async writeJSONFile({ file, content, dir }: { file: string; content: object; dir?: string }) {
24
+ file = `${file}.json`;
25
+
26
+ let destination = path.resolve(this.root, file);
27
+
28
+ if (dir) {
29
+ const dirPath = path.resolve(this.root, dir);
30
+ await this.ensurePathExists({ dir });
31
+ destination = path.resolve(dirPath, file);
32
+ }
33
+
34
+ await fs.writeFile(destination, JSON.stringify(content, null, 2));
35
+ }
36
+
37
+ async readFile({ file }: { file: string }) {
38
+ return await fs.readFile(path.resolve(this.root, file), "utf-8");
39
+ }
40
+
41
+ async readJSONFile<T>({ file, dir }: { file: string; dir?: string }) {
42
+ try {
43
+ file = `${file}.json`;
44
+ const fullPath = path.resolve(this.root, dir ?? "", file);
45
+ const data = await fs.readFile(fullPath, "utf-8");
46
+ return JSON.parse(data) as T;
47
+ } catch (error) {
48
+ console.error(`Failed to read JSON file at ${file}:`, error);
49
+ return null;
50
+ }
51
+ }
52
+
53
+ async readYamlFile({ file, dir }: { file: string; dir?: string }) {
54
+ try {
55
+ file = `${file}.yaml`;
56
+ const fullPath = path.resolve(this.root, dir ?? "", file);
57
+ const data = await fs.readFile(fullPath, "utf-8");
58
+ return YAML.parseDocument(data);
59
+ } catch (error) {
60
+ console.error(`Failed to read Yaml file at ${file}:`, error);
61
+ return null;
62
+ }
63
+ }
64
+
65
+ async ensurePathExists({ dir }: { dir: string }) {
66
+ const fullPath = path.resolve(this.root, dir);
67
+ if (!(await this.pathExists(fullPath))) {
68
+ await fs.mkdir(fullPath, { recursive: true });
69
+ }
70
+ }
71
+
72
+ async avoidOverriding({ file }: { file: string }) {
73
+ const fullPath = path.resolve(this.root, file);
74
+ if (await this.pathExists(fullPath)) {
75
+ throw new Error(`File ${fullPath} already exists`);
76
+ }
77
+ }
78
+
79
+ async removeFile({ file }: { file: string }) {
80
+ const fullPath = path.resolve(this.root, file);
81
+ if (await this.pathExists(fullPath)) {
82
+ await fs.unlink(fullPath);
83
+ }
84
+ }
85
+
86
+ async removeDirectory({ dir, target }: { dir: string; target: string }) {
87
+ const fullPath = path.resolve(this.root, dir, target);
88
+ if (await this.pathExists(fullPath)) {
89
+ await fs.rm(fullPath, { recursive: true, force: true });
90
+ }
91
+ }
92
+
93
+ async copyFile({ from, to }: { from: string; to: string }) {
94
+ await this.ensurePathExists({ dir: path.dirname(to) });
95
+ await fs.copyFile(path.resolve(this.root, from), path.resolve(this.root, to));
96
+ }
97
+
98
+ async copyDirectory({
99
+ from,
100
+ to,
101
+
102
+ recursive = true,
103
+ include,
104
+ exclude,
105
+ }: {
106
+ from: string;
107
+ to: string;
108
+ recursive?: boolean;
109
+ include?: RegExp;
110
+ exclude?: RegExp;
111
+ }) {
112
+ const source = path.resolve(this.root, from);
113
+ const destination = path.resolve(this.root, to);
114
+
115
+ if (!(await this.pathExists(source))) return;
116
+
117
+ await this.ensurePathExists({ dir: path.join(to) });
118
+
119
+ const entries = await fs.readdir(source, { withFileTypes: true });
120
+
121
+ for (const entry of entries) {
122
+ const srcPath = path.join(source, entry.name);
123
+ const destPath = path.join(destination, entry.name);
124
+
125
+ const shouldInclude =
126
+ (!include || include.test(entry.name)) && (!exclude || !exclude.test(entry.name));
127
+
128
+ if (entry.isDirectory()) {
129
+ if (recursive) {
130
+ await this.copyDirectory({
131
+ from: path.join(from, entry.name),
132
+ to: path.join(to, entry.name),
133
+ recursive,
134
+ include,
135
+ exclude,
136
+ });
137
+ }
138
+ } else if (entry.isFile()) {
139
+ if (shouldInclude) {
140
+ await fs.copyFile(srcPath, destPath);
141
+ }
142
+ }
143
+ }
144
+ }
145
+ async listDirectories({ dir }: { dir: string }) {
146
+ try {
147
+ const entries = await fs.readdir(path.resolve(this.root, dir), {
148
+ withFileTypes: true,
149
+ });
150
+ return entries.filter(e => e.isDirectory()).map(e => e.name);
151
+ } catch (error) {
152
+ console.error(`Error listing directories in ${dir}:`, error); // Exposes the error
153
+ return [];
154
+ }
155
+ }
156
+
157
+ async listFiles({ dir }: { dir: string }) {
158
+ try {
159
+ const entries = await fs.readdir(path.resolve(this.root, dir), {
160
+ withFileTypes: true,
161
+ });
162
+ return entries.filter(e => e.isFile()).map(e => e.name);
163
+ } catch (error) {
164
+ console.error(`Error listing files in ${dir}:`, error); // Exposes the error
165
+ return [];
166
+ }
167
+ }
168
+ }
169
+
170
+ export const fsTool = new FStool();
@@ -1,9 +1,9 @@
1
- import bcrypt from "bcryptjs";
2
- export class HashingModule {
3
- static async hash(password: string) {
4
- return await bcrypt.hash(password, 10);
5
- }
6
- static async compare(password: string, hash: string) {
7
- return await bcrypt.compare(password, hash);
8
- }
9
- }
1
+ import bcrypt from "bcryptjs";
2
+ export class HashingModule {
3
+ static async hash(password: string) {
4
+ return await bcrypt.hash(password, 10);
5
+ }
6
+ static async compare(password: string, hash: string) {
7
+ return await bcrypt.compare(password, hash);
8
+ }
9
+ }
@@ -1,27 +1 @@
1
- // eslint-disable-next-line import-x/export
2
- export type * from "./custom-type.js";
3
1
  export * from "./utils.js";
4
- export * from "./logger-module/logger.js";
5
- export * from "./notification-module/push-notification.js";
6
- export * from "./token-module.js";
7
- export * from "./bucket-module/file-storage.js";
8
- export * from "./bucket-module/s3-storage.js";
9
- export * from "./bucket-module/utils.js";
10
- // export * from "./compression-module/compression-module.js";
11
-
12
- // export * from "./env.js";
13
- export * from "./file-system/index.js";
14
- export * from "./mail-module/mock.js";
15
- export * from "./mail-module/nodemailer.js";
16
-
17
- export * from "./cookie-module.js";
18
- export * from "./hashing-module.js";
19
-
20
- export * from "./oauth2-client.js";
21
- export * from "./otp-module.js";
22
- export * from "./pagination-module.js";
23
- export * from "./error-handlers-module/index.js";
24
- export * from "./validation-module.js";
25
- export * from "./command-module.js";
26
- export * from "./logger-module/memory-profiler.js";
27
- export * from "./user-session.js";
@@ -0,0 +1,2 @@
1
+ export * from "./mock.js";
2
+ export * from "./nodemailer.js";