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.
- package/.prettierignore +0 -13
- package/.prettierrc.js +52 -52
- package/.vscode/launch.json +32 -0
- package/.vscode/settings.json +9 -3
- package/apps/core-server/.env.example +18 -24
- package/apps/core-server/Dockerfile +35 -61
- package/apps/core-server/eslint.config.ts +7 -0
- package/apps/core-server/package.json +41 -52
- package/apps/core-server/src/config/custom-type.ts +2 -40
- package/apps/core-server/src/events/index.ts +37 -37
- package/apps/core-server/src/index.ts +4 -13
- package/apps/core-server/src/middlewares/auth-middleware.ts +24 -7
- package/apps/core-server/src/middlewares/cors-middleware.ts +7 -6
- package/apps/core-server/src/middlewares/error-middleware.ts +7 -4
- package/apps/core-server/src/middlewares/logger-middleware.ts +81 -21
- package/apps/core-server/src/middlewares/notfound-middleware.ts +6 -14
- package/apps/core-server/src/middlewares/serve-static.ts +30 -24
- package/apps/core-server/src/routes/files/router.ts +9 -7
- package/apps/core-server/src/routes/server.ts +30 -36
- package/apps/core-server/tsdown.config.ts +4 -3
- package/biome.json +58 -60
- package/configs/eslint-config/package.json +16 -19
- package/configs/eslint-config/src/configs/base.ts +185 -225
- package/configs/eslint-config/src/configs/extend.ts +3 -0
- package/configs/eslint-config/src/configs/frontend.ts +81 -56
- package/configs/eslint-config/src/configs/node.ts +6 -6
- package/configs/eslint-config/src/plugin.ts +1 -0
- package/configs/eslint-config/src/rules/index.ts +8 -12
- package/configs/eslint-config/src/rules/no-json-parse-json-stringify.test.ts +30 -17
- package/configs/eslint-config/src/rules/no-json-parse-json-stringify.ts +52 -49
- package/configs/eslint-config/src/rules/no-uncaught-json-parse.ts +43 -45
- package/configs/tsdown-config/package.json +10 -3
- package/configs/typescript-config/package.json +10 -1
- package/configs/typescript-config/tsconfig.common.json +3 -3
- package/configs/vitest-config/dist/base.mjs +1 -0
- package/configs/vitest-config/dist/frontend.mjs +1 -0
- package/configs/vitest-config/dist/node.mjs +1 -0
- package/configs/vitest-config/package.json +12 -0
- package/configs/vitest-config/src/base.ts +17 -29
- package/configs/vitest-config/src/index.ts +1 -0
- package/package.json +15 -26
- package/packages/@repo/constants/eslint.config.ts +4 -0
- package/packages/@repo/constants/package.json +16 -0
- package/packages/@repo/constants/src/index.ts +8 -8
- package/packages/@repo/db/eslint.config.ts +4 -0
- package/packages/@repo/db/package.json +16 -8
- package/packages/@repo/db/src/index.ts +26 -20
- package/packages/@repo/db/src/schema/common.ts +45 -49
- package/packages/@repo/env/eslint.config.ts +4 -0
- package/packages/@repo/env/package.json +39 -0
- package/packages/@repo/env/src/default-env.ts +12 -0
- package/packages/@repo/env/src/define-env.ts +70 -0
- package/packages/@repo/env/src/index.ts +2 -0
- package/packages/@repo/env/src/utils.ts +52 -0
- package/packages/@repo/env/tsconfig.json +7 -0
- package/packages/@repo/lib/eslint.config.ts +4 -0
- package/packages/@repo/lib/package.json +34 -34
- package/packages/@repo/lib/src/bucket-module/file-storage.ts +50 -49
- package/packages/@repo/lib/src/bucket-module/index.ts +3 -0
- package/packages/@repo/lib/src/bucket-module/s3-storage.ts +120 -114
- package/packages/@repo/lib/src/bucket-module/utils.ts +10 -11
- package/packages/@repo/lib/src/{cookie-module.ts → cookie-module/cookie-module.ts} +48 -42
- package/packages/@repo/lib/src/cookie-module/index.ts +1 -0
- package/packages/@repo/lib/src/extra/index.ts +1 -0
- package/packages/@repo/lib/src/extra/pagination-module.ts +35 -0
- package/packages/@repo/lib/src/{token-module.ts → extra/token-module.ts} +12 -5
- package/packages/@repo/lib/src/file-system-module/index.ts +170 -0
- package/packages/@repo/lib/src/{hashing-module.ts → hashing-module/index.ts} +9 -9
- package/packages/@repo/lib/src/index.ts +0 -26
- package/packages/@repo/lib/src/mail-module/index.ts +2 -0
- package/packages/@repo/lib/src/mail-module/mock.ts +8 -8
- package/packages/@repo/lib/src/mail-module/nodemailer.ts +17 -7
- package/packages/@repo/lib/src/notification-module/index.ts +1 -172
- package/packages/@repo/lib/src/notification-module/push-notification.ts +97 -90
- package/packages/@repo/lib/src/{oauth2-client.ts → oauth2-module/index.ts} +107 -109
- package/packages/@repo/lib/src/otp-module/index.ts +91 -0
- package/packages/@repo/lib/src/session-module/index.ts +113 -0
- package/packages/@repo/lib/src/utils.ts +43 -42
- package/packages/@repo/lib/src/validation-module/index.ts +242 -0
- package/packages/@repo/logger/eslint.config.ts +4 -0
- package/packages/@repo/logger/package.json +40 -0
- package/packages/@repo/logger/src/index.ts +2 -0
- package/packages/@repo/logger/src/logger.ts +72 -0
- package/packages/@repo/{lib/src/logger-module → logger/src}/memory-profiler.ts +64 -65
- package/packages/@repo/logger/tsconfig.json +7 -0
- package/packages/@repo/mail/eslint.config.ts +4 -0
- package/packages/@repo/mail/package.json +10 -3
- package/packages/@repo/mail/src/emails/admin/OtpEmail.tsx +169 -168
- package/packages/@repo/mail/src/index.ts +1 -2
- package/packages/@repo/mail/tsconfig.json +3 -3
- package/packages/@repo/redis/dist/index.d.mts +3 -0
- package/packages/@repo/redis/dist/index.mjs +5 -0
- package/packages/@repo/redis/dist/lib/redis-client.d.mts +7 -0
- package/packages/@repo/redis/dist/lib/redis-client.mjs +25 -0
- package/packages/@repo/redis/dist/lib/redis-client.mjs.map +1 -0
- package/packages/@repo/redis/dist/lib/redis-module.d.mts +5 -0
- package/packages/@repo/redis/dist/lib/redis-module.mjs +6 -0
- package/packages/@repo/redis/dist/lib/redis-module.mjs.map +1 -0
- package/packages/@repo/redis/eslint.config.ts +4 -0
- package/packages/@repo/redis/package.json +13 -10
- package/packages/@repo/redis/src/index.ts +2 -2
- package/packages/@repo/redis/src/lib/redis-client.ts +36 -23
- package/packages/@repo/redis/src/lib/redis-module.ts +69 -3
- package/packages/cli/dist/index.mjs +203 -0
- package/packages/cli/eslint.config.ts +4 -0
- package/packages/cli/package.json +44 -0
- package/packages/cli/tsconfig.json +12 -0
- package/packages/cli/tsdown.config.ts +17 -0
- package/packages/ui/components.json +0 -1
- package/packages/ui/eslint.config.ts +4 -0
- package/packages/ui/package.json +16 -3
- package/packages/ui/postcss.config.mjs +9 -9
- package/packages/ui/src/components/lib/utils.ts +53 -53
- package/packages/ui/src/components/ui/alert-dialog.tsx +118 -116
- package/packages/ui/src/components/ui/avatar.tsx +52 -53
- package/packages/ui/src/components/ui/badge.tsx +45 -46
- package/packages/ui/src/components/ui/breadcrumb.tsx +108 -109
- package/packages/ui/src/components/ui/card.tsx +91 -92
- package/packages/ui/src/components/ui/carousel.tsx +243 -243
- package/packages/ui/src/components/ui/checkbox.tsx +32 -32
- package/packages/ui/src/components/ui/command.tsx +144 -155
- package/packages/ui/src/components/ui/dialog.tsx +124 -127
- package/packages/ui/src/components/ui/form.tsx +166 -165
- package/packages/ui/src/components/ui/input-otp.tsx +74 -76
- package/packages/ui/src/components/ui/input.tsx +19 -21
- package/packages/ui/src/components/ui/multiple-select.tsx +4 -4
- package/packages/ui/src/{components/lucide.tsx → lucide.ts} +3 -3
- package/packages/ui/tailwind.config.ts +94 -94
- package/packages/ui/tsconfig.json +7 -1
- package/pnpm-workspace.yaml +41 -1
- package/startx.json +22 -0
- package/turbo.json +20 -27
- package/apps/core-server/eslint.config.mjs +0 -47
- package/configs/eslint-config/src/rules/no-dynamic-import-template.ts +0 -32
- package/configs/eslint-config/src/rules/no-plain-errors.ts +0 -50
- package/configs/eslint-config/tsdown.config.ts +0 -11
- package/packages/@repo/constants/eslint.config.mjs +0 -21
- package/packages/@repo/db/eslint.config.mjs +0 -21
- package/packages/@repo/lib/eslint.config.mjs +0 -49
- package/packages/@repo/lib/src/command-module.ts +0 -77
- package/packages/@repo/lib/src/constants.ts +0 -3
- package/packages/@repo/lib/src/custom-type.ts +0 -54
- package/packages/@repo/lib/src/env.ts +0 -13
- package/packages/@repo/lib/src/file-system/index.ts +0 -90
- package/packages/@repo/lib/src/logger-module/log-config.ts +0 -16
- package/packages/@repo/lib/src/logger-module/logger.ts +0 -78
- package/packages/@repo/lib/src/mail-module/api.ts +0 -0
- package/packages/@repo/lib/src/otp-module.ts +0 -98
- package/packages/@repo/lib/src/pagination-module.ts +0 -49
- package/packages/@repo/lib/src/user-session.ts +0 -117
- package/packages/@repo/lib/src/validation-module.ts +0 -187
- package/packages/@repo/mail/tsconfig.build.json +0 -14
- package/packages/@repo/mail/tsdown.config.ts +0 -9
- package/packages/@repo/redis/eslint.config.mjs +0 -8
- 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
|
-
|
|
12
|
-
|
|
13
|
-
const credentials = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
export
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
//
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
this.refreshToken.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
this.refreshToken.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
7
|
-
const
|
|
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 =
|
|
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";
|