startx 0.7.2 → 0.9.0

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 (35) hide show
  1. package/.prettierrc.js +2 -2
  2. package/.vscode/settings.json +2 -1
  3. package/apps/core-server/package.json +1 -1
  4. package/apps/core-server/src/index.ts +0 -1
  5. package/apps/startx-cli/dist/index.mjs +2 -2
  6. package/apps/startx-cli/src/commands/init.ts +179 -257
  7. package/apps/startx-cli/src/configs/deps.ts +6 -1
  8. package/apps/startx-cli/src/configs/files.ts +3 -4
  9. package/apps/startx-cli/src/configs/scripts.ts +25 -7
  10. package/apps/startx-cli/src/types.ts +18 -6
  11. package/apps/startx-cli/src/utils/cli-utils.ts +60 -49
  12. package/apps/startx-cli/src/utils/file-handler.ts +14 -5
  13. package/biome.json +1 -1
  14. package/configs/eslint-config/eslint.config.ts +0 -0
  15. package/configs/eslint-config/src/configs/base.ts +32 -79
  16. package/configs/eslint-config/src/configs/extend.ts +2 -2
  17. package/configs/eslint-config/src/configs/frontend.ts +29 -19
  18. package/configs/eslint-config/src/configs/node.ts +46 -6
  19. package/configs/vitest-config/package.json +3 -2
  20. package/package.json +3 -2
  21. package/packages/@repo/db/drizzle.config.ts +14 -0
  22. package/packages/@repo/db/package.json +5 -1
  23. package/packages/@repo/db/src/index.ts +1 -1
  24. package/packages/@repo/lib/src/otp-module/index.ts +6 -13
  25. package/packages/@repo/lib/tsconfig.json +2 -1
  26. package/packages/@repo/mail/eslint.config.ts +2 -2
  27. package/packages/@repo/mail/src/emails/admin/OtpEmail.tsx +3 -9
  28. package/packages/@repo/mail/src/emails/emails.ts +1 -0
  29. package/packages/@repo/mail/src/index.ts +10 -9
  30. package/packages/@repo/mail/tsconfig.json +4 -2
  31. package/packages/ui/package.json +1 -0
  32. package/packages/ui/src/components/ui/command.tsx +5 -15
  33. package/pnpm-workspace.yaml +1 -0
  34. package/turbo.json +9 -0
  35. package/apps/startx-cli/src/utils/config.ts +0 -104
@@ -1,10 +1,50 @@
1
- import { defineConfig } from "eslint/config";
2
1
  import globals from "globals";
2
+ import tseslint from "typescript-eslint";
3
+
3
4
  import { baseConfig } from "./base.js";
4
5
 
