create-sprint 0.0.44 → 0.0.48
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 +38 -29
- package/dist/index.js +20 -3
- package/package.json +1 -1
- package/src/generators.ts +40 -30
- package/src/index.ts +18 -4
package/dist/generators.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
2
|
export function generateJWTKeys() {
|
|
3
|
-
const
|
|
3
|
+
const keys = crypto.generateKeyPairSync("ec", {
|
|
4
4
|
namedCurve: "prime256v1",
|
|
5
5
|
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
6
6
|
privateKeyEncoding: { type: "pkcs8", format: "pem" }
|
|
7
7
|
});
|
|
8
|
-
return
|
|
8
|
+
return keys;
|
|
9
9
|
}
|
|
10
10
|
export function getTypeScriptPackageJson(name, telemetry) {
|
|
11
11
|
const deps = {
|
|
@@ -65,10 +65,11 @@ export function getJavaScriptPackageJson(name, telemetry) {
|
|
|
65
65
|
export function getTsConfig() {
|
|
66
66
|
return JSON.stringify({
|
|
67
67
|
compilerOptions: {
|
|
68
|
-
target: "
|
|
69
|
-
module: "
|
|
70
|
-
moduleResolution: "
|
|
71
|
-
lib: ["
|
|
68
|
+
target: "ES2022",
|
|
69
|
+
module: "NodeNext",
|
|
70
|
+
moduleResolution: "NodeNext",
|
|
71
|
+
lib: ["ES2022"],
|
|
72
|
+
types: ["node"],
|
|
72
73
|
outDir: "./dist",
|
|
73
74
|
rootDir: "./src",
|
|
74
75
|
strict: true,
|
|
@@ -79,7 +80,6 @@ export function getTsConfig() {
|
|
|
79
80
|
declaration: true,
|
|
80
81
|
declarationMap: true,
|
|
81
82
|
sourceMap: true,
|
|
82
|
-
tabWidth: 4,
|
|
83
83
|
baseUrl: ".",
|
|
84
84
|
paths: {
|
|
85
85
|
"@/*": ["./src/*"]
|
|
@@ -153,28 +153,28 @@ export default router;
|
|
|
153
153
|
export function getAdminRoute(language) {
|
|
154
154
|
if (language === "typescript") {
|
|
155
155
|
return `import { Router } from "sprint-es";
|
|
156
|
-
import { adminSchema } from "@/schemas/admin";
|
|
156
|
+
import { adminSchema, jwtGenerateSchema } from "@/schemas/admin";
|
|
157
157
|
import { adminController, adminUsersController, jwtGenerateController, jwtValidateController } from "@/controllers/admin";
|
|
158
158
|
|
|
159
159
|
const router = Router();
|
|
160
160
|
|
|
161
161
|
router.get("/", adminSchema, adminController);
|
|
162
162
|
router.get("/users", adminSchema, adminUsersController);
|
|
163
|
-
router.post("/jwt/generate", jwtGenerateController);
|
|
163
|
+
router.post("/jwt/generate", jwtGenerateSchema, jwtGenerateController);
|
|
164
164
|
router.post("/jwt/validate", jwtValidateController);
|
|
165
165
|
|
|
166
166
|
export default router;
|
|
167
167
|
`;
|
|
168
168
|
}
|
|
169
169
|
return `import { Router } from "sprint-es";
|
|
170
|
-
import { adminSchema } from "../schemas/admin.js";
|
|
170
|
+
import { adminSchema, jwtGenerateSchema } from "../schemas/admin.js";
|
|
171
171
|
import { adminController, adminUsersController, jwtGenerateController, jwtValidateController } from "../controllers/admin.js";
|
|
172
172
|
|
|
173
173
|
const router = Router();
|
|
174
174
|
|
|
175
175
|
router.get("/", adminSchema, adminController);
|
|
176
176
|
router.get("/users", adminSchema, adminUsersController);
|
|
177
|
-
router.post("/jwt/generate", jwtGenerateController);
|
|
177
|
+
router.post("/jwt/generate", jwtGenerateSchema, jwtGenerateController);
|
|
178
178
|
router.post("/jwt/validate", jwtValidateController);
|
|
179
179
|
|
|
180
180
|
export default router;
|
|
@@ -226,10 +226,6 @@ export const adminUsersController: Handler = (req, res) => {
|
|
|
226
226
|
export const jwtGenerateController: Handler = (req, res) => {
|
|
227
227
|
const { userId, role } = req.body || {};
|
|
228
228
|
|
|
229
|
-
if (!userId) {
|
|
230
|
-
return res.status(400).json({ error: "userId is required" });
|
|
231
|
-
}
|
|
232
|
-
|
|
233
229
|
try {
|
|
234
230
|
const { privateKey } = getJwtFromEnv();
|
|
235
231
|
const payload = { userId, role: role || "user" };
|
|
@@ -284,10 +280,6 @@ export const adminUsersController = (req, res) => {
|
|
|
284
280
|
export const jwtGenerateController = (req, res) => {
|
|
285
281
|
const { userId, role } = req.body || {};
|
|
286
282
|
|
|
287
|
-
if (!userId) {
|
|
288
|
-
return res.status(400).json({ error: "userId is required" });
|
|
289
|
-
}
|
|
290
|
-
|
|
291
283
|
try {
|
|
292
284
|
const { privateKey } = getJwtFromEnv();
|
|
293
285
|
const payload = { userId, role: role || "user" };
|
|
@@ -345,6 +337,13 @@ export const adminSchema = defineRouteSchema({
|
|
|
345
337
|
email: z.string().email().optional()
|
|
346
338
|
})
|
|
347
339
|
});
|
|
340
|
+
|
|
341
|
+
export const jwtGenerateSchema = defineRouteSchema({
|
|
342
|
+
body: z.object({
|
|
343
|
+
userId: z.string().min(1),
|
|
344
|
+
role: z.string().optional()
|
|
345
|
+
})
|
|
346
|
+
});
|
|
348
347
|
`;
|
|
349
348
|
}
|
|
350
349
|
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
@@ -358,6 +357,13 @@ export const adminSchema = defineRouteSchema({
|
|
|
358
357
|
email: z.string().email().optional()
|
|
359
358
|
})
|
|
360
359
|
});
|
|
360
|
+
|
|
361
|
+
export const jwtGenerateSchema = defineRouteSchema({
|
|
362
|
+
body: z.object({
|
|
363
|
+
userId: z.string().min(1),
|
|
364
|
+
role: z.string().optional()
|
|
365
|
+
})
|
|
366
|
+
});
|
|
361
367
|
`;
|
|
362
368
|
}
|
|
363
369
|
export function getAuthMiddleware(language) {
|
|
@@ -580,7 +586,7 @@ initTelemetry({
|
|
|
580
586
|
return config;
|
|
581
587
|
}
|
|
582
588
|
export function getEnvExample(telemetry) {
|
|
583
|
-
let env = `PORT=
|
|
589
|
+
let env = `PORT=5000
|
|
584
590
|
|
|
585
591
|
# Development: npm run dev (NODE_ENV=development)
|
|
586
592
|
# Production: npm start (NODE_ENV=production)
|
|
@@ -599,12 +605,15 @@ DISCORD_WEBHOOK_URL=
|
|
|
599
605
|
}
|
|
600
606
|
return env;
|
|
601
607
|
}
|
|
608
|
+
function envKey(key) {
|
|
609
|
+
return key;
|
|
610
|
+
}
|
|
602
611
|
export function getEnvDevelopment(telemetry) {
|
|
603
|
-
const
|
|
612
|
+
const keys = generateJWTKeys();
|
|
604
613
|
let env = `NODE_ENV=development
|
|
605
|
-
PORT=
|
|
606
|
-
JWT_PUBLIC_KEY
|
|
607
|
-
JWT_PRIVATE_KEY
|
|
614
|
+
PORT=5000
|
|
615
|
+
JWT_PUBLIC_KEY='${keys.publicKey}'
|
|
616
|
+
JWT_PRIVATE_KEY='${keys.privateKey}'
|
|
608
617
|
`;
|
|
609
618
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
610
619
|
env += `
|
|
@@ -621,11 +630,11 @@ DISCORD_WEBHOOK_URL=
|
|
|
621
630
|
return env;
|
|
622
631
|
}
|
|
623
632
|
export function getEnvProduction(telemetry) {
|
|
624
|
-
const
|
|
633
|
+
const keys = generateJWTKeys();
|
|
625
634
|
let env = `NODE_ENV=production
|
|
626
|
-
PORT=
|
|
627
|
-
JWT_PUBLIC_KEY
|
|
628
|
-
JWT_PRIVATE_KEY
|
|
635
|
+
PORT=5000
|
|
636
|
+
JWT_PUBLIC_KEY='${keys.publicKey}'
|
|
637
|
+
JWT_PRIVATE_KEY='${keys.privateKey}'
|
|
629
638
|
`;
|
|
630
639
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
631
640
|
env += `
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
2
|
import { existsSync } from "fs";
|
|
3
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
3
|
+
import { mkdir, writeFile as fsWriteFile } from "fs/promises";
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import * as p from "@clack/prompts";
|
|
6
6
|
import { validateProjectName } from "./validators.js";
|
|
7
7
|
import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getViteConfig, getMainFile, getHomeRoute, getAdminRoute, getHomeController, getAdminController, getAuthMiddleware, getHomeSchema, getAdminSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction, getExampleCronJob } from "./generators.js";
|
|
8
|
+
export async function writeFile(path, content, options) {
|
|
9
|
+
if (typeof content === "string")
|
|
10
|
+
content = content.trimEnd();
|
|
11
|
+
await fsWriteFile(path, content, options);
|
|
12
|
+
}
|
|
13
|
+
;
|
|
8
14
|
export async function runCLI(args) {
|
|
9
15
|
const options = parseArgs(args);
|
|
10
16
|
p.intro("Sprint — Quickly API Framework");
|
|
@@ -47,7 +53,18 @@ export async function runCLI(args) {
|
|
|
47
53
|
const s2 = p.spinner();
|
|
48
54
|
s2.start("Installing dependencies");
|
|
49
55
|
try {
|
|
50
|
-
|
|
56
|
+
await new Promise((resolve, reject) => {
|
|
57
|
+
const child = spawn("npm", ["install"], {
|
|
58
|
+
cwd: targetDir,
|
|
59
|
+
stdio: "pipe"
|
|
60
|
+
});
|
|
61
|
+
child.on("close", (code) => {
|
|
62
|
+
if (code === 0)
|
|
63
|
+
resolve();
|
|
64
|
+
else
|
|
65
|
+
reject(new Error(`npm install exited with code ${code}`));
|
|
66
|
+
});
|
|
67
|
+
});
|
|
51
68
|
s2.stop("Dependencies installed");
|
|
52
69
|
}
|
|
53
70
|
catch {
|
package/package.json
CHANGED
package/src/generators.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
2
|
|
|
3
3
|
export interface JWTKeys {
|
|
4
4
|
publicKey: string;
|
|
@@ -6,12 +6,12 @@ export interface JWTKeys {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export function generateJWTKeys(): JWTKeys {
|
|
9
|
-
const
|
|
9
|
+
const keys = crypto.generateKeyPairSync("ec", {
|
|
10
10
|
namedCurve: "prime256v1",
|
|
11
11
|
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
12
12
|
privateKeyEncoding: { type: "pkcs8", format: "pem" }
|
|
13
|
-
});
|
|
14
|
-
return
|
|
13
|
+
}) as unknown as { publicKey: string; privateKey: string };
|
|
14
|
+
return keys;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export function getTypeScriptPackageJson(name: string, telemetry: string) {
|
|
@@ -77,10 +77,11 @@ export function getJavaScriptPackageJson(name: string, telemetry: string) {
|
|
|
77
77
|
export function getTsConfig() {
|
|
78
78
|
return JSON.stringify({
|
|
79
79
|
compilerOptions: {
|
|
80
|
-
target: "
|
|
81
|
-
module: "
|
|
82
|
-
moduleResolution: "
|
|
83
|
-
lib: ["
|
|
80
|
+
target: "ES2022",
|
|
81
|
+
module: "NodeNext",
|
|
82
|
+
moduleResolution: "NodeNext",
|
|
83
|
+
lib: ["ES2022"],
|
|
84
|
+
types: ["node"],
|
|
84
85
|
outDir: "./dist",
|
|
85
86
|
rootDir: "./src",
|
|
86
87
|
strict: true,
|
|
@@ -91,7 +92,6 @@ export function getTsConfig() {
|
|
|
91
92
|
declaration: true,
|
|
92
93
|
declarationMap: true,
|
|
93
94
|
sourceMap: true,
|
|
94
|
-
tabWidth: 4,
|
|
95
95
|
baseUrl: ".",
|
|
96
96
|
paths: {
|
|
97
97
|
"@/*": ["./src/*"]
|
|
@@ -170,28 +170,28 @@ export default router;
|
|
|
170
170
|
export function getAdminRoute(language: string) {
|
|
171
171
|
if (language === "typescript") {
|
|
172
172
|
return `import { Router } from "sprint-es";
|
|
173
|
-
import { adminSchema } from "@/schemas/admin";
|
|
173
|
+
import { adminSchema, jwtGenerateSchema } from "@/schemas/admin";
|
|
174
174
|
import { adminController, adminUsersController, jwtGenerateController, jwtValidateController } from "@/controllers/admin";
|
|
175
175
|
|
|
176
176
|
const router = Router();
|
|
177
177
|
|
|
178
178
|
router.get("/", adminSchema, adminController);
|
|
179
179
|
router.get("/users", adminSchema, adminUsersController);
|
|
180
|
-
router.post("/jwt/generate", jwtGenerateController);
|
|
180
|
+
router.post("/jwt/generate", jwtGenerateSchema, jwtGenerateController);
|
|
181
181
|
router.post("/jwt/validate", jwtValidateController);
|
|
182
182
|
|
|
183
183
|
export default router;
|
|
184
184
|
`;
|
|
185
185
|
}
|
|
186
186
|
return `import { Router } from "sprint-es";
|
|
187
|
-
import { adminSchema } from "../schemas/admin.js";
|
|
187
|
+
import { adminSchema, jwtGenerateSchema } from "../schemas/admin.js";
|
|
188
188
|
import { adminController, adminUsersController, jwtGenerateController, jwtValidateController } from "../controllers/admin.js";
|
|
189
189
|
|
|
190
190
|
const router = Router();
|
|
191
191
|
|
|
192
192
|
router.get("/", adminSchema, adminController);
|
|
193
193
|
router.get("/users", adminSchema, adminUsersController);
|
|
194
|
-
router.post("/jwt/generate", jwtGenerateController);
|
|
194
|
+
router.post("/jwt/generate", jwtGenerateSchema, jwtGenerateController);
|
|
195
195
|
router.post("/jwt/validate", jwtValidateController);
|
|
196
196
|
|
|
197
197
|
export default router;
|
|
@@ -245,10 +245,6 @@ export const adminUsersController: Handler = (req, res) => {
|
|
|
245
245
|
export const jwtGenerateController: Handler = (req, res) => {
|
|
246
246
|
const { userId, role } = req.body || {};
|
|
247
247
|
|
|
248
|
-
if (!userId) {
|
|
249
|
-
return res.status(400).json({ error: "userId is required" });
|
|
250
|
-
}
|
|
251
|
-
|
|
252
248
|
try {
|
|
253
249
|
const { privateKey } = getJwtFromEnv();
|
|
254
250
|
const payload = { userId, role: role || "user" };
|
|
@@ -303,10 +299,6 @@ export const adminUsersController = (req, res) => {
|
|
|
303
299
|
export const jwtGenerateController = (req, res) => {
|
|
304
300
|
const { userId, role } = req.body || {};
|
|
305
301
|
|
|
306
|
-
if (!userId) {
|
|
307
|
-
return res.status(400).json({ error: "userId is required" });
|
|
308
|
-
}
|
|
309
|
-
|
|
310
302
|
try {
|
|
311
303
|
const { privateKey } = getJwtFromEnv();
|
|
312
304
|
const payload = { userId, role: role || "user" };
|
|
@@ -366,6 +358,13 @@ export const adminSchema = defineRouteSchema({
|
|
|
366
358
|
email: z.string().email().optional()
|
|
367
359
|
})
|
|
368
360
|
});
|
|
361
|
+
|
|
362
|
+
export const jwtGenerateSchema = defineRouteSchema({
|
|
363
|
+
body: z.object({
|
|
364
|
+
userId: z.string().min(1),
|
|
365
|
+
role: z.string().optional()
|
|
366
|
+
})
|
|
367
|
+
});
|
|
369
368
|
`;
|
|
370
369
|
}
|
|
371
370
|
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
@@ -379,6 +378,13 @@ export const adminSchema = defineRouteSchema({
|
|
|
379
378
|
email: z.string().email().optional()
|
|
380
379
|
})
|
|
381
380
|
});
|
|
381
|
+
|
|
382
|
+
export const jwtGenerateSchema = defineRouteSchema({
|
|
383
|
+
body: z.object({
|
|
384
|
+
userId: z.string().min(1),
|
|
385
|
+
role: z.string().optional()
|
|
386
|
+
})
|
|
387
|
+
});
|
|
382
388
|
`;
|
|
383
389
|
}
|
|
384
390
|
|
|
@@ -611,7 +617,7 @@ initTelemetry({
|
|
|
611
617
|
}
|
|
612
618
|
|
|
613
619
|
export function getEnvExample(telemetry: string) {
|
|
614
|
-
let env = `PORT=
|
|
620
|
+
let env = `PORT=5000
|
|
615
621
|
|
|
616
622
|
# Development: npm run dev (NODE_ENV=development)
|
|
617
623
|
# Production: npm start (NODE_ENV=production)
|
|
@@ -632,12 +638,16 @@ DISCORD_WEBHOOK_URL=
|
|
|
632
638
|
return env;
|
|
633
639
|
}
|
|
634
640
|
|
|
641
|
+
function envKey(key: any): string {
|
|
642
|
+
return key;
|
|
643
|
+
}
|
|
644
|
+
|
|
635
645
|
export function getEnvDevelopment(telemetry: string) {
|
|
636
|
-
const
|
|
646
|
+
const keys = generateJWTKeys();
|
|
637
647
|
let env = `NODE_ENV=development
|
|
638
|
-
PORT=
|
|
639
|
-
JWT_PUBLIC_KEY
|
|
640
|
-
JWT_PRIVATE_KEY
|
|
648
|
+
PORT=5000
|
|
649
|
+
JWT_PUBLIC_KEY='${keys.publicKey}'
|
|
650
|
+
JWT_PRIVATE_KEY='${keys.privateKey}'
|
|
641
651
|
`;
|
|
642
652
|
|
|
643
653
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
@@ -656,11 +666,11 @@ DISCORD_WEBHOOK_URL=
|
|
|
656
666
|
}
|
|
657
667
|
|
|
658
668
|
export function getEnvProduction(telemetry: string) {
|
|
659
|
-
const
|
|
669
|
+
const keys = generateJWTKeys();
|
|
660
670
|
let env = `NODE_ENV=production
|
|
661
|
-
PORT=
|
|
662
|
-
JWT_PUBLIC_KEY
|
|
663
|
-
JWT_PRIVATE_KEY
|
|
671
|
+
PORT=5000
|
|
672
|
+
JWT_PUBLIC_KEY='${keys.publicKey}'
|
|
673
|
+
JWT_PRIVATE_KEY='${keys.privateKey}'
|
|
664
674
|
`;
|
|
665
675
|
|
|
666
676
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync } from "fs";
|
|
3
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { existsSync, writeFileSync } from "fs";
|
|
3
|
+
import { mkdir, writeFile as fsWriteFile } from "fs/promises";
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import * as p from "@clack/prompts";
|
|
6
6
|
import { validateProjectName } from "./validators.js";
|
|
@@ -15,6 +15,11 @@ export interface CLIOptions {
|
|
|
15
15
|
skipPrompts?: boolean;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
export async function writeFile(path: string, content: string, options?: any) {
|
|
19
|
+
if (typeof content === "string") content = content.trimEnd();
|
|
20
|
+
await fsWriteFile(path, content, options);
|
|
21
|
+
};
|
|
22
|
+
|
|
18
23
|
export async function runCLI(args: string[]) {
|
|
19
24
|
const options = parseArgs(args);
|
|
20
25
|
|
|
@@ -78,7 +83,16 @@ export async function runCLI(args: string[]) {
|
|
|
78
83
|
const s2 = p.spinner();
|
|
79
84
|
s2.start("Installing dependencies");
|
|
80
85
|
try {
|
|
81
|
-
|
|
86
|
+
await new Promise<void>((resolve, reject) => {
|
|
87
|
+
const child = spawn("npm", ["install"], {
|
|
88
|
+
cwd: targetDir,
|
|
89
|
+
stdio: "pipe"
|
|
90
|
+
});
|
|
91
|
+
child.on("close", (code) => {
|
|
92
|
+
if (code === 0) resolve();
|
|
93
|
+
else reject(new Error(`npm install exited with code ${code}`));
|
|
94
|
+
});
|
|
95
|
+
});
|
|
82
96
|
s2.stop("Dependencies installed");
|
|
83
97
|
} catch {
|
|
84
98
|
s2.stop("Install failed — run npm install manually");
|