create-sprint 0.0.36 → 0.0.38
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 +82 -8
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/src/generators.ts +84 -8
- package/src/index.ts +2 -2
package/dist/generators.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
export function generateJWT_SECRET() {
|
|
3
|
+
return randomBytes(32).toString("hex");
|
|
4
|
+
}
|
|
1
5
|
export function getTypeScriptPackageJson(name, telemetry) {
|
|
2
6
|
const deps = {
|
|
3
|
-
"sprint-es": "^0.0.
|
|
4
|
-
"node-cron": "^3.0.3",
|
|
5
|
-
dotenv: "^17.0.0",
|
|
7
|
+
"sprint-es": "^0.0.37",
|
|
6
8
|
};
|
|
7
9
|
const devDeps = {
|
|
8
10
|
"@types/node": "^22.0.0",
|
|
@@ -24,6 +26,7 @@ export function getTypeScriptPackageJson(name, telemetry) {
|
|
|
24
26
|
build: "sprint-es build",
|
|
25
27
|
start: "sprint-es start",
|
|
26
28
|
dev: "sprint-es dev",
|
|
29
|
+
"generate:keys": "sprint-es generate-keys"
|
|
27
30
|
},
|
|
28
31
|
dependencies: deps,
|
|
29
32
|
devDependencies: devDeps,
|
|
@@ -31,9 +34,7 @@ export function getTypeScriptPackageJson(name, telemetry) {
|
|
|
31
34
|
}
|
|
32
35
|
export function getJavaScriptPackageJson(name, telemetry) {
|
|
33
36
|
const deps = {
|
|
34
|
-
"sprint-es": "^0.0.
|
|
35
|
-
"node-cron": "^3.0.3",
|
|
36
|
-
dotenv: "^17.0.0",
|
|
37
|
+
"sprint-es": "^0.0.37",
|
|
37
38
|
};
|
|
38
39
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
39
40
|
deps["@sentry/node"] = "^8.0.0";
|
|
@@ -51,6 +52,7 @@ export function getJavaScriptPackageJson(name, telemetry) {
|
|
|
51
52
|
build: "sprint-es build",
|
|
52
53
|
start: "sprint-es start",
|
|
53
54
|
dev: "sprint-es dev",
|
|
55
|
+
"generate:keys": "sprint-es generate-keys"
|
|
54
56
|
},
|
|
55
57
|
dependencies: deps,
|
|
56
58
|
};
|
|
@@ -147,24 +149,28 @@ export function getAdminRoute(language) {
|
|
|
147
149
|
if (language === "typescript") {
|
|
148
150
|
return `import { Router } from "sprint-es";
|
|
149
151
|
import { adminSchema } from "@/schemas/admin";
|
|
150
|
-
import { adminController, adminUsersController } from "@/controllers/admin";
|
|
152
|
+
import { adminController, adminUsersController, jwtGenerateController, jwtValidateController } from "@/controllers/admin";
|
|
151
153
|
|
|
152
154
|
const router = Router();
|
|
153
155
|
|
|
154
156
|
router.get("/", adminSchema, adminController);
|
|
155
157
|
router.get("/users", adminSchema, adminUsersController);
|
|
158
|
+
router.post("/jwt/generate", jwtGenerateController);
|
|
159
|
+
router.post("/jwt/validate", jwtValidateController);
|
|
156
160
|
|
|
157
161
|
export default router;
|
|
158
162
|
`;
|
|
159
163
|
}
|
|
160
164
|
return `import { Router } from "sprint-es";
|
|
161
165
|
import { adminSchema } from "../schemas/admin.js";
|
|
162
|
-
import { adminController, adminUsersController } from "../controllers/admin.js";
|
|
166
|
+
import { adminController, adminUsersController, jwtGenerateController, jwtValidateController } from "../controllers/admin.js";
|
|
163
167
|
|
|
164
168
|
const router = Router();
|
|
165
169
|
|
|
166
170
|
router.get("/", adminSchema, adminController);
|
|
167
171
|
router.get("/users", adminSchema, adminUsersController);
|
|
172
|
+
router.post("/jwt/generate", jwtGenerateController);
|
|
173
|
+
router.post("/jwt/validate", jwtValidateController);
|
|
168
174
|
|
|
169
175
|
export default router;
|
|
170
176
|
`;
|
|
@@ -194,6 +200,9 @@ export const homeController = (req, res) => {
|
|
|
194
200
|
export function getAdminController(language) {
|
|
195
201
|
if (language === "typescript") {
|
|
196
202
|
return `import { Handler } from "sprint-es";
|
|
203
|
+
import { signEncrypted, verifyEncrypted } from "sprint-es/jwt";
|
|
204
|
+
|
|
205
|
+
const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key-change-in-production";
|
|
197
206
|
|
|
198
207
|
export const adminController: Handler = (req, res) => {
|
|
199
208
|
res.json({
|
|
@@ -210,9 +219,41 @@ export const adminUsersController: Handler = (req, res) => {
|
|
|
210
219
|
]
|
|
211
220
|
});
|
|
212
221
|
};
|
|
222
|
+
|
|
223
|
+
export const jwtGenerateController: Handler = (req, res) => {
|
|
224
|
+
const { userId, role } = req.body || {};
|
|
225
|
+
|
|
226
|
+
if (!userId) {
|
|
227
|
+
return res.status(400).json({ error: "userId is required" });
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const payload = { userId, role: role || "user" };
|
|
231
|
+
const token = signEncrypted(payload, JWT_SECRET, { expiresIn: "1h" });
|
|
232
|
+
|
|
233
|
+
res.json({ token });
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
export const jwtValidateController: Handler = (req, res) => {
|
|
237
|
+
const token = req.sprint?.getAuthorization() || req.headers.authorization;
|
|
238
|
+
|
|
239
|
+
if (!token) {
|
|
240
|
+
return res.status(401).json({ error: "No token provided" });
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const decoded = verifyEncrypted(token, JWT_SECRET);
|
|
244
|
+
|
|
245
|
+
if (!decoded) {
|
|
246
|
+
return res.status(401).json({ error: "Invalid token" });
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
res.json({ valid: true, payload: decoded });
|
|
250
|
+
};
|
|
213
251
|
`;
|
|
214
252
|
}
|
|
215
253
|
return `import { Handler } from "sprint-es";
|
|
254
|
+
import { signEncrypted, verifyEncrypted } from "sprint-es/jwt";
|
|
255
|
+
|
|
256
|
+
const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key-change-in-production";
|
|
216
257
|
|
|
217
258
|
export const adminController = (req, res) => {
|
|
218
259
|
res.json({
|
|
@@ -229,6 +270,35 @@ export const adminUsersController = (req, res) => {
|
|
|
229
270
|
]
|
|
230
271
|
});
|
|
231
272
|
};
|
|
273
|
+
|
|
274
|
+
export const jwtGenerateController = (req, res) => {
|
|
275
|
+
const { userId, role } = req.body || {};
|
|
276
|
+
|
|
277
|
+
if (!userId) {
|
|
278
|
+
return res.status(400).json({ error: "userId is required" });
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const payload = { userId, role: role || "user" };
|
|
282
|
+
const token = signEncrypted(payload, JWT_SECRET, { expiresIn: "1h" });
|
|
283
|
+
|
|
284
|
+
res.json({ token });
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
export const jwtValidateController = (req, res) => {
|
|
288
|
+
const token = req.sprint?.getAuthorization() || req.headers.authorization;
|
|
289
|
+
|
|
290
|
+
if (!token) {
|
|
291
|
+
return res.status(401).json({ error: "No token provided" });
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const decoded = verifyEncrypted(token, JWT_SECRET);
|
|
295
|
+
|
|
296
|
+
if (!decoded) {
|
|
297
|
+
return res.status(401).json({ error: "Invalid token" });
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
res.json({ valid: true, payload: decoded });
|
|
301
|
+
};
|
|
232
302
|
`;
|
|
233
303
|
}
|
|
234
304
|
export function getHomeSchema(language) {
|
|
@@ -511,8 +581,10 @@ DISCORD_WEBHOOK_URL=
|
|
|
511
581
|
return env;
|
|
512
582
|
}
|
|
513
583
|
export function getEnvDevelopment(telemetry) {
|
|
584
|
+
const jwtSecret = generateJWT_SECRET();
|
|
514
585
|
let env = `NODE_ENV=development
|
|
515
586
|
PORT=3000
|
|
587
|
+
JWT_SECRET=${jwtSecret}
|
|
516
588
|
`;
|
|
517
589
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
518
590
|
env += `
|
|
@@ -529,8 +601,10 @@ DISCORD_WEBHOOK_URL=
|
|
|
529
601
|
return env;
|
|
530
602
|
}
|
|
531
603
|
export function getEnvProduction(telemetry) {
|
|
604
|
+
const jwtSecret = generateJWT_SECRET();
|
|
532
605
|
let env = `NODE_ENV=production
|
|
533
606
|
PORT=3000
|
|
607
|
+
JWT_SECRET=${jwtSecret}
|
|
534
608
|
`;
|
|
535
609
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
536
610
|
env += `
|
package/dist/index.js
CHANGED
|
@@ -193,8 +193,8 @@ async function createProject(projectName, language, telemetryArg, useDockerArg)
|
|
|
193
193
|
await writeFile(join(srcDir, "cronjobs", "example." + (language === "typescript" ? "ts" : "js")), getExampleCronJob(language));
|
|
194
194
|
await writeFile(join(targetDir, ".env.development.example"), getEnvDevelopment(telemetry));
|
|
195
195
|
await writeFile(join(targetDir, ".env.production.example"), getEnvProduction(telemetry));
|
|
196
|
-
await writeFile(join(targetDir, ".env.development"),
|
|
197
|
-
await writeFile(join(targetDir, ".env.production"),
|
|
196
|
+
await writeFile(join(targetDir, ".env.development"), getEnvDevelopment(telemetry));
|
|
197
|
+
await writeFile(join(targetDir, ".env.production"), getEnvProduction(telemetry));
|
|
198
198
|
await writeFile(join(targetDir, ".gitignore"), getGitignore());
|
|
199
199
|
if (useDocker) {
|
|
200
200
|
await writeFile(join(targetDir, "Dockerfile"), getDockerfile(language));
|
package/package.json
CHANGED
package/src/generators.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
export function generateJWT_SECRET(): string {
|
|
4
|
+
return randomBytes(32).toString("hex");
|
|
5
|
+
}
|
|
6
|
+
|
|
1
7
|
export function getTypeScriptPackageJson(name: string, telemetry: string) {
|
|
2
8
|
const deps: Record<string, string> = {
|
|
3
|
-
"sprint-es": "^0.0.
|
|
4
|
-
"node-cron": "^3.0.3",
|
|
5
|
-
dotenv: "^17.0.0",
|
|
9
|
+
"sprint-es": "^0.0.37",
|
|
6
10
|
};
|
|
7
11
|
|
|
8
12
|
const devDeps: Record<string, string> = {
|
|
@@ -26,6 +30,7 @@ export function getTypeScriptPackageJson(name: string, telemetry: string) {
|
|
|
26
30
|
build: "sprint-es build",
|
|
27
31
|
start: "sprint-es start",
|
|
28
32
|
dev: "sprint-es dev",
|
|
33
|
+
"generate:keys": "sprint-es generate-keys"
|
|
29
34
|
},
|
|
30
35
|
dependencies: deps,
|
|
31
36
|
devDependencies: devDeps,
|
|
@@ -34,9 +39,7 @@ export function getTypeScriptPackageJson(name: string, telemetry: string) {
|
|
|
34
39
|
|
|
35
40
|
export function getJavaScriptPackageJson(name: string, telemetry: string) {
|
|
36
41
|
const deps: Record<string, string> = {
|
|
37
|
-
"sprint-es": "^0.0.
|
|
38
|
-
"node-cron": "^3.0.3",
|
|
39
|
-
dotenv: "^17.0.0",
|
|
42
|
+
"sprint-es": "^0.0.37",
|
|
40
43
|
};
|
|
41
44
|
|
|
42
45
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
@@ -55,6 +58,7 @@ export function getJavaScriptPackageJson(name: string, telemetry: string) {
|
|
|
55
58
|
build: "sprint-es build",
|
|
56
59
|
start: "sprint-es start",
|
|
57
60
|
dev: "sprint-es dev",
|
|
61
|
+
"generate:keys": "sprint-es generate-keys"
|
|
58
62
|
},
|
|
59
63
|
dependencies: deps,
|
|
60
64
|
};
|
|
@@ -157,24 +161,28 @@ export function getAdminRoute(language: string) {
|
|
|
157
161
|
if (language === "typescript") {
|
|
158
162
|
return `import { Router } from "sprint-es";
|
|
159
163
|
import { adminSchema } from "@/schemas/admin";
|
|
160
|
-
import { adminController, adminUsersController } from "@/controllers/admin";
|
|
164
|
+
import { adminController, adminUsersController, jwtGenerateController, jwtValidateController } from "@/controllers/admin";
|
|
161
165
|
|
|
162
166
|
const router = Router();
|
|
163
167
|
|
|
164
168
|
router.get("/", adminSchema, adminController);
|
|
165
169
|
router.get("/users", adminSchema, adminUsersController);
|
|
170
|
+
router.post("/jwt/generate", jwtGenerateController);
|
|
171
|
+
router.post("/jwt/validate", jwtValidateController);
|
|
166
172
|
|
|
167
173
|
export default router;
|
|
168
174
|
`;
|
|
169
175
|
}
|
|
170
176
|
return `import { Router } from "sprint-es";
|
|
171
177
|
import { adminSchema } from "../schemas/admin.js";
|
|
172
|
-
import { adminController, adminUsersController } from "../controllers/admin.js";
|
|
178
|
+
import { adminController, adminUsersController, jwtGenerateController, jwtValidateController } from "../controllers/admin.js";
|
|
173
179
|
|
|
174
180
|
const router = Router();
|
|
175
181
|
|
|
176
182
|
router.get("/", adminSchema, adminController);
|
|
177
183
|
router.get("/users", adminSchema, adminUsersController);
|
|
184
|
+
router.post("/jwt/generate", jwtGenerateController);
|
|
185
|
+
router.post("/jwt/validate", jwtValidateController);
|
|
178
186
|
|
|
179
187
|
export default router;
|
|
180
188
|
`;
|
|
@@ -206,6 +214,9 @@ export const homeController = (req, res) => {
|
|
|
206
214
|
export function getAdminController(language: string) {
|
|
207
215
|
if (language === "typescript") {
|
|
208
216
|
return `import { Handler } from "sprint-es";
|
|
217
|
+
import { signEncrypted, verifyEncrypted } from "sprint-es/jwt";
|
|
218
|
+
|
|
219
|
+
const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key-change-in-production";
|
|
209
220
|
|
|
210
221
|
export const adminController: Handler = (req, res) => {
|
|
211
222
|
res.json({
|
|
@@ -222,9 +233,41 @@ export const adminUsersController: Handler = (req, res) => {
|
|
|
222
233
|
]
|
|
223
234
|
});
|
|
224
235
|
};
|
|
236
|
+
|
|
237
|
+
export const jwtGenerateController: Handler = (req, res) => {
|
|
238
|
+
const { userId, role } = req.body || {};
|
|
239
|
+
|
|
240
|
+
if (!userId) {
|
|
241
|
+
return res.status(400).json({ error: "userId is required" });
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const payload = { userId, role: role || "user" };
|
|
245
|
+
const token = signEncrypted(payload, JWT_SECRET, { expiresIn: "1h" });
|
|
246
|
+
|
|
247
|
+
res.json({ token });
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
export const jwtValidateController: Handler = (req, res) => {
|
|
251
|
+
const token = req.sprint?.getAuthorization() || req.headers.authorization;
|
|
252
|
+
|
|
253
|
+
if (!token) {
|
|
254
|
+
return res.status(401).json({ error: "No token provided" });
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const decoded = verifyEncrypted(token, JWT_SECRET);
|
|
258
|
+
|
|
259
|
+
if (!decoded) {
|
|
260
|
+
return res.status(401).json({ error: "Invalid token" });
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
res.json({ valid: true, payload: decoded });
|
|
264
|
+
};
|
|
225
265
|
`;
|
|
226
266
|
}
|
|
227
267
|
return `import { Handler } from "sprint-es";
|
|
268
|
+
import { signEncrypted, verifyEncrypted } from "sprint-es/jwt";
|
|
269
|
+
|
|
270
|
+
const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key-change-in-production";
|
|
228
271
|
|
|
229
272
|
export const adminController = (req, res) => {
|
|
230
273
|
res.json({
|
|
@@ -241,6 +284,35 @@ export const adminUsersController = (req, res) => {
|
|
|
241
284
|
]
|
|
242
285
|
});
|
|
243
286
|
};
|
|
287
|
+
|
|
288
|
+
export const jwtGenerateController = (req, res) => {
|
|
289
|
+
const { userId, role } = req.body || {};
|
|
290
|
+
|
|
291
|
+
if (!userId) {
|
|
292
|
+
return res.status(400).json({ error: "userId is required" });
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const payload = { userId, role: role || "user" };
|
|
296
|
+
const token = signEncrypted(payload, JWT_SECRET, { expiresIn: "1h" });
|
|
297
|
+
|
|
298
|
+
res.json({ token });
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
export const jwtValidateController = (req, res) => {
|
|
302
|
+
const token = req.sprint?.getAuthorization() || req.headers.authorization;
|
|
303
|
+
|
|
304
|
+
if (!token) {
|
|
305
|
+
return res.status(401).json({ error: "No token provided" });
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const decoded = verifyEncrypted(token, JWT_SECRET);
|
|
309
|
+
|
|
310
|
+
if (!decoded) {
|
|
311
|
+
return res.status(401).json({ error: "Invalid token" });
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
res.json({ valid: true, payload: decoded });
|
|
315
|
+
};
|
|
244
316
|
`;
|
|
245
317
|
}
|
|
246
318
|
|
|
@@ -537,8 +609,10 @@ DISCORD_WEBHOOK_URL=
|
|
|
537
609
|
}
|
|
538
610
|
|
|
539
611
|
export function getEnvDevelopment(telemetry: string) {
|
|
612
|
+
const jwtSecret = generateJWT_SECRET();
|
|
540
613
|
let env = `NODE_ENV=development
|
|
541
614
|
PORT=3000
|
|
615
|
+
JWT_SECRET=${jwtSecret}
|
|
542
616
|
`;
|
|
543
617
|
|
|
544
618
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
@@ -557,8 +631,10 @@ DISCORD_WEBHOOK_URL=
|
|
|
557
631
|
}
|
|
558
632
|
|
|
559
633
|
export function getEnvProduction(telemetry: string) {
|
|
634
|
+
const jwtSecret = generateJWT_SECRET();
|
|
560
635
|
let env = `NODE_ENV=production
|
|
561
636
|
PORT=3000
|
|
637
|
+
JWT_SECRET=${jwtSecret}
|
|
562
638
|
`;
|
|
563
639
|
|
|
564
640
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
package/src/index.ts
CHANGED
|
@@ -232,8 +232,8 @@ async function createProject(
|
|
|
232
232
|
await writeFile(join(targetDir, ".env.development.example"), getEnvDevelopment(telemetry));
|
|
233
233
|
await writeFile(join(targetDir, ".env.production.example"), getEnvProduction(telemetry));
|
|
234
234
|
|
|
235
|
-
await writeFile(join(targetDir, ".env.development"),
|
|
236
|
-
await writeFile(join(targetDir, ".env.production"),
|
|
235
|
+
await writeFile(join(targetDir, ".env.development"), getEnvDevelopment(telemetry));
|
|
236
|
+
await writeFile(join(targetDir, ".env.production"), getEnvProduction(telemetry));
|
|
237
237
|
|
|
238
238
|
await writeFile(join(targetDir, ".gitignore"), getGitignore());
|
|
239
239
|
|