5
- export const nodeConfig = defineConfig(baseConfig, {
6
- languageOptions: {
7
- ecmaVersion: 2024,
8
- globals: globals.node,
6
+ export const nodeConfig = tseslint.config(
7
+ ...baseConfig,
8
+
9
+ // 1. Backend/Node Specific Globals & Environments
10
+ {
11
+ files: ["**/*.ts", "**/*.js", "**/*.cjs", "**/*.mjs"],
12
+ languageOptions: {
13
+ // "latest" perfectly aligns with Node 20+ (ES2023/ES2024 features)
14
+ ecmaVersion: "latest",
15
+ sourceType: "module",
16
+ globals: {
17
+ ...globals.node,
18
+ ...globals.nodeBuiltin, // Explicitly adds modern Node built-ins (like fetch, structuredClone)
19
+ },
20
+ },
9
21
  },
10
- });
22
+
23
+ // 2. Node-Specific Overrides & Best Practices
24
+ {
25
+ files: ["**/*.ts", "**/*.js"],
26
+ rules: {
27
+ // Enforce the 'node:' protocol for built-ins (e.g., `import fs from 'node:fs'`)
28
+ // This is a modern Node.js standard that improves performance and security
29
+ "unicorn/prefer-node-protocol": "error",
30
+
31
+ // Prevent accidental use of obscure browser globals that sometimes slip through
32
+ "no-restricted-globals": [
33
+ "error",
34
+ {
35
+ name: "name",
36
+ message: "Global 'name' is deprecated. Did you mean to declare a local variable?",
37
+ },
38
+ {
39
+ name: "event",
40
+ message: "Global 'event' is a browser feature. Do not use it in Node.js.",
41
+ },
42
+ ],
43
+
44
+ // In Node apps, developers often accidentally leave floating promises
45
+ // which can cause unhandled promise rejections crashing the server.
46
+ // (This inherits from baseConfig, but I am noting it here as a critical backend safeguard).
47
+ // "@typescript-eslint/no-floating-promises": "error",
48
+ },
49
+ }
50
+ );
@@ -3,9 +3,10 @@
3
3
  "version": "1.5.0",
4
4
  "type": "module",
5
5
  "devDependencies": {
6
- "vitest": "catalog:",
6
+ "jsdom": "^29.0.1",
7
7
  "typescript-config": "workspace:*",
8
- "vite": "catalog:"
8
+ "vite": "catalog:",
9
+ "vitest": "catalog:"
9
10
  },
10
11
  "exports": {
11
12
  ".": "./src/index.ts",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "startx",
3
3
  "description": "",
4
- "version": "0.7.2",
4
+ "version": "0.9.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/avinashid/startx.git"
@@ -31,6 +31,7 @@
31
31
  "typecheck": "turbo typecheck",
32
32
  "clean": "turbo clean",
33
33
  "test": "turbo test",
34
- "format": "turbo format"
34
+ "format": "turbo format",
35
+ "db:push": "turbo db:push"
35
36
  }
36
37
  }
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from "drizzle-kit";
2
+ import { defineEnv } from "@repo/env";
3
+ import z from "zod";
4
+ const env = defineEnv({
5
+ DATABASE_URL: z.string(),
6
+ });
7
+ export default defineConfig({
8
+ out: "./drizzle",
9
+ schema: "./src/schema/index.ts",
10
+ dialect: "postgresql",
11
+ dbCredentials: {
12
+ url: env.DATABASE_URL!,
13
+ },
14
+ });
@@ -11,11 +11,13 @@
11
11
  "format:check": "biome ci .",
12
12
  "lint": "eslint .",
13
13
  "lint:fix": "eslint . --fix",
14
+ "db:push": "drizzle-kit push",
14
15
  "watch": "tsc -p tsconfig.build.json --watch"
15
16
  },
16
17
  "exports": "./src/index.ts",
17
18
  "devDependencies": {
18
19
  "@types/pg": "catalog:",
20
+ "drizzle-kit": "catalog:",
19
21
  "eslint-config": "workspace:*",
20
22
  "vitest-config": "workspace:*",
21
23
  "typescript-config": "workspace:*"
@@ -30,8 +32,10 @@
30
32
  "node",
31
33
  "backend"
32
34
  ],
35
+ "gTags": [
36
+ "db"
37
+ ],
33
38
  "tags": [
34
- "db",
35
39
  "drizzle"
36
40
  ],
