stackkit 0.1.6 → 0.1.8

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/dist/cli/add.js CHANGED
@@ -49,10 +49,10 @@ async function getAddConfig(module, options, projectInfo) {
49
49
  if (module === "database" || module === "auth") {
50
50
  if (!options?.provider) {
51
51
  if (module === "database") {
52
- throw new Error('Provider is required for database. Use: `npx stackkit add database --provider <provider>`');
52
+ throw new Error("Provider is required for database. Use: `npx stackkit add database --provider <provider>`");
53
53
  }
54
54
  else {
55
- throw new Error('Provider is required for auth. Use: `npx stackkit add auth --provider <provider>`');
55
+ throw new Error("Provider is required for auth. Use: `npx stackkit add auth --provider <provider>`");
56
56
  }
57
57
  }
58
58
  if (module === "database") {
@@ -306,7 +306,8 @@ async function processGeneratorEnvVars(config, targetDir) {
306
306
  const generator = await fs_extra_1.default.readJson(dbGeneratorPath);
307
307
  if (generator.operations) {
308
308
  for (const operation of generator.operations) {
309
- if (operation.type === "add-env" && (!operation.condition || checkCondition(operation.condition, config))) {
309
+ if (operation.type === "add-env" &&
310
+ (!operation.condition || checkCondition(operation.condition, config))) {
310
311
  for (const [key, value] of Object.entries(operation.envVars)) {
311
312
  envVars.push({
312
313
  key,
@@ -326,7 +327,8 @@ async function processGeneratorEnvVars(config, targetDir) {
326
327
  const generator = await fs_extra_1.default.readJson(authGeneratorPath);
327
328
  if (generator.operations) {
328
329
  for (const operation of generator.operations) {
329
- if (operation.type === "add-env" && (!operation.condition || checkCondition(operation.condition, config))) {
330
+ if (operation.type === "add-env" &&
331
+ (!operation.condition || checkCondition(operation.condition, config))) {
330
332
  for (const [key, value] of Object.entries(operation.envVars)) {
331
333
  envVars.push({
332
334
  key,
package/dist/index.js CHANGED
@@ -7,11 +7,14 @@ const add_1 = require("./cli/add");
7
7
  const doctor_1 = require("./cli/doctor");
8
8
  const list_1 = require("./cli/list");
9
9
  const logger_1 = require("./lib/ui/logger");
10
+ const fs_1 = require("fs");
11
+ const path_1 = require("path");
12
+ const packageJson = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, "../package.json"), "utf-8"));
10
13
  const program = new commander_1.Command();
11
14
  program
12
15
  .name("stackkit")
13
16
  .description("CLI for creating and managing StackKit projects")
14
- .version("0.1.6")
17
+ .version(packageJson.version)
15
18
  .configureHelp({
16
19
  subcommandTerm: (cmd) => {
17
20
  const name = cmd.name();
@@ -8,8 +8,6 @@ exports.removeEnvVariables = removeEnvVariables;
8
8
  const fs_extra_1 = __importDefault(require("fs-extra"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const logger_1 = require("../ui/logger");
11
- const ENV_MARKER_START = "# StackKit:";
12
- const ENV_MARKER_END = "# End StackKit";
13
11
  async function addEnvVariables(projectRoot, variables, options = {}) {
14
12
  const envExamplePath = path_1.default.join(projectRoot, ".env.example");
15
13
  const envPath = path_1.default.join(projectRoot, ".env");
@@ -59,14 +57,11 @@ async function appendToEnvFile(filePath, variables, fileType, options = {}) {
59
57
  if (content && !content.endsWith("\n")) {
60
58
  content += "\n";
61
59
  }
62
- // Add marker and variables
63
- content += "\n";
64
- content += `${ENV_MARKER_START} Added by StackKit\n`;
60
+ // Append variables
65
61
  for (const variable of newVariables) {
66
62
  const value = fileType === "example" ? variable.value || "" : variable.value || "";
67
63
  content += `${variable.key}=${value}\n`;
68
64
  }
69
- content += `${ENV_MARKER_END}\n`;
70
65
  await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
71
66
  await fs_extra_1.default.writeFile(filePath, content, "utf-8");
72
67
  }
@@ -86,23 +81,12 @@ async function removeFromEnvFile(filePath, keys) {
86
81
  const content = await fs_extra_1.default.readFile(filePath, "utf-8");
87
82
  const lines = content.split("\n");
88
83
  const newLines = [];
89
- let inStackKitBlock = false;
90
84
  for (const line of lines) {
91
- if (line.includes(ENV_MARKER_START)) {
92
- inStackKitBlock = true;
93
- continue;
94
- }
95
- if (line.includes(ENV_MARKER_END)) {
96
- inStackKitBlock = false;
97
- continue;
98
- }
99
85
  const match = line.match(/^([A-Z_][A-Z0-9_]*)=/);
100
86
  if (match && keys.includes(match[1])) {
101
87
  continue;
102
88
  }
103
- if (!inStackKitBlock || !line.startsWith("#")) {
104
- newLines.push(line);
105
- }
89
+ newLines.push(line);
106
90
  }
107
91
  while (newLines.length > 0 && newLines[newLines.length - 1].trim() === "") {
108
92
  newLines.pop();
@@ -175,7 +175,7 @@ class AdvancedCodeGenerator {
175
175
  conditionMet = typeof actualVal === "string" && actualVal.endsWith(cleanExpectedVal);
176
176
  break;
177
177
  }
178
- const contentToProcess = conditionMet ? blockContent : (elseContent || "");
178
+ const contentToProcess = conditionMet ? blockContent : elseContent || "";
179
179
  return this.processTemplateRecursive(contentToProcess, context)
180
180
  .replace(/^\n+/, "")
181
181
  .replace(/\n+$/, "");
@@ -185,7 +185,7 @@ class AdvancedCodeGenerator {
185
185
  const conditionParts = condition.split("==");
186
186
  if (conditionParts.length === 2) {
187
187
  const [varName, expectedValue] = conditionParts.map((s) => s.trim().replace(/['"]/g, ""));
188
- const contentToProcess = context[varName] === expectedValue ? blockContent : (elseContent || "");
188
+ const contentToProcess = context[varName] === expectedValue ? blockContent : elseContent || "";
189
189
  return this.processTemplateRecursive(contentToProcess, context)
190
190
  .replace(/^\n+/, "")
191
191
  .replace(/\n+$/, "");
@@ -195,7 +195,7 @@ class AdvancedCodeGenerator {
195
195
  const [arrayName, item] = conditionFunc[0].split("(");
196
196
  const itemValue = item.replace(")", "").replace(/['"]/g, "");
197
197
  const array = context[arrayName] || [];
198
- const contentToProcess = Array.isArray(array) && array.includes(itemValue) ? blockContent : (elseContent || "");
198
+ const contentToProcess = Array.isArray(array) && array.includes(itemValue) ? blockContent : elseContent || "";
199
199
  return this.processTemplateRecursive(contentToProcess, context)
200
200
  .replace(/^\n+/, "")
201
201
  .replace(/\n+$/, "");
@@ -214,14 +214,14 @@ class AdvancedCodeGenerator {
214
214
  const [, caseValue, caseContent] = caseMatch;
215
215
  const cleanCaseValue = caseValue.trim().replace(/['"]/g, "");
216
216
  if (cleanCaseValue === "default") {
217
- defaultCase = caseContent;
217
+ defaultCase = caseContent.trim();
218
218
  }
219
219
  else if (actualVal === cleanCaseValue) {
220
- result = caseContent;
220
+ result = caseContent.trim();
221
221
  break;
222
222
  }
223
223
  }
224
- return result || defaultCase || "";
224
+ return (result || defaultCase || "").trim();
225
225
  });
226
226
  // Handle variable replacement with advanced expressions
227
227
  content = content.replace(/\{\{([^}]+)\}\}/g, (match, varExpr) => {
@@ -378,6 +378,18 @@ class AdvancedCodeGenerator {
378
378
  !relativePath.startsWith("node_modules/"));
379
379
  },
380
380
  });
381
+ // If template provides a .env.example, create a .env from it when
382
+ // the target project does not already have a .env file.
383
+ try {
384
+ const envExampleSrc = path.join(templatePath, ".env.example");
385
+ const envDest = path.join(outputPath, ".env");
386
+ if ((await fs.pathExists(envExampleSrc)) && !(await fs.pathExists(envDest))) {
387
+ await fs.copy(envExampleSrc, envDest);
388
+ }
389
+ }
390
+ catch {
391
+ // ignore failures here — not critical
392
+ }
381
393
  }
382
394
  }
383
395
  processOperationTemplates(operation, context) {
@@ -469,34 +481,107 @@ class AdvancedCodeGenerator {
469
481
  switch (patchOp.type) {
470
482
  case "add-import":
471
483
  if (patchOp.imports) {
484
+ // Process imports and trim any accidental surrounding blank lines
472
485
  const imports = patchOp.imports
473
486
  .map((imp) => this.processTemplate(imp, context))
474
- .join("\n");
475
- // Add imports at the top, after existing imports
487
+ .join("\n")
488
+ .replace(/^\n+/, "")
489
+ .replace(/\n+$/, "");
490
+ // Add imports at the top, after existing imports without introducing
491
+ // extra blank lines.
476
492
  const lines = content.split("\n");
477
- let insertIndex = 0;
493
+ // Find the last import line index
494
+ let lastImportIndex = -1;
478
495
  for (let i = 0; i < lines.length; i++) {
479
- if (lines[i].trim().startsWith("import") || lines[i].trim() === "") {
480
- insertIndex = i + 1;
496
+ if (lines[i].trim().startsWith("import"))
497
+ lastImportIndex = i;
498
+ }
499
+ // Insert right after the last import. If there's a blank line
500
+ // immediately after the imports, overwrite that blank line to
501
+ // avoid introducing an extra empty line above the inserted imports.
502
+ const insertIndex = lastImportIndex === -1 ? 0 : lastImportIndex + 1;
503
+ // Only add imports that don't already exist in the file
504
+ const importLines = imports
505
+ .split("\n")
506
+ .map((l) => l.trim())
507
+ .filter(Boolean);
508
+ const newImportLines = importLines.filter((imp) => !lines.some((ln) => ln.trim() === imp));
509
+ if (newImportLines.length > 0) {
510
+ // Insert imports
511
+ if (insertIndex < lines.length && lines[insertIndex].trim() === "") {
512
+ lines.splice(insertIndex, 1, ...newImportLines);
481
513
  }
482
514
  else {
483
- break;
515
+ lines.splice(insertIndex, 0, ...newImportLines);
516
+ }
517
+ // After insertion, ensure exactly one blank line after the import block
518
+ // Find last import line index again
519
+ let lastIdx = -1;
520
+ for (let i = 0; i < lines.length; i++) {
521
+ if (lines[i].trim().startsWith("import"))
522
+ lastIdx = i;
523
+ }
524
+ const nextIdx = lastIdx + 1;
525
+ if (lastIdx !== -1) {
526
+ // Remove multiple blank lines after imports
527
+ let j = nextIdx;
528
+ while (j < lines.length && lines[j].trim() === "") {
529
+ j++;
530
+ }
531
+ // Ensure exactly one blank line after imports unless imports end at EOF
532
+ if (nextIdx < lines.length) {
533
+ lines.splice(nextIdx, j - nextIdx, "");
534
+ }
484
535
  }
485
536
  }
486
- lines.splice(insertIndex, 0, imports);
487
537
  content = lines.join("\n");
488
538
  }
489
539
  break;
490
540
  case "add-code":
491
- if (patchOp.code && patchOp.after) {
541
+ if (patchOp.code) {
492
542
  const processedCode = this.processTemplate(patchOp.code, context);
493
- const afterPattern = this.processTemplate(patchOp.after, context);
494
- const index = content.indexOf(afterPattern);
495
- if (index !== -1) {
496
- content =
497
- content.slice(0, index + afterPattern.length) +
498
- processedCode +
499
- content.slice(index + afterPattern.length);
543
+ // Skip insertion if the exact code already exists in the file
544
+ const codeTrimmed = processedCode.trim();
545
+ if (codeTrimmed && content.includes(codeTrimmed)) {
546
+ break;
547
+ }
548
+ // Insert after pattern if provided
549
+ if (patchOp.after) {
550
+ const afterPattern = this.processTemplate(patchOp.after, context);
551
+ const index = content.indexOf(afterPattern);
552
+ if (index !== -1) {
553
+ const left = content.slice(0, index + afterPattern.length);
554
+ const right = content.slice(index + afterPattern.length);
555
+ // Normalize code: trim surrounding newlines and ensure single trailing newline
556
+ let codeNormalized = processedCode.replace(/^\n+|\n+$/g, "") + "\n";
557
+ // If right already starts with a newline, avoid double-blank by
558
+ // removing trailing newline from codeNormalized so only one newline remains
559
+ const rightStartsWithNewline = right.startsWith("\n");
560
+ if (rightStartsWithNewline && codeNormalized.endsWith("\n")) {
561
+ codeNormalized = codeNormalized.replace(/\n+$/, "");
562
+ }
563
+ const leftNeedsNewline = !left.endsWith("\n");
564
+ content = left + (leftNeedsNewline ? "\n" : "") + codeNormalized + right;
565
+ }
566
+ }
567
+ // Insert before pattern if provided
568
+ if (patchOp.before) {
569
+ const beforePattern = this.processTemplate(patchOp.before, context);
570
+ const index = content.indexOf(beforePattern);
571
+ if (index !== -1) {
572
+ const left = content.slice(0, index);
573
+ const right = content.slice(index);
574
+ // Normalize code: trim surrounding newlines and ensure single trailing newline
575
+ let codeNormalized = processedCode.replace(/^\n+|\n+$/g, "") + "\n";
576
+ // If right already starts with a newline, avoid double-blank by
577
+ // removing trailing newline from codeNormalized so only one newline remains
578
+ const rightStartsWithNewline = right.startsWith("\n");
579
+ if (rightStartsWithNewline && codeNormalized.endsWith("\n")) {
580
+ codeNormalized = codeNormalized.replace(/\n+$/, "");
581
+ }
582
+ const leftNeedsNewline = !left.endsWith("\n");
583
+ content = left + (leftNeedsNewline ? "\n" : "") + codeNormalized + right;
584
+ }
500
585
  }
501
586
  }
502
587
  break;
@@ -546,6 +631,8 @@ class AdvancedCodeGenerator {
546
631
  }
547
632
  }
548
633
  }
634
+ // Normalize excessive blank lines introduced during patching
635
+ content = content.replace(/\n{3,}/g, "\n\n");
549
636
  // Write back the modified content
550
637
  await fs.writeFile(filePath, content, "utf-8");
551
638
  }
@@ -620,8 +707,8 @@ class AdvancedCodeGenerator {
620
707
  if ((type === "framework" && name === selectedModules.framework) ||
621
708
  (type === "database" && name === selectedModules.database) ||
622
709
  (type === "auth" && name === selectedModules.auth)) {
623
- Object.assign(allDeps, generator.dependencies);
624
- Object.assign(allDevDeps, generator.devDependencies);
710
+ // Dependencies and devDependencies are now provided via `add-dependency`
711
+ // operations. Keep merging scripts from generator configs for now.
625
712
  Object.assign(allScripts, generator.scripts);
626
713
  }
627
714
  }
@@ -90,11 +90,24 @@ async function mergeGeneratorIntoModuleMetadata(metadata, modulePath) {
90
90
  }
91
91
  }
92
92
  }
93
- if (generator.dependencies) {
94
- metadata.dependencies = { ...metadata.dependencies, ...generator.dependencies };
95
- }
96
- if (generator.devDependencies) {
97
- metadata.devDependencies = { ...metadata.devDependencies, ...generator.devDependencies };
93
+ // Collect dependencies/devDependencies from add-dependency operations
94
+ if (generator.operations && Array.isArray(generator.operations)) {
95
+ for (const operation of generator.operations) {
96
+ if (operation.type === "add-dependency") {
97
+ if (operation.dependencies) {
98
+ metadata.dependencies = {
99
+ ...metadata.dependencies,
100
+ ...operation.dependencies,
101
+ };
102
+ }
103
+ if (operation.devDependencies) {
104
+ metadata.devDependencies = {
105
+ ...metadata.devDependencies,
106
+ ...operation.devDependencies,
107
+ };
108
+ }
109
+ }
110
+ }
98
111
  }
99
112
  if (generator.postInstall && Array.isArray(generator.postInstall)) {
100
113
  metadata.postInstall = metadata.postInstall || [];
@@ -1,6 +1,2 @@
1
- import NextAuth from "next-auth";
2
- import { authOptions } from "@/lib/auth";
3
-
4
- const handler = NextAuth(authOptions);
5
-
6
- export { handler as GET, handler as POST };
1
+ import { handlers } from "@/auth"
2
+ export const { GET, POST } = handlers
@@ -1,36 +1,22 @@
1
- import { NextAuthOptions } from "next-auth";
2
- import { PrismaAdapter } from "@auth/prisma-adapter";
3
- import { prisma } from "@/lib/prisma";
4
- import GoogleProvider from "next-auth/providers/google";
1
+ import NextAuth from "next-auth"
2
+ import { PrismaAdapter } from "@auth/prisma-adapter"
3
+ import prisma from "@/lib/prisma"
4
+ import Google from "next-auth/providers/google"
5
+ import { encode, decode } from 'next-auth/jwt';
5
6
 
6
- export const authOptions: NextAuthOptions = {
7
+ export const { handlers, signIn, signOut, auth } = NextAuth({
7
8
  adapter: PrismaAdapter(prisma),
8
9
  providers: [
9
- GoogleProvider({
10
- clientId: process.env.GOOGLE_CLIENT_ID!,
11
- clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
10
+ Google({
11
+ clientId: process.env.AUTH_GOOGLE_ID,
12
+ clientSecret: process.env.AUTH_GOOGLE_SECRET,
12
13
  }),
13
14
  ],
14
- session: {
15
- strategy: "jwt",
16
- },
17
- callbacks: {
18
- async jwt({ token, user }) {
19
- if (user) {
20
- token.id = user.id;
21
- }
22
- return token;
23
- },
24
- async session({ session, token }) {
25
- if (token) {
26
- session.user.id = token.id as string;
27
- }
28
- return session;
29
- },
30
- },
15
+ session: { strategy: "jwt" },
16
+ secret: process.env.AUTH_SECRET,
17
+ jwt: { encode, decode },
31
18
  pages: {
32
- signIn: "/auth/signin",
33
- signOut: "/auth/signout",
34
- error: "/auth/error",
19
+ signIn: '/sign-in',
20
+ error: '/error',
35
21
  },
36
- };
22
+ })
@@ -1,10 +1,10 @@
1
-
1
+ {{#var defaultId = {{#if prismaProvider == "mongodb"}}@default(auto()) @map("_id") @db.ObjectId{{else}}@default(cuid()){{/if}}}}
2
2
  model Account {
3
- id String @id {{idDefault}}
4
- userId String {{userIdType}}
3
+ id String @id {{defaultId}}
4
+ userId String @map("user_id")
5
5
  type String
6
6
  provider String
7
- providerAccountId String
7
+ providerAccountId String @map("provider_account_id")
8
8
  refresh_token String? @db.Text
9
9
  access_token String? @db.Text
10
10
  expires_at Int?
@@ -16,30 +16,36 @@ model Account {
16
16
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
17
17
 
18
18
  @@unique([provider, providerAccountId])
19
+ @@map("accounts")
19
20
  }
20
21
 
21
22
  model Session {
22
- id String @id {{idDefault}}
23
- sessionToken String @unique
24
- userId String {{userIdType}}
23
+ id String @id {{defaultId}}
24
+ sessionToken String @unique @map("session_token")
25
+ userId String {{#if prismaProvider == "mongodb"}} @db.ObjectId{{/if}} @map("user_id")
25
26
  expires DateTime
26
27
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
28
+
29
+ @@map("sessions")
27
30
  }
28
31
 
29
32
  model User {
30
- id String @id {{idDefault}}
33
+ id String @id {{defaultId}}
31
34
  name String?
32
- email String @unique
33
- emailVerified DateTime?
35
+ email String? @unique
36
+ emailVerified DateTime? @map("email_verified")
34
37
  image String?
35
38
  accounts Account[]
36
39
  sessions Session[]
40
+
41
+ @@map("users")
37
42
  }
38
43
 
39
44
  model VerificationToken {
40
45
  identifier String
41
- token String @unique
46
+ token String
42
47
  expires DateTime
43
48
 
44
49
  @@unique([identifier, token])
50
+ @@map("verification_tokens")
45
51
  }
@@ -2,8 +2,53 @@
2
2
  "name": "authjs",
3
3
  "type": "auth",
4
4
  "priority": 10,
5
- "operations": [],
6
- "dependencies": {},
7
- "devDependencies": {},
8
- "scripts": {}
5
+ "operations": [
6
+ {
7
+ "type": "create-file",
8
+ "source": "lib/auth.ts",
9
+ "destination": "lib/auth.ts"
10
+ },
11
+ {
12
+ "type": "create-file",
13
+ "source": "api/auth/[...nextauth]/route.ts",
14
+ "destination": "app/api/auth/[...nextauth]/route.ts"
15
+ },
16
+ {
17
+ "type": "create-file",
18
+ "destination": "proxy.ts",
19
+ "content": "export { auth as middleware } from \"@/auth\""
20
+ },
21
+ {
22
+ "type": "patch-file",
23
+ "destination": "prisma/schema.prisma",
24
+ "condition": { "database": "prisma" },
25
+ "operations": [
26
+ {
27
+ "type": "add-to-bottom",
28
+ "source": "prisma/schema.prisma"
29
+ }
30
+ ]
31
+ },
32
+ {
33
+ "type": "add-dependency",
34
+ "condition": { "database": "prisma" },
35
+ "dependencies": {
36
+ "@auth/prisma-adapter": "^0.5.0"
37
+ }
38
+ },
39
+ {
40
+ "type": "add-env",
41
+ "envVars": {
42
+ "AUTH_SECRET": "",
43
+ "AUTH_GOOGLE_ID": "",
44
+ "AUTH_GOOGLE_SECRET": ""
45
+ }
46
+ },
47
+ {
48
+ "type": "add-dependency",
49
+ "dependencies": {
50
+ "next-auth": "^5.0.0-beta.30"
51
+ }
52
+ }
53
+ ]
9
54
  }
@@ -1,4 +1,4 @@
1
- import { betterAuth } from "better-auth";
1
+ import { betterAuth, env } from "better-auth";
2
2
  import { sendEmail } from "./email/email-service";
3
3
  import { getVerificationEmailTemplate, getPasswordResetEmailTemplate } from "./email/email-templates";
4
4
  {{#switch database}}
@@ -13,6 +13,12 @@ import { mongodbAdapter } from "better-auth/adapters/mongodb";
13
13
  {{/switch}}
14
14
 
15
15
  export async function initAuth() {
16
+ {{#if database == 'mongoose'}}
17
+ const mongooseInstance = await mongoose();
18
+ const client = mongooseInstance.connection.getClient();
19
+ const db = client.db();
20
+ {{/if}}
21
+
16
22
  return betterAuth({
17
23
  {{#switch database}}
18
24
  {{#case prisma}}
@@ -21,12 +27,10 @@ return betterAuth({
21
27
  }),
22
28
  {{/case}}
23
29
  {{#case mongoose}}
24
- const mongooseInstance = await mongoose();
25
- const client = mongooseInstance.connection.getClient();
26
- const db = client.db();
27
30
  database: mongodbAdapter(db, { client }),
28
31
  {{/case}}
29
32
  {{/switch}}
33
+ secret: env.BETTER_AUTH_SECRET,
30
34
  user: {
31
35
  additionalFields: {
32
36
  role: {
@@ -1,7 +1,7 @@
1
1
  import nodemailer from "nodemailer";
2
2
 
3
3
  // Create email transporter
4
- const transporter = nodemailer.createTransporter({
4
+ const transporter = nodemailer.createTransport({
5
5
  host: process.env.EMAIL_HOST,
6
6
  port: parseInt(process.env.EMAIL_PORT || "587"),
7
7
  secure: process.env.EMAIL_PORT === "465",
@@ -27,7 +27,6 @@ export const sendEmail = async ({ to, subject, text, html }: {
27
27
  html,
28
28
  });
29
29
  } catch (error) {
30
- // eslint-disable-next-line no-console
31
30
  console.error("Email sending failed:", error);
32
31
  throw error;
33
32
  }
@@ -1,4 +1,4 @@
1
- {{#var defaultId = {{#if prismaProvider == mongodb}}@default(auto()) @map("_id") @db.ObjectId{{else}}@default(cuid()){{/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 {{#if prismaProvider == mongodb}} @db.ObjectId{{/if}}
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 {{#if prismaProvider == mongodb}} @db.ObjectId{{/if}}
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?
@@ -51,7 +51,7 @@
51
51
  "operations": [
52
52
  {
53
53
  "type": "add-import",
54
- "imports": ["import { initAuth } from \"@/lib/auth\";"]
54
+ "imports": ["import { initAuth } from \"../lib/auth\";"]
55
55
  },
56
56
  {
57
57
  "type": "add-code",
@@ -67,7 +67,7 @@
67
67
  "operations": [
68
68
  {
69
69
  "type": "add-import",
70
- "imports": ["import { auth } from \"@/lib/auth\";",
70
+ "imports": ["import { auth } from \"../lib/auth\";",
71
71
  "import { toNodeHandler } from \"better-auth/node\";"]
72
72
  },
73
73
  {
@@ -97,12 +97,13 @@
97
97
  "EMAIL_USER": "",
98
98
  "EMAIL_PASS": "",
99
99
  "EMAIL_FROM": "noreply@yourapp.com"
100
+ }
101
+ },
102
+ {
103
+ "type": "add-dependency",
104
+ "dependencies": {
105
+ "better-auth": "^1.4.12"
100
106
  }
101
107
  }
102
- ],
103
- "dependencies": {
104
- "better-auth": "^1.4.12"
105
- },
106
- "devDependencies": {},
107
- "scripts": {}
108
+ ]
108
109
  }
@@ -6,7 +6,7 @@
6
6
  {
7
7
  "type": "create-file",
8
8
  "source": "lib/mongoose.ts",
9
- "destination": "src/lib/mongoose.ts"
9
+ "destination": "lib/mongoose.ts"
10
10
  },
11
11
  {
12
12
  "type": "create-file",
@@ -20,7 +20,7 @@
20
20
  "operations": [
21
21
  {
22
22
  "type": "add-import",
23
- "imports": ["import { mongoose } from \"@/lib/mongoose\";"]
23
+ "imports": ["import { mongoose } from \"../lib/mongoose\";"]
24
24
  },
25
25
  {
26
26
  "type": "add-code",
@@ -34,10 +34,12 @@
34
34
  "envVars": {
35
35
  "MONGODB_URI": "mongodb://localhost:27017/database_name"
36
36
  }
37
+ },
38
+ {
39
+ "type": "add-dependency",
40
+ "dependencies": {
41
+ "mongoose": "^8.8.0"
42
+ }
37
43
  }
38
- ],
39
- "dependencies": {
40
- "mongoose": "^8.8.0"
41
- },
42
- "devDependencies": {}
44
+ ]
43
45
  }
@@ -6,7 +6,7 @@ const globalForPrisma = globalThis as unknown as {
6
6
  }
7
7
 
8
8
  {{#switch prismaProvider}}
9
- {{#case postgresql}}
9
+ {{#case "postgresql"}}
10
10
  import { PrismaPg } from '@prisma/adapter-pg'
11
11
 
12
12
  const connectionString = `${process.env.DATABASE_URL}`
@@ -16,13 +16,13 @@ const prisma = new PrismaClient({ adapter })
16
16
 
17
17
  export { prisma }
18
18
  {{/case}}
19
- {{#case mongodb}}
19
+ {{#case "mongodb"}}
20
20
 
21
21
  const prisma = new PrismaClient()
22
22
 
23
23
  export { prisma }
24
24
  {{/case}}
25
- {{#case mysql}}
25
+ {{#case "mysql"}}
26
26
  import { PrismaMariaDb } from '@prisma/adapter-mariadb';
27
27
 
28
28
  const adapter = new PrismaMariaDb({
@@ -36,7 +36,7 @@ const prisma = new PrismaClient({ adapter });
36
36
 
37
37
  export { prisma }
38
38
  {{/case}}
39
- {{#case sqlite}}
39
+ {{#case "sqlite"}}
40
40
  import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";
41
41
 
42
42
  const connectionString = `${process.env.DATABASE_URL}`;
@@ -1,6 +1,6 @@
1
1
  import "dotenv/config";
2
2
  {{#switch prismaProvider}}
3
- {{#case mongodb}}
3
+ {{#case "mongodb"}}
4
4
  import { defineConfig, env } from "prisma/config";
5
5
  {{/case}}
6
6
  {{#case default}}
@@ -14,7 +14,7 @@ export default defineConfig({
14
14
  path: "prisma/migrations",
15
15
  },
16
16
  {{#switch prismaProvider}}
17
- {{#case mongodb}}
17
+ {{#case "mongodb"}}
18
18
  engine: "classic",
19
19
  datasource: {
20
20
  url: env('DATABASE_URL'),
@@ -91,17 +91,22 @@
91
91
  "envVars": {
92
92
  "DATABASE_URL": "mongodb://localhost:27017/database_name"
93
93
  }
94
+ },
95
+ {
96
+ "type": "add-dependency",
97
+ "dependencies": {
98
+ "dotenv": "^17.2.3"
99
+ }
100
+ },
101
+ {
102
+ "type": "add-script",
103
+ "scripts": {
104
+ "db:generate": "npx prisma generate",
105
+ "db:push": "npx prisma db push",
106
+ "db:seed": "tsx prisma/seed.ts",
107
+ "db:migrate": "npx prisma migrate dev",
108
+ "db:studio": "npx prisma studio"
109
+ }
94
110
  }
95
- ],
96
- "dependencies": {
97
- "dotenv": "^17.2.3"
98
- },
99
- "devDependencies": {},
100
- "scripts": {
101
- "db:generate": "npx prisma generate",
102
- "db:push": "npx prisma db push",
103
- "db:seed": "tsx prisma/seed.ts",
104
- "db:migrate": "npx prisma migrate dev",
105
- "db:studio": "npx prisma studio"
106
- }
111
+ ]
107
112
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stackkit",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
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,11 +0,0 @@
1
- import { getServerSession } from "next-auth/next";
2
- import { authOptions } from "@/lib/auth";
3
-
4
- export async function getSession() {
5
- return await getServerSession(authOptions);
6
- }
7
-
8
- export async function getCurrentUser() {
9
- const session = await getSession();
10
- return session?.user;
11
- }