create-sprint 0.0.62 → 0.0.66
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/generators.js +2 -704
- package/dist/templates/configFiles.js +122 -0
- package/dist/templates/controllers.js +103 -0
- package/dist/templates/cronjobs.js +25 -0
- package/dist/templates/docker.js +49 -0
- package/dist/templates/env.js +73 -0
- package/dist/templates/index.js +20 -0
- package/dist/templates/middlewares.js +99 -0
- package/dist/templates/misc.js +61 -0
- package/dist/templates/packageJson.js +67 -0
- package/dist/templates/routes.js +69 -0
- package/dist/templates/schemas.js +56 -0
- package/package.json +1 -1
- package/src/generators.ts +2 -741
- package/src/templates/configFiles.ts +124 -0
- package/src/templates/controllers.ts +101 -0
- package/src/templates/cronjobs.ts +24 -0
- package/src/templates/docker.ts +48 -0
- package/src/templates/env.ts +76 -0
- package/src/templates/index.ts +29 -0
- package/src/templates/middlewares.ts +98 -0
- package/src/templates/misc.ts +60 -0
- package/src/templates/packageJson.ts +75 -0
- package/src/templates/routes.ts +69 -0
- package/src/templates/schemas.ts +55 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
export function getTsConfig() {
|
|
2
|
+
return JSON.stringify({
|
|
3
|
+
compilerOptions: {
|
|
4
|
+
target: "ES2022",
|
|
5
|
+
module: "NodeNext",
|
|
6
|
+
moduleResolution: "NodeNext",
|
|
7
|
+
lib: ["ES2022"],
|
|
8
|
+
types: ["node"],
|
|
9
|
+
outDir: "./dist",
|
|
10
|
+
rootDir: "./src",
|
|
11
|
+
strict: true,
|
|
12
|
+
esModuleInterop: true,
|
|
13
|
+
skipLibCheck: true,
|
|
14
|
+
forceConsistentCasingInFileNames: true,
|
|
15
|
+
resolveJsonModule: true,
|
|
16
|
+
declaration: true,
|
|
17
|
+
declarationMap: true,
|
|
18
|
+
sourceMap: true,
|
|
19
|
+
baseUrl: ".",
|
|
20
|
+
paths: {
|
|
21
|
+
"@/*": ["./src/*"]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
include: ["src/**/*"],
|
|
25
|
+
exclude: ["node_modules", "dist"],
|
|
26
|
+
}, null, 2);
|
|
27
|
+
}
|
|
28
|
+
;
|
|
29
|
+
export function getViteConfig() {
|
|
30
|
+
return `import { defineConfig } from "vite";
|
|
31
|
+
import { resolve } from "path";
|
|
32
|
+
|
|
33
|
+
export default defineConfig({
|
|
34
|
+
build: {
|
|
35
|
+
lib: {
|
|
36
|
+
entry: resolve(__dirname, "src/index.ts"),
|
|
37
|
+
formats: ["es"],
|
|
38
|
+
fileName: "index",
|
|
39
|
+
},
|
|
40
|
+
outDir: "dist",
|
|
41
|
+
rollupOptions: {
|
|
42
|
+
external: ["sprint-es", "express", "cors", "morgan", "serve-favicon", "dotenv"],
|
|
43
|
+
},
|
|
44
|
+
target: "ES2020",
|
|
45
|
+
},
|
|
46
|
+
resolve: {
|
|
47
|
+
alias: {
|
|
48
|
+
"@": resolve(__dirname, "src"),
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
`;
|
|
53
|
+
}
|
|
54
|
+
;
|
|
55
|
+
export function getSprintConfigFile(language, telemetry) {
|
|
56
|
+
if (language === "typescript") {
|
|
57
|
+
let config = `import type { SprintOptions } from "sprint-es";
|
|
58
|
+
|
|
59
|
+
export const config: SprintOptions = {
|
|
60
|
+
openapi: {
|
|
61
|
+
/* Generate OpenAPI spec on build - Coming Soon */
|
|
62
|
+
generateOnBuild: false
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Add Vite config here if needed
|
|
67
|
+
// export const vite = {
|
|
68
|
+
// build: { ... }
|
|
69
|
+
// };
|
|
70
|
+
`;
|
|
71
|
+
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
72
|
+
config += `import { initTelemetry } from "sprint-es/telemetry";
|
|
73
|
+
|
|
74
|
+
initTelemetry({
|
|
75
|
+
provider: "${telemetry}",
|
|
76
|
+
dsn: process.env.SENTRY_DSN || "",
|
|
77
|
+
environment: process.env.NODE_ENV || "development"
|
|
78
|
+
});
|
|
79
|
+
`;
|
|
80
|
+
}
|
|
81
|
+
else if (telemetry === "discord") {
|
|
82
|
+
config += `import { initTelemetry } from "sprint-es/telemetry";
|
|
83
|
+
|
|
84
|
+
initTelemetry({
|
|
85
|
+
provider: "discord",
|
|
86
|
+
webhookUrl: process.env.DISCORD_TELEMETRY_WEBHOOK_URL || ""
|
|
87
|
+
});
|
|
88
|
+
`;
|
|
89
|
+
}
|
|
90
|
+
return config;
|
|
91
|
+
}
|
|
92
|
+
let config = `export const config = {
|
|
93
|
+
openapi: {
|
|
94
|
+
/* Generate OpenAPI spec on build - Coming Soon */
|
|
95
|
+
generateOnBuild: false
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
`;
|
|
99
|
+
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
100
|
+
config += `
|
|
101
|
+
import { initTelemetry } from "sprint-es/telemetry";
|
|
102
|
+
|
|
103
|
+
initTelemetry({
|
|
104
|
+
provider: "${telemetry}",
|
|
105
|
+
dsn: process.env.SENTRY_DSN || "",
|
|
106
|
+
environment: process.env.NODE_ENV || "development"
|
|
107
|
+
});
|
|
108
|
+
`;
|
|
109
|
+
}
|
|
110
|
+
else if (telemetry === "discord") {
|
|
111
|
+
config += `
|
|
112
|
+
import { initTelemetry } from "sprint-es/telemetry";
|
|
113
|
+
|
|
114
|
+
initTelemetry({
|
|
115
|
+
provider: "discord",
|
|
116
|
+
webhookUrl: process.env.DISCORD_TELEMETRY_WEBHOOK_URL || ""
|
|
117
|
+
});
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
return config;
|
|
121
|
+
}
|
|
122
|
+
;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
export function getHomeController(language) {
|
|
2
|
+
if (language === "typescript") {
|
|
3
|
+
return `import { Handler, SprintRequest, SprintResponse } from "sprint-es";
|
|
4
|
+
import { verifyEncrypted, getJwtFromEnv } from "sprint-es/jwt";
|
|
5
|
+
|
|
6
|
+
export const homeController: Handler = (req: SprintRequest, res: SprintResponse) => {
|
|
7
|
+
res.json({
|
|
8
|
+
message: "Hello World",
|
|
9
|
+
status: "ok"
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const jwtValidateController: Handler = (req: SprintRequest, res: SprintResponse) => {
|
|
14
|
+
return res.json(req.custom.user);
|
|
15
|
+
};
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
18
|
+
return `export const homeController = (req, res) => {
|
|
19
|
+
res.json({
|
|
20
|
+
message: "Hello World",
|
|
21
|
+
status: "ok"
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const jwtValidateController = (req, res) => {
|
|
26
|
+
return res.json(req.custom.user);
|
|
27
|
+
};
|
|
28
|
+
`;
|
|
29
|
+
}
|
|
30
|
+
;
|
|
31
|
+
export function getAdminController(language) {
|
|
32
|
+
if (language === "typescript") {
|
|
33
|
+
return `import { Handler, SprintRequest, SprintResponse } from "sprint-es";
|
|
34
|
+
import { signEncrypted, getJwtFromEnv } from "sprint-es/jwt";
|
|
35
|
+
|
|
36
|
+
export const adminController: Handler = (req: SprintRequest, res: SprintResponse) => {
|
|
37
|
+
res.json({
|
|
38
|
+
message: "Admin Dashboard",
|
|
39
|
+
status: "ok"
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const adminUsersController: Handler = (req: SprintRequest, res: SprintResponse) => {
|
|
44
|
+
res.json({
|
|
45
|
+
users: [
|
|
46
|
+
{ id: 1, name: "John Doe", role: "admin" },
|
|
47
|
+
{ id: 2, name: "Jane Smith", role: "user" }
|
|
48
|
+
]
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const { privateKey, encryptionSecret } = getJwtFromEnv();
|
|
53
|
+
|
|
54
|
+
export const jwtGenerateController: Handler = (req: SprintRequest, res: SprintResponse) => {
|
|
55
|
+
const { userId, role } = req.body || {};
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const payload = { userId, role: role || "user" };
|
|
59
|
+
const token = signEncrypted(payload, privateKey, encryptionSecret, { expiresIn: "1h" });
|
|
60
|
+
res.json({ token });
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return res.status(500).json({ error: "JWT not configured" });
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
`;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
return `import { signEncrypted } from "sprint-es/jwt";
|
|
69
|
+
|
|
70
|
+
const privateKey = process.env.JWT_PRIVATE_KEY;
|
|
71
|
+
const encryptionSecret = process.env.JWT_ENCRYPTION_SECRET;
|
|
72
|
+
|
|
73
|
+
export const adminController = (req, res) => {
|
|
74
|
+
res.json({
|
|
75
|
+
message: "Admin Dashboard",
|
|
76
|
+
status: "ok"
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const adminUsersController = (req, res) => {
|
|
81
|
+
res.json({
|
|
82
|
+
users: [
|
|
83
|
+
{ id: 1, name: "John Doe", role: "admin" },
|
|
84
|
+
{ id: 2, name: "Jane Smith", role: "user" }
|
|
85
|
+
]
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const jwtGenerateController = (req, res) => {
|
|
90
|
+
const { userId, role } = req.body || {};
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const payload = { userId, role: role || "user" };
|
|
94
|
+
const token = signEncrypted(payload, privateKey, encryptionSecret, { expiresIn: "1h" });
|
|
95
|
+
res.json({ token });
|
|
96
|
+
} catch (error) {
|
|
97
|
+
return res.status(500).json({ error: "JWT not configured" });
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function getExampleCronJob(language) {
|
|
2
|
+
if (language === "typescript") {
|
|
3
|
+
return `import { defineCronJob } from "sprint-es/cronjobs";
|
|
4
|
+
|
|
5
|
+
export default defineCronJob({
|
|
6
|
+
name: "daily-task",
|
|
7
|
+
cronExpression: "0 21 * * *",
|
|
8
|
+
handler: () => {
|
|
9
|
+
console.log("Hello World from cronjob!");
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
`;
|
|
13
|
+
}
|
|
14
|
+
return `import { defineCronJob } from "sprint-es/cronjobs";
|
|
15
|
+
|
|
16
|
+
export default defineCronJob({
|
|
17
|
+
name: "daily-task",
|
|
18
|
+
cronExpression: "0 21 * * *",
|
|
19
|
+
handler: () => {
|
|
20
|
+
console.log("Hello World from cronjob!");
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
`;
|
|
24
|
+
}
|
|
25
|
+
;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export function getDockerfile(language) {
|
|
2
|
+
if (language === "typescript") {
|
|
3
|
+
return `FROM node:20-alpine
|
|
4
|
+
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
|
|
7
|
+
COPY package*.json ./
|
|
8
|
+
|
|
9
|
+
RUN npm ci
|
|
10
|
+
|
|
11
|
+
COPY . .
|
|
12
|
+
|
|
13
|
+
RUN npm run build
|
|
14
|
+
|
|
15
|
+
EXPOSE 3000
|
|
16
|
+
|
|
17
|
+
CMD ["npm", "start"]
|
|
18
|
+
`;
|
|
19
|
+
}
|
|
20
|
+
return `FROM node:20-alpine
|
|
21
|
+
|
|
22
|
+
WORKDIR /app
|
|
23
|
+
|
|
24
|
+
COPY package*.json ./
|
|
25
|
+
|
|
26
|
+
RUN npm ci
|
|
27
|
+
|
|
28
|
+
COPY . .
|
|
29
|
+
|
|
30
|
+
EXPOSE 3000
|
|
31
|
+
|
|
32
|
+
CMD ["npm", "start"]
|
|
33
|
+
`;
|
|
34
|
+
}
|
|
35
|
+
;
|
|
36
|
+
export function getDockerCompose(language) {
|
|
37
|
+
return `
|
|
38
|
+
services:
|
|
39
|
+
app:
|
|
40
|
+
build: .
|
|
41
|
+
ports:
|
|
42
|
+
- "3000:3000"
|
|
43
|
+
environment:
|
|
44
|
+
- NODE_ENV=production
|
|
45
|
+
- PORT=5000
|
|
46
|
+
restart: unless-stopped
|
|
47
|
+
`;
|
|
48
|
+
}
|
|
49
|
+
;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
|
+
import { generateJWTKeys } from "./packageJson.js";
|
|
3
|
+
export function getEnvExample(telemetry) {
|
|
4
|
+
let env = `PORT=5000
|
|
5
|
+
|
|
6
|
+
JWT_PUBLIC_KEY=""
|
|
7
|
+
JWT_PRIVATE_KEY=""
|
|
8
|
+
JWT_ENCRYPTION_SECRET=""
|
|
9
|
+
|
|
10
|
+
# Development: npm run dev (NODE_ENV=development)
|
|
11
|
+
# Production: npm start (NODE_ENV=production)
|
|
12
|
+
`;
|
|
13
|
+
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
14
|
+
env += `
|
|
15
|
+
# Sentry / GlitchTip (use GlitchTip DSN for self-hosted)
|
|
16
|
+
SENTRY_DSN=""
|
|
17
|
+
`;
|
|
18
|
+
}
|
|
19
|
+
else if (telemetry === "discord") {
|
|
20
|
+
env += `
|
|
21
|
+
# Discord Webhook URL for error notifications
|
|
22
|
+
DISCORD_TELEMETRY_WEBHOOK_URL=""
|
|
23
|
+
`;
|
|
24
|
+
}
|
|
25
|
+
return env;
|
|
26
|
+
}
|
|
27
|
+
;
|
|
28
|
+
export function getEnvDevelopment(telemetry) {
|
|
29
|
+
const keys = generateJWTKeys();
|
|
30
|
+
let env = `NODE_ENV=development
|
|
31
|
+
PORT=5000
|
|
32
|
+
JWT_PUBLIC_KEY='${keys.publicKey}'
|
|
33
|
+
JWT_PRIVATE_KEY='${keys.privateKey}'
|
|
34
|
+
JWT_ENCRYPTION_SECRET='${crypto.randomBytes(32).toString("hex")}'
|
|
35
|
+
`;
|
|
36
|
+
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
37
|
+
env += `
|
|
38
|
+
# Sentry / GlitchTip
|
|
39
|
+
SENTRY_DSN=""
|
|
40
|
+
`;
|
|
41
|
+
}
|
|
42
|
+
else if (telemetry === "discord") {
|
|
43
|
+
env += `
|
|
44
|
+
# Discord Webhook URL
|
|
45
|
+
DISCORD_TELEMETRY_WEBHOOK_URL=""
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
return env;
|
|
49
|
+
}
|
|
50
|
+
;
|
|
51
|
+
export function getEnvProduction(telemetry) {
|
|
52
|
+
const keys = generateJWTKeys();
|
|
53
|
+
let env = `NODE_ENV=production
|
|
54
|
+
PORT=5000
|
|
55
|
+
JWT_PUBLIC_KEY='${keys.publicKey}'
|
|
56
|
+
JWT_PRIVATE_KEY='${keys.privateKey}'
|
|
57
|
+
JWT_ENCRYPTION_SECRET='${crypto.randomBytes(32).toString("hex")}'
|
|
58
|
+
`;
|
|
59
|
+
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
60
|
+
env += `
|
|
61
|
+
# Sentry / GlitchTip
|
|
62
|
+
SENTRY_DSN=
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
else if (telemetry === "discord") {
|
|
66
|
+
env += `
|
|
67
|
+
# Discord Webhook URL
|
|
68
|
+
DISCORD_TELEMETRY_WEBHOOK_URL=
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
71
|
+
return env;
|
|
72
|
+
}
|
|
73
|
+
;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Package JSON
|
|
2
|
+
export { generateJWTKeys, getTypeScriptPackageJson, getJavaScriptPackageJson } from "./packageJson.js";
|
|
3
|
+
// Config Files (tsconfig, vite.config, sprint.config)
|
|
4
|
+
export { getTsConfig, getViteConfig, getSprintConfigFile } from "./configFiles.js";
|
|
5
|
+
// Environment Files
|
|
6
|
+
export { getEnvExample, getEnvDevelopment, getEnvProduction } from "./env.js";
|
|
7
|
+
// Routes
|
|
8
|
+
export { getMainFile, getHomeRoute, getAdminRoute } from "./routes.js";
|
|
9
|
+
// Controllers
|
|
10
|
+
export { getHomeController, getAdminController } from "./controllers.js";
|
|
11
|
+
// Middlewares
|
|
12
|
+
export { getInternalAuthMiddleware, getUserAuthMiddleware } from "./middlewares.js";
|
|
13
|
+
// Schemas
|
|
14
|
+
export { getHomeSchema, getAdminSchema } from "./schemas.js";
|
|
15
|
+
// Cronjobs
|
|
16
|
+
export { getExampleCronJob } from "./cronjobs.js";
|
|
17
|
+
// Docker
|
|
18
|
+
export { getDockerfile, getDockerCompose } from "./docker.js";
|
|
19
|
+
// Misc
|
|
20
|
+
export { getGitignore, getDockerIgnore } from "./misc.js";
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export function getInternalAuthMiddleware(language) {
|
|
2
|
+
if (language === "typescript") {
|
|
3
|
+
return `import { defineMiddleware, SprintRequest, SprintResponse, NextFunction } from "sprint-es";
|
|
4
|
+
|
|
5
|
+
export default defineMiddleware({
|
|
6
|
+
name: "adminAuth",
|
|
7
|
+
priority: 10,
|
|
8
|
+
include: "/admin/**",
|
|
9
|
+
handler: (req: SprintRequest, res: SprintResponse, next: NextFunction) => {
|
|
10
|
+
const auth = req.sprint.getAuthorization();
|
|
11
|
+
if (!auth) return res.status(401).json({ error: "No authorization header" });
|
|
12
|
+
|
|
13
|
+
const token = auth.replace("Bearer ", "");
|
|
14
|
+
|
|
15
|
+
if (token !== "admin-token") return res.status(403).json({ error: "Invalid token" });
|
|
16
|
+
|
|
17
|
+
next();
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
`;
|
|
21
|
+
}
|
|
22
|
+
return `import { defineMiddleware } from "sprint-es";
|
|
23
|
+
|
|
24
|
+
export default defineMiddleware({
|
|
25
|
+
name: "adminAuth",
|
|
26
|
+
priority: 10,
|
|
27
|
+
include: "/admin/**",
|
|
28
|
+
handler: (req, res, next) => {
|
|
29
|
+
const auth = req.sprint.getAuthorization();
|
|
30
|
+
if (!auth) return res.status(401).json({ error: "No authorization header" });
|
|
31
|
+
|
|
32
|
+
const token = auth.replace("Bearer ", "");
|
|
33
|
+
|
|
34
|
+
if (token !== "admin-token") return res.status(403).json({ error: "Invalid token" });
|
|
35
|
+
|
|
36
|
+
next();
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
`;
|
|
40
|
+
}
|
|
41
|
+
;
|
|
42
|
+
export function getUserAuthMiddleware(language) {
|
|
43
|
+
if (language === "typescript") {
|
|
44
|
+
return `import { defineMiddleware, SprintRequest, SprintResponse, NextFunction } from "sprint-es";
|
|
45
|
+
import { verifyEncrypted, getJwtFromEnv } from "sprint-es/jwt";
|
|
46
|
+
|
|
47
|
+
const { publicKey, encryptionSecret } = getJwtFromEnv();
|
|
48
|
+
|
|
49
|
+
export default defineMiddleware({
|
|
50
|
+
name: "userAuth",
|
|
51
|
+
priority: 10,
|
|
52
|
+
include: "/**",
|
|
53
|
+
exclude: "/admin/**",
|
|
54
|
+
handler: (req: SprintRequest, res: SprintResponse, next: NextFunction) => {
|
|
55
|
+
const auth = req.sprint.getAuthorization();
|
|
56
|
+
if (!auth) return res.status(401).json({ error: "No authorization header" });
|
|
57
|
+
|
|
58
|
+
const token = auth.replace("Bearer ", "");
|
|
59
|
+
|
|
60
|
+
const decoded = verifyEncrypted(token, publicKey, encryptionSecret);
|
|
61
|
+
|
|
62
|
+
if (!decoded) return res.status(403).json({ error: "Invalid token" });
|
|
63
|
+
|
|
64
|
+
req.custom.user = decoded;
|
|
65
|
+
|
|
66
|
+
next();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
71
|
+
return `import { defineMiddleware } from "sprint-es";
|
|
72
|
+
import { verifyEncrypted } from "sprint-es/jwt";
|
|
73
|
+
|
|
74
|
+
const publicKey = process.env.JWT_PUBLIC_KEY;
|
|
75
|
+
const encryptionSecret = process.env.JWT_ENCRYPTION_SECRET;
|
|
76
|
+
|
|
77
|
+
export default defineMiddleware({
|
|
78
|
+
name: "userAuth",
|
|
79
|
+
priority: 10,
|
|
80
|
+
include: "/**",
|
|
81
|
+
exclude: "/admin/**",
|
|
82
|
+
handler: (req, res, next) => {
|
|
83
|
+
const auth = req.sprint.getAuthorization();
|
|
84
|
+
if (!auth) return res.status(401).json({ error: "No authorization header" });
|
|
85
|
+
|
|
86
|
+
const token = auth.replace("Bearer ", "");
|
|
87
|
+
|
|
88
|
+
const decoded = verifyEncrypted(token, publicKey, encryptionSecret);
|
|
89
|
+
|
|
90
|
+
if (!decoded) return res.status(403).json({ error: "Invalid token" });
|
|
91
|
+
|
|
92
|
+
req.custom.user = decoded;
|
|
93
|
+
|
|
94
|
+
next();
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
`;
|
|
98
|
+
}
|
|
99
|
+
;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export function getGitignore() {
|
|
2
|
+
return `# Dependencies
|
|
3
|
+
node_modules/
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
|
|
8
|
+
# Build
|
|
9
|
+
dist/
|
|
10
|
+
build/
|
|
11
|
+
*.tsbuildinfo
|
|
12
|
+
|
|
13
|
+
# Environment
|
|
14
|
+
.env.development
|
|
15
|
+
.env.production
|
|
16
|
+
.env.local
|
|
17
|
+
.env.*.local
|
|
18
|
+
|
|
19
|
+
# IDE
|
|
20
|
+
.vscode/
|
|
21
|
+
.idea/
|
|
22
|
+
*.swp
|
|
23
|
+
*.swo
|
|
24
|
+
*~
|
|
25
|
+
|
|
26
|
+
# OS
|
|
27
|
+
.DS_Store
|
|
28
|
+
Thumbs.db
|
|
29
|
+
|
|
30
|
+
# Logs
|
|
31
|
+
logs/
|
|
32
|
+
*.log
|
|
33
|
+
|
|
34
|
+
# Test
|
|
35
|
+
coverage/
|
|
36
|
+
|
|
37
|
+
# Temporary
|
|
38
|
+
tmp/
|
|
39
|
+
temp/
|
|
40
|
+
`;
|
|
41
|
+
}
|
|
42
|
+
;
|
|
43
|
+
export function getDockerIgnore() {
|
|
44
|
+
return `node_modules
|
|
45
|
+
npm-debug.log
|
|
46
|
+
.env
|
|
47
|
+
.env.*
|
|
48
|
+
.git
|
|
49
|
+
.gitignore
|
|
50
|
+
README.md
|
|
51
|
+
dist
|
|
52
|
+
build
|
|
53
|
+
coverage
|
|
54
|
+
.vscode
|
|
55
|
+
.idea
|
|
56
|
+
*.log
|
|
57
|
+
tmp
|
|
58
|
+
temp
|
|
59
|
+
`;
|
|
60
|
+
}
|
|
61
|
+
;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
|
+
export function generateJWTKeys() {
|
|
3
|
+
const keys = crypto.generateKeyPairSync("rsa", {
|
|
4
|
+
modulusLength: 4096,
|
|
5
|
+
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
6
|
+
privateKeyEncoding: { type: "pkcs8", format: "pem" }
|
|
7
|
+
});
|
|
8
|
+
return keys;
|
|
9
|
+
}
|
|
10
|
+
;
|
|
11
|
+
export function getTypeScriptPackageJson(name, telemetry) {
|
|
12
|
+
const deps = {
|
|
13
|
+
"sprint-es": "^0.0.54"
|
|
14
|
+
};
|
|
15
|
+
const devDeps = {
|
|
16
|
+
"@types/node": "^22.0.0",
|
|
17
|
+
"tsx": "^4.19.0",
|
|
18
|
+
typescript: "^5.6.0",
|
|
19
|
+
};
|
|
20
|
+
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
21
|
+
deps["@sentry/node"] = "^8.0.0";
|
|
22
|
+
}
|
|
23
|
+
else if (telemetry === "discord") {
|
|
24
|
+
deps["axios"] = "^1.6.0";
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
name: name === "." ? "sprint-app" : name,
|
|
28
|
+
version: "0.0.1",
|
|
29
|
+
description: "Sprint API",
|
|
30
|
+
main: "dist/index.js",
|
|
31
|
+
scripts: {
|
|
32
|
+
build: "sprint-es build",
|
|
33
|
+
start: "sprint-es start",
|
|
34
|
+
dev: "sprint-es dev",
|
|
35
|
+
"generate:keys": "sprint-es generate-keys"
|
|
36
|
+
},
|
|
37
|
+
dependencies: deps,
|
|
38
|
+
devDependencies: devDeps,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
;
|
|
42
|
+
export function getJavaScriptPackageJson(name, telemetry) {
|
|
43
|
+
const deps = {
|
|
44
|
+
"sprint-es": "^0.0.54"
|
|
45
|
+
};
|
|
46
|
+
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
47
|
+
deps["@sentry/node"] = "^8.0.0";
|
|
48
|
+
}
|
|
49
|
+
else if (telemetry === "discord") {
|
|
50
|
+
deps["axios"] = "^1.6.0";
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
name: name === "." ? "sprint-app" : name,
|
|
54
|
+
version: "0.0.1",
|
|
55
|
+
description: "Sprint API",
|
|
56
|
+
main: "src/index.js",
|
|
57
|
+
type: "module",
|
|
58
|
+
scripts: {
|
|
59
|
+
build: "sprint-es build",
|
|
60
|
+
start: "sprint-es start",
|
|
61
|
+
dev: "sprint-es dev",
|
|
62
|
+
"generate:keys": "sprint-es generate-keys"
|
|
63
|
+
},
|
|
64
|
+
dependencies: deps
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export function getMainFile(language) {
|
|
2
|
+
if (language === "typescript") {
|
|
3
|
+
return `import Sprint from "sprint-es";
|
|
4
|
+
|
|
5
|
+
const app = new Sprint();
|
|
6
|
+
`;
|
|
7
|
+
}
|
|
8
|
+
return `import Sprint from "sprint-es";
|
|
9
|
+
|
|
10
|
+
const app = new Sprint();
|
|
11
|
+
`;
|
|
12
|
+
}
|
|
13
|
+
;
|
|
14
|
+
export function getHomeRoute(language) {
|
|
15
|
+
if (language === "typescript") {
|
|
16
|
+
return `import { Router } from "sprint-es";
|
|
17
|
+
import { homeSchema } from "@/schemas/home";
|
|
18
|
+
import { homeController, jwtValidateController } from "@/controllers/home";
|
|
19
|
+
|
|
20
|
+
const router = Router();
|
|
21
|
+
|
|
22
|
+
router.get("/", homeSchema, homeController);
|
|
23
|
+
router.post("/me", jwtValidateController);
|
|
24
|
+
|
|
25
|
+
export default router;
|
|
26
|
+
`;
|
|
27
|
+
}
|
|
28
|
+
return `import { Router } from "sprint-es";
|
|
29
|
+
import { homeSchema } from "../schemas/home.js";
|
|
30
|
+
import { homeController, jwtValidateController } from "../controllers/home.js";
|
|
31
|
+
|
|
32
|
+
const router = Router();
|
|
33
|
+
|
|
34
|
+
router.get("/", homeSchema, homeController);
|
|
35
|
+
router.post("/me", jwtValidateController);
|
|
36
|
+
|
|
37
|
+
export default router;
|
|
38
|
+
`;
|
|
39
|
+
}
|
|
40
|
+
;
|
|
41
|
+
export function getAdminRoute(language) {
|
|
42
|
+
if (language === "typescript") {
|
|
43
|
+
return `import { Router } from "sprint-es";
|
|
44
|
+
import { adminSchema, jwtGenerateSchema } from "@/schemas/admin";
|
|
45
|
+
import { adminController, adminUsersController, jwtGenerateController } from "@/controllers/admin";
|
|
46
|
+
|
|
47
|
+
const router = Router();
|
|
48
|
+
|
|
49
|
+
router.get("/", adminSchema, adminController);
|
|
50
|
+
router.get("/users", adminSchema, adminUsersController);
|
|
51
|
+
router.post("/jwt/generate", jwtGenerateSchema, jwtGenerateController);
|
|
52
|
+
|
|
53
|
+
export default router;
|
|
54
|
+
`;
|
|
55
|
+
}
|
|
56
|
+
return `import { Router } from "sprint-es";
|
|
57
|
+
import { adminSchema, jwtGenerateSchema } from "../schemas/admin.js";
|
|
58
|
+
import { adminController, adminUsersController, jwtGenerateController } from "../controllers/admin.js";
|
|
59
|
+
|
|
60
|
+
const router = Router();
|
|
61
|
+
|
|
62
|
+
router.get("/", adminSchema, adminController);
|
|
63
|
+
router.get("/users", adminSchema, adminUsersController);
|
|
64
|
+
router.post("/jwt/generate", jwtGenerateSchema, jwtGenerateController);
|
|
65
|
+
|
|
66
|
+
export default router;
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
;
|