create-authenik8-app 2.0.7 → 2.0.9
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 +19 -11
- package/dist/bin/index.d.ts +5 -0
- package/dist/bin/index.d.ts.map +1 -1
- package/dist/bin/index.js +308 -180
- package/dist/bin/index.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +265 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/constants.d.ts +4 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +25 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/process.d.ts +7 -0
- package/dist/lib/process.d.ts.map +1 -0
- package/dist/lib/process.js +56 -0
- package/dist/lib/process.js.map +1 -0
- package/dist/lib/state.d.ts +8 -0
- package/dist/lib/state.d.ts.map +1 -0
- package/dist/lib/state.js +31 -0
- package/dist/lib/state.js.map +1 -0
- package/dist/lib/types.d.ts +17 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/ui.d.ts +7 -0
- package/dist/lib/ui.d.ts.map +1 -0
- package/dist/lib/ui.js +124 -0
- package/dist/lib/ui.js.map +1 -0
- package/dist/steps/configurePrisma.d.ts +3 -0
- package/dist/steps/configurePrisma.d.ts.map +1 -0
- package/dist/steps/configurePrisma.js +41 -0
- package/dist/steps/configurePrisma.js.map +1 -0
- package/dist/steps/createProject.d.ts +4 -0
- package/dist/steps/createProject.d.ts.map +1 -0
- package/dist/steps/createProject.js +16 -0
- package/dist/steps/createProject.js.map +1 -0
- package/dist/steps/finalSetup.d.ts +7 -0
- package/dist/steps/finalSetup.d.ts.map +1 -0
- package/dist/steps/finalSetup.js +113 -0
- package/dist/steps/finalSetup.js.map +1 -0
- package/dist/steps/installAuth.d.ts +2 -0
- package/dist/steps/installAuth.d.ts.map +1 -0
- package/dist/steps/installAuth.js +34 -0
- package/dist/steps/installAuth.js.map +1 -0
- package/dist/steps/installDeps.d.ts +3 -0
- package/dist/steps/installDeps.d.ts.map +1 -0
- package/dist/steps/installDeps.js +31 -0
- package/dist/steps/installDeps.js.map +1 -0
- package/dist/steps/prompts.d.ts +3 -0
- package/dist/steps/prompts.d.ts.map +1 -0
- package/dist/steps/prompts.js +76 -0
- package/dist/steps/prompts.js.map +1 -0
- package/dist/utils/hash.d.ts +3 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +41 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/output.d.ts +3 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +62 -0
- package/dist/utils/output.js.map +1 -0
- package/package.json +3 -2
- package/templates/express-auth/ecosystem.config.ts +0 -16
- package/templates/express-auth+/ecosystem.config.ts +0 -16
- package/templates/express-base/ecosystem.config.ts +0 -16
package/dist/bin/index.js
CHANGED
|
@@ -5,18 +5,86 @@ import chalk from "chalk";
|
|
|
5
5
|
import inquirer from "inquirer";
|
|
6
6
|
import { ExitPromptError } from "@inquirer/core";
|
|
7
7
|
import ora from "ora";
|
|
8
|
-
import { execSync } from "child_process";
|
|
8
|
+
import { execSync, ChildProcess } from "child_process";
|
|
9
9
|
import { fileURLToPath } from "url";
|
|
10
|
-
import { spawnSync } from "child_process";
|
|
10
|
+
import { spawnSync, spawn } from "child_process";
|
|
11
11
|
import os from "os";
|
|
12
|
-
|
|
12
|
+
const spinner = ora().start();
|
|
13
|
+
const activeProcesses = new Set();
|
|
14
|
+
export function run(cmd, args, options) {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
const child = spawn(cmd, args, {
|
|
17
|
+
cwd: options.cwd,
|
|
18
|
+
stdio: "ignore",
|
|
19
|
+
});
|
|
20
|
+
activeProcesses.add(child);
|
|
21
|
+
child.on("exit", (code) => {
|
|
22
|
+
activeProcesses.delete(child);
|
|
23
|
+
if (code === 0) {
|
|
24
|
+
resolve();
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
reject(new Error(`${cmd} exited with code ${code}`));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
child.on("error", (err) => {
|
|
31
|
+
activeProcesses.delete(child);
|
|
32
|
+
reject(err);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function killAllProcesses() {
|
|
37
|
+
for (const proc of activeProcesses) {
|
|
38
|
+
try {
|
|
39
|
+
proc.kill("SIGINT");
|
|
40
|
+
}
|
|
41
|
+
catch { }
|
|
42
|
+
}
|
|
43
|
+
activeProcesses.clear();
|
|
44
|
+
}
|
|
45
|
+
function getCommand(cmd) {
|
|
46
|
+
const isWin = process.platform === "win32";
|
|
47
|
+
if (cmd === "npm")
|
|
48
|
+
return isWin ? "npm.cmd" : "npm";
|
|
49
|
+
if (cmd === "npx")
|
|
50
|
+
return isWin ? "npx.cmd" : "npx";
|
|
51
|
+
if (cmd === "git")
|
|
52
|
+
return isWin ? "git.exe" : "git";
|
|
53
|
+
return cmd;
|
|
54
|
+
}
|
|
55
|
+
//make sure steps are completed
|
|
56
|
+
function stepActuallyCompleted(step) {
|
|
57
|
+
switch (step) {
|
|
58
|
+
case "deps-installed":
|
|
59
|
+
return fs.existsSync(path.join(targetDir, "node_modules"));
|
|
60
|
+
case "prisma-generated":
|
|
61
|
+
return fs.existsSync(path.join(targetDir, "node_modules/.prisma/client"));
|
|
62
|
+
case "git-initialized":
|
|
63
|
+
return fs.existsSync(path.join(targetDir, ".git"));
|
|
64
|
+
default:
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const args = process.argv.slice(2);
|
|
69
|
+
const projectNameArg = args.find(arg => !arg.startsWith("--"));
|
|
70
|
+
//const projectNameArg = process.argv[2];
|
|
71
|
+
if (!projectNameArg) {
|
|
72
|
+
console.log(chalk.red("❌ Please provide a project name"));
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
const projectName = projectNameArg;
|
|
76
|
+
//let answers:any = {};
|
|
77
|
+
let state = {
|
|
78
|
+
step: "start",
|
|
79
|
+
projectName,
|
|
80
|
+
};
|
|
13
81
|
const platform = os.platform();
|
|
14
82
|
// 'linux' | 'darwin' | 'win32'
|
|
15
83
|
const isTermux = process.env.PREFIX?.includes("com.termux") ||
|
|
16
84
|
process.env.TERMUX === "true";
|
|
17
85
|
function getBestHashLib() {
|
|
18
86
|
if (isTermux)
|
|
19
|
-
return "bcryptjs";
|
|
87
|
+
return "bcryptjs";
|
|
20
88
|
if (platform === "win32")
|
|
21
89
|
return "bcryptjs";
|
|
22
90
|
// avoids build tools issues for most users
|
|
@@ -56,14 +124,9 @@ return bcrypt.compare(password, hash);
|
|
|
56
124
|
}
|
|
57
125
|
const __filename = fileURLToPath(import.meta.url);
|
|
58
126
|
const __dirname = path.dirname(__filename);
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
const isProduction = process.argv.includes("--production-ready");
|
|
65
|
-
const isResume = process.argv.includes("--resume");
|
|
66
|
-
const targetDir = path.join(process.cwd(), projectName);
|
|
127
|
+
const isProduction = args.includes("--production-ready");
|
|
128
|
+
const isResume = args.includes("--resume");
|
|
129
|
+
const targetDir = path.resolve(process.cwd(), projectName);
|
|
67
130
|
let projectCreated = false;
|
|
68
131
|
const stepOrder = [
|
|
69
132
|
"start",
|
|
@@ -77,18 +140,28 @@ const stepOrder = [
|
|
|
77
140
|
"git-initialized",
|
|
78
141
|
"done",
|
|
79
142
|
];
|
|
80
|
-
const
|
|
143
|
+
const stepLabels = {
|
|
144
|
+
start: "Starting",
|
|
145
|
+
prompts: "Collecting inputs",
|
|
146
|
+
"project-created": "Project scaffold",
|
|
147
|
+
"auth-installed": "Auth setup",
|
|
148
|
+
"prisma-configured": "Prisma setup",
|
|
149
|
+
"deps-installed": "Dependencies install",
|
|
150
|
+
"prisma-generated": "Prisma generate",
|
|
151
|
+
"production-configured": "Production setup",
|
|
152
|
+
"git-initialized": "Git init",
|
|
153
|
+
done: "Completed",
|
|
154
|
+
};
|
|
155
|
+
const globalStateDir = path.join(process.cwd(), ".authenik8");
|
|
156
|
+
const stateFile = path.join(globalStateDir, `${projectName}.json`);
|
|
81
157
|
function hasReachedStep(currentStep, targetStep) {
|
|
82
158
|
return stepOrder.indexOf(currentStep) >= stepOrder.indexOf(targetStep);
|
|
83
159
|
}
|
|
84
|
-
function saveState(step, extra = {}) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
...answers,
|
|
90
|
-
...extra,
|
|
91
|
-
}, { spaces: 2 });
|
|
160
|
+
//function saveState(step: StepName, extra: Partial<CliState> = {}) {
|
|
161
|
+
function saveState(update) {
|
|
162
|
+
state = { ...state, ...update };
|
|
163
|
+
fs.ensureDirSync(path.dirname(stateFile));
|
|
164
|
+
fs.writeJsonSync(stateFile, state, { spaces: 2 });
|
|
92
165
|
}
|
|
93
166
|
function loadState() {
|
|
94
167
|
if (!fs.existsSync(stateFile))
|
|
@@ -100,6 +173,27 @@ function clearState() {
|
|
|
100
173
|
fs.removeSync(stateFile);
|
|
101
174
|
}
|
|
102
175
|
}
|
|
176
|
+
function renderStep(current) {
|
|
177
|
+
console.clear();
|
|
178
|
+
renderHeader();
|
|
179
|
+
for (const step of stepOrder) {
|
|
180
|
+
const label = stepLabels[step];
|
|
181
|
+
if (step === "production-configured" && !isProduction) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (step === current) {
|
|
185
|
+
console.log(chalk.yellow(`⏳ ${label}...`));
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
if (hasReachedStep(current, step)) {
|
|
189
|
+
console.log(chalk.green(`✔ ${label}`));
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.log(chalk.gray(`○ ${label}`));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
console.log("");
|
|
196
|
+
}
|
|
103
197
|
function isInterruptedError(err) {
|
|
104
198
|
return (typeof err === "object" &&
|
|
105
199
|
err !== null &&
|
|
@@ -107,12 +201,10 @@ function isInterruptedError(err) {
|
|
|
107
201
|
(err.signal === "SIGINT" ||
|
|
108
202
|
err.signal === "SIGTERM"));
|
|
109
203
|
}
|
|
110
|
-
function exitForInterrupt(err) {
|
|
204
|
+
async function exitForInterrupt(err) {
|
|
111
205
|
if (isInterruptedError(err)) {
|
|
112
206
|
throw err;
|
|
113
207
|
}
|
|
114
|
-
console.error(err);
|
|
115
|
-
process.exit(1);
|
|
116
208
|
}
|
|
117
209
|
async function cleanupIncompleteProject() {
|
|
118
210
|
if (projectCreated && fs.existsSync(targetDir)) {
|
|
@@ -121,87 +213,92 @@ async function cleanupIncompleteProject() {
|
|
|
121
213
|
}
|
|
122
214
|
}
|
|
123
215
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
124
|
-
const cleanLogo = `
|
|
125
|
-
|
|
126
|
-
█████╗ █████╗
|
|
127
|
-
██╔══██╗ ██╔══██╗
|
|
128
|
-
███████║ ╚█████╔╝
|
|
129
|
-
██╔══██║ ██╔══██╗
|
|
130
|
-
██║ ██║ ╚█████╔╝
|
|
131
|
-
╚═╝ ╚═╝ ╚════╝
|
|
132
|
-
|
|
133
|
-
A8
|
|
134
|
-
|
|
135
|
-
Authenik8 CLI
|
|
136
|
-
Build Faster
|
|
137
|
-
More , Secure
|
|
216
|
+
const cleanLogo = `
|
|
217
|
+
|
|
218
|
+
█████╗ █████╗
|
|
219
|
+
██╔══██╗ ██╔══██╗
|
|
220
|
+
███████║ ╚█████╔╝
|
|
221
|
+
██╔══██║ ██╔══██╗
|
|
222
|
+
██║ ██║ ╚█████╔╝
|
|
223
|
+
╚═╝ ╚═╝ ╚════╝
|
|
224
|
+
|
|
225
|
+
A8
|
|
226
|
+
|
|
227
|
+
Authenik8 CLI
|
|
228
|
+
Build Faster
|
|
229
|
+
More , Secure
|
|
138
230
|
`;
|
|
139
231
|
const glitchFrames = [
|
|
140
232
|
`
|
|
141
|
-
█████╗ █████╗
|
|
142
|
-
██╔══██╗ ██▒▒▒▒██
|
|
143
|
-
███████║ ╚█████╔╝
|
|
144
|
-
██╔══██║ ██▒▒▒▒██
|
|
145
|
-
██║ ██║ ╚█████╔╝
|
|
146
|
-
╚═╝ ╚═╝ ╚════╝
|
|
147
|
-
|
|
233
|
+
█████╗ █████╗
|
|
234
|
+
██╔══██╗ ██▒▒▒▒██
|
|
235
|
+
███████║ ╚█████╔╝
|
|
236
|
+
██╔══██║ ██▒▒▒▒██
|
|
237
|
+
██║ ██║ ╚█████╔╝
|
|
238
|
+
╚═╝ ╚═╝ ╚════╝
|
|
239
|
+
|
|
148
240
|
A8
|
|
149
241
|
Authenik8 CLI
|
|
150
|
-
|
|
151
|
-
More
|
|
242
|
+
|
|
243
|
+
More
|
|
152
244
|
`,
|
|
153
|
-
`
|
|
154
|
-
██▓▓██╗ ██▓▓██╗
|
|
155
|
-
██▒▒██╔╝ ██▒▒██╔╝
|
|
156
|
-
██▒▒▒▒██ ╚█████╔╝
|
|
157
|
-
██▓▓██╔╝ ██▒▒██╗
|
|
158
|
-
██▒▒██║ ╚█████╔╝
|
|
159
|
-
╚═════╝ ╚════╝
|
|
160
|
-
|
|
245
|
+
`
|
|
246
|
+
██▓▓██╗ ██▓▓██╗
|
|
247
|
+
██▒▒██╔╝ ██▒▒██╔╝
|
|
248
|
+
██▒▒▒▒██ ╚█████╔╝
|
|
249
|
+
██▓▓██╔╝ ██▒▒██╗
|
|
250
|
+
██▒▒██║ ╚█████╔╝
|
|
251
|
+
╚═════╝ ╚════╝
|
|
252
|
+
|
|
161
253
|
A8
|
|
162
254
|
Authenik8 CLI
|
|
163
|
-
Faster
|
|
255
|
+
Faster
|
|
164
256
|
`,
|
|
165
|
-
`
|
|
166
|
-
██▒▒██╗ ██▒▒██╗
|
|
167
|
-
██▓▓██╔╝ ██▓▓██╔╝
|
|
168
|
-
██▒▒▒▒██ ╚█████╔╝
|
|
169
|
-
██▓▓██╔╝ ██▓▓██╗
|
|
170
|
-
██▒▒██║ ╚█████╔╝
|
|
171
|
-
╚═════╝ ╚════╝
|
|
172
|
-
|
|
257
|
+
`
|
|
258
|
+
██▒▒██╗ ██▒▒██╗
|
|
259
|
+
██▓▓██╔╝ ██▓▓██╔╝
|
|
260
|
+
██▒▒▒▒██ ╚█████╔╝
|
|
261
|
+
██▓▓██╔╝ ██▓▓██╗
|
|
262
|
+
██▒▒██║ ╚█████╔╝
|
|
263
|
+
╚═════╝ ╚════╝
|
|
264
|
+
|
|
173
265
|
A8
|
|
174
266
|
Authenik8 CLI
|
|
175
|
-
Build
|
|
267
|
+
Build
|
|
176
268
|
`,
|
|
177
|
-
`
|
|
178
|
-
██▓▓██╗ ██▓▓██╗
|
|
179
|
-
██▒▒██╔╝ ██▒▒██╔╝
|
|
180
|
-
██▒▒▒▒██ ╚█████╔╝
|
|
181
|
-
██▓▓██╔╝ ██▒▒██╗
|
|
182
|
-
██▒▒██║ ╚█████╔╝
|
|
183
|
-
╚═════╝ ╚════╝
|
|
184
|
-
|
|
269
|
+
`
|
|
270
|
+
██▓▓██╗ ██▓▓██╗
|
|
271
|
+
██▒▒██╔╝ ██▒▒██╔╝
|
|
272
|
+
██▒▒▒▒██ ╚█████╔╝
|
|
273
|
+
██▓▓██╔╝ ██▒▒██╗
|
|
274
|
+
██▒▒██║ ╚█████╔╝
|
|
275
|
+
╚═════╝ ╚════╝
|
|
276
|
+
|
|
185
277
|
A8
|
|
186
|
-
Authenik8 CLI
|
|
187
|
-
|
|
278
|
+
Authenik8 CLI
|
|
279
|
+
|
|
188
280
|
`
|
|
189
281
|
];
|
|
282
|
+
function renderHeader() {
|
|
283
|
+
console.log(chalk.cyan.bold("Happy building \nAuthenik8 CLI"));
|
|
284
|
+
console.log(chalk.gray("────────────────────"));
|
|
285
|
+
console.log("");
|
|
286
|
+
}
|
|
190
287
|
async function showBootLogo() {
|
|
191
288
|
console.clear();
|
|
192
|
-
|
|
193
|
-
// Phase 1: clean → unstable
|
|
289
|
+
spinner.text = "Initializing Authenik8 engine...";
|
|
290
|
+
// Phase 1: clean → unstable
|
|
194
291
|
console.clear();
|
|
195
292
|
console.log(chalk.cyan(cleanLogo));
|
|
196
293
|
await sleep(200);
|
|
197
|
-
// Phase 2: glitch burst (irregular feel)
|
|
294
|
+
// Phase 2: glitch burst (irregular feel)
|
|
198
295
|
for (let i = 0; i < 5; i++) {
|
|
199
296
|
console.clear();
|
|
200
297
|
const frame = glitchFrames[Math.floor(Math.random() * glitchFrames.length)];
|
|
201
298
|
console.log(chalk.cyan(frame));
|
|
202
299
|
await sleep(120 + Math.random() * 120);
|
|
203
300
|
}
|
|
204
|
-
// Phase 3: stabilization flicker
|
|
301
|
+
// Phase 3: stabilization flicker
|
|
205
302
|
for (let i = 0; i < 2; i++) {
|
|
206
303
|
console.clear();
|
|
207
304
|
console.log(chalk.cyan(cleanLogo));
|
|
@@ -210,16 +307,19 @@ async function showBootLogo() {
|
|
|
210
307
|
console.log(chalk.gray(cleanLogo));
|
|
211
308
|
await sleep(120);
|
|
212
309
|
}
|
|
213
|
-
// Final render
|
|
310
|
+
// Final render
|
|
214
311
|
console.clear();
|
|
215
312
|
console.log(chalk.cyan.bold(cleanLogo));
|
|
216
313
|
await sleep(800);
|
|
217
|
-
|
|
314
|
+
spinner.succeed("Engine ready");
|
|
218
315
|
}
|
|
219
316
|
async function main() {
|
|
220
317
|
process.on("SIGINT", async () => {
|
|
221
|
-
console.log("\n
|
|
222
|
-
|
|
318
|
+
console.log("\n");
|
|
319
|
+
spinner.stop();
|
|
320
|
+
killAllProcesses();
|
|
321
|
+
console.log(chalk.yellow("⏸ Setup interrupted."));
|
|
322
|
+
console.log(chalk.gray(`↻ Resume with: create-authenik8-app ${projectName} --resume`));
|
|
223
323
|
process.exit(0);
|
|
224
324
|
});
|
|
225
325
|
try {
|
|
@@ -274,6 +374,8 @@ Features:
|
|
|
274
374
|
• Prisma ORM (optional)
|
|
275
375
|
• Git initialization (optional)
|
|
276
376
|
• OAuth + Auth
|
|
377
|
+
|
|
378
|
+
|
|
277
379
|
`));
|
|
278
380
|
const savedState = loadState();
|
|
279
381
|
let currentStep = "start";
|
|
@@ -286,23 +388,28 @@ Features:
|
|
|
286
388
|
}
|
|
287
389
|
process.exit(1);
|
|
288
390
|
}
|
|
391
|
+
if (isResume || fs.existsSync(stateFile)) {
|
|
392
|
+
console.log(chalk.gray(`
|
|
393
|
+
Resumable steps:
|
|
394
|
+
✔ project scaffold
|
|
395
|
+
✔ auth install
|
|
396
|
+
✔ prisma setup
|
|
397
|
+
✔ deps install
|
|
398
|
+
✔ prisma generate
|
|
399
|
+
✔ git init
|
|
400
|
+
`));
|
|
401
|
+
}
|
|
289
402
|
if (isResume) {
|
|
290
403
|
if (!savedState) {
|
|
291
404
|
console.log(chalk.red(`❌ No saved setup state found for "${projectName}".`));
|
|
292
405
|
process.exit(1);
|
|
293
406
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
usePrisma: savedState.usePrisma,
|
|
297
|
-
database: savedState.database,
|
|
298
|
-
useGit: savedState.useGit,
|
|
299
|
-
authMode: savedState.authMode,
|
|
300
|
-
};
|
|
301
|
-
currentStep = savedState.step;
|
|
407
|
+
state = savedState;
|
|
408
|
+
currentStep = state.step;
|
|
302
409
|
console.log(chalk.yellow(`\n↻ Resuming setup for ${projectName} from "${currentStep}"...\n`));
|
|
303
410
|
}
|
|
304
411
|
else {
|
|
305
|
-
|
|
412
|
+
const promptAnswers = await inquirer.prompt([
|
|
306
413
|
{
|
|
307
414
|
type: "list",
|
|
308
415
|
name: "framework",
|
|
@@ -344,7 +451,17 @@ Features:
|
|
|
344
451
|
default: "base"
|
|
345
452
|
}
|
|
346
453
|
]);
|
|
347
|
-
saveState(
|
|
454
|
+
//saveState({
|
|
455
|
+
//...promptAnswers,
|
|
456
|
+
//step:"prompts"});
|
|
457
|
+
state = {
|
|
458
|
+
...state,
|
|
459
|
+
...promptAnswers,
|
|
460
|
+
step: "prompts"
|
|
461
|
+
};
|
|
462
|
+
saveState({
|
|
463
|
+
...state
|
|
464
|
+
});
|
|
348
465
|
currentStep = "prompts";
|
|
349
466
|
}
|
|
350
467
|
function assertRequired(value, name) {
|
|
@@ -353,36 +470,35 @@ Features:
|
|
|
353
470
|
process.exit(1);
|
|
354
471
|
}
|
|
355
472
|
}
|
|
356
|
-
assertRequired(
|
|
357
|
-
assertRequired(
|
|
358
|
-
if (
|
|
359
|
-
if (!
|
|
360
|
-
|
|
473
|
+
assertRequired(state.framework, "framework");
|
|
474
|
+
assertRequired(state.authMode, "authMode");
|
|
475
|
+
if (state.usePrisma) {
|
|
476
|
+
if (!state.database) {
|
|
477
|
+
state.database = "sqlite";
|
|
361
478
|
}
|
|
362
|
-
assertRequired(
|
|
479
|
+
assertRequired(state.database, "database");
|
|
363
480
|
}
|
|
364
|
-
console.log(chalk.cyan("\
|
|
481
|
+
console.log(chalk.cyan("\nSetting up your project\n"));
|
|
365
482
|
const templateRoot = path.resolve(__dirname, "../../templates");
|
|
366
483
|
let templateName = "express-base";
|
|
367
|
-
if (
|
|
484
|
+
if (state.authMode === "auth") {
|
|
368
485
|
templateName = "express-auth";
|
|
369
486
|
}
|
|
370
|
-
if (
|
|
487
|
+
if (state.authMode === "auth-oauth") {
|
|
371
488
|
templateName = "express-auth+";
|
|
372
489
|
}
|
|
373
490
|
const templatePath = path.join(templateRoot, templateName);
|
|
374
491
|
// 📁 Create project (SPINNER)
|
|
375
492
|
if (!hasReachedStep(currentStep, "project-created")) {
|
|
376
|
-
|
|
493
|
+
renderStep("project-created");
|
|
377
494
|
try {
|
|
378
495
|
await fs.copy(templatePath, targetDir);
|
|
379
496
|
projectCreated = true;
|
|
380
|
-
|
|
381
|
-
saveState("project-created");
|
|
497
|
+
saveState({ step: "project-created" });
|
|
382
498
|
currentStep = "project-created";
|
|
499
|
+
renderStep(currentStep);
|
|
383
500
|
}
|
|
384
501
|
catch (err) {
|
|
385
|
-
createSpinner.fail("Failed to create project");
|
|
386
502
|
console.error(err);
|
|
387
503
|
process.exit(1);
|
|
388
504
|
}
|
|
@@ -392,53 +508,44 @@ Features:
|
|
|
392
508
|
}
|
|
393
509
|
let selectedHash = "bcryptjs"; // default safe fallback
|
|
394
510
|
if (!hasReachedStep(currentStep, "auth-installed")) {
|
|
395
|
-
if (
|
|
396
|
-
|
|
511
|
+
if (state.authMode !== "base") {
|
|
512
|
+
spinner.start("Installing password auth...");
|
|
397
513
|
selectedHash = getBestHashLib();
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
authSpinner.succeed(`Password auth ready ${selectedHash}`);
|
|
514
|
+
try {
|
|
515
|
+
const installResult = await run(getCommand("npm"), ["install", selectedHash], {
|
|
516
|
+
cwd: targetDir,
|
|
517
|
+
stdio: "ignore"
|
|
518
|
+
});
|
|
404
519
|
}
|
|
405
|
-
|
|
520
|
+
catch {
|
|
406
521
|
if (selectedHash !== "bcryptjs") {
|
|
407
|
-
|
|
408
|
-
const fallbackResult =
|
|
522
|
+
spinner.warn(`${selectedHash} failed, falling back to bcryptjs`);
|
|
523
|
+
const fallbackResult = await run(getCommand("npm"), ["install", "bcryptjs"], {
|
|
409
524
|
cwd: targetDir,
|
|
410
525
|
stdio: "ignore",
|
|
411
526
|
});
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
}
|
|
416
|
-
else {
|
|
417
|
-
authSpinner.fail("Failed to install password auth");
|
|
418
|
-
process.exit(1);
|
|
419
|
-
}
|
|
527
|
+
spinner.stop();
|
|
528
|
+
selectedHash = "bcryptjs";
|
|
529
|
+
renderStep("auth-installed");
|
|
420
530
|
}
|
|
421
531
|
else {
|
|
422
|
-
|
|
532
|
+
spinner.fail("Failed to install password auth");
|
|
533
|
+
process.exit(1);
|
|
534
|
+
spinner.fail("Failed to install password auth");
|
|
423
535
|
process.exit(1);
|
|
424
536
|
}
|
|
425
537
|
}
|
|
426
538
|
}
|
|
427
|
-
|
|
539
|
+
renderStep("auth-installed");
|
|
540
|
+
if (state.authMode !== "base") {
|
|
541
|
+
spinner.start("Installing password auth...");
|
|
428
542
|
const hashLib = selectedHash;
|
|
429
543
|
await fs.writeFile(path.join(targetDir, "src/utils/hash.ts"), generateHashModule(hashLib));
|
|
430
|
-
//const deps = [];
|
|
431
|
-
//if (hashLib === "argon2") deps.push("argon2");
|
|
432
|
-
//if (hashLib === "bcryptjs") deps.push("bcryptjs");
|
|
433
|
-
//if (deps.length) {
|
|
434
|
-
//execSync(`npm install ${deps.join(" ")}`, {
|
|
435
|
-
//cwd: targetDir,
|
|
436
|
-
//stdio: "ignore",
|
|
437
|
-
//});
|
|
438
|
-
//};
|
|
439
544
|
}
|
|
440
|
-
saveState("auth-installed",
|
|
545
|
+
saveState({ step: "auth-installed", ...(state.authMode !== "base" && { hashLib: selectedHash })
|
|
546
|
+
});
|
|
441
547
|
currentStep = "auth-installed";
|
|
548
|
+
renderStep(currentStep);
|
|
442
549
|
}
|
|
443
550
|
else {
|
|
444
551
|
selectedHash = savedState?.hashLib ?? selectedHash;
|
|
@@ -451,12 +558,12 @@ Features:
|
|
|
451
558
|
...pkg.dependencies,
|
|
452
559
|
ioredis: "^5.8.1",
|
|
453
560
|
};
|
|
454
|
-
if (
|
|
455
|
-
|
|
561
|
+
if (state.usePrisma) {
|
|
562
|
+
spinner.start("Adding Prisma setup...");
|
|
456
563
|
try {
|
|
457
|
-
const dbType =
|
|
458
|
-
"postgresql" ? "postgresql"
|
|
459
|
-
|
|
564
|
+
const dbType = state.database ===
|
|
565
|
+
"postgresql" ? "postgresql" :
|
|
566
|
+
"sqlite";
|
|
460
567
|
const prismaTemplatePath = path.join(templateRoot, `prisma/${dbType}`);
|
|
461
568
|
// Copy prisma schema
|
|
462
569
|
await fs.copy(path.join(prismaTemplatePath, "schema.prisma"), path.join(targetDir, "prisma/schema.prisma"));
|
|
@@ -478,92 +585,106 @@ Features:
|
|
|
478
585
|
"prisma:migrate": "prisma migrate dev",
|
|
479
586
|
};
|
|
480
587
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
481
|
-
|
|
588
|
+
spinner.succeed(`Prisma (${dbType}) configured`);
|
|
482
589
|
}
|
|
483
590
|
catch (err) {
|
|
484
|
-
|
|
591
|
+
spinner.fail("Failed to setup Prisma");
|
|
485
592
|
exitForInterrupt(err);
|
|
486
593
|
}
|
|
487
594
|
}
|
|
488
595
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
489
|
-
saveState("prisma-configured",
|
|
596
|
+
saveState({ step: "prisma-configured", ...(state.authMode !== "base" && { hashLib: selectedHash })
|
|
597
|
+
});
|
|
490
598
|
currentStep = "prisma-configured";
|
|
599
|
+
renderStep(currentStep);
|
|
491
600
|
}
|
|
492
601
|
else {
|
|
493
|
-
console.log(chalk.gray("
|
|
602
|
+
console.log(chalk.gray(" Skipping Prisma/package setup (already completed)"));
|
|
494
603
|
}
|
|
495
604
|
if (!hasReachedStep(currentStep, "deps-installed")) {
|
|
496
|
-
|
|
605
|
+
renderStep("deps-installed");
|
|
606
|
+
spinner.start("Installing dependencies...(this may take a few minutes)");
|
|
497
607
|
try {
|
|
498
|
-
|
|
608
|
+
await run(getCommand("npm"), ["install"], {
|
|
499
609
|
cwd: targetDir,
|
|
500
610
|
stdio: "ignore",
|
|
501
611
|
});
|
|
502
|
-
|
|
612
|
+
spinner.stop();
|
|
503
613
|
}
|
|
504
614
|
catch (err) {
|
|
505
|
-
|
|
615
|
+
spinner.fail("Failed to install dependencies");
|
|
506
616
|
exitForInterrupt(err);
|
|
507
617
|
}
|
|
508
|
-
saveState("deps-installed",
|
|
618
|
+
saveState({ step: "deps-installed", ...(state.authMode !== "base" && { hashLib: selectedHash })
|
|
619
|
+
});
|
|
509
620
|
currentStep = "deps-installed";
|
|
621
|
+
renderStep(currentStep);
|
|
510
622
|
}
|
|
511
623
|
else {
|
|
512
|
-
|
|
624
|
+
await run(getCommand("npm"), ["install"], {
|
|
625
|
+
cwd: targetDir,
|
|
626
|
+
stdio: "ignore",
|
|
627
|
+
});
|
|
513
628
|
}
|
|
514
629
|
if (!hasReachedStep(currentStep, "prisma-generated")) {
|
|
515
|
-
if (
|
|
516
|
-
|
|
630
|
+
if (state.usePrisma) {
|
|
631
|
+
spinner.start("Generating Prisma client...");
|
|
517
632
|
try {
|
|
518
|
-
|
|
633
|
+
await run(getCommand("npx"), ["prisma@5.22.0", "generate"], {
|
|
519
634
|
cwd: targetDir,
|
|
520
635
|
stdio: "ignore"
|
|
521
636
|
});
|
|
522
|
-
|
|
637
|
+
spinner.stop();
|
|
523
638
|
}
|
|
524
639
|
catch (err) {
|
|
525
|
-
|
|
640
|
+
spinner.fail("Failed to generate Prisma client");
|
|
526
641
|
exitForInterrupt(err);
|
|
527
642
|
}
|
|
528
643
|
}
|
|
529
|
-
saveState("prisma-generated",
|
|
644
|
+
saveState({ step: "prisma-generated", ...(state.authMode !== "base" && { hashLib: selectedHash })
|
|
645
|
+
});
|
|
530
646
|
currentStep = "prisma-generated";
|
|
647
|
+
renderStep(currentStep);
|
|
531
648
|
}
|
|
532
649
|
else {
|
|
533
650
|
console.log(chalk.gray("↷ Skipping Prisma client generation (already completed)"));
|
|
534
651
|
}
|
|
535
652
|
if (isProduction && !hasReachedStep(currentStep, "production-configured")) {
|
|
536
|
-
|
|
653
|
+
spinner.start("Setting up production mode (PM2)...");
|
|
537
654
|
try {
|
|
538
|
-
|
|
655
|
+
await run(getCommand("npm"), ["install pm2"], {
|
|
539
656
|
cwd: targetDir,
|
|
540
657
|
stdio: "ignore",
|
|
541
658
|
});
|
|
542
|
-
|
|
659
|
+
spinner.stop();
|
|
543
660
|
}
|
|
544
661
|
catch (err) {
|
|
545
|
-
|
|
662
|
+
spinner.fail("Failed to install PM2");
|
|
546
663
|
exitForInterrupt(err);
|
|
547
664
|
}
|
|
548
|
-
saveState("production-configured",
|
|
665
|
+
saveState({ step: "production-configured", ...(state.authMode !== "base" && { hashLib: selectedHash })
|
|
666
|
+
});
|
|
549
667
|
currentStep = "production-configured";
|
|
668
|
+
renderStep(currentStep);
|
|
550
669
|
}
|
|
551
670
|
if (!hasReachedStep(currentStep, "git-initialized")) {
|
|
552
|
-
if (
|
|
553
|
-
|
|
671
|
+
if (state.useGit) {
|
|
672
|
+
renderStep("git-initialized");
|
|
554
673
|
try {
|
|
555
|
-
|
|
674
|
+
await run(getCommand("git"), ["init"], {
|
|
556
675
|
cwd: targetDir,
|
|
557
676
|
stdio: "ignore",
|
|
558
677
|
});
|
|
559
|
-
|
|
678
|
+
spinner.stop();
|
|
560
679
|
}
|
|
561
680
|
catch (err) {
|
|
562
|
-
|
|
681
|
+
spinner.fail("Git init failed");
|
|
563
682
|
}
|
|
564
683
|
}
|
|
565
|
-
saveState("git-initialized",
|
|
684
|
+
saveState({ step: "git-initialized", ...(state.authMode !== "base" && { hashLib: selectedHash }),
|
|
685
|
+
});
|
|
566
686
|
currentStep = "git-initialized";
|
|
687
|
+
renderStep("done");
|
|
567
688
|
}
|
|
568
689
|
else {
|
|
569
690
|
console.log(chalk.gray("↷ Skipping git init (already completed)"));
|
|
@@ -598,28 +719,28 @@ redis-server --daemonize yes
|
|
|
598
719
|
npm run dev
|
|
599
720
|
|
|
600
721
|
Auth Features:
|
|
601
|
-
${
|
|
722
|
+
${state.authMode === "base"
|
|
602
723
|
? "✓ JWT only"
|
|
603
|
-
:
|
|
724
|
+
: state.authMode === "auth"
|
|
604
725
|
? "✓ Email + Password"
|
|
605
726
|
: "✓ Password + OAuth (Google/GitHub)"}
|
|
606
727
|
|
|
607
728
|
🛠 Stack:
|
|
608
729
|
✔ Express
|
|
609
|
-
✔ ${
|
|
610
|
-
✔ ${
|
|
730
|
+
✔ ${state.usePrisma ? (state.database === "postgresql" ? "PostgreSQL" : "SQLite") : "No database"}
|
|
731
|
+
✔ ${state.usePrisma ? "Prisma ORM" : "No ORM"}
|
|
611
732
|
|
|
612
733
|
📡 API Routes:
|
|
613
|
-
${
|
|
734
|
+
${state.authMode === "base"
|
|
614
735
|
? `
|
|
615
736
|
GET /public
|
|
616
737
|
GET /guest
|
|
617
738
|
GET /protected
|
|
618
739
|
POST /refresh
|
|
619
740
|
`
|
|
620
|
-
:
|
|
741
|
+
: state.authMode === "auth"
|
|
621
742
|
? `
|
|
622
|
-
POST /auth/register
|
|
743
|
+
POST /auth/register
|
|
623
744
|
POST /auth/login
|
|
624
745
|
POST /auth/refresh
|
|
625
746
|
GET /protected
|
|
@@ -647,17 +768,24 @@ Run:
|
|
|
647
768
|
npm run pm2:start
|
|
648
769
|
`);
|
|
649
770
|
}
|
|
650
|
-
saveState("done",
|
|
771
|
+
saveState({ step: "done", ...(state.authMode !== "base" && { hashLib: selectedHash }),
|
|
772
|
+
});
|
|
651
773
|
clearState();
|
|
652
774
|
}
|
|
653
775
|
catch (err) {
|
|
654
|
-
|
|
655
|
-
|
|
776
|
+
if (err instanceof ExitPromptError) {
|
|
777
|
+
throw err;
|
|
778
|
+
console.error("Fatal error", err);
|
|
779
|
+
process.exit(1);
|
|
780
|
+
}
|
|
656
781
|
}
|
|
657
782
|
}
|
|
658
783
|
main().catch(async (err) => {
|
|
659
784
|
if (err instanceof ExitPromptError) {
|
|
660
|
-
console.log("\n👋 Authenik8 setup cancelled.");
|
|
785
|
+
console.log("\n👋 Authenik8 setup cancelled.You can --resume later");
|
|
786
|
+
killAllProcesses();
|
|
787
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
788
|
+
console.log(chalk.bgYellow.black(" SETUP CANCELLED "));
|
|
661
789
|
await cleanupIncompleteProject();
|
|
662
790
|
process.exit(0);
|
|
663
791
|
}
|