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.
@@ -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.35",
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",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-sprint",
3
- "version": "0.0.36",
3
+ "version": "0.0.38",
4
4
  "description": "Create a new Sprint API project",
5
5
  "type": "module",
6
6
  "bin": {
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.35",
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.35",
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