stackkit 0.2.0 → 0.2.2

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.
@@ -45,15 +45,55 @@ class FrameworkUtils {
45
45
  this.frameworkConfigs.set(frameworkName, config);
46
46
  return config;
47
47
  }
48
- // Default config if no template.json exists
48
+ // Derive compatibility dynamically from available modules if possible
49
49
  const defaultConfig = {
50
50
  name: frameworkName,
51
51
  displayName: frameworkName.charAt(0).toUpperCase() + frameworkName.slice(1),
52
52
  compatibility: {
53
- databases: ["prisma", "mongoose"],
54
- auth: ["better-auth", "authjs"],
53
+ databases: [],
54
+ auth: [],
55
55
  },
56
56
  };
57
+ try {
58
+ const modulesDir = path.join(templatesDir, "..", "modules");
59
+ const dbDir = path.join(modulesDir, "database");
60
+ const authDir = path.join(modulesDir, "auth");
61
+ if (await fs.pathExists(dbDir)) {
62
+ const dbs = await fs.readdir(dbDir);
63
+ for (const d of dbs) {
64
+ const moduleJson = path.join(dbDir, d, "module.json");
65
+ if (await fs.pathExists(moduleJson)) {
66
+ try {
67
+ const m = await fs.readJson(moduleJson);
68
+ if (m && m.name)
69
+ defaultConfig.compatibility.databases.push(m.name);
70
+ }
71
+ catch {
72
+ // ignore malformed
73
+ }
74
+ }
75
+ }
76
+ }
77
+ if (await fs.pathExists(authDir)) {
78
+ const auths = await fs.readdir(authDir);
79
+ for (const a of auths) {
80
+ const moduleJson = path.join(authDir, a, "module.json");
81
+ if (await fs.pathExists(moduleJson)) {
82
+ try {
83
+ const m = await fs.readJson(moduleJson);
84
+ if (m && m.name)
85
+ defaultConfig.compatibility.auth.push(m.name);
86
+ }
87
+ catch {
88
+ // ignore malformed
89
+ }
90
+ }
91
+ }
92
+ }
93
+ }
94
+ catch {
95
+ // ignore discovery errors and leave empty lists
96
+ }
57
97
  this.frameworkConfigs.set(frameworkName, defaultConfig);
58
98
  return defaultConfig;
59
99
  }
@@ -390,6 +390,24 @@ class AdvancedCodeGenerator {
390
390
  catch {
391
391
  // ignore failures here — not critical
392
392
  }
393
+ // Ensure gitignore is present in target even if template authors
394
+ // renamed it to avoid npm/package issues (e.g. 'gitignore' or '_gitignore')
395
+ try {
396
+ const gitCandidates = [".gitignore", "gitignore", "_gitignore"];
397
+ for (const g of gitCandidates) {
398
+ const src = path.join(templatePath, g);
399
+ if (await fs.pathExists(src)) {
400
+ const dest = path.join(outputPath, ".gitignore");
401
+ if (!(await fs.pathExists(dest))) {
402
+ await fs.copy(src, dest);
403
+ }
404
+ break;
405
+ }
406
+ }
407
+ }
408
+ catch {
409
+ // ignore
410
+ }
393
411
  }
394
412
  }
395
413
  processOperationTemplates(operation, context) {
@@ -20,41 +20,32 @@ async function detectPackageManager(cwd) {
20
20
  }
21
21
  }
22
22
  async function installDependencies(cwd, pm) {
23
- const args = [];
24
- if (pm === "npm") {
25
- args.push("install");
26
- }
27
- else if (pm === "yarn") {
28
- args.push("install");
29
- }
30
- else if (pm === "pnpm") {
31
- args.push("install");
32
- }
33
- else if (pm === "bun") {
34
- args.push("install");
35
- }
36
- await (0, execa_1.default)(pm, args, { cwd, stdio: "pipe" });
23
+ const args = ["install"];
24
+ const stdio = "pipe";
25
+ await (0, execa_1.default)(pm, args, { cwd, stdio });
37
26
  }
