stackkit 0.1.4 → 0.1.5

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.
@@ -40,23 +40,26 @@ const fs = __importStar(require("fs-extra"));
40
40
  const path = __importStar(require("path"));
41
41
  const package_root_1 = require("../utils/package-root");
42
42
  async function mergeModuleIntoGeneratorConfig(config, modulePath) {
43
- const modulePathJson = path.join(modulePath, 'module.json');
43
+ const modulePathJson = path.join(modulePath, "module.json");
44
44
  if (await fs.pathExists(modulePathJson)) {
45
45
  try {
46
46
  const moduleConfig = await fs.readJson(modulePathJson);
47
47
  if (moduleConfig.postInstall && Array.isArray(moduleConfig.postInstall)) {
48
48
  config.postInstall = moduleConfig.postInstall;
49
49
  }
50
- if (moduleConfig.dependencies && typeof moduleConfig.dependencies === 'object') {
50
+ if (moduleConfig.dependencies && typeof moduleConfig.dependencies === "object") {
51
51
  config.dependencies = { ...(config.dependencies || {}), ...moduleConfig.dependencies };
52
52
  }
53
- if (moduleConfig.devDependencies && typeof moduleConfig.devDependencies === 'object') {
54
- config.devDependencies = { ...(config.devDependencies || {}), ...moduleConfig.devDependencies };
53
+ if (moduleConfig.devDependencies && typeof moduleConfig.devDependencies === "object") {
54
+ config.devDependencies = {
55
+ ...(config.devDependencies || {}),
56
+ ...moduleConfig.devDependencies,
57
+ };
55
58
  }
56
- if (moduleConfig.scripts && typeof moduleConfig.scripts === 'object') {
59
+ if (moduleConfig.scripts && typeof moduleConfig.scripts === "object") {
57
60
  config.scripts = { ...(config.scripts || {}), ...moduleConfig.scripts };
58
61
  }
59
- if (moduleConfig.envVars && typeof moduleConfig.envVars === 'object') {
62
+ if (moduleConfig.envVars && typeof moduleConfig.envVars === "object") {
60
63
  config.envVars = { ...(config.envVars || {}), ...moduleConfig.envVars };
61
64
  }
62
65
  }
@@ -67,14 +70,19 @@ async function mergeModuleIntoGeneratorConfig(config, modulePath) {
67
70
  return config;
68
71
  }
69
72
  async function mergeGeneratorIntoModuleMetadata(metadata, modulePath) {
70
- const generatorPath = path.join(modulePath, 'generator.json');
73
+ const generatorPath = path.join(modulePath, "generator.json");
71
74
  if (await fs.pathExists(generatorPath)) {
72
75
  try {
73
76
  const generator = await fs.readJson(generatorPath);
74
77
  if (generator.envVars) {
75
78
  metadata.envVars = metadata.envVars || [];
76
79
  for (const [key, value] of Object.entries(generator.envVars)) {
77
- metadata.envVars.push({ key, value: value, description: `Environment variable for ${key}`, required: true });
80
+ metadata.envVars.push({
81
+ key,
82
+ value: value,
83
+ description: `Environment variable for ${key}`,
84
+ required: true,
85
+ });
78
86
  }
79
87
  }
80
88
  if (generator.dependencies) {
@@ -96,12 +104,12 @@ async function mergeGeneratorIntoModuleMetadata(metadata, modulePath) {
96
104
  }
97
105
  function locateOperationSource(generatorType, generatorName, sourceRel) {
98
106
  const packageRoot = (0, package_root_1.getPackageRoot)();
99
- const modulesPath = path.join(packageRoot, 'modules');
100
- const templatesPath = path.join(packageRoot, 'templates');
101
- const moduleBasePath = generatorType === 'framework'
107
+ const modulesPath = path.join(packageRoot, "modules");
108
+ const templatesPath = path.join(packageRoot, "templates");
109
+ const moduleBasePath = generatorType === "framework"
102
110
  ? path.join(templatesPath, generatorName)
103
111
  : path.join(modulesPath, generatorType, generatorName);
104
- const sourcePath = path.join(moduleBasePath, 'files', sourceRel);
112
+ const sourcePath = path.join(moduleBasePath, "files", sourceRel);
105
113
  try {
106
114
  return sourcePath;
107
115
  }
@@ -37,9 +37,9 @@ exports.getPackageRoot = getPackageRoot;
37
37
  const path = __importStar(require("path"));
38
38
  function getPackageRoot() {
39
39
  try {
40
- return path.dirname(require.resolve('stackkit/package.json'));
40
+ return path.dirname(require.resolve("stackkit/package.json"));
41
41
  }
42
42
  catch {
43
- return path.resolve(__dirname, '..', '..', '..');
43
+ return path.resolve(__dirname, "..", "..", "..");
44
44
  }
45
45
  }
@@ -1,24 +1,32 @@
1
1
  import { betterAuth } from "better-auth";
2
2
  import { sendEmail } from "./email/email-service";
3
3
  import { getVerificationEmailTemplate, getPasswordResetEmailTemplate } from "./email/email-templates";
4
- {{#if database == 'prisma'}}
4
+ {{#switch database}}
5
+ {{#case prisma}}
5
6
  import { prisma } from "{{framework == 'nextjs' ? '@/lib' : '.'}}/prisma";
6
7
  import { prismaAdapter } from "better-auth/adapters/prisma";
7
- {{/if}}
8
- {{#if database == 'mongoose'}}
9
- import { mongoClient, db } from "{{framework == 'nextjs' ? '@/lib' : '.'}}/db";
8
+ {{/case}}
9
+ {{#case mongoose}}
10
+ import { mongoose } from "{{framework == 'nextjs' ? '@/lib' : '.'}}/mongoose";
10
11
  import { mongodbAdapter } from "better-auth/adapters/mongodb";
11
- {{/if}}
12
+ {{/case}}
13
+ {{/switch}}
12
14
 
13
- export const auth = betterAuth({
14
- {{#if database == 'prisma'}}
15
+ export async function initAuth() {
16
+ return betterAuth({
17
+ {{#switch database}}
18
+ {{#case prisma}}
15
19
  database: prismaAdapter(prisma, {
16
- provider: "{{prismaProvider}}",
20
+ provider: "{{prismaProvider}}",
17
21
  }),
18
- {{/if}}
19
- {{#if database == 'mongoose'}}
20
- database: mongodbAdapter(db),
21
- {{/if}}
22
+ {{/case}}
23
+ {{#case mongoose}}
24
+ const mongooseInstance = await mongoose();
25
+ const client = mongooseInstance.connection.getClient();
26
+ const db = client.db();
27
+ database: mongodbAdapter(db, { client }),
28
+ {{/case}}
29
+ {{/switch}}
22
30
  user: {
23
31
  additionalFields: {
24
32
  role: {
@@ -31,6 +39,15 @@ export const auth = betterAuth({
31
39
  emailAndPassword: {
32
40
  enabled: true,
33
41
  requireEmailVerification: true,
42
+ sendResetPassword: async ({ user, url }) => {
43
+ const { html, text } = getPasswordResetEmailTemplate(user, url);
44
+ await sendEmail({
45
+ to: user.email,
46
+ subject: "Reset Your Password",
47
+ text,
48
+ html,
49
+ });
50
+ },
34
51
  },
35
52
  socialProviders: {
36
53
  google: {
@@ -50,22 +67,9 @@ export const auth = betterAuth({
50
67
  },
51
68
  sendOnSignIn: true,
52
69
  },
53
- password: {
54
- reset: {
55
- sendResetEmail: async ({ user, url }) => {
56
- const { html, text } = getPasswordResetEmailTemplate(user, url);
57
- await sendEmail({
58
- to: user.email,
59
- subject: "Reset Your Password",
60
- text,
61
- html,
62
- });
63
- },
64
- },
65
- },
66
70
  rateLimit: {
67
- window: 10, // 10 seconds
68
- max: 100, // max requests per window
71
+ window: 10,
72
+ max: 100,
69
73
  },
70
74
  account: {
71
75
  accountLinking: {
@@ -77,7 +81,10 @@ export const auth = betterAuth({
77
81
  cookieCache: {
78
82
  enabled: true,
79
83
  },
80
- expiresIn: 60 * 60 * 24 * 7, // 7 days
81
- updateAge: 60 * 60 * 24, // 1 day
84
+ expiresIn: 60 * 60 * 24 * 7,
85
+ updateAge: 60 * 60 * 24,
82
86
  }
83
- });
87
+ })
88
+ };
89
+
90
+ export const auth = await initAuth();
@@ -1,4 +1,4 @@
1
- {{#var defaultId = {{#if prismaProvider == postgresql}}@default(cuid()){{/if}}{{#if prismaProvider == mysql}}@default(uuid()){{/if}}{{#if prismaProvider == sqlite}}@default(uuid()){{/if}}}}
1
+ {{#var defaultId = {{#if prismaProvider == mongodb}}@default(auto()) @map("_id") @db.ObjectId{{else}}@default(cuid()){{/if}}}}
2
2
  model User {
3
3
  id String @id {{defaultId}}
4
4
  name String
@@ -23,7 +23,7 @@ model Session {
23
23
  updatedAt DateTime @updatedAt
24
24
  ipAddress String?
25
25
  userAgent String?
26
- userId String
26
+ userId String {{#if prismaProvider == mongodb}} @db.ObjectId{{/if}}
27
27
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
28
28
 
29
29
  @@index([userId])
@@ -34,7 +34,7 @@ model Account {
34
34
  id String @id {{defaultId}}
35
35
  accountId String
36
36
  providerId String
37
- userId String
37
+ userId String {{#if prismaProvider == mongodb}} @db.ObjectId{{/if}}
38
38
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
39
39
  accessToken String?
40
40
  refreshToken String?
@@ -33,12 +33,6 @@
33
33
  "destination": "lib/auth-client.ts",
34
34
  "condition": { "framework": ["nextjs", "react"] }
35
35
  },
36
- {
37
- "type": "create-file",
38
- "destination": "proxy.ts",
39
- "condition": { "framework": "nextjs" },
40
- "content": "import { auth } from \"@/lib/auth\";\n\nexport default auth((req) => {\n console.log('middleware', req.auth)\n})\n\nexport const config = {\n matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],\n}"
41
- },
42
36
  {
43
37
  "type": "patch-file",
44
38
  "destination": "prisma/schema.prisma",
@@ -50,6 +44,39 @@
50
44
  }
51
45
  ]
52
46
  },
47
+ {
48
+ "type": "patch-file",
49
+ "destination": "src/server.ts",
50
+ "condition": { "framework": "express" },
51
+ "operations": [
52
+ {
53
+ "type": "add-import",
54
+ "imports": ["import { initAuth } from \"@/lib/auth\";"]
55
+ },
56
+ {
57
+ "type": "add-code",
58
+ "before": "const port = env.port;",
59
+ "code": "await initAuth();"
60
+ }
61
+ ]
62
+ },
63
+ {
64
+ "type": "patch-file",
65
+ "destination": "src/app.ts",
66
+ "condition": { "framework": "express" },
67
+ "operations": [
68
+ {
69
+ "type": "add-import",
70
+ "imports": ["import { auth } from \"@/lib/auth\";",
71
+ "import { toNodeHandler } from \"better-auth/node\";"]
72
+ },
73
+ {
74
+ "type": "add-code",
75
+ "after": "// routes",
76
+ "code": "app.all(\"/api/auth/*splat\", toNodeHandler(auth));"
77
+ }
78
+ ]
79
+ },
53
80
  {
54
81
  "type": "add-dependency",
55
82
  "condition": { "framework": ["nextjs", "express"] },
@@ -59,20 +86,23 @@
59
86
  "devDependencies": {
60
87
  "@types/nodemailer": "^7.0.5"
61
88
  }
89
+ },
90
+ {
91
+ "type": "add-env",
92
+ "envVars": {
93
+ "BETTER_AUTH_SECRET": "",
94
+ "BETTER_AUTH_URL": "http://localhost:3000",
95
+ "EMAIL_HOST": "smtp.gmail.com",
96
+ "EMAIL_PORT": "587",
97
+ "EMAIL_USER": "",
98
+ "EMAIL_PASS": "",
99
+ "EMAIL_FROM": "noreply@yourapp.com"
100
+ }
62
101
  }
63
102
  ],
64
103
  "dependencies": {
65
104
  "better-auth": "^1.4.12"
66
105
  },
67
106
  "devDependencies": {},
68
- "scripts": {},
69
- "envVars": {
70
- "BETTER_AUTH_SECRET": "",
71
- "BETTER_AUTH_URL": "http://localhost:3000",
72
- "EMAIL_HOST": "smtp.gmail.com",
73
- "EMAIL_PORT": "587",
74
- "EMAIL_USER": "",
75
- "EMAIL_PASS": "",
76
- "EMAIL_FROM": "noreply@yourapp.com"
77
- }
107
+ "scripts": {}
78
108
  }
@@ -12,13 +12,32 @@
12
12
  "type": "create-file",
13
13
  "source": "models/health.ts",
14
14
  "destination": "models/health.ts"
15
+ },
16
+ {
17
+ "type": "patch-file",
18
+ "destination": "src/server.ts",
19
+ "condition": { "framework": "express" },
20
+ "operations": [
21
+ {
22
+ "type": "add-import",
23
+ "imports": ["import { mongoose } from \"@/lib/mongoose\";"]
24
+ },
25
+ {
26
+ "type": "add-code",
27
+ "after": "async function startServer() {",
28
+ "code": "await mongoose();"
29
+ }
30
+ ]
31
+ },
32
+ {
33
+ "type": "add-env",
34
+ "envVars": {
35
+ "MONGODB_URI": "mongodb://localhost:27017/database_name"
36
+ }
15
37
  }
16
38
  ],
17
39
  "dependencies": {
18
40
  "mongoose": "^8.8.0"
19
41
  },
20
- "devDependencies": {},
21
- "envVars": {
22
- "MONGODB_URI": "mongodb://localhost:27017/database_name"
23
- }
42
+ "devDependencies": {}
24
43
  }
@@ -1,27 +1,28 @@
1
- import 'dotenv/config'
1
+ import 'dotenv/config';
2
2
  import { PrismaClient } from './generated/prisma/client'
3
3
 
4
4
  const globalForPrisma = globalThis as unknown as {
5
5
  prisma: PrismaClient | undefined
6
6
  }
7
7
 
8
- {{#if prismaProvider == "postgresql"}}
9
- import { PrismaPg } from "@prisma/adapter-pg";
8
+ {{#switch prismaProvider}}
9
+ {{#case postgresql}}
10
+ import { PrismaPg } from '@prisma/adapter-pg'
10
11
 
11
- const adapter = new PrismaPg({
12
- connectionString: process.env.DATABASE_URL!,
13
- });
12
+ const connectionString = `${process.env.DATABASE_URL}`
14
13
 
15
- export const prisma = globalForPrisma.prisma ?? new PrismaClient({
16
- adapter,
17
- });
18
- {{/if}}
14
+ const adapter = new PrismaPg({ connectionString })
15
+ const prisma = new PrismaClient({ adapter })
16
+
17
+ export { prisma }
18
+ {{/case}}
19
+ {{#case mongodb}}
19
20
 
20
- {{#if prismaProvider == "mongodb"}}
21
- export const prisma = globalForPrisma.prisma ?? new PrismaClient();
22
- {{/if}}
21
+ const prisma = new PrismaClient()
23
22
 
24
- {{#if prismaProvider == "mysql"}}
23
+ export { prisma }
24
+ {{/case}}
25
+ {{#case mysql}}
25
26
  import { PrismaMariaDb } from '@prisma/adapter-mariadb';
26
27
 
27
28
  const adapter = new PrismaMariaDb({
@@ -31,16 +32,20 @@ const adapter = new PrismaMariaDb({
31
32
  database: process.env.DATABASE_NAME,
32
33
  connectionLimit: 5
33
34
  });
35
+ const prisma = new PrismaClient({ adapter });
34
36
 
35
- export const prisma = globalForPrisma.prisma ?? new PrismaClient({ adapter });
36
- {{/if}}
37
-
38
- {{#if prismaProvider == "sqlite"}}
37
+ export { prisma }
38
+ {{/case}}
39
+ {{#case sqlite}}
39
40
  import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";
40
41
 
41
- const adapter = new PrismaBetterSqlite3({ url: process.env.DATABASE_URL });
42
+ const connectionString = `${process.env.DATABASE_URL}`;
43
+
44
+ const adapter = new PrismaBetterSqlite3({ url: connectionString });
45
+ const prisma = new PrismaClient({ adapter });
42
46
 
43
- export const prisma = globalForPrisma.prisma ?? new PrismaClient({ adapter });
44
- {{/if}}
47
+ export { prisma };
48
+ {{/case}}
49
+ {{/switch}}
45
50
 
46
51
  if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
@@ -1,12 +1,29 @@
1
1
  import "dotenv/config";
2
+ {{#switch prismaProvider}}
3
+ {{#case mongodb}}
4
+ import { defineConfig, env } from "prisma/config";
5
+ {{/case}}
6
+ {{#case default}}
2
7
  import { defineConfig } from "prisma/config";
8
+ {{/case}}
9
+ {{/switch}}
3
10
 
4
11
  export default defineConfig({
5
12
  schema: "prisma/schema.prisma",
6
13
  migrations: {
7
14
  path: "prisma/migrations",
8
15
  },
16
+ {{#switch prismaProvider}}
17
+ {{#case mongodb}}
18
+ engine: "classic",
19
+ datasource: {
20
+ url: env('DATABASE_URL'),
21
+ },
22
+ {{/case}}
23
+ {{#case default}}
9
24
  datasource: {
10
25
  url: process.env["DATABASE_URL"],
11
26
  },
27
+ {{/case}}
28
+ {{/switch}}
12
29
  });
@@ -22,47 +22,86 @@
22
22
  "type": "add-dependency",
23
23
  "condition": { "prismaProvider": "postgresql" },
24
24
  "dependencies": {
25
- "@prisma/adapter-pg": "^5.0.0",
25
+ "@prisma/adapter-pg": "^7.0.0",
26
+ "@prisma/client": "^7.2.0",
26
27
  "pg": "^8.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "prisma": "^7.2.0"
27
31
  }
28
32
  },
29
33
  {
30
34
  "type": "add-dependency",
31
35
  "condition": { "prismaProvider": "mysql" },
32
36
  "dependencies": {
33
- "@prisma/adapter-mariadb": "^5.0.0",
37
+ "@prisma/adapter-mariadb": "^7.0.0",
38
+ "@prisma/client": "^7.2.0",
34
39
  "mysql2": "^3.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "prisma": "^7.2.0"
35
43
  }
36
44
  },
37
45
  {
38
46
  "type": "add-dependency",
39
47
  "condition": { "prismaProvider": "sqlite" },
40
48
  "dependencies": {
41
- "@prisma/adapter-better-sqlite3": "^5.0.0",
49
+ "@prisma/adapter-better-sqlite3": "^7.0.0",
50
+ "@prisma/client": "^7.2.0",
42
51
  "better-sqlite3": "^9.0.0"
52
+ },
53
+ "devDependencies": {
54
+ "prisma": "^7.2.0"
43
55
  }
44
56
  },
45
57
  {
46
58
  "type": "add-dependency",
47
59
  "condition": { "prismaProvider": "mongodb" },
48
- "dependencies": {}
60
+ "dependencies": {
61
+ "@prisma/client": "^6.19.0"
62
+ },
63
+ "devDependencies": {
64
+ "prisma": "^6.19.0"
65
+ }
66
+ },
67
+ {
68
+ "type": "add-env",
69
+ "condition": { "prismaProvider": "postgresql" },
70
+ "envVars": {
71
+ "DATABASE_URL": "postgresql://username:password@localhost:5432/database_name"
72
+ }
73
+ },
74
+ {
75
+ "type": "add-env",
76
+ "condition": { "prismaProvider": "mysql" },
77
+ "envVars": {
78
+ "DATABASE_URL": "mysql://username:password@localhost:3306/database_name"
79
+ }
80
+ },
81
+ {
82
+ "type": "add-env",
83
+ "condition": { "prismaProvider": "sqlite" },
84
+ "envVars": {
85
+ "DATABASE_URL": "file:./dev.db"
86
+ }
87
+ },
88
+ {
89
+ "type": "add-env",
90
+ "condition": { "prismaProvider": "mongodb" },
91
+ "envVars": {
92
+ "DATABASE_URL": "mongodb://localhost:27017/database_name"
93
+ }
49
94
  }
50
95
  ],
51
96
  "dependencies": {
52
- "@prisma/client": "^7.2.0",
53
97
  "dotenv": "^17.2.3"
54
98
  },
55
- "devDependencies": {
56
- "prisma": "^7.2.0"
57
- },
99
+ "devDependencies": {},
58
100
  "scripts": {
59
101
  "db:generate": "npx prisma generate",
60
102
  "db:push": "npx prisma db push",
61
103
  "db:seed": "tsx prisma/seed.ts",
62
104
  "db:migrate": "npx prisma migrate dev",
63
105
  "db:studio": "npx prisma studio"
64
- },
65
- "envVars": {
66
- "DATABASE_URL": "postgresql://username:password@localhost:5432/database_name"
67
106
  }
68
107
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stackkit",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Production-ready CLI to create and extend JavaScript or TypeScript apps with modular stacks.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -1,8 +1,14 @@
1
1
  import app from "./app";
2
2
  import { env } from "./config/env";
3
3
 
4
- const port = env.port;
4
+ async function startServer() {
5
+ const port = env.port;
6
+ app.listen(port, () => {
7
+ console.log(`Server is running on http://localhost:${port}`);
8
+ });
9
+ }
5
10
 
6
- app.listen(port, () => {
7
- console.log(`Server is running on http://localhost:${port}`);
11
+ startServer().catch((err) => {
12
+ console.error("Failed to start server:", err);
13
+ process.exit(1);
8
14
  });
@@ -4,6 +4,6 @@
4
4
  "moduleResolution": "node",
5
5
  "target": "ES2023",
6
6
  "strict": true,
7
- "esModuleInterop": true,
7
+ "esModuleInterop": true
8
8
  }
9
- }
9
+ }
@@ -5,4 +5,4 @@ export const env = {
5
5
 
6
6
  isDev: process.env.NODE_ENV === "development",
7
7
  isProd: process.env.NODE_ENV === "production",
8
- } as const;
8
+ } as const;