create-authenik8-app 2.4.6 → 2.4.8
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/dist/src/bin/index.d.ts +3 -0
- package/dist/src/bin/index.d.ts.map +1 -0
- package/dist/src/bin/index.js +275 -0
- package/dist/src/bin/index.js.map +1 -0
- package/dist/src/lib/constants.d.ts +4 -0
- package/dist/src/lib/constants.d.ts.map +1 -0
- package/dist/src/lib/constants.js +25 -0
- package/dist/src/lib/constants.js.map +1 -0
- package/dist/src/lib/process.d.ts +7 -0
- package/dist/src/lib/process.d.ts.map +1 -0
- package/dist/src/lib/process.js +60 -0
- package/dist/src/lib/process.js.map +1 -0
- package/dist/src/lib/state.d.ts +8 -0
- package/dist/src/lib/state.d.ts.map +1 -0
- package/dist/src/lib/state.js +31 -0
- package/dist/src/lib/state.js.map +1 -0
- package/dist/src/lib/types.d.ts +19 -0
- package/dist/src/lib/types.d.ts.map +1 -0
- package/dist/src/lib/types.js +2 -0
- package/dist/src/lib/types.js.map +1 -0
- package/dist/src/lib/ui.d.ts +7 -0
- package/dist/src/lib/ui.d.ts.map +1 -0
- package/dist/src/lib/ui.js +124 -0
- package/dist/src/lib/ui.js.map +1 -0
- package/dist/src/steps/configurePrisma.d.ts +3 -0
- package/dist/src/steps/configurePrisma.d.ts.map +1 -0
- package/dist/src/steps/configurePrisma.js +62 -0
- package/dist/src/steps/configurePrisma.js.map +1 -0
- package/dist/src/steps/createProject.d.ts +5 -0
- package/dist/src/steps/createProject.d.ts.map +1 -0
- package/dist/src/steps/createProject.js +202 -0
- package/dist/src/steps/createProject.js.map +1 -0
- package/dist/src/steps/finalSetup.d.ts +7 -0
- package/dist/src/steps/finalSetup.d.ts.map +1 -0
- package/dist/src/steps/finalSetup.js +110 -0
- package/dist/src/steps/finalSetup.js.map +1 -0
- package/dist/src/steps/installAuth.d.ts +3 -0
- package/dist/src/steps/installAuth.d.ts.map +1 -0
- package/dist/src/steps/installAuth.js +16 -0
- package/dist/src/steps/installAuth.js.map +1 -0
- package/dist/src/steps/installDeps.d.ts +5 -0
- package/dist/src/steps/installDeps.d.ts.map +1 -0
- package/dist/src/steps/installDeps.js +99 -0
- package/dist/src/steps/installDeps.js.map +1 -0
- package/dist/src/steps/prompts.d.ts +3 -0
- package/dist/src/steps/prompts.d.ts.map +1 -0
- package/dist/src/steps/prompts.js +93 -0
- package/dist/src/steps/prompts.js.map +1 -0
- package/dist/src/tests/templated-routes.test.d.ts +2 -0
- package/dist/src/tests/templated-routes.test.d.ts.map +1 -0
- package/dist/src/tests/templated-routes.test.js +325 -0
- package/dist/src/tests/templated-routes.test.js.map +1 -0
- package/dist/src/utils/hash.d.ts +4 -0
- package/dist/src/utils/hash.d.ts.map +1 -0
- package/dist/src/utils/hash.js +17 -0
- package/dist/src/utils/hash.js.map +1 -0
- package/dist/src/utils/output.d.ts +3 -0
- package/dist/src/utils/output.d.ts.map +1 -0
- package/dist/src/utils/output.js +81 -0
- package/dist/src/utils/output.js.map +1 -0
- package/dist/templates/THREAT_MODEL.md +138 -0
- package/dist/templates/express-auth/src/controllers/protected.controller.d.ts +8 -0
- package/dist/templates/express-auth/src/controllers/protected.controller.d.ts.map +1 -0
- package/dist/templates/express-auth/src/controllers/protected.controller.js +50 -0
- package/dist/templates/express-auth/src/controllers/protected.controller.js.map +1 -0
- package/dist/templates/express-auth/src/routes/protected.routes.d.ts +2 -0
- package/dist/templates/express-auth/src/routes/protected.routes.d.ts.map +1 -0
- package/dist/templates/express-auth/src/routes/protected.routes.js +16 -0
- package/dist/templates/express-auth/src/routes/protected.routes.js.map +1 -0
- package/dist/templates/express-auth/src/utils/security.d.ts +8 -0
- package/dist/templates/express-auth/src/utils/security.d.ts.map +1 -0
- package/dist/templates/express-auth/src/utils/security.js +55 -0
- package/dist/templates/express-auth/src/utils/security.js.map +1 -0
- package/dist/templates/express-base/controllers/base.controller.d.ts +12 -0
- package/dist/templates/express-base/controllers/base.controller.d.ts.map +1 -0
- package/dist/templates/express-base/controllers/base.controller.js +77 -0
- package/dist/templates/express-base/controllers/base.controller.js.map +1 -0
- package/dist/templates/express-base/routes/base.routes.d.ts +2 -0
- package/dist/templates/express-base/routes/base.routes.d.ts.map +1 -0
- package/dist/templates/express-base/routes/base.routes.js +20 -0
- package/dist/templates/express-base/routes/base.routes.js.map +1 -0
- package/dist/templates/express-base/utils/security.d.ts +5 -0
- package/dist/templates/express-base/utils/security.d.ts.map +1 -0
- package/dist/templates/express-base/utils/security.js +40 -0
- package/dist/templates/express-base/utils/security.js.map +1 -0
- package/dist/templates/package.json +27 -0
- package/package.json +4 -3
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { spinner } from "../lib/ui.js";
|
|
4
|
+
import { exitForInterrupt } from "../lib/process.js";
|
|
5
|
+
export async function configurePrisma(state, targetDir, templateRoot) {
|
|
6
|
+
const pkgPath = path.join(targetDir, "package.json");
|
|
7
|
+
const pkg = await fs.readJson(pkgPath);
|
|
8
|
+
pkg.dependencies = {
|
|
9
|
+
...pkg.dependencies,
|
|
10
|
+
ioredis: "^5.8.1",
|
|
11
|
+
// redis-server:"^1.2.2",
|
|
12
|
+
};
|
|
13
|
+
if (state.usePrisma) {
|
|
14
|
+
spinner.start("Adding Prisma setup...");
|
|
15
|
+
try {
|
|
16
|
+
const dbType = state.database === "postgresql" ? "postgresql" : "sqlite";
|
|
17
|
+
const prismaTemplatePath = path.join(templateRoot, `prisma/${dbType}`);
|
|
18
|
+
await fs.copy(path.join(prismaTemplatePath, "schema.prisma"), path.join(targetDir, "prisma/schema.prisma"));
|
|
19
|
+
await fs.copy(path.join(prismaTemplatePath, ".env.example"), path.join(targetDir, ".env"));
|
|
20
|
+
const providers = state.authMode === "auth-oauth"
|
|
21
|
+
? (state.oauthProviders?.length ? state.oauthProviders : ["google", "github"])
|
|
22
|
+
: [];
|
|
23
|
+
const envPath = path.join(targetDir, ".env");
|
|
24
|
+
if (providers.length > 0) {
|
|
25
|
+
const env = await fs.readFile(envPath, "utf-8");
|
|
26
|
+
const providerPrefixes = new Set(providers.map((provider) => provider.toUpperCase()));
|
|
27
|
+
const filteredEnv = env
|
|
28
|
+
.split("\n")
|
|
29
|
+
.filter((line) => {
|
|
30
|
+
if (line.startsWith("GOOGLE_") || line.startsWith("GITHUB_")) {
|
|
31
|
+
const prefix = line.split("_")[0] ?? "";
|
|
32
|
+
return providerPrefixes.has(prefix);
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
})
|
|
36
|
+
.join("\n")
|
|
37
|
+
.replace(/\n*$/, "\n");
|
|
38
|
+
await fs.writeFile(envPath, `${filteredEnv}AUTHENIK8_OAUTH_PROVIDERS="${providers.join(",")}"\n`);
|
|
39
|
+
}
|
|
40
|
+
pkg.dependencies = {
|
|
41
|
+
...pkg.dependencies,
|
|
42
|
+
"@prisma/client": "5.22.0",
|
|
43
|
+
};
|
|
44
|
+
pkg.devDependencies = {
|
|
45
|
+
...pkg.devDependencies,
|
|
46
|
+
prisma: "5.22.0",
|
|
47
|
+
};
|
|
48
|
+
pkg.scripts = {
|
|
49
|
+
...pkg.scripts,
|
|
50
|
+
"prisma:generate": "prisma generate",
|
|
51
|
+
"prisma:migrate": "prisma migrate dev",
|
|
52
|
+
};
|
|
53
|
+
spinner.succeed(`Prisma (${dbType}) configured`);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
spinner.fail("Failed to setup Prisma");
|
|
57
|
+
exitForInterrupt(err);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=configurePrisma.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configurePrisma.js","sourceRoot":"","sources":["../../../src/steps/configurePrisma.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CliState } from "../lib/types.js";
|
|
2
|
+
export declare function resolveTemplateName(authMode: string): string;
|
|
3
|
+
export declare function configurePackageJson(targetDir: string, usePrisma: boolean): void;
|
|
4
|
+
export declare function createProject(state: CliState, targetDir: string, templateRoot: string): Promise<void>;
|
|
5
|
+
//# sourceMappingURL=createProject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createProject.d.ts","sourceRoot":"","sources":["../../../src/steps/createProject.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAKhD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI5D;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAgBhF;AAmMD,wBAAsB,aAAa,CACjC,KAAK,EAAE,QAAQ,EACf,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
const supportedOAuthProviders = ["google", "github"];
|
|
4
|
+
export function resolveTemplateName(authMode) {
|
|
5
|
+
if (authMode === "auth")
|
|
6
|
+
return "express-auth";
|
|
7
|
+
if (authMode === "auth-oauth")
|
|
8
|
+
return "express-auth+";
|
|
9
|
+
return "express-base";
|
|
10
|
+
}
|
|
11
|
+
export function configurePackageJson(targetDir, usePrisma) {
|
|
12
|
+
const pkgPath = path.join(targetDir, "package.json");
|
|
13
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
14
|
+
if (!pkg.scripts.postinstall?.includes("prisma")) {
|
|
15
|
+
pkg.scripts.postinstall = "npx prisma@5.22.0 generate";
|
|
16
|
+
}
|
|
17
|
+
if (usePrisma) {
|
|
18
|
+
const currentDev = pkg.scripts.dev || "tsx watch src/index.ts";
|
|
19
|
+
if (!currentDev.includes("prisma@5.22.0 generate")) {
|
|
20
|
+
pkg.scripts.dev = `npx prisma@5.22.0 generate && ${currentDev}`;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
24
|
+
}
|
|
25
|
+
function resolveOAuthProviders(state) {
|
|
26
|
+
const selected = state.oauthProviders?.filter((provider) => supportedOAuthProviders.includes(provider));
|
|
27
|
+
return selected?.length ? selected : ["google", "github"];
|
|
28
|
+
}
|
|
29
|
+
function providerTitle(provider) {
|
|
30
|
+
return provider === "github" ? "GitHub" : "Google";
|
|
31
|
+
}
|
|
32
|
+
function providerEnvBlock(provider) {
|
|
33
|
+
const upper = provider.toUpperCase();
|
|
34
|
+
return `${provider}: {
|
|
35
|
+
clientId: requiredEnv("${upper}_CLIENT_ID"),
|
|
36
|
+
clientSecret: requiredEnv("${upper}_CLIENT_SECRET"),
|
|
37
|
+
redirectUri: requiredEnv("${upper}_REDIRECT_URI"),
|
|
38
|
+
},`;
|
|
39
|
+
}
|
|
40
|
+
function providerControllerBlock(provider) {
|
|
41
|
+
return `${provider}Redirect(req: Request, res: Response) {
|
|
42
|
+
requireProvider("${provider}", res)?.redirect(req, res);
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
async ${provider}Callback(req: Request, res: Response) {
|
|
46
|
+
const provider = requireProvider("${provider}", res);
|
|
47
|
+
if (!provider) return;
|
|
48
|
+
|
|
49
|
+
const result = await provider.handleCallback(req);
|
|
50
|
+
|
|
51
|
+
res.json({
|
|
52
|
+
provider: "${provider}",
|
|
53
|
+
...result,
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
${provider}Link(req: Request, res: Response) {
|
|
58
|
+
requireProvider("${provider}", res)?.redirect(req, res, "link");
|
|
59
|
+
},`;
|
|
60
|
+
}
|
|
61
|
+
function providerRoutesBlock(provider) {
|
|
62
|
+
return `router.get("/${provider}", oauthController.${provider}Redirect);
|
|
63
|
+
router.get("/${provider}/callback", oauthController.${provider}Callback);
|
|
64
|
+
router.get("/${provider}/link", authMiddleware, oauthController.${provider}Link);`;
|
|
65
|
+
}
|
|
66
|
+
async function writeProviderSpecificOAuthFiles(targetDir, providers) {
|
|
67
|
+
const authPath = path.join(targetDir, "src/auth/auth.ts");
|
|
68
|
+
const routesPath = path.join(targetDir, "src/auth/routes/oauth.routes.ts");
|
|
69
|
+
const controllerPath = path.join(targetDir, "src/auth/controllers/oauth.controller.ts");
|
|
70
|
+
const readmePath = path.join(targetDir, "README.md");
|
|
71
|
+
const providerUnion = providers.map((provider) => `"${provider}"`).join(" | ");
|
|
72
|
+
await fs.writeFile(authPath, `import { createAuthenik8 } from "authenik8-core";
|
|
73
|
+
import dotenv from "dotenv";
|
|
74
|
+
import { requiredEnv, requiredSecret } from "../utils/security";
|
|
75
|
+
|
|
76
|
+
dotenv.config();
|
|
77
|
+
|
|
78
|
+
let authInstance: any;
|
|
79
|
+
|
|
80
|
+
function oauthConfig() {
|
|
81
|
+
return {
|
|
82
|
+
${providers.map(providerEnvBlock).join("\n ")}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function initAuth() {
|
|
87
|
+
authInstance= await createAuthenik8({
|
|
88
|
+
jwtSecret: requiredSecret("JWT_SECRET"),
|
|
89
|
+
refreshSecret: requiredSecret("REFRESH_SECRET"),
|
|
90
|
+
oauth: oauthConfig(),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
export function getAuth() {
|
|
95
|
+
if (!authInstance) {
|
|
96
|
+
throw new Error("Auth not initialized. Call initAuth() first.");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return authInstance;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const auth = new Proxy(
|
|
103
|
+
{},
|
|
104
|
+
{
|
|
105
|
+
get(_target, property) {
|
|
106
|
+
return getAuth()[property as keyof ReturnType<typeof getAuth>];
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
) as any;
|
|
110
|
+
`);
|
|
111
|
+
await fs.writeFile(routesPath, `import express from "express";
|
|
112
|
+
import { authMiddleware } from "../middleware/auth.middleware";
|
|
113
|
+
import { oauthController } from "../controllers/oauth.controller";
|
|
114
|
+
|
|
115
|
+
const router = express.Router();
|
|
116
|
+
|
|
117
|
+
${providers.map(providerRoutesBlock).join("\n")}
|
|
118
|
+
|
|
119
|
+
export default router;
|
|
120
|
+
`);
|
|
121
|
+
await fs.writeFile(controllerPath, `import { Request, Response } from "express";
|
|
122
|
+
import { getAuth } from "../auth";
|
|
123
|
+
|
|
124
|
+
type OAuthProvider = ${providerUnion};
|
|
125
|
+
|
|
126
|
+
function requireProvider(provider: OAuthProvider, res: Response) {
|
|
127
|
+
const oauthProvider = getAuth().oauth?.[provider];
|
|
128
|
+
|
|
129
|
+
if (!oauthProvider) {
|
|
130
|
+
res.status(404).json({ error: \`\${provider} OAuth is not configured\` });
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return oauthProvider;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const oauthController = {
|
|
138
|
+
${providers.map(providerControllerBlock).join("\n\n ")}
|
|
139
|
+
};
|
|
140
|
+
`);
|
|
141
|
+
if (await fs.pathExists(readmePath)) {
|
|
142
|
+
const selectedList = providers.join(",");
|
|
143
|
+
const routeList = providers
|
|
144
|
+
.flatMap((provider) => [
|
|
145
|
+
`GET /auth/${provider}`,
|
|
146
|
+
`GET /auth/${provider}/callback`,
|
|
147
|
+
`GET /auth/${provider}/link`,
|
|
148
|
+
])
|
|
149
|
+
.join("\n");
|
|
150
|
+
const browserUrls = providers.map((provider) => `http://localhost:3000/auth/${provider}`).join("\n");
|
|
151
|
+
const callbackUrls = providers
|
|
152
|
+
.map((provider) => `${providerTitle(provider)} callback URL:\n\n\`\`\`text\nhttp://localhost:3000/auth/${provider}/callback\n\`\`\``)
|
|
153
|
+
.join("\n\n");
|
|
154
|
+
let readme = await fs.readFile(readmePath, "utf-8");
|
|
155
|
+
readme = readme.replace("AUTHENIK8_OAUTH_PROVIDERS=google,github", `AUTHENIK8_OAUTH_PROVIDERS=${selectedList}`);
|
|
156
|
+
readme = readme.replace(/GOOGLE_CLIENT_ID=your-google-client-id\nGOOGLE_CLIENT_SECRET=your-google-client-secret\nGOOGLE_REDIRECT_URI=http:\/\/localhost:3000\/auth\/google\/callback\nGITHUB_CLIENT_ID=your-github-client-id\nGITHUB_CLIENT_SECRET=your-github-client-secret\nGITHUB_REDIRECT_URI=http:\/\/localhost:3000\/auth\/github\/callback/, providers
|
|
157
|
+
.flatMap((provider) => {
|
|
158
|
+
const upper = provider.toUpperCase();
|
|
159
|
+
return [
|
|
160
|
+
`${upper}_CLIENT_ID=your-${provider}-client-id`,
|
|
161
|
+
`${upper}_CLIENT_SECRET=your-${provider}-client-secret`,
|
|
162
|
+
`${upper}_REDIRECT_URI=http://localhost:3000/auth/${provider}/callback`,
|
|
163
|
+
];
|
|
164
|
+
})
|
|
165
|
+
.join("\n"));
|
|
166
|
+
readme = readme.replace(/GET \/auth\/google\nGET \/auth\/google\/callback\nGET \/auth\/github\nGET \/auth\/github\/callback\nGET \/auth\/google\/link\nGET \/auth\/github\/link/, routeList);
|
|
167
|
+
readme = readme.replace(/http:\/\/localhost:3000\/auth\/google\nhttp:\/\/localhost:3000\/auth\/github/, browserUrls);
|
|
168
|
+
readme = readme.replace(/Google callback URL:\n\n```text\nhttp:\/\/localhost:3000\/auth\/google\/callback\n```\n\nGitHub callback URL:\n\n```text\nhttp:\/\/localhost:3000\/auth\/github\/callback\n```/, callbackUrls);
|
|
169
|
+
if (!providers.includes("google")) {
|
|
170
|
+
readme = readme.replace(/\n- `GOOGLE_REDIRECT_URI`: must exactly match the callback URL configured in Google Cloud\./, "");
|
|
171
|
+
readme = readme.replace(/\n\nexport function loginWithGoogle\(\) {\n window\.location\.href = "http:\/\/localhost:3000\/auth\/google";\n}/, '\n\nexport function loginWithGitHub() {\n window.location.href = "http://localhost:3000/auth/github";\n}');
|
|
172
|
+
readme = readme.replace(/\n\n`google OAuth is not configured`: add `google` to `AUTHENIK8_OAUTH_PROVIDERS` and set the Google env vars, or use only the enabled provider route\./, "");
|
|
173
|
+
}
|
|
174
|
+
if (!providers.includes("github")) {
|
|
175
|
+
readme = readme.replace(/\n- `GITHUB_REDIRECT_URI`: must exactly match the callback URL configured in GitHub OAuth Apps\./, "");
|
|
176
|
+
readme = readme.replace(/\n\n`github OAuth is not configured`: add `github` to `AUTHENIK8_OAUTH_PROVIDERS` and set the GitHub env vars, or use only the enabled provider route\./, "");
|
|
177
|
+
}
|
|
178
|
+
if (providers.includes("github") && !providers.includes("google")) {
|
|
179
|
+
readme = readme.replace("For OAuth, redirect the browser to `/auth/google` or `/auth/github`.", "For OAuth, redirect the browser to `/auth/github`.");
|
|
180
|
+
}
|
|
181
|
+
else if (providers.includes("google") && !providers.includes("github")) {
|
|
182
|
+
readme = readme.replace("For OAuth, redirect the browser to `/auth/google` or `/auth/github`.", "For OAuth, redirect the browser to `/auth/google`.");
|
|
183
|
+
}
|
|
184
|
+
await fs.writeFile(readmePath, readme);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
export async function createProject(state, targetDir, templateRoot) {
|
|
188
|
+
const templateName = resolveTemplateName(state.authMode ?? "base");
|
|
189
|
+
const templatePath = path.join(templateRoot, templateName);
|
|
190
|
+
const pkgExists = fs.existsSync(path.join(templatePath, "package.json"));
|
|
191
|
+
if (!pkgExists) {
|
|
192
|
+
throw new Error(`Template "${templateName}" is missing package.json at ${templatePath}`);
|
|
193
|
+
}
|
|
194
|
+
await fs.copy(templatePath, targetDir, {
|
|
195
|
+
filter: (source) => !source.split(path.sep).includes("oauth-providers"),
|
|
196
|
+
});
|
|
197
|
+
await fs.copy(path.join(templateRoot, "THREAT_MODEL.md"), path.join(targetDir, "THREAT_MODEL.md"));
|
|
198
|
+
if (state.authMode === "auth-oauth") {
|
|
199
|
+
await writeProviderSpecificOAuthFiles(targetDir, resolveOAuthProviders(state));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=createProject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createProject.js","sourceRoot":"","sources":["../../../src/steps/createProject.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function hasBun(): boolean;
|
|
2
|
+
export declare function resolveRuntime(runtime: any): "node" | "bun";
|
|
3
|
+
export declare function createPm2Config(targetDir: string, projectName: string, runtime: "node" | "bun"): void;
|
|
4
|
+
export declare function configureProduction(targetDir: string, projectName: string, runtime: "node" | "bun"): Promise<void>;
|
|
5
|
+
export declare function initGit(targetDir: string): Promise<void>;
|
|
6
|
+
export declare function appendProductionReadme(targetDir: string, projectName: string): void;
|
|
7
|
+
//# sourceMappingURL=finalSetup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finalSetup.d.ts","sourceRoot":"","sources":["../../../src/steps/finalSetup.ts"],"names":[],"mappings":"AAUA,wBAAgB,MAAM,IAAI,OAAO,CAOhC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,GAAG,KAAK,CAO3D;AAGD,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAC,OAAO,EAAE,MAAM,GAAE,KAAK,GAAG,IAAI,CAuCnG;AAGD,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAC,WAAW,EAAC,MAAM,EAAG,OAAO,EAAC,MAAM,GAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBnH;AAKH,wBAAsB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAU9D;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAuBnF"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { run, getCommand } from "../lib/process.js";
|
|
4
|
+
import { spinner } from "../lib/ui.js";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
const PM2_VERSION = "^5.4.2";
|
|
7
|
+
const TS_NODE_VERSION = "^10.9.2";
|
|
8
|
+
export function hasBun() {
|
|
9
|
+
try {
|
|
10
|
+
execSync("bun --version", { stdio: "ignore" });
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function resolveRuntime(runtime) {
|
|
18
|
+
if (runtime === "bun" && !hasBun()) {
|
|
19
|
+
console.log("⚠️ Bun not found, falling back to Node");
|
|
20
|
+
return "node";
|
|
21
|
+
}
|
|
22
|
+
if (runtime === "bun")
|
|
23
|
+
return "bun";
|
|
24
|
+
return "node";
|
|
25
|
+
}
|
|
26
|
+
export function createPm2Config(targetDir, projectName, runtime) {
|
|
27
|
+
const configPath = path.join(targetDir, "ecosystem.config.js");
|
|
28
|
+
const useBun = runtime === "bun";
|
|
29
|
+
const content = useBun
|
|
30
|
+
? `module.exports = {
|
|
31
|
+
apps: [
|
|
32
|
+
{
|
|
33
|
+
name: "${projectName}",
|
|
34
|
+
script: "src/server.ts",
|
|
35
|
+
interpreter: "bun",
|
|
36
|
+
instances: "max",
|
|
37
|
+
exec_mode: "cluster",
|
|
38
|
+
watch: false,
|
|
39
|
+
env: {
|
|
40
|
+
NODE_ENV: "production"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}` :
|
|
45
|
+
`module.exports = {
|
|
46
|
+
apps: [
|
|
47
|
+
{
|
|
48
|
+
name: "${projectName}",
|
|
49
|
+
script: "src/server.ts",
|
|
50
|
+
instances: "max",
|
|
51
|
+
interpreter:"node",
|
|
52
|
+
interpreter_args: "-r ts-node/register",
|
|
53
|
+
exec_mode: "cluster",
|
|
54
|
+
watch: false,
|
|
55
|
+
max_memory_restart: "300M",
|
|
56
|
+
env: {
|
|
57
|
+
NODE_ENV: "production"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
};`;
|
|
62
|
+
fs.writeFileSync(configPath, content, "utf-8");
|
|
63
|
+
}
|
|
64
|
+
export async function configureProduction(targetDir, projectName, runtime) {
|
|
65
|
+
const pkgPath = path.join(targetDir, "package.json");
|
|
66
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
67
|
+
pkg.dependencies["pm2"] = PM2_VERSION;
|
|
68
|
+
if (runtime === "node") {
|
|
69
|
+
pkg.dependencies["ts-node"] = TS_NODE_VERSION;
|
|
70
|
+
}
|
|
71
|
+
pkg.scripts["pm2:start"] = "npx pm2 start ecosystem.config.js";
|
|
72
|
+
pkg.scripts["pm2:stop"] = `npx pm2 stop ${projectName}`;
|
|
73
|
+
pkg.scripts["pm2:logs"] = "npx pm2 logs";
|
|
74
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
75
|
+
createPm2Config(targetDir, projectName, runtime);
|
|
76
|
+
}
|
|
77
|
+
export async function initGit(targetDir) {
|
|
78
|
+
try {
|
|
79
|
+
await run(getCommand("git"), ["init"], {
|
|
80
|
+
cwd: targetDir,
|
|
81
|
+
stdio: "ignore",
|
|
82
|
+
});
|
|
83
|
+
spinner.stop();
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
spinner.fail("Git init failed");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export function appendProductionReadme(targetDir, projectName) {
|
|
90
|
+
fs.appendFileSync(path.join(targetDir, "README.md"), `
|
|
91
|
+
|
|
92
|
+
🚀 Production Mode
|
|
93
|
+
|
|
94
|
+
This project is configured for production using PM2.
|
|
95
|
+
|
|
96
|
+
Start app in cluster mode:
|
|
97
|
+
|
|
98
|
+
npm run pm2:start
|
|
99
|
+
|
|
100
|
+
View logs:
|
|
101
|
+
|
|
102
|
+
npm run pm2:logs
|
|
103
|
+
|
|
104
|
+
Stop app:
|
|
105
|
+
|
|
106
|
+
npm run pm2:stop
|
|
107
|
+
|
|
108
|
+
`);
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=finalSetup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finalSetup.js","sourceRoot":"","sources":["../../../src/steps/finalSetup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installAuth.d.ts","sourceRoot":"","sources":["../../../src/steps/installAuth.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIvD,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EAAC,EAAE,EAAE,cAAc,GACnC,OAAO,CAAC,MAAM,CAAC,CAqBjB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { getBestHashLib, generateHashModule } from "../utils/hash.js";
|
|
4
|
+
import { spinner } from "../lib/ui.js";
|
|
5
|
+
export async function installAuth(targetDir, pm) {
|
|
6
|
+
let selectedHash = getBestHashLib(pm);
|
|
7
|
+
spinner.start("Installing password auth...");
|
|
8
|
+
const pkgPath = path.join(targetDir, "package.json");
|
|
9
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
10
|
+
pkg.dependencies.bcryptjs = "^2.4.3";
|
|
11
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
12
|
+
spinner.stop();
|
|
13
|
+
await fs.writeFile(path.join(targetDir, "src/utils/hash.ts"), generateHashModule("bcryptjs"));
|
|
14
|
+
return selectedHash;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=installAuth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installAuth.js","sourceRoot":"","sources":["../../../src/steps/installAuth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAKvC,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAiB,EAAC,EAAkB;IAEpC,IAAI,YAAY,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC;IAGtC,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAE7C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAE1D,GAAG,CAAC,YAAY,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAErC,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAE1D,OAAO,CAAC,IAAI,EAAE,CAAC;IAEb,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,EACzC,kBAAkB,CAAC,UAAU,CAAC,CAC/B,CAAC;IAEF,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type PackageManager = "pnpm" | "bun" | "npm";
|
|
2
|
+
export declare function detectPackageManager(): PackageManager;
|
|
3
|
+
export declare function ensureRedisServerInstalled(): void;
|
|
4
|
+
export declare function installDependencies(targetDir: string): Promise<void>;
|
|
5
|
+
//# sourceMappingURL=installDeps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installDeps.d.ts","sourceRoot":"","sources":["../../../src/steps/installDeps.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;AAWpD,wBAAgB,oBAAoB,IAAI,cAAc,CAarD;AAyBD,wBAAgB,0BAA0B,IAAI,IAAI,CAWjD;AAeD,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB1E"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { run, getCommand, exitForInterrupt } from "../lib/process.js";
|
|
3
|
+
import { spinner } from "../lib/ui.js";
|
|
4
|
+
function commandSucceeds(command) {
|
|
5
|
+
try {
|
|
6
|
+
execSync(command, { stdio: "ignore" });
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function detectPackageManager() {
|
|
14
|
+
try {
|
|
15
|
+
if (process.env.npm_execpath?.includes("pnpm"))
|
|
16
|
+
return "pnpm";
|
|
17
|
+
if (process.env.npm_execpath?.includes("bun"))
|
|
18
|
+
return "bun";
|
|
19
|
+
if (process.env.npm_execpath?.includes("npm"))
|
|
20
|
+
return "npm";
|
|
21
|
+
execSync("pnpm --version", { stdio: "ignore" });
|
|
22
|
+
return "pnpm";
|
|
23
|
+
}
|
|
24
|
+
catch { }
|
|
25
|
+
try {
|
|
26
|
+
execSync("bun --version", { stdio: "ignore" });
|
|
27
|
+
return "bun";
|
|
28
|
+
}
|
|
29
|
+
catch { }
|
|
30
|
+
return "npm";
|
|
31
|
+
}
|
|
32
|
+
function getRedisInstallCommand() {
|
|
33
|
+
if (process.platform === "darwin" && commandSucceeds("brew --version")) {
|
|
34
|
+
return "brew install redis";
|
|
35
|
+
}
|
|
36
|
+
if (process.platform === "linux") {
|
|
37
|
+
if (commandSucceeds("apt-get --version")) {
|
|
38
|
+
return "sudo apt-get update && sudo apt-get install -y redis-server";
|
|
39
|
+
}
|
|
40
|
+
if (commandSucceeds("dnf --version")) {
|
|
41
|
+
return "sudo dnf install -y redis";
|
|
42
|
+
}
|
|
43
|
+
if (commandSucceeds("yum --version")) {
|
|
44
|
+
return "sudo yum install -y redis";
|
|
45
|
+
}
|
|
46
|
+
if (commandSucceeds("pacman --version")) {
|
|
47
|
+
return "sudo pacman -Sy --noconfirm redis";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
export function ensureRedisServerInstalled() {
|
|
53
|
+
if (commandSucceeds("redis-server --version")) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const installCommand = getRedisInstallCommand();
|
|
57
|
+
if (!installCommand) {
|
|
58
|
+
throw new Error("Redis server is required but could not be installed automatically.");
|
|
59
|
+
}
|
|
60
|
+
execSync(installCommand, { stdio: "inherit" });
|
|
61
|
+
}
|
|
62
|
+
function getInstallArgs(pm, targetDir) {
|
|
63
|
+
switch (pm) {
|
|
64
|
+
case "pnpm":
|
|
65
|
+
return ["install", "--prefer-offline"];
|
|
66
|
+
case "bun":
|
|
67
|
+
return ["install"];
|
|
68
|
+
case "npm":
|
|
69
|
+
default:
|
|
70
|
+
return ["install", "--prefer-offline", "--no-audit", "--no-fund"];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export async function installDependencies(targetDir) {
|
|
74
|
+
const pm = detectPackageManager();
|
|
75
|
+
spinner.start("Installing Redis server if needed...");
|
|
76
|
+
try {
|
|
77
|
+
ensureRedisServerInstalled();
|
|
78
|
+
spinner.stop();
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
spinner.fail("Failed to install Redis server");
|
|
82
|
+
await exitForInterrupt(err);
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
spinner.start("Installing dependencies...(this may take a few minutes)");
|
|
86
|
+
try {
|
|
87
|
+
await run(getCommand(pm), getInstallArgs(pm, targetDir), {
|
|
88
|
+
cwd: targetDir,
|
|
89
|
+
stdio: "ignore",
|
|
90
|
+
});
|
|
91
|
+
spinner.stop();
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
spinner.fail("Failed to install dependencies");
|
|
95
|
+
await exitForInterrupt(err);
|
|
96
|
+
throw err;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=installDeps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installDeps.js","sourceRoot":"","sources":["../../../src/steps/installDeps.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/steps/prompts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGhD,wBAAsB,UAAU,CAAC,KAAK,EAAC,QAAQ,EAAC,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CA2FjG"}
|