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.
- package/README.md +76 -69
- package/bin/stackpatch.js +79 -0
- package/bin/stackpatch.ts +2445 -3
- package/boilerplate/auth/app/api/auth/[...nextauth]/route.ts +124 -0
- package/boilerplate/auth/app/api/auth/signup/route.ts +45 -0
- package/boilerplate/auth/app/auth/login/page.tsx +24 -50
- package/boilerplate/auth/app/auth/signup/page.tsx +56 -69
- package/boilerplate/auth/app/dashboard/page.tsx +82 -0
- package/boilerplate/auth/app/login/page.tsx +136 -0
- package/boilerplate/auth/app/page.tsx +48 -0
- package/boilerplate/auth/components/auth-button.tsx +43 -0
- package/boilerplate/auth/components/auth-navbar.tsx +118 -0
- package/boilerplate/auth/components/protected-route.tsx +74 -0
- package/boilerplate/auth/components/session-provider.tsx +11 -0
- package/boilerplate/auth/middleware.ts +51 -0
- package/package.json +5 -6
- package/boilerplate/auth/app/stackpatch/page.tsx +0 -269
- package/boilerplate/auth/components/auth-wrapper.tsx +0 -61
- package/src/auth/generator.ts +0 -569
- package/src/auth/index.ts +0 -372
- package/src/auth/setup.ts +0 -293
- package/src/commands/add.ts +0 -112
- package/src/commands/create.ts +0 -128
- package/src/commands/revert.ts +0 -389
- package/src/config.ts +0 -52
- package/src/fileOps/copy.ts +0 -224
- package/src/fileOps/layout.ts +0 -304
- package/src/fileOps/protected.ts +0 -67
- package/src/index.ts +0 -215
- package/src/manifest.ts +0 -87
- package/src/ui/logo.ts +0 -24
- package/src/ui/progress.ts +0 -82
- package/src/utils/dependencies.ts +0 -114
- package/src/utils/deps-check.ts +0 -45
- package/src/utils/files.ts +0 -58
- package/src/utils/paths.ts +0 -217
- package/src/utils/scanner.ts +0 -109
package/src/utils/paths.ts
DELETED
|
@@ -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
|
-
}
|
package/src/utils/scanner.ts
DELETED
|
@@ -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
|
-
}
|