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,49 +1,45 @@
1
- import { pgTable, uuid, varchar, timestamp, pgEnum, text } from "drizzle-orm/pg-core";
2
-
3
- // Helper function to generate current timestamp
4
-
5
- export const userRoleEnum = pgEnum("user_role", ["user", "admin", "superuser"]);
6
-
7
- export const usersTable = pgTable("users", {
8
- id: uuid("id").primaryKey().defaultRandom(),
9
- email: varchar("email", { length: 255 }).notNull().unique(),
10
- fullName: varchar("full_name", { length: 255 }).default("Guest").notNull(),
11
- password: varchar("password", { length: 255 }).default("foresight").notNull(),
12
- countries: varchar("countries", { length: 255 }).array().notNull().default([]),
13
- verifiedAt: timestamp("verified_at"),
14
- pwdUpdatedAt: timestamp("pwd_updated_at"),
15
- deletedAt: timestamp("deleted_at"),
16
- createdAt: timestamp("created_at").defaultNow(),
17
- lastLoginAt: timestamp("last_login_at").defaultNow(),
18
- updatedAt: timestamp("updated_at")
19
- .defaultNow()
20
- .$onUpdate(() => new Date()),
21
- });
22
-
23
- export const filesTable = pgTable("files", {
24
- id: uuid("id").primaryKey().defaultRandom(),
25
- fileName: varchar("file_name", { length: 255 }).notNull(),
26
- url: text("url").notNull(),
27
- mimetype: text("mimetype").notNull(),
28
- preview: text("preview"),
29
- createdAt: timestamp("created_at").defaultNow(),
30
- updatedAt: timestamp("updated_at")
31
- .defaultNow()
32
- .$onUpdate(() => new Date()),
33
- });
34
-
35
- export const otps = pgTable("otp", {
36
- id: uuid("id").primaryKey().defaultRandom(),
37
- email: varchar("email", { length: 255 }).notNull().unique(),
38
- phone: varchar("phone", { length: 50 }),
39
- status: varchar("status", { enum: ["pending", "verified"] })
40
- .notNull()
41
- .default("pending"),
42
- otp: varchar("otp", { length: 255 }).notNull(),
43
- createdAt: timestamp("created_at").defaultNow(),
44
- updatedAt: timestamp("updated_at")
45
- .defaultNow()
46
- .$onUpdate(() => new Date()),
47
- });
48
-
49
- // ----------------------------------------------------------------------------
1
+ import { pgEnum, pgTable, text, timestamp, uuid, varchar } from "drizzle-orm/pg-core";
2
+
3
+ export const userRoleEnum = pgEnum("user_role", ["user", "admin", "superuser"]);
4
+
5
+ export const usersTable = pgTable("users", {
6
+ id: uuid("id").primaryKey().defaultRandom(),
7
+ email: varchar("email", { length: 255 }).notNull().unique(),
8
+ fullName: varchar("full_name", { length: 255 }).default("Guest").notNull(),
9
+ password: varchar("password", { length: 255 }).default("foresight").notNull(),
10
+ countries: varchar("countries", { length: 255 }).array().notNull().default([]),
11
+ verifiedAt: timestamp("verified_at"),
12
+ pwdUpdatedAt: timestamp("pwd_updated_at"),
13
+ deletedAt: timestamp("deleted_at"),
14
+ createdAt: timestamp("created_at").defaultNow(),
15
+ lastLoginAt: timestamp("last_login_at").defaultNow(),
16
+ updatedAt: timestamp("updated_at")
17
+ .defaultNow()
18
+ .$onUpdate(() => new Date()),
19
+ });
20
+
21
+ export const filesTable = pgTable("files", {
22
+ id: uuid("id").primaryKey().defaultRandom(),
23
+ fileName: varchar("file_name", { length: 255 }).notNull(),
24
+ url: text("url").notNull(),
25
+ mimetype: text("mimetype").notNull(),
26
+ preview: text("preview"),
27
+ createdAt: timestamp("created_at").defaultNow(),
28
+ updatedAt: timestamp("updated_at")
29
+ .defaultNow()
30
+ .$onUpdate(() => new Date()),
31
+ });
32
+
33
+ export const otps = pgTable("otp", {
34
+ id: uuid("id").primaryKey().defaultRandom(),
35
+ email: varchar("email", { length: 255 }).notNull().unique(),
36
+ phone: varchar("phone", { length: 50 }),
37
+ status: varchar("status", { enum: ["pending", "verified"] })
38
+ .notNull()
39
+ .default("pending"),
40
+ otp: varchar("otp", { length: 255 }).notNull(),
41
+ createdAt: timestamp("created_at").defaultNow(),
42
+ updatedAt: timestamp("updated_at")
43
+ .defaultNow()
44
+ .$onUpdate(() => new Date()),
45
+ });
@@ -0,0 +1,4 @@
1
+ import { baseConfig } from "eslint-config/base";
2
+ import { extend } from "eslint-config/extend";
3
+
4
+ export default extend(baseConfig);
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@repo/env",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "private": true,
6
+ "scripts": {
7
+ "clean": "rimraf dist .turbo",
8
+ "watch:dev": "pnpm watch",
9
+ "typecheck": "tsc --noEmit",
10
+ "format": "biome format --write .",
11
+ "format:check": "biome ci .",
12
+ "lint": "eslint .",
13
+ "lint:fix": "eslint . --fix",
14
+ "watch": "tsc -p tsconfig.build.json --watch"
15
+ },
16
+ "exports": "./src/index.ts",
17
+ "types": "./src/index.ts",
18
+
19
+ "devDependencies": {
20
+ "eslint-config": "workspace:*",
21
+ "typescript-config": "workspace:*",
22
+ "vitest": "catalog:",
23
+ "vitest-config": "workspace:*"
24
+ },
25
+ "dependencies": {
26
+ "dotenv": "catalog:"
27
+ },
28
+ "startx": {
29
+ "tags": [
30
+ "node"
31
+ ],
32
+ "requiredDeps": [
33
+ "@repo/env"
34
+ ],
35
+ "requiredDevDeps": [
36
+ "typescript-config"
37
+ ]
38
+ }
39
+ }
@@ -0,0 +1,12 @@
1
+ import z from "zod";
2
+
3
+ import { defineEnv } from "./define-env.js";
4
+
5
+ export const ENV = defineEnv({
6
+ NODE_ENV: z.enum(["development", "production", "test", "staging"]).default("production"),
7
+ CLIENT_URL: z.string().optional().default("http://localhost:5000"),
8
+ SERVER_URL: z.string().optional().default("http://localhost:3000"),
9
+ CORS_URL: z.string().optional().default("http://localhost:3000"),
10
+ PORT: z.string().optional().default("3000"),
11
+ LOG_LEVEL: z.enum(["error", "warn", "info", "http", "debug"]).default("debug"),
12
+ });
@@ -0,0 +1,70 @@
1
+ import type { ZodTypeAny } from "zod";
2
+ import { ZodError, z } from "zod";
3
+
4
+ import { loadDotenv } from "./utils.js";
5
+
6
+ loadDotenv();
7
+
8
+ type SpecEntry =
9
+ | ZodTypeAny
10
+ | {
11
+ schema: ZodTypeAny;
12
+ default?: unknown;
13
+ env?: string;
14
+ description?: string;
15
+ };
16
+
17
+ type Spec = Record<string, SpecEntry>;
18
+
19
+ type InferSpec<S extends Spec> = {
20
+ [K in keyof S]: S[K] extends ZodTypeAny
21
+ ? z.infer<S[K]>
22
+ : S[K] extends { schema: ZodTypeAny }
23
+ ? z.infer<S[K]["schema"]>
24
+ : never;
25
+ };
26
+
27
+ function isZod(v: SpecEntry): v is ZodTypeAny {
28
+ return typeof v === "object" && v !== null && "parse" in v;
29
+ }
30
+
31
+ const tempEnv = new Map<string, string>();
32
+
33
+ export function defineEnv<S extends Spec>(spec: S): InferSpec<S> {
34
+ const rawEnv: Record<string, unknown> = {};
35
+ const zodShape: Record<string, ZodTypeAny> = {};
36
+
37
+ for (const key of Object.keys(spec) as Array<keyof S>) {
38
+ const entry = spec[key];
39
+
40
+ const normalized = isZod(entry)
41
+ ? { schema: entry, default: undefined, env: key as string }
42
+ : {
43
+ schema: entry.schema,
44
+ default: entry.default,
45
+ env: entry.env ?? (key as string),
46
+ };
47
+
48
+ if (process.env[normalized.env]) {
49
+ tempEnv.set(normalized.env, process.env[normalized.env] ?? "");
50
+ delete process.env[normalized.env];
51
+ }
52
+ const raw = tempEnv.get(normalized.env);
53
+
54
+ rawEnv[key as string] = raw === undefined ? normalized.default : raw;
55
+
56
+ zodShape[key as string] = normalized.schema;
57
+ }
58
+
59
+ try {
60
+ const result = z.object(zodShape).parse(rawEnv);
61
+ return result as InferSpec<S>;
62
+ } catch (err: unknown) {
63
+ if (err instanceof ZodError) {
64
+ const messages = err.issues.map(e => `${e.path.join(".")}: ${e.message}`);
65
+
66
+ throw new Error(`Invalid environment variables:\n ❌ ${messages.join("\n ❌ ")}`);
67
+ }
68
+ throw err;
69
+ }
70
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./default-env.js";
2
+ export { defineEnv } from "./define-env.js";
@@ -0,0 +1,52 @@
1
+ process.env.DOTENV_CONFIG_QUIET = "true";
2
+
3
+ import { config } from "dotenv";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+
7
+ /**
8
+ * Resolve a stable project root:
9
+ * - prefer explicit PROJECT_ROOT env var if set (handy for CI)
10
+ * - else, base on this file's location (safe in ESM)
11
+ * - fallback to process.cwd()
12
+ */
13
+ export function projectRoot() {
14
+ if (process.env.PROJECT_ROOT) return path.resolve(process.env.PROJECT_ROOT);
15
+ try {
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const thisDir = path.dirname(__filename);
18
+ return path.resolve(thisDir, "../../../../");
19
+ } catch (error) {
20
+ console.error({ error });
21
+ return process.cwd();
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Load .env files with a clear precedence:
27
+ * - test: .env.test (and optional .env.test.local)
28
+ * - otherwise: .env -> .env.local (local should override .env)
29
+ *
30
+ * Behavior: load base first, then local override with override: true so local wins.
31
+ */
32
+ export function loadDotenv(opts?: { root?: string }) {
33
+ const root = opts?.root ?? projectRoot();
34
+
35
+ if (process.env.NODE_ENV === "test") {
36
+ config({ path: path.join(root, ".env.test") });
37
+ // optional: if you want local test overrides
38
+ config({ path: path.join(root, ".env.test.local"), override: true });
39
+ return;
40
+ }
41
+
42
+ // production/dev flow
43
+ config({ path: path.join(process.cwd(), ".env") }); // prod
44
+ // dev env
45
+ config({ path: path.join(root, ".env") });
46
+ // .env.local should override the base (for dev machine secrets)
47
+ config({ path: path.join(root, ".env.local"), override: true });
48
+ // also load .env.${NODE_ENV}.local if you want per-env local overrides:
49
+ if (process.env.NODE_ENV) {
50
+ config({ path: path.join(root, `.env.${process.env.NODE_ENV}.local`), override: true });
51
+ }
52
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "typescript-config/tsconfig.node.json",
3
+ "compilerOptions": {
4
+ "baseUrl": "./src"
5
+ },
6
+ "include": ["src/**/*.ts"]
7
+ }
@@ -0,0 +1,4 @@
1
+ import { baseConfig } from "eslint-config/base";
2
+ import { extend } from "eslint-config/extend";
3
+
4
+ export default extend(baseConfig);
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@repo/lib",
3
3
  "version": "0.0.0",
4
+ "type": "module",
4
5
  "private": true,
5
6
  "scripts": {
6
7
  "clean": "rimraf dist .turbo",
@@ -12,46 +13,45 @@
12
13
  "lint:fix": "eslint . --fix",
13
14
  "watch": "tsc -p tsconfig.build.json --watch"
14
15
  },
15
- "files": [
16
- "dist/**/*"
17
- ],
18
- "exports": "./src/index.ts",
16
+ "exports": {
17
+ ".": "./src/index.ts",
18
+ "./*": "./src/*/index.ts"
19
+ },
19
20
  "devDependencies": {
20
- "@repo/email": "workspace:*",
21
- "@repo/redis": "workspace:*",
22
- "@types/eslint": "^8.56.5",
23
- "@types/express": "^5.0.0",
24
- "@types/node": "^20.16.5",
25
21
  "@types/jsonwebtoken": "^9.0.7",
26
22
  "@types/nodemailer": "^6.4.16",
27
23
  "eslint-config": "workspace:*",
28
- "tsc-alias": "^1.8.10",
29
24
  "typescript-config": "workspace:*",
30
- "vitest": "catalog:",
31
- "vitest-config": "workspace:*",
32
- "vitest-mock-extended": "^3.1.0",
33
- "vine": "link:@types/vinejs/vine"
25
+ "vine": "link:@types/vinejs/vine",
26
+ "vitest-config": "workspace:*"
34
27
  },
35
28
  "dependencies": {
36
- "@aws-sdk/client-s3": "^3.693.0",
37
- "@repo/db": "workspace:^",
38
- "@types/express-fileupload": "^1.5.1",
39
- "@vinejs/vine": "^4.3.0",
40
- "@repo/email": "workspace:*",
41
- "axios": "^1.7.7",
42
- "bcryptjs": "^3.0.2",
43
- "country-state-city": "^3.2.1",
44
- "dayjs": "^1.11.13",
45
- "dayjs-plugin-utc": "^0.1.2",
46
- "dotenv": "^16.6.1",
47
- "drizzle-orm": "^0.36.0",
48
- "express": "^4.21.1",
49
- "express-fileupload": "^1.5.1",
50
- "firebase-admin": "^13.0.2",
51
- "fs.promises.exists": "^1.1.4",
52
- "jsonwebtoken": "^9.0.2",
53
- "nodemailer": "^6.9.16",
54
- "winston": "^3.16.0",
55
- "winston-daily-rotate-file": "^5.0.0"
29
+ "@repo/redis": "workspace:*",
30
+ "@aws-sdk/client-s3": "catalog:",
31
+ "@repo/mail": "workspace:*",
32
+ "@repo/logger": "workspace:*",
33
+ "@repo/env": "workspace:*",
34
+ "@types/express": "catalog:",
35
+ "@types/express-fileupload": "catalog:",
36
+ "bcryptjs": "catalog:",
37
+ "firebase-admin": "catalog:",
38
+ "jsonwebtoken": "catalog:",
39
+ "nodemailer": "catalog:",
40
+ "yaml": "^2.8.2"
41
+ },
42
+ "startx": {
43
+ "tags": [
44
+ "node",
45
+ "backend"
46
+ ],
47
+ "requiredDeps": [
48
+ "@repo/env",
49
+ "@repo/logger",
50
+ "@repo/mail",
51
+ "@repo/redis"
52
+ ],
53
+ "requiredDevDeps": [
54
+ "typescript-config"
55
+ ]
56
56
  }
57
57
  }
@@ -1,49 +1,50 @@
1
- import type { UploadedFile } from "express-fileupload";
2
- import fs from "fs";
3
- import path from "path";
4
-
5
- import { logger } from "../logger-module/logger";
6
- import { Random } from "../utils";
7
-
8
- export class FileBasedBucket {
9
- static async upload(file: UploadedFile, subpath?: string) {
10
- const fileName = Random.generateString(4, "hex") + path.extname(file.name);
11
- const filePath = path.join(process.cwd(), "storage", subpath ?? "", fileName);
12
- await FileBasedBucket.createDirectoryIfNotExists(`storage/${subpath ?? ""}`);
13
- await file.mv(filePath);
14
- const publicUrl = FileBasedBucket.getPublicUrl(`${subpath ?? ""}/${fileName}`);
15
- return publicUrl;
16
- }
17
- static deleteFile(url: string) {
18
- const filePath = FileBasedBucket.getPath(url);
19
- try {
20
- fs.unlinkSync(filePath);
21
- } catch (error) {
22
- logger.error("Error deleting file:", error);
23
- }
24
- }
25
-
26
- static getPath(url: string) {
27
- const path = url.replace(`${process.env.SERVER_URL}/files/`, `${process.cwd()}/storage/`);
28
- return path;
29
- }
30
-
31
- static getPublicUrl(key: string) {
32
- return path.join(process.env.SERVER_URL, "/files", key);
33
- }
34
-
35
- static async createDirectoryIfNotExists(path: string) {
36
- return await new Promise<boolean>((resolve, reject) => {
37
- if (fs.existsSync(path)) {
38
- resolve(true);
39
- } else {
40
- fs.mkdir(path, { recursive: true }, (err) => {
41
- if (err) {
42
- reject(err);
43
- }
44
- resolve(true);
45
- });
46
- }
47
- });
48
- }
49
- }
1
+ import { ENV } from "@repo/env";
2
+ import { logger } from "@repo/logger";
3
+ import type { UploadedFile } from "express-fileupload";
4
+ import fs from "fs";
5
+ import path from "path";
6
+
7
+ import { Random } from "../utils.js";
8
+
9
+ export class FileBasedBucket {
10
+ static async upload(file: UploadedFile, subpath?: string) {
11
+ const fileName = Random.generateString(4, "hex") + path.extname(file.name);
12
+ const filePath = path.join(process.cwd(), "storage", subpath ?? "", fileName);
13
+ await FileBasedBucket.createDirectoryIfNotExists(`storage/${subpath ?? ""}`);
14
+ await file.mv(filePath);
15
+ const publicUrl = FileBasedBucket.getPublicUrl(`${subpath ?? ""}/${fileName}`);
16
+ return publicUrl;
17
+ }
18
+ static deleteFile(url: string) {
19
+ const filePath = FileBasedBucket.getPath(url);
20
+ try {
21
+ fs.unlinkSync(filePath);
22
+ } catch (error) {
23
+ logger.error("Error deleting file:", error);
24
+ }
25
+ }
26
+
27
+ static getPath(url: string) {
28
+ const path = url.replace(`${ENV.SERVER_URL}/files/`, `${process.cwd()}/storage/`);
29
+ return path;
30
+ }
31
+
32
+ static getPublicUrl(key: string) {
33
+ return path.join(ENV.SERVER_URL, "/files", key);
34
+ }
35
+
36
+ static async createDirectoryIfNotExists(path: string) {
37
+ return await new Promise<boolean>((resolve, reject) => {
38
+ if (fs.existsSync(path)) {
39
+ resolve(true);
40
+ } else {
41
+ fs.mkdir(path, { recursive: true }, err => {
42
+ if (err) {
43
+ reject(err);
44
+ }
45
+ resolve(true);
46
+ });
47
+ }
48
+ });
49
+ }
50
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./file-storage.js";
2
+ export * from "./s3-storage.js";
3
+ export * from "./utils.js";