38
27
  async function addDependencies(cwd, pm, packages, dev = false) {
39
28
  if (packages.length === 0)
40
29
  return;
41
30
  const spinner = logger_1.logger.startSpinner(`Adding ${dev ? "dev " : ""}dependencies: ${packages.join(", ")}...`);
42
31
  try {
43
- const args = [];
44
- if (pm === "npm") {
45
- args.push("install", dev ? "--save-dev" : "--save", ...packages);
32
+ const stdio = "pipe";
33
+ let args = [];
34
+ switch (pm) {
35
+ case "npm":
36
+ args = ["install", ...(dev ? ["--save-dev"] : []), ...packages];
37
+ break;
38
+ case "yarn":
39
+ args = ["add", ...(dev ? ["--dev"] : []), ...packages];
40
+ break;
41
+ case "pnpm":
42
+ args = ["add", ...(dev ? ["-D"] : []), ...packages];
43
+ break;
44
+ case "bun":
45
+ args = ["add", ...(dev ? ["-d"] : []), ...packages];
46
+ break;
46
47
  }
47
- else if (pm === "yarn") {
48
- args.push("add", dev ? "--dev" : "", ...packages);
49
- }
50
- else if (pm === "pnpm") {
51
- args.push("add", dev ? "-D" : "", ...packages);
52
- }
53
- else if (pm === "bun") {
54
- // bun uses `bun add` and `-d` for dev dependencies
55
- args.push("add", ...(dev ? ["-d"] : []), ...packages);
56
- }
57
- await (0, execa_1.default)(pm, args.filter(Boolean), { cwd, stdio: "pipe" });
48
+ await (0, execa_1.default)(pm, args, { cwd, stdio });
58
49
  spinner.succeed(`Dependencies added successfully`);
59
50
  }
60
51
  catch (error) {
@@ -63,7 +54,43 @@ async function addDependencies(cwd, pm, packages, dev = false) {
63
54
  }
64
55
  }
65
56
  async function initGit(cwd) {
66
- await (0, execa_1.default)("git", ["init"], { cwd });
67
- await (0, execa_1.default)("git", ["add", "."], { cwd });
68
- await (0, execa_1.default)("git", ["commit", "-m", "Initial commit from StackKit"], { cwd });
57
+ const spinner = logger_1.logger.startSpinner("Initializing git repository...");
58
+ const run = async (stdio) => {
59
+ await (0, execa_1.default)("git", ["init"], { cwd, stdio });
60
+ await (0, execa_1.default)("git", ["add", "."], { cwd, stdio });
61
+ await (0, execa_1.default)("git", ["commit", "-m", "Initial commit from StackKit"], { cwd, stdio });
62
+ };
63
+ try {
64
+ await run("pipe");
65
+ spinner.succeed("Git repository initialized");
66
+ return;
67
+ }
68
+ catch (error) {
69
+ const err = error;
70
+ spinner.fail(`Git init failed: ${err.message}`);
71
+ const isENOBUFS = (e) => {
72
+ if (!e || typeof e !== "object")
73
+ return false;
74
+ const obj = e;
75
+ return (obj.code === "ENOBUFS" ||
76
+ obj.errno === "ENOBUFS" ||
77
+ String(obj.message ?? "").includes("ENOBUFS"));
78
+ };
79
+ if (isENOBUFS(err)) {
80
+ logger_1.logger.warn("ENOBUFS detected; skipping git initialization.");
81
+ logger_1.logger.info("Skipped git initialization due to system resource limits.");
82
+ return;
83
+ }
84
+ try {
85
+ await run("inherit");
86
+ spinner.succeed("Git repository initialized (fallback)");
87
+ return;
88
+ }
89
+ catch (fallbackErr) {
90
+ const fe = fallbackErr;
91
+ logger_1.logger.warn(`Git init fallback failed: ${fe.message}`);
92
+ spinner.fail("Git initialization skipped");
93
+ return;
94
+ }
95
+ }
69
96
  }
@@ -16,7 +16,7 @@
16
16
  {
17
17
  "type": "create-file",
18
18
  "destination": "proxy.ts",
19
- "content": "export { auth as middleware } from \"@/lib/auth\""
19
+ "content": "export { auth as proxy } from \"@/lib/auth\""
20
20
  },
21
21
  {
22
22
  "type": "patch-file",
@@ -30,7 +30,9 @@ return betterAuth({
30
30
  database: mongodbAdapter(db, { client }),
31
31
  {{/case}}
32
32
  {{/switch}}
33
- secret: env.BETTER_AUTH_SECRET,
33
+ baseURL: process.env.BETTER_AUTH_URL,
34
+ secret: process.env.BETTER_AUTH_SECRET,
35
+ trustedOrigins: [process.env.APP_URL],
34
36
  user: {
35
37
  additionalFields: {
36
38
  role: {
@@ -84,9 +86,11 @@ return betterAuth({
84
86
  session: {
85
87
  cookieCache: {
86
88
  enabled: true,
89
+ maxAge: 60 * 60 * 24 * 7,
87
90
  },
88
91
  expiresIn: 60 * 60 * 24 * 7,
89
92
  updateAge: 60 * 60 * 24,
93
+ cookieName: "better-auth.session_token",
90
94
  }
91
95
  })
92
96
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stackkit",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
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": {
@@ -2,14 +2,12 @@
2
2
 
3
3
  Production-ready Express (TypeScript) starter for building REST APIs and backend services.
4
4
 
5
- Requirements
6
- ------------
5
+ ## Requirements
7
6
 
8
7
  - Node.js 18+ (LTS recommended)
9
8
  - pnpm or npm
10
9
 
11
- Quick Start
12
- -----------
10
+ ## Quick Start
13
11
 
14
12
  Install dependencies and start the development server:
15
13
 
@@ -23,15 +21,13 @@ npm install
23
21
  npm run dev
24
22
  ```
25
23
 
26
- Scripts
27
- -------
24
+ ## Scripts
28
25
 
29
26
  - `npm run dev` - Start development server
30
27
  - `npm run build` - Build TypeScript
31
28
  - `npm start` - Start production server
32
29
 
33
- Environment
34
- -----------
30
+ ## Environment
35
31
 
36
32
  Use a `.env` file or environment variables for configuration. See `.env.example` for available keys.
37
33
 
@@ -45,4 +41,3 @@ This project was scaffolded using **StackKit** — a CLI toolkit for building pr
45
41
 
46
42
  Learn more about StackKit:
47
43
  https://github.com/tariqul420/stackkit
48
-
@@ -7,7 +7,15 @@
7
7
  "databases": ["prisma", "mongoose"],
8
8
  "auth": ["better-auth"]
9
9
  },
10
- "files": ["src/", ".gitignore", "package.json", "tsconfig.json", ".env.example"],
10
+ "files": [
11
+ "src/",
12
+ ".env.example",
13
+ ".gitignore",
14
+ "eslint.config.cjs",
15
+ "package.json",
16
+ "README.md",
17
+ "tsconfig.json"
18
+ ],
11
19
  "scripts": {
12
20
  "dev": "tsx watch src/server.ts",
13
21
  "build": "tsc",
@@ -0,0 +1 @@
1
+ NEXT_PUBLIC_APP_URL=http://localhost:3000
@@ -2,14 +2,12 @@
2
2
 
3
3
  Production-ready Next.js starter with TypeScript and App Router.
4
4
 
5
- Requirements
6
- ------------
5
+ ## Requirements
7
6
 
8
7
  - Node.js 18+ (LTS recommended)
9
8
  - pnpm or npm
10
9
 
11
- Quick Start
12
- -----------
10
+ ## Quick Start
13
11
 
14
12
  Install dependencies and start a development server:
15
13
 
@@ -75,4 +73,3 @@ This project was scaffolded using **StackKit** — a CLI toolkit for building pr
75
73
 
76
74
  Learn more about StackKit:
77
75
  https://github.com/tariqul420/stackkit
78
-
@@ -9,7 +9,9 @@
9
9
  },
10
10
  "files": [
11
11
  "app/",
12
+ "lib/",
12
13
  "public/",
14
+ ".env.example",
13
15
  ".gitignore",
14
16
  "eslint.config.mjs",
15
17
  "next-env.d.ts",
@@ -2,14 +2,12 @@
2
2
 
3
3
  Production-ready React starter with TypeScript, Vite, and essential libraries.
4
4
 
5
- Requirements
6
- ------------
5
+ ## Requirements
7
6
 
8
7
  - Node.js 18+ (LTS recommended)
9
8
  - pnpm (recommended) or npm
10
9
 
11
- Quick Start
12
- -----------
10
+ ## Quick Start
13
11
 
14
12
  Install dependencies and run the dev server:
15
13
 
@@ -89,4 +87,3 @@ This project was scaffolded using **StackKit** — a CLI toolkit for building pr
89
87
 
90
88
  Learn more about StackKit:
91
89
  https://github.com/tariqul420/stackkit
92
-
@@ -3,8 +3,8 @@ import { QueryClient } from "@tanstack/react-query";
3
3
  export const queryClient = new QueryClient({
4
4
  defaultOptions: {
5
5
  queries: {
6
- staleTime: 1000 * 60 * 5, // 5 minutes
7
- gcTime: 1000 * 60 * 10, // 10 minutes (formerly cacheTime)
6
+ staleTime: 1000 * 60 * 5,
7
+ gcTime: 1000 * 60 * 10,
8
8
  retry: 1,
9
9
  refetchOnWindowFocus: false,
10
10
  },
@@ -0,0 +1,3 @@
1
+ export function cn(...classes: (string | boolean | undefined | null)[]): string {
2
+ return classes.filter(Boolean).join(" ");
3
+ }
@@ -12,6 +12,8 @@
12
12
  "public/",
13
13
  ".env.example",
14
14
  ".gitignore",
15
+ ".prettierignore",
16
+ ".prettierrc",
15
17
  "eslint.config.js",
16
18
  "index.html",
17
19
  "package.json",
@@ -1,5 +0,0 @@
1
- export const APP_NAME = import.meta.env.VITE_APP_NAME || "React App";
2
- export const APP_VERSION = import.meta.env.VITE_APP_VERSION || "1.0.0";
3
- export const API_URL = import.meta.env.VITE_API_URL || "http://localhost:3000/api";
4
- export const IS_DEV = import.meta.env.DEV;
5
- export const IS_PROD = import.meta.env.PROD;
@@ -1,64 +0,0 @@
1
- import { useEffect, useState } from "react";
2
-
3
- export function useDebounce<T>(value: T, delay: number): T {
4
- const [debouncedValue, setDebouncedValue] = useState<T>(value);
5
-
6
- useEffect(() => {
7
- const handler = setTimeout(() => {
8
- setDebouncedValue(value);
9
- }, delay);
10
-
11
- return () => {
12
- clearTimeout(handler);
13
- };
14
- }, [value, delay]);
15
-
16
- return debouncedValue;
17
- }
18
-
19
- export function useLocalStorage<T>(
20
- key: string,
21
- initialValue: T,
22
- ): [T, (value: T | ((val: T) => T)) => void] {
23
- const [storedValue, setStoredValue] = useState<T>(() => {
24
- try {
25
- const item = window.localStorage.getItem(key);
26
- return item ? JSON.parse(item) : initialValue;
27
- } catch (error) {
28
- console.error(error);
29
- return initialValue;
30
- }
31
- });
32
-
33
- const setValue = (value: T | ((val: T) => T)) => {
34
- try {
35
- const valueToStore = value instanceof Function ? value(storedValue) : value;
36
- setStoredValue(valueToStore);
37
- window.localStorage.setItem(key, JSON.stringify(valueToStore));
38
- } catch (error) {
39
- console.error(error);
40
- }
41
- };
42
-
43
- return [storedValue, setValue];
44
- }
45
-
46
- export function useMediaQuery(query: string): boolean {
47
- const [matches, setMatches] = useState(() => {
48
- if (typeof window !== "undefined") {
49
- return window.matchMedia(query).matches;
50
- }
51
- return false;
52
- });
53
-
54
- useEffect(() => {
55
- const media = window.matchMedia(query);
56
-
57
- const listener = () => setMatches(media.matches);
58
- media.addEventListener("change", listener);
59
-
60
- return () => media.removeEventListener("change", listener);
61
- }, [query]);
62
-
63
- return matches;
64
- }
@@ -1,51 +0,0 @@
1
- export function cn(...classes: (string | boolean | undefined | null)[]): string {
2
- return classes.filter(Boolean).join(" ");
3
- }
4
-
5
- export function formatDate(date: Date | string): string {
6
- const d = typeof date === "string" ? new Date(date) : date;
7
- return d.toLocaleDateString("en-US", {
8
- year: "numeric",
9
- month: "long",
10
- day: "numeric",
11
- });
12
- }
13
-
14
- export function truncate(str: string, maxLength: number): string {
15
- if (str.length <= maxLength) return str;
16
- return str.slice(0, maxLength) + "...";
17
- }
18
-
19
- export function delay(ms: number): Promise<void> {
20
- return new Promise((resolve) => setTimeout(resolve, ms));
21
- }
22
-
23
- export function debounce<T extends (...args: never[]) => unknown>(
24
- func: T,
25
- wait: number,
26
- ): (...args: Parameters<T>) => void {
27
- let timeout: ReturnType<typeof setTimeout> | null = null;
28
-
29
- return function executedFunction(...args: Parameters<T>) {
30
- const later = () => {
31
- timeout = null;
32
- func(...args);
33
- };
34
-
35
- if (timeout) clearTimeout(timeout);
36
- timeout = setTimeout(later, wait);
37
- };
38
- }
39
-
40
- export function capitalize(str: string): string {
41
- return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
42
- }
43
-
44
- export function slugify(str: string): string {
45
- return str
46
- .toLowerCase()
47
- .trim()
48
- .replace(/[^\w\s-]/g, "")
49
- .replace(/[\s_-]+/g, "-")
50
- .replace(/^-+|-+$/g, "");
51
- }