create-sprint 0.0.62 → 0.0.64

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.
@@ -0,0 +1,124 @@
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: string, telemetry: string) {
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
+
72
+ if (telemetry === "sentry" || telemetry === "glitchtip") {
73
+ config += `import { initTelemetry } from "sprint-es/telemetry";
74
+
75
+ initTelemetry({
76
+ provider: "${telemetry}",
77
+ dsn: process.env.SENTRY_DSN || "",
78
+ environment: process.env.NODE_ENV || "development"
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
+
91
+ return config;
92
+ }
93
+
94
+ let config = `export const config = {
95
+ openapi: {
96
+ /* Generate OpenAPI spec on build - Coming Soon */
97
+ generateOnBuild: false
98
+ }
99
+ };
100
+ `;
101
+
102
+ if (telemetry === "sentry" || telemetry === "glitchtip") {
103
+ config += `
104
+ import { initTelemetry } from "sprint-es/telemetry";
105
+
106
+ initTelemetry({
107
+ provider: "${telemetry}",
108
+ dsn: process.env.SENTRY_DSN || "",
109
+ environment: process.env.NODE_ENV || "development"
110
+ });
111
+ `;
112
+ } else if (telemetry === "discord") {
113
+ config += `
114
+ import { initTelemetry } from "sprint-es/telemetry";
115
+
116
+ initTelemetry({
117
+ provider: "discord",
118
+ webhookUrl: process.env.DISCORD_TELEMETRY_WEBHOOK_URL || ""
119
+ });
120
+ `;
121
+ }
122
+
123
+ return config;
124
+ };
@@ -0,0 +1,104 @@
1
+ export function getHomeController(language: string) {
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 `import { Handler, SprintRequest, SprintResponse } from "sprint-es";
19
+ import { verifyEncrypted, getJwtFromEnv } from "sprint-es/jwt";
20
+
21
+ export const homeController = (req: SprintRequest, res: SprintResponse) => {
22
+ res.json({
23
+ message: "Hello World",
24
+ status: "ok"
25
+ });
26
+ };
27
+
28
+ export const jwtValidateController = (req: SprintRequest, res: SprintResponse) => {
29
+ return res.json(req.custom.user);
30
+ };
31
+ `;
32
+ };
33
+
34
+ export function getAdminController(language: string) {
35
+ if (language === "typescript") {
36
+ return `import { Handler, SprintRequest, SprintResponse } from "sprint-es";
37
+ import { signEncrypted, getJwtFromEnv } from "sprint-es/jwt";
38
+
39
+ export const adminController: Handler = (req: SprintRequest, res: SprintResponse) => {
40
+ res.json({
41
+ message: "Admin Dashboard",
42
+ status: "ok"
43
+ });
44
+ };
45
+
46
+ export const adminUsersController: Handler = (req: SprintRequest, res: SprintResponse) => {
47
+ res.json({
48
+ users: [
49
+ { id: 1, name: "John Doe", role: "admin" },
50
+ { id: 2, name: "Jane Smith", role: "user" }
51
+ ]
52
+ });
53
+ };
54
+
55
+ const { privateKey, encryptionSecret } = getJwtFromEnv();
56
+
57
+ export const jwtGenerateController: Handler = (req: SprintRequest, res: SprintResponse) => {
58
+ const { userId, role } = req.body || {};
59
+
60
+ try {
61
+ const payload = { userId, role: role || "user" };
62
+ const token = signEncrypted(payload, privateKey, encryptionSecret, { expiresIn: "1h" });
63
+ res.json({ token });
64
+ } catch (error) {
65
+ return res.status(500).json({ error: "JWT not configured" });
66
+ }
67
+ };
68
+ `;
69
+ } else {
70
+ return `import { Handler, SprintRequest, SprintResponse } from "sprint-es";
71
+ import { signEncrypted, getJwtFromEnv } from "sprint-es/jwt";
72
+
73
+ export const adminController = (req: SprintRequest, res: SprintResponse) => {
74
+ res.json({
75
+ message: "Admin Dashboard",
76
+ status: "ok"
77
+ });
78
+ };
79
+
80
+ export const adminUsersController = (req: SprintRequest, res: SprintResponse) => {
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
+ const { privateKey, encryptionSecret } = getJwtFromEnv();
90
+
91
+ export const jwtGenerateController = (req: SprintRequest, res: SprintResponse) => {
92
+ const { userId, role } = req.body || {};
93
+
94
+ try {
95
+ const payload = { userId, role: role || "user" };
96
+ const token = signEncrypted(payload, privateKey, encryptionSecret, { expiresIn: "1h" });
97
+ res.json({ token });
98
+ } catch (error) {
99
+ return res.status(500).json({ error: "JWT not configured" });
100
+ }
101
+ };
102
+ `;
103
+ }
104
+ };
@@ -0,0 +1,24 @@
1
+ export function getExampleCronJob(language: string) {
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
+ };
@@ -0,0 +1,48 @@
1
+ export function getDockerfile(language: string) {
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: string) {
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
+ };
@@ -0,0 +1,76 @@
1
+ import * as crypto from "node:crypto";
2
+ import { generateJWTKeys } from "./packageJson.js";
3
+
4
+ export function getEnvExample(telemetry: string) {
5
+ let env = `PORT=5000
6
+
7
+ JWT_PUBLIC_KEY=""
8
+ JWT_PRIVATE_KEY=""
9
+ JWT_ENCRYPTION_SECRET=""
10
+
11
+ # Development: npm run dev (NODE_ENV=development)
12
+ # Production: npm start (NODE_ENV=production)
13
+ `;
14
+
15
+ if (telemetry === "sentry" || telemetry === "glitchtip") {
16
+ env += `
17
+ # Sentry / GlitchTip (use GlitchTip DSN for self-hosted)
18
+ SENTRY_DSN=""
19
+ `;
20
+ } else if (telemetry === "discord") {
21
+ env += `
22
+ # Discord Webhook URL for error notifications
23
+ DISCORD_TELEMETRY_WEBHOOK_URL=""
24
+ `;
25
+ }
26
+
27
+ return env;
28
+ };
29
+
30
+ export function getEnvDevelopment(telemetry: string) {
31
+ const keys = generateJWTKeys();
32
+ let env = `NODE_ENV=development
33
+ PORT=5000
34
+ JWT_PUBLIC_KEY='${keys.publicKey}'
35
+ JWT_PRIVATE_KEY='${keys.privateKey}'
36
+ JWT_ENCRYPTION_SECRET='${crypto.randomBytes(32).toString("hex")}'
37
+ `;
38
+
39
+ if (telemetry === "sentry" || telemetry === "glitchtip") {
40
+ env += `
41
+ # Sentry / GlitchTip
42
+ SENTRY_DSN=""
43
+ `;
44
+ } else if (telemetry === "discord") {
45
+ env += `
46
+ # Discord Webhook URL
47
+ DISCORD_TELEMETRY_WEBHOOK_URL=""
48
+ `;
49
+ }
50
+
51
+ return env;
52
+ };
53
+
54
+ export function getEnvProduction(telemetry: string) {
55
+ const keys = generateJWTKeys();
56
+ let env = `NODE_ENV=production
57
+ PORT=5000
58
+ JWT_PUBLIC_KEY='${keys.publicKey}'
59
+ JWT_PRIVATE_KEY='${keys.privateKey}'
60
+ JWT_ENCRYPTION_SECRET='${crypto.randomBytes(32).toString("hex")}'
61
+ `;
62
+
63
+ if (telemetry === "sentry" || telemetry === "glitchtip") {
64
+ env += `
65
+ # Sentry / GlitchTip
66
+ SENTRY_DSN=
67
+ `;
68
+ } else if (telemetry === "discord") {
69
+ env += `
70
+ # Discord Webhook URL
71
+ DISCORD_TELEMETRY_WEBHOOK_URL=
72
+ `;
73
+ }
74
+
75
+ return env;
76
+ };
@@ -0,0 +1,29 @@
1
+ // Package JSON
2
+ export { generateJWTKeys, getTypeScriptPackageJson, getJavaScriptPackageJson } from "./packageJson.js";
3
+
4
+ // Config Files (tsconfig, vite.config, sprint.config)
5
+ export { getTsConfig, getViteConfig, getSprintConfigFile } from "./configFiles.js";
6
+
7
+ // Environment Files
8
+ export { getEnvExample, getEnvDevelopment, getEnvProduction } from "./env.js";
9
+
10
+ // Routes
11
+ export { getMainFile, getHomeRoute, getAdminRoute } from "./routes.js";
12
+
13
+ // Controllers
14
+ export { getHomeController, getAdminController } from "./controllers.js";
15
+
16
+ // Middlewares
17
+ export { getInternalAuthMiddleware, getUserAuthMiddleware } from "./middlewares.js";
18
+
19
+ // Schemas
20
+ export { getHomeSchema, getAdminSchema } from "./schemas.js";
21
+
22
+ // Cronjobs
23
+ export { getExampleCronJob } from "./cronjobs.js";
24
+
25
+ // Docker
26
+ export { getDockerfile, getDockerCompose } from "./docker.js";
27
+
28
+ // Misc
29
+ export { getGitignore, getDockerIgnore } from "./misc.js";
@@ -0,0 +1,97 @@
1
+ export function getInternalAuthMiddleware(language: string) {
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: string) {
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, getJwtFromEnv } from "sprint-es/jwt";
73
+
74
+ const { publicKey, encryptionSecret } = getJwtFromEnv();
75
+
76
+ export default defineMiddleware({
77
+ name: "userAuth",
78
+ priority: 10,
79
+ include: "/**",
80
+ exclude: "/admin/**",
81
+ handler: (req, res, next) => {
82
+ const auth = req.sprint.getAuthorization();
83
+ if (!auth) return res.status(401).json({ error: "No authorization header" });
84
+
85
+ const token = auth.replace("Bearer ", "");
86
+
87
+ const decoded = verifyEncrypted(token, publicKey, encryptionSecret);
88
+
89
+ if (!decoded) return res.status(403).json({ error: "Invalid token" });
90
+
91
+ req.custom.user = decoded;
92
+
93
+ next();
94
+ }
95
+ });
96
+ `;
97
+ };
@@ -0,0 +1,60 @@
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
+ };
@@ -0,0 +1,75 @@
1
+ import * as crypto from "node:crypto";
2
+
3
+ export interface JWTKeys {
4
+ publicKey: string;
5
+ privateKey: string;
6
+ }
7
+
8
+ export function generateJWTKeys(): JWTKeys {
9
+ const keys = crypto.generateKeyPairSync("rsa", {
10
+ modulusLength: 4096,
11
+ publicKeyEncoding: { type: "spki", format: "pem" },
12
+ privateKeyEncoding: { type: "pkcs8", format: "pem" }
13
+ }) as unknown as { publicKey: string; privateKey: string };
14
+ return keys;
15
+ };
16
+
17
+ export function getTypeScriptPackageJson(name: string, telemetry: string) {
18
+ const deps: Record<string, string> = {
19
+ "sprint-es": "^0.0.54"
20
+ };
21
+
22
+ const devDeps: Record<string, string> = {
23
+ "@types/node": "^22.0.0",
24
+ "tsx": "^4.19.0",
25
+ typescript: "^5.6.0",
26
+ };
27
+
28
+ if (telemetry === "sentry" || telemetry === "glitchtip") {
29
+ deps["@sentry/node"] = "^8.0.0";
30
+ } else if (telemetry === "discord") {
31
+ deps["axios"] = "^1.6.0";
32
+ }
33
+
34
+ return {
35
+ name: name === "." ? "sprint-app" : name,
36
+ version: "0.0.1",
37
+ description: "Sprint API",
38
+ main: "dist/index.js",
39
+ scripts: {
40
+ build: "sprint-es build",
41
+ start: "sprint-es start",
42
+ dev: "sprint-es dev",
43
+ "generate:keys": "sprint-es generate-keys"
44
+ },
45
+ dependencies: deps,
46
+ devDependencies: devDeps,
47
+ };
48
+ };
49
+
50
+ export function getJavaScriptPackageJson(name: string, telemetry: string) {
51
+ const deps: Record<string, string> = {
52
+ "sprint-es": "^0.0.54"
53
+ };
54
+
55
+ if (telemetry === "sentry" || telemetry === "glitchtip") {
56
+ deps["@sentry/node"] = "^8.0.0";
57
+ } else if (telemetry === "discord") {
58
+ deps["axios"] = "^1.6.0";
59
+ }
60
+
61
+ return {
62
+ name: name === "." ? "sprint-app" : name,
63
+ version: "0.0.1",
64
+ description: "Sprint API",
65
+ main: "src/index.js",
66
+ type: "module",
67
+ scripts: {
68
+ build: "sprint-es build",
69
+ start: "sprint-es start",
70
+ dev: "sprint-es dev",
71
+ "generate:keys": "sprint-es generate-keys"
72
+ },
73
+ dependencies: deps
74
+ };
75
+ };