stackpatch 1.1.4 → 1.1.6

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 (37) hide show
  1. package/README.md +76 -69
  2. package/bin/stackpatch.js +79 -0
  3. package/bin/stackpatch.ts +2445 -3
  4. package/boilerplate/auth/app/api/auth/[...nextauth]/route.ts +124 -0
  5. package/boilerplate/auth/app/api/auth/signup/route.ts +45 -0
  6. package/boilerplate/auth/app/auth/login/page.tsx +24 -50
  7. package/boilerplate/auth/app/auth/signup/page.tsx +56 -69
  8. package/boilerplate/auth/app/dashboard/page.tsx +82 -0
  9. package/boilerplate/auth/app/login/page.tsx +136 -0
  10. package/boilerplate/auth/app/page.tsx +48 -0
  11. package/boilerplate/auth/components/auth-button.tsx +43 -0
  12. package/boilerplate/auth/components/auth-navbar.tsx +118 -0
  13. package/boilerplate/auth/components/protected-route.tsx +74 -0
  14. package/boilerplate/auth/components/session-provider.tsx +11 -0
  15. package/boilerplate/auth/middleware.ts +51 -0
  16. package/package.json +5 -6
  17. package/boilerplate/auth/app/stackpatch/page.tsx +0 -269
  18. package/boilerplate/auth/components/auth-wrapper.tsx +0 -61
  19. package/src/auth/generator.ts +0 -569
  20. package/src/auth/index.ts +0 -372
  21. package/src/auth/setup.ts +0 -293
  22. package/src/commands/add.ts +0 -112
  23. package/src/commands/create.ts +0 -128
  24. package/src/commands/revert.ts +0 -389
  25. package/src/config.ts +0 -52
  26. package/src/fileOps/copy.ts +0 -224
  27. package/src/fileOps/layout.ts +0 -304
  28. package/src/fileOps/protected.ts +0 -67
  29. package/src/index.ts +0 -215
  30. package/src/manifest.ts +0 -87
  31. package/src/ui/logo.ts +0 -24
  32. package/src/ui/progress.ts +0 -82
  33. package/src/utils/dependencies.ts +0 -114
  34. package/src/utils/deps-check.ts +0 -45
  35. package/src/utils/files.ts +0 -58
  36. package/src/utils/paths.ts +0 -217
  37. package/src/utils/scanner.ts +0 -109