37
41
  "requiredDeps": [
@@ -7,7 +7,7 @@ import z from "zod";
7
7
 
8
8
  import * as schema from "./schema/index.js";
9
9
 
10
- export const env = defineEnv({
10
+ const env = defineEnv({
11
11
  DATABASE_URL: z.string(),
12
12
  });
13
13
  export const client = new Pg.Pool({
@@ -1,6 +1,6 @@
1
1
  import { ENV } from "@repo/env";
2
2
  import { logger } from "@repo/logger";
3
- import { AdminEmailTemplate } from "@repo/mail";
3
+ import { EmailTemplate } from "@repo/mail";
4
4
  import { RedisStore } from "@repo/redis";
5
5
 
6
6
  import { HashingModule } from "../hashing-module/index.js";
@@ -41,13 +41,10 @@ export class OTPModule {
41
41
  logger?.info("otp: test-mode - OTP generated", { email: normalizedEmail, otp: otpStr });
42
42
  return;
43
43
  }
44
- const html = await AdminEmailTemplate.getOtpEmail({ otp: otpStr });
45
- await SMTPMailService.sendMail(
46
- normalizedEmail,
47
- `OTP for ${normalizedEmail}`,
48
- `Your OTP is ${otpStr}`,
49
- html
50
- );
44
+ const html = await EmailTemplate("VerifyEmailOtp", {
45
+ verificationCode: otpStr,
46
+ });
47
+ await SMTPMailService.sendMail(normalizedEmail, `OTP for ${normalizedEmail}`, `Your OTP is ${otpStr}`, html);
51
48
  }
52
49
 
53
50
  static async verifyMailOTP(email: string, otp: string, deleteOtp = false): Promise<boolean> {
@@ -67,11 +64,7 @@ export class OTPModule {
67
64
  if (deleteOtp) {
68
65
  await redisOtpStore.del(normalizedEmail);
69
66
  } else {
70
- await redisOtpStore.set(
71
- normalizedEmail,
72
- { ...rows, status: "verified" },
73
- this.otpExpirationMs
74
- );
67
+ await redisOtpStore.set(normalizedEmail, { ...rows, status: "verified" }, this.otpExpirationMs);
75
68
  }
76
69
  return true;
77
70
  }
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "extends": "typescript-config/tsconfig.node.json",
3
3
  "compilerOptions": {
4
- "baseUrl": "./src"
4
+ "baseUrl": "./src",
5
+ "jsx": "react"
5
6
  },
6
7
  "include": ["src/**/*.ts"]
7
8
  }
@@ -1,4 +1,4 @@
1
- import { baseConfig } from "eslint-config/base";
1
+ import { frontendConfig } from "eslint-config/frontend";
2
2
  import { extend } from "eslint-config/extend";
3
3
 
4
- export default extend(baseConfig);
4
+ export default extend(frontendConfig);
@@ -13,12 +13,7 @@ import {
13
13
  Text,
14
14
  } from "@react-email/components";
15
15
  import React from "react";
16
-
17
- export default function VerifyEmailOtp({
18
- verificationCode = "596853",
19
- }: {
20
- verificationCode: string;
21
- }) {
16
+ export function VerifyEmailOtp({ verificationCode = "596853" }: { verificationCode: string }) {
22
17
  return (
23
18
  <Html>
24
19
  <Head>
@@ -57,9 +52,8 @@ export default function VerifyEmailOtp({
57
52
  <Hr />
58
53
  <Section style={lowerSection}>
59
54
  <Text style={cautionText}>
60
- This OTP is valid for 10 minutes. Please do not share this code with anyone for
61
- security reasons. If you did not request this, please ignore this email or contact
62
- our support team immediately.
55
+ This OTP is valid for 10 minutes. Please do not share this code with anyone for security reasons. If you
56
+ did not request this, please ignore this email or contact our support team immediately.
63
57
  </Text>
64
58
  </Section>
65
59
  </Section>
@@ -0,0 +1 @@
1
+ export * from "./admin/OtpEmail.js";
@@ -1,11 +1,12 @@
1
1
  import { render } from "@react-email/render";
2
- import VerifyEmailOtp from "./emails/admin/OtpEmail.js";
3
- export class AdminEmailTemplate {
4
- static getOtpEmail = async (props: { otp: string }) => {
5
- return await render(
6
- VerifyEmailOtp({
7
- verificationCode: props.otp,
8
- })
9
- );
10
- };
2
+ import React, { createElement } from "react";
3
+ import * as emails from "./emails/emails.js";
4
+ export type AvailableEmails = keyof typeof emails;
5
+ export type EmailProps<T extends AvailableEmails> = React.ComponentProps<(typeof emails)[T]>;
6
+
7
+ // eslint-disable-next-line @typescript-eslint/naming-convention
8
+ export function EmailTemplate<T extends AvailableEmails>(name: T, props: EmailProps<T>) {
9
+ // eslint-disable-next-line import-x/namespace
10
+ const Component = emails[name] as React.ElementType;
11
+ return render(createElement(Component, props));
11
12
  }
@@ -2,12 +2,14 @@
2
2
  "extends": "typescript-config/tsconfig.frontend.json",
3
3
  "compilerOptions": {
4
4
  "rootDir": ".",
5
- "types": ["node"],
5
+ "types": ["node", "react"],
6
6
  "baseUrl": "src",
7
7
  "jsx": "react",
8
8
  "tsBuildInfoFile": "dist/typecheck.tsbuildinfo",
9
9
  "experimentalDecorators": true,
10
- "emitDecoratorMetadata": true
10
+ "emitDecoratorMetadata": true,
11
+ "moduleResolution": "nodenext",
12
+ "module": "nodenext"
11
13
  },
12
14
  "include": ["src/**/*.ts", "src/**/*.tsx"]
13
15
  }
@@ -9,6 +9,7 @@
9
9
  "typecheck": "tsc --noEmit",
10
10
  "format": "biome format --write .",
11
11
  "format:check": "biome ci .",
12
+ "test": "vitest run",
12
13
  "lint": "eslint .",
13
14
  "lint:fix": "eslint . --fix",
14
15
  "watch": "tsc -p tsconfig.build.json --watch"
@@ -4,8 +4,9 @@ import type { DialogProps } from "@radix-ui/react-dialog";
4
4
  import { Command as CommandPrimitive } from "cmdk";
5
5
  import { Search } from "lucide-react";
6
6
  import * as React from "react";
7
- import { cn } from "../lib/utils";
7
+
8
8
  import { Dialog, DialogContent } from "./dialog";
9
+ import { cn } from "../lib/utils";
9
10
 
10
11
  const Command = React.forwardRef<
11
12
  React.ElementRef<typeof CommandPrimitive>,
@@ -70,9 +71,7 @@ CommandList.displayName = CommandPrimitive.List.displayName;
70
71
  const CommandEmpty = React.forwardRef<
71
72
  React.ElementRef<typeof CommandPrimitive.Empty>,
72
73
  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
73
- >((props, ref) => (
74
- <CommandPrimitive.Empty ref={ref} className="py-6 text-center text-sm" {...props} />
75
- ));
74
+ >((props, ref) => <CommandPrimitive.Empty ref={ref} className="py-6 text-center text-sm" {...props} />);
76
75
 
77
76
  CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
78
77
 
@@ -96,11 +95,7 @@ const CommandSeparator = React.forwardRef<
96
95
  React.ElementRef<typeof CommandPrimitive.Separator>,
97
96
  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
98
97
  >(({ className, ...props }, ref) => (
99
- <CommandPrimitive.Separator
100
- ref={ref}
101
- className={cn("-mx-1 h-px bg-border", className)}
102
- {...props}
103
- />
98
+ <CommandPrimitive.Separator ref={ref} className={cn("-mx-1 h-px bg-border", className)} {...props} />
104
99
  ));
105
100
  CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
106
101
 
@@ -122,12 +117,7 @@ const CommandItem = React.forwardRef<
122
117
  CommandItem.displayName = CommandPrimitive.Item.displayName;
123
118
 
124
119
  const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
125
- return (
126
- <span
127
- className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)}
128
- {...props}
129
- />
130
- );
120
+ return <span className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)} {...props} />;
131
121
  };
132
122
  CommandShortcut.displayName = "CommandShortcut";
133
123
 
@@ -64,6 +64,7 @@ catalog:
64
64
 
65
65
  # db
66
66
  drizzle-orm: ^0.45.1
67
+ drizzle-kit: ^0.31.10
67
68
  pg: ^8.19.0
68
69
 
69
70
  # db types
package/turbo.json CHANGED
@@ -65,6 +65,15 @@
65
65
  },
66
66
  "deep:clean": {
67
67
  "cache": false
68
+ },
69
+ "db:push": {
70
+ "cache": false,
71
+ "interactive": true
72
+ },
73
+ "db:studio": {
74
+ "cache": false,
75
+ "interactive": false,
76
+ "persistent": true
68
77
  }
69
78
  }
70
79
  }
@@ -1,104 +0,0 @@
1
- /* eslint-disable @typescript-eslint/naming-convention */
2
-
3
- import { Packages } from "../types";
4
-
5
- export const packages = Packages({
6
- "eslint-config": {
7
- source: "./configs/eslint-config",
8
- dependencies: [],
9
- devDependencies: ["typescript-config"],
10
- optional: ["vitest-config"],
11
- dir: ["src"],
12
- file: ["plugins.d.ts"],
13
- tags: ["common"],
14
- },
15
- "typescript-config": {
16
- source: "./configs/typescript-config",
17
- dependencies: [],
18
- devDependencies: [],
19
- dir: [],
20
- files: ["tsconfig.common.json", "tsconfig.frontend.json", "tsconfig.node.json"],
21
- tags: ["required"],
22
- },
23
- "vitest-config": {
24
- source: "./configs/vitest-config",
25
- dependencies: ["typescript-config"],
26
- devDependencies: ["eslint-config"],
27
- dir: [],
28
- tags: ["required"],
29
- },
30
- "@repo/ui": {
31
- source: "./packages/ui",
32
- dependencies: [],
33
- devDependencies: ["typescript-config"],
34
- optional: ["eslint-config"],
35
- dir: [
36
- "src/components/lib",
37
- "src/components/util",
38
- "src/components/ilb",
39
- "src/components/util",
40
- "src/components/custom",
41
- "src/components/extensions",
42
- "src/components/hooks",
43
- "src/components/ui",
44
- ],
45
- files: [
46
- "components.json",
47
- "tailwind.config.ts",
48
- "postcss.config.ts",
49
- "src/globals.css",
50
- "src/lucide.ts",
51
- ],
52
- tags: ["common", "react"],
53
- },
54
- "@repo/constants": {
55
- source: "./packages/@repo/constants",
56
- dependencies: [],
57
- devDependencies: ["typescript-config"],
58
- optional: ["eslint-config"],
59
- dir: ["src"],
60
- tags: ["common"],
61
- },
62
- "@repo/env": {
63
- source: "./packages/@repo/env",
64
- dependencies: [],
65
- devDependencies: ["typescript-config"],
66
- optional: ["eslint-config", "vitest-config"],
67
- dir: ["src"],
68
- tags: ["common", "node"],
69
- },
70
- "@repo/db": {
71
- source: "./packages/@repo/db",
72
- dependencies: ["@repo/env"],
73
- devDependencies: ["typescript-config"],
74
- optional: ["eslint-config"],
75
- dir: ["src"],
76
- tags: ["common", "node"],
77
- },
78
-
79
- "@repo/lib": {
80
- source: "./packages/@repo/lib",
81
- dependencies: ["@repo/env", "@repo/mail", "@repo/db"],
82
- devDependencies: ["typescript-config"],
83
- optional: ["eslint-config", "vitest-config"],
84
- dir: ["src"],
85
- tags: ["common", "node"],
86
- },
87
-
88
- "@repo/mail": {
89
- source: "./packages/@repo/mail",
90
- dependencies: [],
91
- devDependencies: ["typescript-config"],
92
- optional: ["eslint-config"],
93
- dir: ["src"],
94
- tags: ["common", "node"],
95
- },
96
- "@repo/redis": {
97
- source: "./packages/@repo/redis",
98
- dependencies: [],
99
- devDependencies: ["typescript-config"],
100
- optional: ["eslint-config"],
101
- dir: ["src"],
102
- tags: ["common", "node", "extra"],
103
- },
104
- });