create-authenik8-app 2.1.7 → 2.3.3
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 +5 -4
- package/package.json +1 -1
- package/dist/bin/index.d.ts +0 -8
- package/dist/bin/index.d.ts.map +0 -1
- package/dist/bin/index.js +0 -796
- package/dist/bin/index.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -292
- package/dist/index.js.map +0 -1
- package/dist/lib/constants.d.ts +0 -4
- package/dist/lib/constants.d.ts.map +0 -1
- package/dist/lib/constants.js +0 -25
- package/dist/lib/constants.js.map +0 -1
- package/dist/lib/process.d.ts +0 -7
- package/dist/lib/process.d.ts.map +0 -1
- package/dist/lib/process.js +0 -60
- package/dist/lib/process.js.map +0 -1
- package/dist/lib/state.d.ts +0 -8
- package/dist/lib/state.d.ts.map +0 -1
- package/dist/lib/state.js +0 -31
- package/dist/lib/state.js.map +0 -1
- package/dist/lib/types.d.ts +0 -17
- package/dist/lib/types.d.ts.map +0 -1
- package/dist/lib/types.js +0 -2
- package/dist/lib/types.js.map +0 -1
- package/dist/lib/ui.d.ts +0 -7
- package/dist/lib/ui.d.ts.map +0 -1
- package/dist/lib/ui.js +0 -124
- package/dist/lib/ui.js.map +0 -1
- package/dist/steps/configurePrisma.d.ts +0 -3
- package/dist/steps/configurePrisma.d.ts.map +0 -1
- package/dist/steps/configurePrisma.js +0 -41
- package/dist/steps/configurePrisma.js.map +0 -1
- package/dist/steps/createProject.d.ts +0 -5
- package/dist/steps/createProject.d.ts.map +0 -1
- package/dist/steps/createProject.js +0 -35
- package/dist/steps/createProject.js.map +0 -1
- package/dist/steps/finalSetup.d.ts +0 -7
- package/dist/steps/finalSetup.d.ts.map +0 -1
- package/dist/steps/finalSetup.js +0 -110
- package/dist/steps/finalSetup.js.map +0 -1
- package/dist/steps/installAuth.d.ts +0 -3
- package/dist/steps/installAuth.d.ts.map +0 -1
- package/dist/steps/installAuth.js +0 -18
- package/dist/steps/installAuth.js.map +0 -1
- package/dist/steps/installDeps.d.ts +0 -4
- package/dist/steps/installDeps.d.ts.map +0 -1
- package/dist/steps/installDeps.js +0 -50
- package/dist/steps/installDeps.js.map +0 -1
- package/dist/steps/prompts.d.ts +0 -3
- package/dist/steps/prompts.d.ts.map +0 -1
- package/dist/steps/prompts.js +0 -76
- package/dist/steps/prompts.js.map +0 -1
- package/dist/tests/helpers/generator.d.ts +0 -27
- package/dist/tests/helpers/generator.d.ts.map +0 -1
- package/dist/tests/helpers/generator.js +0 -282
- package/dist/tests/helpers/generator.js.map +0 -1
- package/dist/tests/integration/generator.test.d.ts +0 -2
- package/dist/tests/integration/generator.test.d.ts.map +0 -1
- package/dist/tests/integration/generator.test.js +0 -116
- package/dist/tests/integration/generator.test.js.map +0 -1
- package/dist/tests/integration/snapshot.test.d.ts +0 -2
- package/dist/tests/integration/snapshot.test.d.ts.map +0 -1
- package/dist/tests/integration/snapshot.test.js +0 -68
- package/dist/tests/integration/snapshot.test.js.map +0 -1
- package/dist/tests/setup.d.ts +0 -2
- package/dist/tests/setup.d.ts.map +0 -1
- package/dist/tests/setup.js +0 -10
- package/dist/tests/setup.js.map +0 -1
- package/dist/tests/unit/cli.test.d.ts +0 -2
- package/dist/tests/unit/cli.test.d.ts.map +0 -1
- package/dist/tests/unit/cli.test.js +0 -242
- package/dist/tests/unit/cli.test.js.map +0 -1
- package/dist/utils/hash.d.ts +0 -4
- package/dist/utils/hash.d.ts.map +0 -1
- package/dist/utils/hash.js +0 -51
- package/dist/utils/hash.js.map +0 -1
- package/dist/utils/output.d.ts +0 -3
- package/dist/utils/output.d.ts.map +0 -1
- package/dist/utils/output.js +0 -65
- package/dist/utils/output.js.map +0 -1
- package/dist/vitest.config.d.ts +0 -3
- package/dist/vitest.config.d.ts.map +0 -1
- package/dist/vitest.config.js +0 -21
- package/dist/vitest.config.js.map +0 -1
- package/templates/prisma/postgresql/.env +0 -3
- package/templates/prisma/sqlite/.env +0 -1
package/dist/bin/index.js
DELETED
|
@@ -1,796 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import fs from "fs-extra";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import chalk from "chalk";
|
|
5
|
-
import inquirer from "inquirer";
|
|
6
|
-
import { ExitPromptError } from "@inquirer/core";
|
|
7
|
-
import ora from "ora";
|
|
8
|
-
import { execSync, ChildProcess } from "child_process";
|
|
9
|
-
import { fileURLToPath } from "url";
|
|
10
|
-
import { spawnSync, spawn } from "child_process";
|
|
11
|
-
import os from "os";
|
|
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
|
-
};
|
|
81
|
-
const platform = os.platform();
|
|
82
|
-
// 'linux' | 'darwin' | 'win32'
|
|
83
|
-
const isTermux = process.env.PREFIX?.includes("com.termux") ||
|
|
84
|
-
process.env.TERMUX === "true";
|
|
85
|
-
function getBestHashLib() {
|
|
86
|
-
if (isTermux)
|
|
87
|
-
return "bcryptjs";
|
|
88
|
-
if (platform === "win32")
|
|
89
|
-
return "bcryptjs";
|
|
90
|
-
// avoids build tools issues for most users
|
|
91
|
-
if (platform === "darwin")
|
|
92
|
-
return "argon2";
|
|
93
|
-
// mac usually fine
|
|
94
|
-
if (platform === "linux")
|
|
95
|
-
return "argon2";
|
|
96
|
-
// but still fallback later if needed
|
|
97
|
-
return "bcryptjs";
|
|
98
|
-
}
|
|
99
|
-
function generateHashModule(hashLib) {
|
|
100
|
-
if (hashLib === "argon2") {
|
|
101
|
-
return `
|
|
102
|
-
import argon2 from "argon2";
|
|
103
|
-
|
|
104
|
-
export const hashPassword = (password: string) => {
|
|
105
|
-
return argon2.hash(password);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
export const comparePassword = (password: string, hash: string) => {
|
|
109
|
-
return argon2.verify(hash, password);
|
|
110
|
-
};
|
|
111
|
-
`;
|
|
112
|
-
}
|
|
113
|
-
return `
|
|
114
|
-
import bcrypt from "bcryptjs";
|
|
115
|
-
|
|
116
|
-
export const hashPassword = (password: string) => {
|
|
117
|
-
return bcrypt.hash(password, 10);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
export const comparePassword = (password: string, hash: string) => {
|
|
121
|
-
return bcrypt.compare(password, hash);
|
|
122
|
-
};
|
|
123
|
-
`;
|
|
124
|
-
}
|
|
125
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
126
|
-
const __dirname = path.dirname(__filename);
|
|
127
|
-
const isProduction = args.includes("--production-ready");
|
|
128
|
-
const isResume = args.includes("--resume");
|
|
129
|
-
const targetDir = path.resolve(process.cwd(), projectName);
|
|
130
|
-
let projectCreated = false;
|
|
131
|
-
const stepOrder = [
|
|
132
|
-
"start",
|
|
133
|
-
"prompts",
|
|
134
|
-
"project-created",
|
|
135
|
-
"auth-installed",
|
|
136
|
-
"prisma-configured",
|
|
137
|
-
"deps-installed",
|
|
138
|
-
"prisma-generated",
|
|
139
|
-
"production-configured",
|
|
140
|
-
"git-initialized",
|
|
141
|
-
"done",
|
|
142
|
-
];
|
|
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`);
|
|
157
|
-
function hasReachedStep(currentStep, targetStep) {
|
|
158
|
-
return stepOrder.indexOf(currentStep) >= stepOrder.indexOf(targetStep);
|
|
159
|
-
}
|
|
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 });
|
|
165
|
-
}
|
|
166
|
-
function loadState() {
|
|
167
|
-
if (!fs.existsSync(stateFile))
|
|
168
|
-
return null;
|
|
169
|
-
return fs.readJsonSync(stateFile);
|
|
170
|
-
}
|
|
171
|
-
function clearState() {
|
|
172
|
-
if (fs.existsSync(stateFile)) {
|
|
173
|
-
fs.removeSync(stateFile);
|
|
174
|
-
}
|
|
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
|
-
}
|
|
197
|
-
function isInterruptedError(err) {
|
|
198
|
-
return (typeof err === "object" &&
|
|
199
|
-
err !== null &&
|
|
200
|
-
"signal" in err &&
|
|
201
|
-
(err.signal === "SIGINT" ||
|
|
202
|
-
err.signal === "SIGTERM"));
|
|
203
|
-
}
|
|
204
|
-
async function exitForInterrupt(err) {
|
|
205
|
-
if (isInterruptedError(err)) {
|
|
206
|
-
throw err;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
async function cleanupIncompleteProject() {
|
|
210
|
-
if (projectCreated && fs.existsSync(targetDir)) {
|
|
211
|
-
await fs.remove(targetDir);
|
|
212
|
-
console.log("🧹 Cleaned up incomplete project.");
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
216
|
-
const cleanLogo = `
|
|
217
|
-
|
|
218
|
-
█████╗ █████╗
|
|
219
|
-
██╔══██╗ ██╔══██╗
|
|
220
|
-
███████║ ╚█████╔╝
|
|
221
|
-
██╔══██║ ██╔══██╗
|
|
222
|
-
██║ ██║ ╚█████╔╝
|
|
223
|
-
╚═╝ ╚═╝ ╚════╝
|
|
224
|
-
|
|
225
|
-
A8
|
|
226
|
-
|
|
227
|
-
Authenik8 CLI
|
|
228
|
-
Build Faster
|
|
229
|
-
More , Secure
|
|
230
|
-
`;
|
|
231
|
-
const glitchFrames = [
|
|
232
|
-
`
|
|
233
|
-
█████╗ █████╗
|
|
234
|
-
██╔══██╗ ██▒▒▒▒██
|
|
235
|
-
███████║ ╚█████╔╝
|
|
236
|
-
██╔══██║ ██▒▒▒▒██
|
|
237
|
-
██║ ██║ ╚█████╔╝
|
|
238
|
-
╚═╝ ╚═╝ ╚════╝
|
|
239
|
-
|
|
240
|
-
A8
|
|
241
|
-
Authenik8 CLI
|
|
242
|
-
|
|
243
|
-
More
|
|
244
|
-
`,
|
|
245
|
-
`
|
|
246
|
-
██▓▓██╗ ██▓▓██╗
|
|
247
|
-
██▒▒██╔╝ ██▒▒██╔╝
|
|
248
|
-
██▒▒▒▒██ ╚█████╔╝
|
|
249
|
-
██▓▓██╔╝ ██▒▒██╗
|
|
250
|
-
██▒▒██║ ╚█████╔╝
|
|
251
|
-
╚═════╝ ╚════╝
|
|
252
|
-
|
|
253
|
-
A8
|
|
254
|
-
Authenik8 CLI
|
|
255
|
-
Faster
|
|
256
|
-
`,
|
|
257
|
-
`
|
|
258
|
-
██▒▒██╗ ██▒▒██╗
|
|
259
|
-
██▓▓██╔╝ ██▓▓██╔╝
|
|
260
|
-
██▒▒▒▒██ ╚█████╔╝
|
|
261
|
-
██▓▓██╔╝ ██▓▓██╗
|
|
262
|
-
██▒▒██║ ╚█████╔╝
|
|
263
|
-
╚═════╝ ╚════╝
|
|
264
|
-
|
|
265
|
-
A8
|
|
266
|
-
Authenik8 CLI
|
|
267
|
-
Build
|
|
268
|
-
`,
|
|
269
|
-
`
|
|
270
|
-
██▓▓██╗ ██▓▓██╗
|
|
271
|
-
██▒▒██╔╝ ██▒▒██╔╝
|
|
272
|
-
██▒▒▒▒██ ╚█████╔╝
|
|
273
|
-
██▓▓██╔╝ ██▒▒██╗
|
|
274
|
-
██▒▒██║ ╚█████╔╝
|
|
275
|
-
╚═════╝ ╚════╝
|
|
276
|
-
|
|
277
|
-
A8
|
|
278
|
-
Authenik8 CLI
|
|
279
|
-
|
|
280
|
-
`
|
|
281
|
-
];
|
|
282
|
-
function renderHeader() {
|
|
283
|
-
console.log(chalk.cyan.bold("Happy building \nAuthenik8 CLI"));
|
|
284
|
-
console.log(chalk.gray("────────────────────"));
|
|
285
|
-
console.log("");
|
|
286
|
-
}
|
|
287
|
-
async function showBootLogo() {
|
|
288
|
-
console.clear();
|
|
289
|
-
spinner.text = "Initializing Authenik8 engine...";
|
|
290
|
-
// Phase 1: clean → unstable
|
|
291
|
-
console.clear();
|
|
292
|
-
console.log(chalk.cyan(cleanLogo));
|
|
293
|
-
await sleep(200);
|
|
294
|
-
// Phase 2: glitch burst (irregular feel)
|
|
295
|
-
for (let i = 0; i < 5; i++) {
|
|
296
|
-
console.clear();
|
|
297
|
-
const frame = glitchFrames[Math.floor(Math.random() * glitchFrames.length)];
|
|
298
|
-
console.log(chalk.cyan(frame));
|
|
299
|
-
await sleep(120 + Math.random() * 120);
|
|
300
|
-
}
|
|
301
|
-
// Phase 3: stabilization flicker
|
|
302
|
-
for (let i = 0; i < 2; i++) {
|
|
303
|
-
console.clear();
|
|
304
|
-
console.log(chalk.cyan(cleanLogo));
|
|
305
|
-
await sleep(180);
|
|
306
|
-
console.clear();
|
|
307
|
-
console.log(chalk.gray(cleanLogo));
|
|
308
|
-
await sleep(120);
|
|
309
|
-
}
|
|
310
|
-
// Final render
|
|
311
|
-
console.clear();
|
|
312
|
-
console.log(chalk.cyan.bold(cleanLogo));
|
|
313
|
-
await sleep(800);
|
|
314
|
-
spinner.succeed("Engine ready");
|
|
315
|
-
}
|
|
316
|
-
async function main() {
|
|
317
|
-
process.on("SIGINT", async () => {
|
|
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`));
|
|
323
|
-
process.exit(0);
|
|
324
|
-
});
|
|
325
|
-
try {
|
|
326
|
-
await showBootLogo();
|
|
327
|
-
if (process.argv.includes("--help")) {
|
|
328
|
-
console.log(`
|
|
329
|
-
Authenik8 CLI
|
|
330
|
-
|
|
331
|
-
Usage:
|
|
332
|
-
create-authenik8-app <project-name>
|
|
333
|
-
|
|
334
|
-
Options:
|
|
335
|
-
--resume Resume project setup(in development)
|
|
336
|
-
--help Show this help message
|
|
337
|
-
--production-ready production mode
|
|
338
|
-
Features:
|
|
339
|
-
|
|
340
|
-
Express backend (default)
|
|
341
|
-
|
|
342
|
-
Optional Prisma ORM
|
|
343
|
-
|
|
344
|
-
PostgreSQL (production)
|
|
345
|
-
|
|
346
|
-
SQLite (quick start)
|
|
347
|
-
|
|
348
|
-
Optional Git initialization
|
|
349
|
-
|
|
350
|
-
Optional OAuth
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
Examples:
|
|
354
|
-
create-authenik8-app my-app
|
|
355
|
-
`);
|
|
356
|
-
process.exit(0);
|
|
357
|
-
}
|
|
358
|
-
console.log(chalk.gray(`
|
|
359
|
-
Available options:
|
|
360
|
-
Authentication setup:
|
|
361
|
-
• base (JWT only)
|
|
362
|
-
• auth (JWT + Password/Email auth)
|
|
363
|
-
• auth-oauth(JWT+ Password/Email + oauth)
|
|
364
|
-
|
|
365
|
-
Frameworks:
|
|
366
|
-
• Express
|
|
367
|
-
• Fastify(coming soon)
|
|
368
|
-
|
|
369
|
-
Database (if Prisma enabled):
|
|
370
|
-
• PostgreSQL
|
|
371
|
-
• SQLite (quick start)
|
|
372
|
-
|
|
373
|
-
Features:
|
|
374
|
-
• Prisma ORM (optional)
|
|
375
|
-
• Git initialization (optional)
|
|
376
|
-
• OAuth + Auth
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
`));
|
|
380
|
-
const savedState = loadState();
|
|
381
|
-
let currentStep = "start";
|
|
382
|
-
if (!isResume && fs.existsSync(targetDir)) {
|
|
383
|
-
if (savedState) {
|
|
384
|
-
console.log(chalk.red(`❌ "${projectName}" already contains an incomplete Authenik8 setup. Run again with --resume.`));
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
console.log(chalk.red(`❌ Directory "${projectName}" already exists.`));
|
|
388
|
-
}
|
|
389
|
-
process.exit(1);
|
|
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
|
-
}
|
|
402
|
-
if (isResume) {
|
|
403
|
-
if (!savedState) {
|
|
404
|
-
console.log(chalk.red(`❌ No saved setup state found for "${projectName}".`));
|
|
405
|
-
process.exit(1);
|
|
406
|
-
}
|
|
407
|
-
state = savedState;
|
|
408
|
-
currentStep = state.step;
|
|
409
|
-
console.log(chalk.yellow(`\n↻ Resuming setup for ${projectName} from "${currentStep}"...\n`));
|
|
410
|
-
}
|
|
411
|
-
else {
|
|
412
|
-
const promptAnswers = await inquirer.prompt([
|
|
413
|
-
{
|
|
414
|
-
type: "list",
|
|
415
|
-
name: "framework",
|
|
416
|
-
message: "Choose framework:",
|
|
417
|
-
choices: ["Express", "Fastify (coming soon)"],
|
|
418
|
-
default: "Express",
|
|
419
|
-
},
|
|
420
|
-
{
|
|
421
|
-
type: "confirm",
|
|
422
|
-
name: "usePrisma",
|
|
423
|
-
message: "Use Prisma?",
|
|
424
|
-
default: true,
|
|
425
|
-
},
|
|
426
|
-
{
|
|
427
|
-
type: "list",
|
|
428
|
-
name: "database",
|
|
429
|
-
message: "Choose database:",
|
|
430
|
-
choices: [
|
|
431
|
-
{ name: "PostgreSQL", value: "postgresql" },
|
|
432
|
-
{ name: "SQLite ", value: "sqlite" }
|
|
433
|
-
],
|
|
434
|
-
when: (answers) => answers.usePrisma,
|
|
435
|
-
default: "sqlite",
|
|
436
|
-
},
|
|
437
|
-
{
|
|
438
|
-
type: "confirm",
|
|
439
|
-
name: "useGit",
|
|
440
|
-
message: "Initialize git?",
|
|
441
|
-
default: true,
|
|
442
|
-
}, {
|
|
443
|
-
type: "list",
|
|
444
|
-
name: "authMode",
|
|
445
|
-
message: "Choose authentication setup:",
|
|
446
|
-
choices: [
|
|
447
|
-
{ name: "JWT only", value: "base" },
|
|
448
|
-
{ name: "Email + Password Auth", value: "auth" },
|
|
449
|
-
{ name: "Full Auth (Password + OAuth)", value: "auth-oauth" },
|
|
450
|
-
],
|
|
451
|
-
default: "base"
|
|
452
|
-
}
|
|
453
|
-
]);
|
|
454
|
-
//saveState({
|
|
455
|
-
//...promptAnswers,
|
|
456
|
-
//step:"prompts"});
|
|
457
|
-
state = {
|
|
458
|
-
...state,
|
|
459
|
-
...promptAnswers,
|
|
460
|
-
step: "prompts"
|
|
461
|
-
};
|
|
462
|
-
saveState({
|
|
463
|
-
...state
|
|
464
|
-
});
|
|
465
|
-
currentStep = "prompts";
|
|
466
|
-
}
|
|
467
|
-
function assertRequired(value, name) {
|
|
468
|
-
if (value === undefined || value === null || value === "") {
|
|
469
|
-
console.log(`❌ Missing required input: ${name}`);
|
|
470
|
-
process.exit(1);
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
assertRequired(state.framework, "framework");
|
|
474
|
-
assertRequired(state.authMode, "authMode");
|
|
475
|
-
if (state.usePrisma) {
|
|
476
|
-
if (!state.database) {
|
|
477
|
-
state.database = "sqlite";
|
|
478
|
-
}
|
|
479
|
-
assertRequired(state.database, "database");
|
|
480
|
-
}
|
|
481
|
-
console.log(chalk.cyan("\nSetting up your project\n"));
|
|
482
|
-
const templateRoot = path.resolve(__dirname, "../../templates");
|
|
483
|
-
let templateName = "express-base";
|
|
484
|
-
if (state.authMode === "auth") {
|
|
485
|
-
templateName = "express-auth";
|
|
486
|
-
}
|
|
487
|
-
if (state.authMode === "auth-oauth") {
|
|
488
|
-
templateName = "express-auth+";
|
|
489
|
-
}
|
|
490
|
-
const templatePath = path.join(templateRoot, templateName);
|
|
491
|
-
// 📁 Create project (SPINNER)
|
|
492
|
-
if (!hasReachedStep(currentStep, "project-created")) {
|
|
493
|
-
renderStep("project-created");
|
|
494
|
-
try {
|
|
495
|
-
await fs.copy(templatePath, targetDir);
|
|
496
|
-
projectCreated = true;
|
|
497
|
-
saveState({ step: "project-created" });
|
|
498
|
-
currentStep = "project-created";
|
|
499
|
-
renderStep(currentStep);
|
|
500
|
-
}
|
|
501
|
-
catch (err) {
|
|
502
|
-
console.error(err);
|
|
503
|
-
process.exit(1);
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
else {
|
|
507
|
-
console.log(chalk.gray("↷ Skipping project creation (already completed)"));
|
|
508
|
-
}
|
|
509
|
-
let selectedHash = "bcryptjs"; // default safe fallback
|
|
510
|
-
if (!hasReachedStep(currentStep, "auth-installed")) {
|
|
511
|
-
if (state.authMode !== "base") {
|
|
512
|
-
spinner.start("Installing password auth...");
|
|
513
|
-
selectedHash = getBestHashLib();
|
|
514
|
-
try {
|
|
515
|
-
const installResult = await run(getCommand("npm"), ["install", selectedHash], {
|
|
516
|
-
cwd: targetDir,
|
|
517
|
-
stdio: "ignore"
|
|
518
|
-
});
|
|
519
|
-
}
|
|
520
|
-
catch {
|
|
521
|
-
if (selectedHash !== "bcryptjs") {
|
|
522
|
-
spinner.warn(`${selectedHash} failed, falling back to bcryptjs`);
|
|
523
|
-
const fallbackResult = await run(getCommand("npm"), ["install", "bcryptjs"], {
|
|
524
|
-
cwd: targetDir,
|
|
525
|
-
stdio: "ignore",
|
|
526
|
-
});
|
|
527
|
-
spinner.stop();
|
|
528
|
-
selectedHash = "bcryptjs";
|
|
529
|
-
renderStep("auth-installed");
|
|
530
|
-
}
|
|
531
|
-
else {
|
|
532
|
-
spinner.fail("Failed to install password auth");
|
|
533
|
-
process.exit(1);
|
|
534
|
-
spinner.fail("Failed to install password auth");
|
|
535
|
-
process.exit(1);
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
renderStep("auth-installed");
|
|
540
|
-
if (state.authMode !== "base") {
|
|
541
|
-
spinner.start("Installing password auth...");
|
|
542
|
-
const hashLib = selectedHash;
|
|
543
|
-
await fs.writeFile(path.join(targetDir, "src/utils/hash.ts"), generateHashModule(hashLib));
|
|
544
|
-
}
|
|
545
|
-
saveState({ step: "auth-installed", ...(state.authMode !== "base" && { hashLib: selectedHash })
|
|
546
|
-
});
|
|
547
|
-
currentStep = "auth-installed";
|
|
548
|
-
renderStep(currentStep);
|
|
549
|
-
}
|
|
550
|
-
else {
|
|
551
|
-
selectedHash = savedState?.hashLib ?? selectedHash;
|
|
552
|
-
console.log(chalk.gray("↷ Skipping auth setup (already completed)"));
|
|
553
|
-
}
|
|
554
|
-
if (!hasReachedStep(currentStep, "prisma-configured")) {
|
|
555
|
-
const pkgPath = path.join(targetDir, "package.json");
|
|
556
|
-
const pkg = await fs.readJson(pkgPath);
|
|
557
|
-
pkg.dependencies = {
|
|
558
|
-
...pkg.dependencies,
|
|
559
|
-
ioredis: "^5.8.1",
|
|
560
|
-
};
|
|
561
|
-
if (state.usePrisma) {
|
|
562
|
-
spinner.start("Adding Prisma setup...");
|
|
563
|
-
try {
|
|
564
|
-
const dbType = state.database ===
|
|
565
|
-
"postgresql" ? "postgresql" :
|
|
566
|
-
"sqlite";
|
|
567
|
-
const prismaTemplatePath = path.join(templateRoot, `prisma/${dbType}`);
|
|
568
|
-
// Copy prisma schema
|
|
569
|
-
await fs.copy(path.join(prismaTemplatePath, "schema.prisma"), path.join(targetDir, "prisma/schema.prisma"));
|
|
570
|
-
// Copy env
|
|
571
|
-
await fs.copy(path.join(prismaTemplatePath, ".env"), path.join(targetDir, ".env"));
|
|
572
|
-
// Inject dependencies
|
|
573
|
-
pkg.dependencies = {
|
|
574
|
-
...pkg.dependencies,
|
|
575
|
-
"@prisma/client": "5.22.0",
|
|
576
|
-
};
|
|
577
|
-
pkg.devDependencies = {
|
|
578
|
-
...pkg.devDependencies,
|
|
579
|
-
prisma: "5.22.0",
|
|
580
|
-
};
|
|
581
|
-
// Add scripts
|
|
582
|
-
pkg.scripts = {
|
|
583
|
-
...pkg.scripts,
|
|
584
|
-
"prisma:generate": "prisma generate",
|
|
585
|
-
"prisma:migrate": "prisma migrate dev",
|
|
586
|
-
};
|
|
587
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
588
|
-
spinner.succeed(`Prisma (${dbType}) configured`);
|
|
589
|
-
}
|
|
590
|
-
catch (err) {
|
|
591
|
-
spinner.fail("Failed to setup Prisma");
|
|
592
|
-
exitForInterrupt(err);
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
596
|
-
saveState({ step: "prisma-configured", ...(state.authMode !== "base" && { hashLib: selectedHash })
|
|
597
|
-
});
|
|
598
|
-
currentStep = "prisma-configured";
|
|
599
|
-
renderStep(currentStep);
|
|
600
|
-
}
|
|
601
|
-
else {
|
|
602
|
-
console.log(chalk.gray(" Skipping Prisma/package setup (already completed)"));
|
|
603
|
-
}
|
|
604
|
-
if (!hasReachedStep(currentStep, "deps-installed")) {
|
|
605
|
-
renderStep("deps-installed");
|
|
606
|
-
spinner.start("Installing dependencies...(this may take a few minutes)");
|
|
607
|
-
try {
|
|
608
|
-
await run(getCommand("npm"), ["install"], {
|
|
609
|
-
cwd: targetDir,
|
|
610
|
-
stdio: "ignore",
|
|
611
|
-
});
|
|
612
|
-
spinner.stop();
|
|
613
|
-
}
|
|
614
|
-
catch (err) {
|
|
615
|
-
spinner.fail("Failed to install dependencies");
|
|
616
|
-
exitForInterrupt(err);
|
|
617
|
-
}
|
|
618
|
-
saveState({ step: "deps-installed", ...(state.authMode !== "base" && { hashLib: selectedHash })
|
|
619
|
-
});
|
|
620
|
-
currentStep = "deps-installed";
|
|
621
|
-
renderStep(currentStep);
|
|
622
|
-
}
|
|
623
|
-
else {
|
|
624
|
-
await run(getCommand("npm"), ["install"], {
|
|
625
|
-
cwd: targetDir,
|
|
626
|
-
stdio: "ignore",
|
|
627
|
-
});
|
|
628
|
-
}
|
|
629
|
-
if (!hasReachedStep(currentStep, "prisma-generated")) {
|
|
630
|
-
if (state.usePrisma) {
|
|
631
|
-
spinner.start("Generating Prisma client...");
|
|
632
|
-
try {
|
|
633
|
-
await run(getCommand("npx"), ["prisma@5.22.0", "generate"], {
|
|
634
|
-
cwd: targetDir,
|
|
635
|
-
stdio: "ignore"
|
|
636
|
-
});
|
|
637
|
-
spinner.stop();
|
|
638
|
-
}
|
|
639
|
-
catch (err) {
|
|
640
|
-
spinner.fail("Failed to generate Prisma client");
|
|
641
|
-
exitForInterrupt(err);
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
saveState({ step: "prisma-generated", ...(state.authMode !== "base" && { hashLib: selectedHash })
|
|
645
|
-
});
|
|
646
|
-
currentStep = "prisma-generated";
|
|
647
|
-
renderStep(currentStep);
|
|
648
|
-
}
|
|
649
|
-
else {
|
|
650
|
-
console.log(chalk.gray("↷ Skipping Prisma client generation (already completed)"));
|
|
651
|
-
}
|
|
652
|
-
if (isProduction && !hasReachedStep(currentStep, "production-configured")) {
|
|
653
|
-
spinner.start("Setting up production mode (PM2)...");
|
|
654
|
-
try {
|
|
655
|
-
await run(getCommand("npm"), ["install pm2"], {
|
|
656
|
-
cwd: targetDir,
|
|
657
|
-
stdio: "ignore",
|
|
658
|
-
});
|
|
659
|
-
spinner.stop();
|
|
660
|
-
}
|
|
661
|
-
catch (err) {
|
|
662
|
-
spinner.fail("Failed to install PM2");
|
|
663
|
-
exitForInterrupt(err);
|
|
664
|
-
}
|
|
665
|
-
saveState({ step: "production-configured", ...(state.authMode !== "base" && { hashLib: selectedHash })
|
|
666
|
-
});
|
|
667
|
-
currentStep = "production-configured";
|
|
668
|
-
renderStep(currentStep);
|
|
669
|
-
}
|
|
670
|
-
if (!hasReachedStep(currentStep, "git-initialized")) {
|
|
671
|
-
if (state.useGit) {
|
|
672
|
-
renderStep("git-initialized");
|
|
673
|
-
try {
|
|
674
|
-
await run(getCommand("git"), ["init"], {
|
|
675
|
-
cwd: targetDir,
|
|
676
|
-
stdio: "ignore",
|
|
677
|
-
});
|
|
678
|
-
spinner.stop();
|
|
679
|
-
}
|
|
680
|
-
catch (err) {
|
|
681
|
-
spinner.fail("Git init failed");
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
saveState({ step: "git-initialized", ...(state.authMode !== "base" && { hashLib: selectedHash }),
|
|
685
|
-
});
|
|
686
|
-
currentStep = "git-initialized";
|
|
687
|
-
renderStep("done");
|
|
688
|
-
}
|
|
689
|
-
else {
|
|
690
|
-
console.log(chalk.gray("↷ Skipping git init (already completed)"));
|
|
691
|
-
}
|
|
692
|
-
console.log(chalk.green.bold("\n🎉 Authenik8 app created successfully!\n"));
|
|
693
|
-
if (isProduction) {
|
|
694
|
-
fs.appendFileSync(path.join(targetDir, "README.md"), `
|
|
695
|
-
|
|
696
|
-
🚀 Production Mode
|
|
697
|
-
|
|
698
|
-
This project is configured for production using PM2.
|
|
699
|
-
|
|
700
|
-
Start app in cluster mode:
|
|
701
|
-
|
|
702
|
-
npm run pm2:start
|
|
703
|
-
|
|
704
|
-
View logs:
|
|
705
|
-
|
|
706
|
-
npm run pm2:logs
|
|
707
|
-
|
|
708
|
-
Stop app:
|
|
709
|
-
|
|
710
|
-
npm run pm2:stop
|
|
711
|
-
|
|
712
|
-
`);
|
|
713
|
-
}
|
|
714
|
-
console.log(chalk.white(`
|
|
715
|
-
Next steps:
|
|
716
|
-
|
|
717
|
-
cd ${projectName}
|
|
718
|
-
redis-server --daemonize yes
|
|
719
|
-
npm run dev
|
|
720
|
-
|
|
721
|
-
Auth Features:
|
|
722
|
-
${state.authMode === "base"
|
|
723
|
-
? "✓ JWT only"
|
|
724
|
-
: state.authMode === "auth"
|
|
725
|
-
? "✓ Email + Password"
|
|
726
|
-
: "✓ Password + OAuth (Google/GitHub)"}
|
|
727
|
-
|
|
728
|
-
🛠 Stack:
|
|
729
|
-
✔ Express
|
|
730
|
-
✔ ${state.usePrisma ? (state.database === "postgresql" ? "PostgreSQL" : "SQLite") : "No database"}
|
|
731
|
-
✔ ${state.usePrisma ? "Prisma ORM" : "No ORM"}
|
|
732
|
-
|
|
733
|
-
📡 API Routes:
|
|
734
|
-
${state.authMode === "base"
|
|
735
|
-
? `
|
|
736
|
-
GET /public
|
|
737
|
-
GET /guest
|
|
738
|
-
GET /protected
|
|
739
|
-
POST /refresh
|
|
740
|
-
`
|
|
741
|
-
: state.authMode === "auth"
|
|
742
|
-
? `
|
|
743
|
-
POST /auth/register
|
|
744
|
-
POST /auth/login
|
|
745
|
-
POST /auth/refresh
|
|
746
|
-
GET /protected
|
|
747
|
-
`
|
|
748
|
-
: `
|
|
749
|
-
POST /auth/register
|
|
750
|
-
POST /auth/login
|
|
751
|
-
POST /auth/refresh
|
|
752
|
-
GET /auth/google
|
|
753
|
-
GET /auth/github
|
|
754
|
-
GET /protected
|
|
755
|
-
`}
|
|
756
|
-
|
|
757
|
-
🔥 You're ready to build.
|
|
758
|
-
`));
|
|
759
|
-
if (isProduction) {
|
|
760
|
-
console.log(`
|
|
761
|
-
🚀 Production Ready Enabled:
|
|
762
|
-
|
|
763
|
-
✔ PM2 installed
|
|
764
|
-
✔ Cluster mode enabled
|
|
765
|
-
✔ Memory auto-restart (300MB)
|
|
766
|
-
|
|
767
|
-
Run:
|
|
768
|
-
npm run pm2:start
|
|
769
|
-
`);
|
|
770
|
-
}
|
|
771
|
-
saveState({ step: "done", ...(state.authMode !== "base" && { hashLib: selectedHash }),
|
|
772
|
-
});
|
|
773
|
-
clearState();
|
|
774
|
-
}
|
|
775
|
-
catch (err) {
|
|
776
|
-
if (err instanceof ExitPromptError) {
|
|
777
|
-
throw err;
|
|
778
|
-
console.error("Fatal error", err);
|
|
779
|
-
process.exit(1);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
main().catch(async (err) => {
|
|
784
|
-
if (err instanceof ExitPromptError) {
|
|
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 "));
|
|
789
|
-
await cleanupIncompleteProject();
|
|
790
|
-
process.exit(0);
|
|
791
|
-
}
|
|
792
|
-
console.error(chalk.red("\n❌ Unexpected error:"), err);
|
|
793
|
-
await cleanupIncompleteProject();
|
|
794
|
-
process.exit(1);
|
|
795
|
-
});
|
|
796
|
-
//# sourceMappingURL=index.js.map
|