@@ -1,217 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
-
4
- /**
5
- * Utility functions for detecting project structure and paths
6
- */
7
-
8
- /**
9
- * Detect the app directory location (app/ or src/app/)
10
- */
11
- export function detectAppDirectory(target: string): string {
12
- // Check for src/app first (more common in modern Next.js projects)
13
- if (fs.existsSync(path.join(target, "src", "app"))) {
14
- return "src/app";
15
- }
16
- // Check for app directory
17
- if (fs.existsSync(path.join(target, "app"))) {
18
- return "app";
19
- }
20
- // Check for src/pages (legacy)
21
- if (fs.existsSync(path.join(target, "src", "pages"))) {
22
- return "src/pages";
23
- }
24
- // Check for pages (legacy)
25
- if (fs.existsSync(path.join(target, "pages"))) {
26
- return "pages";
27
- }
28
- // Default to app if nothing found (will fail gracefully later)
29
- return "app";
30
- }
31
-
32
- /**
33
- * Detect the components directory location (components/ or src/components/)
34
- */
35
- export function detectComponentsDirectory(target: string): string {
36
- const appDir = detectAppDirectory(target);
37
-
38
- // If app is in src/app, components should be in src/components
39
- if (appDir.startsWith("src/")) {
40
- // Check if src/components exists
41
- if (fs.existsSync(path.join(target, "src", "components"))) {
42
- return "src/components";
43
- }
44
- // Even if it doesn't exist yet, return src/components to match app structure
45
- return "src/components";
46
- }
47
-
48
- // If app is in root, components should be in root
49
- if (fs.existsSync(path.join(target, "components"))) {
50
- return "components";
51
- }
52
-
53
- // Default to components
54
- return "components";
55
- }
56
-
57
- /**
58
- * Detect path aliases from tsconfig.json
59
- */
60
- export function detectPathAliases(target: string): { alias: string; path: string } | null {
61
- const tsconfigPath = path.join(target, "tsconfig.json");
62
-
63
- if (!fs.existsSync(tsconfigPath)) {
64
- return null;
65
- }
66
-
67
- try {
68
- const tsconfigContent = fs.readFileSync(tsconfigPath, "utf-8");
69
- const tsconfig = JSON.parse(tsconfigContent);
70
-
71
- const paths = tsconfig.compilerOptions?.paths;
72
- if (!paths || typeof paths !== "object") {
73
- return null;
74
- }
75
-
76
- // Look for common aliases like @/*, ~/*, etc.
77
- for (const [alias, pathsArray] of Object.entries(paths)) {
78
- if (Array.isArray(pathsArray) && pathsArray.length > 0) {
79
- // Remove the /* from alias (e.g., "@/*" -> "@")
80
- const cleanAlias = alias.replace(/\/\*$/, "");
81
- // Get the first path and remove /* from it
82
- const cleanPath = pathsArray[0].replace(/\/\*$/, "");
83
- return { alias: cleanAlias, path: cleanPath };
84
- }
85
- }
86
- } catch (error) {
87
- // If parsing fails, return null
88
- }
89
-
90
- return null;
91
- }
92
-
93
- /**
94
- * Generate import path for components
95
- */
96
- export function generateComponentImportPath(
97
- target: string,
98
- componentName: string,
99
- fromFile: string
100
- ): string {
101
- const pathAlias = detectPathAliases(target);
102
- const componentsDir = detectComponentsDirectory(target);
103
-
104
- // If we have a path alias, use it
105
- if (pathAlias) {
106
- // Check if the alias path matches components directory
107
- const aliasPath = pathAlias.path.replace(/^\.\//, ""); // Remove leading ./
108
-
109
- // If alias points to root and components is in root, use alias
110
- if (aliasPath === "" && componentsDir === "components") {
111
- return `${pathAlias.alias}/components/${componentName}`;
112
- }
113
-
114
- // If alias points to src and components is in src/components, use alias
115
- if (aliasPath === "src" && componentsDir === "src/components") {
116
- return `${pathAlias.alias}/components/${componentName}`;
117
- }
118
-
119
- // Try to match the alias path structure
120
- if (componentsDir.startsWith(aliasPath)) {
121
- const relativeFromAlias = componentsDir.replace(new RegExp(`^${aliasPath}/?`), "");
122
- return `${pathAlias.alias}/${relativeFromAlias}/${componentName}`;
123
- }
124
-
125
- // If alias path is "./" (root), components should be accessible via alias
126
- if (aliasPath === "" || aliasPath === ".") {
127
- return `${pathAlias.alias}/components/${componentName}`;
128
- }
129
- }
130
-
131
- // Fallback: calculate relative path
132
- // fromFile is the full path to the file we're importing into
133
- const fromDir = path.dirname(fromFile);
134
- const toComponents = path.join(target, componentsDir);
135
-
136
- // Calculate relative path from the file's directory to components directory
137
- const relativePath = path.relative(fromDir, toComponents).replace(/\\/g, "/");
138
- const normalizedPath = relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
139
-
140
- return `${normalizedPath}/${componentName}`;
141
- }
142
-
143
- /**
144
- * Get all parent directories of a file path
145
- */
146
- export function getParentDirectories(filePath: string, rootPath: string): string[] {
147
- const dirs: string[] = [];
148
- let current = path.dirname(filePath);
149
- const root = path.resolve(rootPath);
150
-
151
- while (current !== root && current !== path.dirname(current)) {
152
- dirs.push(current);
153
- current = path.dirname(current);
154
- }
155
-
156
- return dirs;
157
- }
158
-
159
- /**
160
- * Auto-detect target directory for Next.js app
161
- */
162
- export function detectTargetDirectory(startDir: string = process.cwd()): string {
163
- let target = startDir;
164
-
165
- // Check if we're in a Next.js app (has app/, src/app/, pages/, or src/pages/ directory)
166
- const hasAppDir =
167
- fs.existsSync(path.join(target, "app")) || fs.existsSync(path.join(target, "src", "app"));
168
- const hasPagesDir =
169
- fs.existsSync(path.join(target, "pages")) || fs.existsSync(path.join(target, "src", "pages"));
170
-
171
- if (!hasAppDir && !hasPagesDir) {
172
- // Try parent directory
173
- const parent = path.resolve(target, "..");
174
- if (
175
- fs.existsSync(path.join(parent, "app")) ||
176
- fs.existsSync(path.join(parent, "src", "app")) ||
177
- fs.existsSync(path.join(parent, "pages")) ||
178
- fs.existsSync(path.join(parent, "src", "pages"))
179
- ) {
180
- target = parent;
181
- } else {
182
- // Try common monorepo locations: apps/, packages/, or root
183
- const possiblePaths = [
184
- path.join(target, "apps"),
185
- path.join(parent, "apps"),
186
- path.join(target, "packages"),
187
- path.join(parent, "packages"),
188
- ];
189
-
190
- let foundApp = false;
191
- for (const possiblePath of possiblePaths) {
192
- if (fs.existsSync(possiblePath)) {
193
- // Look for Next.js apps in this directory
194
- const entries = fs.readdirSync(possiblePath, { withFileTypes: true });
195
- for (const entry of entries) {
196
- if (entry.isDirectory()) {
197
- const appPath = path.join(possiblePath, entry.name);
198
- if (
199
- fs.existsSync(path.join(appPath, "app")) ||
200
- fs.existsSync(path.join(appPath, "src", "app")) ||
201
- fs.existsSync(path.join(appPath, "pages")) ||
202
- fs.existsSync(path.join(appPath, "src", "pages"))
203
- ) {
204
- target = appPath;
205
- foundApp = true;
206
- break;
207
- }
208
- }
209
- }
210
- if (foundApp) break;
211
- }
212
- }
213
- }
214
- }
215
-
216
- return target;
217
- }
@@ -1,109 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
-
4
- /**
5
- * Project scanner to detect project configuration
6
- */
7
-
8
- export interface ProjectScan {
9
- framework: "nextjs" | "unknown";
10
- router: "app" | "pages" | "unknown";
11
- typescript: boolean;
12
- packageManager: "pnpm" | "npm" | "yarn" | "bun" | "unknown";
13
- runtime: "node" | "bun" | "unknown";
14
- hasSrcDir: boolean;
15
- existingAuth: "better-auth" | "next-auth" | "none";
16
- }
17
-
18
- /**
19
- * Scan project to detect configuration
20
- */
21
- export function scanProject(target: string): ProjectScan {
22
- const scan: ProjectScan = {
23
- framework: "unknown",
24
- router: "unknown",
25
- typescript: false,
26
- packageManager: "unknown",
27
- runtime: "node",
28
- hasSrcDir: false,
29
- existingAuth: "none",
30
- };
31
-
32
- // Check for Next.js
33
- const packageJsonPath = path.join(target, "package.json");
34
- if (fs.existsSync(packageJsonPath)) {
35
- try {
36
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
37
- const deps = {
38
- ...packageJson.dependencies,
39
- ...packageJson.devDependencies,
40
- };
41
-
42
- if (deps.next || deps["next"]) {
43
- scan.framework = "nextjs";
44
- }
45
-
46
- // Detect package manager from lock files
47
- if (fs.existsSync(path.join(target, "pnpm-lock.yaml"))) {
48
- scan.packageManager = "pnpm";
49
- } else if (fs.existsSync(path.join(target, "yarn.lock"))) {
50
- scan.packageManager = "yarn";
51
- } else if (fs.existsSync(path.join(target, "package-lock.json"))) {
52
- scan.packageManager = "npm";
53
- } else if (fs.existsSync(path.join(target, "bun.lockb"))) {
54
- scan.packageManager = "bun";
55
- scan.runtime = "bun";
56
- }
57
-
58
- // Check for existing auth
59
- if (deps["better-auth"]) {
60
- scan.existingAuth = "better-auth";
61
- } else if (deps["next-auth"]) {
62
- scan.existingAuth = "next-auth";
63
- }
64
- } catch {
65
- // Ignore errors
66
- }
67
- }
68
-
69
- // Check for TypeScript
70
- if (
71
- fs.existsSync(path.join(target, "tsconfig.json")) ||
72
- fs.existsSync(path.join(target, "src", "tsconfig.json"))
73
- ) {
74
- scan.typescript = true;
75
- }
76
-
77
- // Check for src directory
78
- if (fs.existsSync(path.join(target, "src"))) {
79
- scan.hasSrcDir = true;
80
- }
81
-
82
- // Detect router type
83
- if (fs.existsSync(path.join(target, "app")) || fs.existsSync(path.join(target, "src", "app"))) {
84
- scan.router = "app";
85
- } else if (
86
- fs.existsSync(path.join(target, "pages")) ||
87
- fs.existsSync(path.join(target, "src", "pages"))
88
- ) {
89
- scan.router = "pages";
90
- }
91
-
92
- return scan;
93
- }
94
-
95
- /**
96
- * Format scan results for display
97
- */
98
- export function formatScanResults(scan: ProjectScan): string[] {
99
- const results: string[] = [];
100
-
101
- results.push(`✔ Framework: ${scan.framework === "nextjs" ? "Next.js" : "Unknown"} ${scan.router !== "unknown" ? `(${scan.router === "app" ? "App Router" : "Pages Router"})` : ""}`);
102
- results.push(`✔ TypeScript: ${scan.typescript ? "Yes" : "No"}`);
103
- results.push(`✔ Package Manager: ${scan.packageManager !== "unknown" ? scan.packageManager : "Unknown"}`);
104
- results.push(`✔ Runtime: ${scan.runtime === "bun" ? "Bun" : "Node"}`);
105
- results.push(`✔ src directory: ${scan.hasSrcDir ? "Yes" : "No"}`);
106
- results.push(`✔ Existing auth: ${scan.existingAuth === "none" ? "None" : scan.existingAuth === "better-auth" ? "Better Auth" : "NextAuth"}`);
107
-
108
- return results;
109
- }