create-sprint 0.0.8 → 0.0.34
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 -34
- package/dist/index.js +27 -34
- package/dist/validators.js +7 -12
- package/package.json +4 -3
- package/src/cli.ts +1 -1
- package/src/generators.ts +39 -34
- package/src/index.ts +33 -56
- package/src/validators.ts +10 -21
package/dist/generators.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export function getTypeScriptPackageJson(name, telemetry) {
|
|
2
2
|
const deps = {
|
|
3
|
-
"sprint-es": "^0.0.
|
|
4
|
-
"
|
|
3
|
+
"sprint-es": "^0.0.35",
|
|
4
|
+
"node-cron": "^3.0.3",
|
|
5
5
|
dotenv: "^17.0.0",
|
|
6
6
|
};
|
|
7
7
|
const devDeps = {
|
|
@@ -21,9 +21,9 @@ export function getTypeScriptPackageJson(name, telemetry) {
|
|
|
21
21
|
description: "Sprint API",
|
|
22
22
|
main: "dist/index.js",
|
|
23
23
|
scripts: {
|
|
24
|
-
build: "sprint build",
|
|
25
|
-
start: "sprint start",
|
|
26
|
-
dev: "sprint dev",
|
|
24
|
+
build: "sprint-es build",
|
|
25
|
+
start: "sprint-es start",
|
|
26
|
+
dev: "sprint-es dev",
|
|
27
27
|
},
|
|
28
28
|
dependencies: deps,
|
|
29
29
|
devDependencies: devDeps,
|
|
@@ -31,8 +31,8 @@ export function getTypeScriptPackageJson(name, telemetry) {
|
|
|
31
31
|
}
|
|
32
32
|
export function getJavaScriptPackageJson(name, telemetry) {
|
|
33
33
|
const deps = {
|
|
34
|
-
"sprint-es": "^0.0.
|
|
35
|
-
"
|
|
34
|
+
"sprint-es": "^0.0.35",
|
|
35
|
+
"node-cron": "^3.0.3",
|
|
36
36
|
dotenv: "^17.0.0",
|
|
37
37
|
};
|
|
38
38
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
@@ -48,9 +48,9 @@ export function getJavaScriptPackageJson(name, telemetry) {
|
|
|
48
48
|
main: "src/index.js",
|
|
49
49
|
type: "module",
|
|
50
50
|
scripts: {
|
|
51
|
-
build: "sprint build",
|
|
52
|
-
start: "sprint start",
|
|
53
|
-
dev: "sprint dev",
|
|
51
|
+
build: "sprint-es build",
|
|
52
|
+
start: "sprint-es start",
|
|
53
|
+
dev: "sprint-es dev",
|
|
54
54
|
},
|
|
55
55
|
dependencies: deps,
|
|
56
56
|
};
|
|
@@ -235,22 +235,12 @@ export function getHomeSchema(language) {
|
|
|
235
235
|
if (language === "typescript") {
|
|
236
236
|
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
237
237
|
|
|
238
|
-
export const homeSchema = defineRouteSchema({
|
|
239
|
-
input: z.object({
|
|
240
|
-
message: z.string(),
|
|
241
|
-
status: z.string()
|
|
242
|
-
})
|
|
243
|
-
});
|
|
238
|
+
export const homeSchema = defineRouteSchema({});
|
|
244
239
|
`;
|
|
245
240
|
}
|
|
246
241
|
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
247
242
|
|
|
248
|
-
export const homeSchema = defineRouteSchema({
|
|
249
|
-
input: z.object({
|
|
250
|
-
message: z.string(),
|
|
251
|
-
status: z.string()
|
|
252
|
-
})
|
|
253
|
-
});
|
|
243
|
+
export const homeSchema = defineRouteSchema({});
|
|
254
244
|
`;
|
|
255
245
|
}
|
|
256
246
|
export function getAdminSchema(language) {
|
|
@@ -258,16 +248,11 @@ export function getAdminSchema(language) {
|
|
|
258
248
|
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
259
249
|
|
|
260
250
|
export const adminSchema = defineRouteSchema({
|
|
261
|
-
|
|
251
|
+
queryParams: z.object({
|
|
262
252
|
id: z.string().uuid()
|
|
263
253
|
}),
|
|
264
254
|
body: z.object({
|
|
265
255
|
name: z.string().min(1),
|
|
266
|
-
email: z.email().optional()
|
|
267
|
-
}),
|
|
268
|
-
input: z.object({
|
|
269
|
-
id: z.string().uuid(),
|
|
270
|
-
name: z.string(),
|
|
271
256
|
email: z.string().email().optional()
|
|
272
257
|
})
|
|
273
258
|
});
|
|
@@ -276,16 +261,11 @@ export const adminSchema = defineRouteSchema({
|
|
|
276
261
|
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
277
262
|
|
|
278
263
|
export const adminSchema = defineRouteSchema({
|
|
279
|
-
|
|
264
|
+
queryParams: z.object({
|
|
280
265
|
id: z.string().uuid()
|
|
281
266
|
}),
|
|
282
267
|
body: z.object({
|
|
283
268
|
name: z.string().min(1),
|
|
284
|
-
email: z.email().optional()
|
|
285
|
-
}),
|
|
286
|
-
input: z.object({
|
|
287
|
-
id: z.string().uuid(),
|
|
288
|
-
name: z.string(),
|
|
289
269
|
email: z.string().email().optional()
|
|
290
270
|
})
|
|
291
271
|
});
|
|
@@ -566,3 +546,27 @@ DISCORD_WEBHOOK_URL=
|
|
|
566
546
|
}
|
|
567
547
|
return env;
|
|
568
548
|
}
|
|
549
|
+
export function getExampleCronJob(language) {
|
|
550
|
+
if (language === "typescript") {
|
|
551
|
+
return `import { defineCronJob } from "sprint-es/cronjobs";
|
|
552
|
+
|
|
553
|
+
export default defineCronJob({
|
|
554
|
+
name: "daily-task",
|
|
555
|
+
cronExpression: "0 21 * * *",
|
|
556
|
+
handler: () => {
|
|
557
|
+
console.log("Hello World from cronjob!");
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
`;
|
|
561
|
+
}
|
|
562
|
+
return `import { defineCronJob } from "sprint-es/cronjobs";
|
|
563
|
+
|
|
564
|
+
export default defineCronJob({
|
|
565
|
+
name: "daily-task",
|
|
566
|
+
cronExpression: "0 21 * * *",
|
|
567
|
+
handler: () => {
|
|
568
|
+
console.log("Hello World from cronjob!");
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
`;
|
|
572
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { mkdir, writeFile } from "fs/promises";
|
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import { input, select, confirm } from "@inquirer/prompts";
|
|
6
6
|
import { validateProjectName } from "./validators.js";
|
|
7
|
-
import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getViteConfig, getMainFile, getHomeRoute, getAdminRoute, getHomeController, getAdminController, getAuthMiddleware, getHomeSchema, getAdminSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction } from "./generators.js";
|
|
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
8
|
export async function runCLI(args) {
|
|
9
9
|
const options = parseArgs(args);
|
|
10
10
|
console.log("\n🚀 Welcome to Sprint - Quickly API Framework\n");
|
|
@@ -61,46 +61,39 @@ function parseArgs(args) {
|
|
|
61
61
|
const hasJs = args.includes("--js") || args.includes("--javascript");
|
|
62
62
|
const hasName = args.indexOf("--name");
|
|
63
63
|
const telemetryArg = args.includes("--telemetry") ? args[args.indexOf("--telemetry") + 1] : null;
|
|
64
|
-
if (args.includes("--yes") || args.includes("-y"))
|
|
64
|
+
if (args.includes("--yes") || args.includes("-y"))
|
|
65
65
|
options.skipPrompts = true;
|
|
66
|
-
}
|
|
67
66
|
if (!options.skipPrompts) {
|
|
68
|
-
if (hasTs)
|
|
67
|
+
if (hasTs)
|
|
69
68
|
options.language = "typescript";
|
|
70
|
-
|
|
71
|
-
else if (hasJs) {
|
|
69
|
+
else if (hasJs)
|
|
72
70
|
options.language = "javascript";
|
|
73
|
-
}
|
|
74
71
|
}
|
|
75
|
-
else
|
|
72
|
+
else
|
|
76
73
|
options.language = "typescript";
|
|
77
|
-
|
|
78
|
-
if (hasName !== -1 && args[hasName + 1]) {
|
|
74
|
+
if (hasName !== -1 && args[hasName + 1])
|
|
79
75
|
options.projectName = args[hasName + 1];
|
|
80
|
-
|
|
81
|
-
if (args.includes("--current")) {
|
|
76
|
+
if (args.includes("--current"))
|
|
82
77
|
options.projectName = ".";
|
|
83
|
-
|
|
84
|
-
if (args.includes("--docker")) {
|
|
78
|
+
if (args.includes("--docker"))
|
|
85
79
|
options.docker = true;
|
|
86
|
-
|
|
87
|
-
if (args.includes("--no-install")) {
|
|
80
|
+
if (args.includes("--no-install"))
|
|
88
81
|
options.skipInstall = true;
|
|
89
|
-
|
|
90
|
-
if (telemetryArg && ["sentry", "glitchtip", "discord", "none"].includes(telemetryArg)) {
|
|
82
|
+
if (telemetryArg && ["sentry", "glitchtip", "discord", "none"].includes(telemetryArg))
|
|
91
83
|
options.telemetry = telemetryArg;
|
|
92
|
-
}
|
|
93
84
|
return options;
|
|
94
85
|
}
|
|
86
|
+
;
|
|
95
87
|
async function getProjectName() {
|
|
96
88
|
const name = await input({
|
|
97
89
|
message: "Enter project name:",
|
|
98
90
|
validate: (value) => {
|
|
99
91
|
return validateProjectName(value) || true;
|
|
100
|
-
}
|
|
92
|
+
}
|
|
101
93
|
});
|
|
102
94
|
return name;
|
|
103
95
|
}
|
|
96
|
+
;
|
|
104
97
|
async function selectLanguage() {
|
|
105
98
|
const language = await select({
|
|
106
99
|
message: "Select your preferred language:",
|
|
@@ -114,11 +107,12 @@ async function selectLanguage() {
|
|
|
114
107
|
name: "JavaScript",
|
|
115
108
|
value: "javascript",
|
|
116
109
|
description: "Vanilla JavaScript for simpler projects",
|
|
117
|
-
}
|
|
118
|
-
]
|
|
110
|
+
}
|
|
111
|
+
]
|
|
119
112
|
});
|
|
120
113
|
return language;
|
|
121
114
|
}
|
|
115
|
+
;
|
|
122
116
|
async function selectTelemetry() {
|
|
123
117
|
const telemetry = await select({
|
|
124
118
|
message: "Select error tracking/telemetry solution:",
|
|
@@ -142,11 +136,12 @@ async function selectTelemetry() {
|
|
|
142
136
|
name: "Discord Webhook",
|
|
143
137
|
value: "discord",
|
|
144
138
|
description: "Send error notifications to Discord channel",
|
|
145
|
-
}
|
|
146
|
-
]
|
|
139
|
+
}
|
|
140
|
+
]
|
|
147
141
|
});
|
|
148
142
|
return telemetry;
|
|
149
143
|
}
|
|
144
|
+
;
|
|
150
145
|
async function createProject(projectName, language, telemetryArg, useDockerArg) {
|
|
151
146
|
const isCurrentDir = projectName === ".";
|
|
152
147
|
const targetDir = isCurrentDir ? process.cwd() : join(process.cwd(), projectName);
|
|
@@ -154,13 +149,11 @@ async function createProject(projectName, language, telemetryArg, useDockerArg)
|
|
|
154
149
|
console.error(`Error: Directory ${projectName} already exists`);
|
|
155
150
|
process.exit(1);
|
|
156
151
|
}
|
|
157
|
-
if (!isCurrentDir)
|
|
152
|
+
if (!isCurrentDir)
|
|
158
153
|
await mkdir(targetDir, { recursive: true });
|
|
159
|
-
}
|
|
160
154
|
let telemetry = telemetryArg || "none";
|
|
161
|
-
if (!telemetryArg)
|
|
155
|
+
if (!telemetryArg)
|
|
162
156
|
telemetry = await selectTelemetry();
|
|
163
|
-
}
|
|
164
157
|
let useDocker = useDockerArg || false;
|
|
165
158
|
if (!useDockerArg) {
|
|
166
159
|
useDocker = await confirm({
|
|
@@ -169,27 +162,25 @@ async function createProject(projectName, language, telemetryArg, useDockerArg)
|
|
|
169
162
|
});
|
|
170
163
|
}
|
|
171
164
|
let pkgJson;
|
|
172
|
-
if (language === "typescript")
|
|
165
|
+
if (language === "typescript")
|
|
173
166
|
pkgJson = getTypeScriptPackageJson(projectName, telemetry);
|
|
174
|
-
|
|
175
|
-
else {
|
|
167
|
+
else
|
|
176
168
|
pkgJson = getJavaScriptPackageJson(projectName, telemetry);
|
|
177
|
-
}
|
|
178
169
|
await writeFile(join(targetDir, "package.json"), JSON.stringify(pkgJson, null, 2));
|
|
179
170
|
if (language === "typescript") {
|
|
180
171
|
await writeFile(join(targetDir, "tsconfig.json"), getTsConfig());
|
|
181
172
|
await writeFile(join(targetDir, "vite.config.ts"), getViteConfig());
|
|
182
173
|
await writeFile(join(targetDir, "sprint.config.ts"), getSprintConfigFile(language, telemetry));
|
|
183
174
|
}
|
|
184
|
-
else
|
|
175
|
+
else
|
|
185
176
|
await writeFile(join(targetDir, "sprint.config.js"), getSprintConfigFile(language, telemetry));
|
|
186
|
-
}
|
|
187
177
|
const srcDir = join(targetDir, "src");
|
|
188
178
|
await mkdir(srcDir, { recursive: true });
|
|
189
179
|
await mkdir(join(srcDir, "middlewares"), { recursive: true });
|
|
190
180
|
await mkdir(join(srcDir, "routes"), { recursive: true });
|
|
191
181
|
await mkdir(join(srcDir, "controllers"), { recursive: true });
|
|
192
182
|
await mkdir(join(srcDir, "schemas"), { recursive: true });
|
|
183
|
+
await mkdir(join(srcDir, "cronjobs"), { recursive: true });
|
|
193
184
|
await writeFile(join(srcDir, "middlewares", ".gitkeep"), "");
|
|
194
185
|
await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getMainFile(language));
|
|
195
186
|
await writeFile(join(srcDir, "routes", "home." + (language === "typescript" ? "ts" : "js")), getHomeRoute(language));
|
|
@@ -199,6 +190,7 @@ async function createProject(projectName, language, telemetryArg, useDockerArg)
|
|
|
199
190
|
await writeFile(join(srcDir, "middlewares", "auth." + (language === "typescript" ? "ts" : "js")), getAuthMiddleware(language));
|
|
200
191
|
await writeFile(join(srcDir, "schemas", "home." + (language === "typescript" ? "ts" : "js")), getHomeSchema(language));
|
|
201
192
|
await writeFile(join(srcDir, "schemas", "admin." + (language === "typescript" ? "ts" : "js")), getAdminSchema(language));
|
|
193
|
+
await writeFile(join(srcDir, "cronjobs", "example." + (language === "typescript" ? "ts" : "js")), getExampleCronJob(language));
|
|
202
194
|
await writeFile(join(targetDir, ".env.development.example"), getEnvDevelopment(telemetry));
|
|
203
195
|
await writeFile(join(targetDir, ".env.production.example"), getEnvProduction(telemetry));
|
|
204
196
|
await writeFile(join(targetDir, ".env.development"), "");
|
|
@@ -210,3 +202,4 @@ async function createProject(projectName, language, telemetryArg, useDockerArg)
|
|
|
210
202
|
await writeFile(join(targetDir, ".dockerignore"), getDockerIgnore());
|
|
211
203
|
}
|
|
212
204
|
}
|
|
205
|
+
;
|
package/dist/validators.js
CHANGED
|
@@ -2,24 +2,19 @@ export function validateProjectName(name) {
|
|
|
2
2
|
if (!name.trim())
|
|
3
3
|
return "Please enter a project name";
|
|
4
4
|
const n = name.trim();
|
|
5
|
-
if (n !== n.toLowerCase())
|
|
5
|
+
if (n !== n.toLowerCase())
|
|
6
6
|
return "Project name must be lowercase";
|
|
7
|
-
|
|
8
|
-
if (n.length > 214) {
|
|
7
|
+
if (n.length > 214)
|
|
9
8
|
return "Project name must be less than 214 characters";
|
|
10
|
-
|
|
11
|
-
if (n.startsWith("-") || n.startsWith(".")) {
|
|
9
|
+
if (n.startsWith("-") || n.startsWith("."))
|
|
12
10
|
return "Project name cannot start with - or .";
|
|
13
|
-
}
|
|
14
|
-
if (/[~!@#$%^&*(){}[\]<>?:]/.test(n)) {
|
|
11
|
+
if (/[~!@#$%^&*(){}[\]<>?:]/.test(n))
|
|
15
12
|
return "Project name cannot contain special characters (only letters, numbers, - and _)";
|
|
16
|
-
|
|
17
|
-
if (n !== encodeURIComponent(n)) {
|
|
13
|
+
if (n !== encodeURIComponent(n))
|
|
18
14
|
return "Project name must be URL-safe";
|
|
19
|
-
}
|
|
20
15
|
const reserved = ["node_modules", "favicon.ico"];
|
|
21
|
-
if (reserved.includes(n.toLowerCase()))
|
|
16
|
+
if (reserved.includes(n.toLowerCase()))
|
|
22
17
|
return `Cannot use "${n}" as project name`;
|
|
23
|
-
}
|
|
24
18
|
return null;
|
|
25
19
|
}
|
|
20
|
+
;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-sprint",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.34",
|
|
4
4
|
"description": "Create a new Sprint API project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
15
|
"build": "tsc && node -e \"const fs=require('fs');const p='dist/cli.js';let c=fs.readFileSync(p,'utf8');if(!c.startsWith('#!')){fs.writeFileSync(p,'#!/usr/bin/env node\\n'+c)}\"",
|
|
16
|
-
"prepublishOnly": "npm run build",
|
|
16
|
+
"prepublishOnly": "npm version patch && npm run build",
|
|
17
17
|
"start": "node dist/cli.js"
|
|
18
18
|
},
|
|
19
19
|
"keywords": [
|
|
@@ -29,10 +29,11 @@
|
|
|
29
29
|
"@inquirer/prompts": "^7.10.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
+
"@types/node": "^25.3.3",
|
|
32
33
|
"tsx": "^4.19.0",
|
|
33
34
|
"typescript": "^5.9.3"
|
|
34
35
|
},
|
|
35
36
|
"engines": {
|
|
36
37
|
"node": ">=18.0.0"
|
|
37
38
|
}
|
|
38
|
-
}
|
|
39
|
+
}
|
package/src/cli.ts
CHANGED
package/src/generators.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export function getTypeScriptPackageJson(name: string, telemetry: string) {
|
|
2
2
|
const deps: Record<string, string> = {
|
|
3
|
-
"sprint-es": "^0.0.
|
|
4
|
-
"
|
|
3
|
+
"sprint-es": "^0.0.35",
|
|
4
|
+
"node-cron": "^3.0.3",
|
|
5
5
|
dotenv: "^17.0.0",
|
|
6
6
|
};
|
|
7
7
|
|
|
@@ -23,9 +23,9 @@ export function getTypeScriptPackageJson(name: string, telemetry: string) {
|
|
|
23
23
|
description: "Sprint API",
|
|
24
24
|
main: "dist/index.js",
|
|
25
25
|
scripts: {
|
|
26
|
-
build: "sprint build",
|
|
27
|
-
start: "sprint start",
|
|
28
|
-
dev: "sprint dev",
|
|
26
|
+
build: "sprint-es build",
|
|
27
|
+
start: "sprint-es start",
|
|
28
|
+
dev: "sprint-es dev",
|
|
29
29
|
},
|
|
30
30
|
dependencies: deps,
|
|
31
31
|
devDependencies: devDeps,
|
|
@@ -34,8 +34,8 @@ export function getTypeScriptPackageJson(name: string, telemetry: string) {
|
|
|
34
34
|
|
|
35
35
|
export function getJavaScriptPackageJson(name: string, telemetry: string) {
|
|
36
36
|
const deps: Record<string, string> = {
|
|
37
|
-
"sprint-es": "^0.0.
|
|
38
|
-
"
|
|
37
|
+
"sprint-es": "^0.0.35",
|
|
38
|
+
"node-cron": "^3.0.3",
|
|
39
39
|
dotenv: "^17.0.0",
|
|
40
40
|
};
|
|
41
41
|
|
|
@@ -52,9 +52,9 @@ export function getJavaScriptPackageJson(name: string, telemetry: string) {
|
|
|
52
52
|
main: "src/index.js",
|
|
53
53
|
type: "module",
|
|
54
54
|
scripts: {
|
|
55
|
-
build: "sprint build",
|
|
56
|
-
start: "sprint start",
|
|
57
|
-
dev: "sprint dev",
|
|
55
|
+
build: "sprint-es build",
|
|
56
|
+
start: "sprint-es start",
|
|
57
|
+
dev: "sprint-es dev",
|
|
58
58
|
},
|
|
59
59
|
dependencies: deps,
|
|
60
60
|
};
|
|
@@ -248,22 +248,12 @@ export function getHomeSchema(language: string) {
|
|
|
248
248
|
if (language === "typescript") {
|
|
249
249
|
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
250
250
|
|
|
251
|
-
export const homeSchema = defineRouteSchema({
|
|
252
|
-
input: z.object({
|
|
253
|
-
message: z.string(),
|
|
254
|
-
status: z.string()
|
|
255
|
-
})
|
|
256
|
-
});
|
|
251
|
+
export const homeSchema = defineRouteSchema({});
|
|
257
252
|
`;
|
|
258
253
|
}
|
|
259
254
|
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
260
255
|
|
|
261
|
-
export const homeSchema = defineRouteSchema({
|
|
262
|
-
input: z.object({
|
|
263
|
-
message: z.string(),
|
|
264
|
-
status: z.string()
|
|
265
|
-
})
|
|
266
|
-
});
|
|
256
|
+
export const homeSchema = defineRouteSchema({});
|
|
267
257
|
`;
|
|
268
258
|
}
|
|
269
259
|
|
|
@@ -272,16 +262,11 @@ export function getAdminSchema(language: string) {
|
|
|
272
262
|
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
273
263
|
|
|
274
264
|
export const adminSchema = defineRouteSchema({
|
|
275
|
-
|
|
265
|
+
queryParams: z.object({
|
|
276
266
|
id: z.string().uuid()
|
|
277
267
|
}),
|
|
278
268
|
body: z.object({
|
|
279
269
|
name: z.string().min(1),
|
|
280
|
-
email: z.email().optional()
|
|
281
|
-
}),
|
|
282
|
-
input: z.object({
|
|
283
|
-
id: z.string().uuid(),
|
|
284
|
-
name: z.string(),
|
|
285
270
|
email: z.string().email().optional()
|
|
286
271
|
})
|
|
287
272
|
});
|
|
@@ -290,16 +275,11 @@ export const adminSchema = defineRouteSchema({
|
|
|
290
275
|
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
291
276
|
|
|
292
277
|
export const adminSchema = defineRouteSchema({
|
|
293
|
-
|
|
278
|
+
queryParams: z.object({
|
|
294
279
|
id: z.string().uuid()
|
|
295
280
|
}),
|
|
296
281
|
body: z.object({
|
|
297
282
|
name: z.string().min(1),
|
|
298
|
-
email: z.email().optional()
|
|
299
|
-
}),
|
|
300
|
-
input: z.object({
|
|
301
|
-
id: z.string().uuid(),
|
|
302
|
-
name: z.string(),
|
|
303
283
|
email: z.string().email().optional()
|
|
304
284
|
})
|
|
305
285
|
});
|
|
@@ -595,3 +575,28 @@ DISCORD_WEBHOOK_URL=
|
|
|
595
575
|
|
|
596
576
|
return env;
|
|
597
577
|
}
|
|
578
|
+
|
|
579
|
+
export function getExampleCronJob(language: string) {
|
|
580
|
+
if (language === "typescript") {
|
|
581
|
+
return `import { defineCronJob } from "sprint-es/cronjobs";
|
|
582
|
+
|
|
583
|
+
export default defineCronJob({
|
|
584
|
+
name: "daily-task",
|
|
585
|
+
cronExpression: "0 21 * * *",
|
|
586
|
+
handler: () => {
|
|
587
|
+
console.log("Hello World from cronjob!");
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
`;
|
|
591
|
+
}
|
|
592
|
+
return `import { defineCronJob } from "sprint-es/cronjobs";
|
|
593
|
+
|
|
594
|
+
export default defineCronJob({
|
|
595
|
+
name: "daily-task",
|
|
596
|
+
cronExpression: "0 21 * * *",
|
|
597
|
+
handler: () => {
|
|
598
|
+
console.log("Hello World from cronjob!");
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
`;
|
|
602
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { mkdir, writeFile } from "fs/promises";
|
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import { input, select, confirm } from "@inquirer/prompts";
|
|
6
6
|
import { validateProjectName } from "./validators.js";
|
|
7
|
-
import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getViteConfig, getMainFile, getHomeRoute, getAdminRoute, getHomeController, getAdminController, getAuthMiddleware, getHomeSchema, getAdminSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction } from "./generators.js";
|
|
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
8
|
|
|
9
9
|
export interface CLIOptions {
|
|
10
10
|
projectName?: string;
|
|
@@ -83,53 +83,36 @@ function parseArgs(args: string[]): CLIOptions {
|
|
|
83
83
|
const hasName = args.indexOf("--name");
|
|
84
84
|
const telemetryArg = args.includes("--telemetry") ? args[args.indexOf("--telemetry") + 1] : null;
|
|
85
85
|
|
|
86
|
-
if (args.includes("--yes") || args.includes("-y"))
|
|
87
|
-
options.skipPrompts = true;
|
|
88
|
-
}
|
|
86
|
+
if (args.includes("--yes") || args.includes("-y")) options.skipPrompts = true;
|
|
89
87
|
|
|
90
88
|
if (!options.skipPrompts) {
|
|
91
|
-
if (hasTs)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
} else {
|
|
97
|
-
options.language = "typescript";
|
|
98
|
-
}
|
|
89
|
+
if (hasTs) options.language = "typescript";
|
|
90
|
+
else if (hasJs) options.language = "javascript";
|
|
91
|
+
} else options.language = "typescript";
|
|
92
|
+
|
|
93
|
+
if (hasName !== -1 && args[hasName + 1]) options.projectName = args[hasName + 1];
|
|
99
94
|
|
|
100
|
-
if (
|
|
101
|
-
options.projectName = args[hasName + 1];
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (args.includes("--current")) {
|
|
105
|
-
options.projectName = ".";
|
|
106
|
-
}
|
|
95
|
+
if (args.includes("--current")) options.projectName = ".";
|
|
107
96
|
|
|
108
|
-
if (args.includes("--docker"))
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (args.includes("--no-install")) {
|
|
113
|
-
options.skipInstall = true;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (telemetryArg && ["sentry", "glitchtip", "discord", "none"].includes(telemetryArg)) {
|
|
117
|
-
options.telemetry = telemetryArg as CLIOptions["telemetry"];
|
|
118
|
-
}
|
|
97
|
+
if (args.includes("--docker")) options.docker = true;
|
|
98
|
+
|
|
99
|
+
if (args.includes("--no-install")) options.skipInstall = true;
|
|
119
100
|
|
|
101
|
+
if (telemetryArg && ["sentry", "glitchtip", "discord", "none"].includes(telemetryArg)) options.telemetry = telemetryArg as CLIOptions["telemetry"];
|
|
102
|
+
|
|
120
103
|
return options;
|
|
121
|
-
}
|
|
104
|
+
};
|
|
122
105
|
|
|
123
106
|
async function getProjectName(): Promise<string> {
|
|
124
107
|
const name = await input({
|
|
125
108
|
message: "Enter project name:",
|
|
126
109
|
validate: (value) => {
|
|
127
110
|
return validateProjectName(value) || true;
|
|
128
|
-
}
|
|
111
|
+
}
|
|
129
112
|
});
|
|
130
113
|
|
|
131
114
|
return name;
|
|
132
|
-
}
|
|
115
|
+
};
|
|
133
116
|
|
|
134
117
|
async function selectLanguage(): Promise<"typescript" | "javascript"> {
|
|
135
118
|
const language = await select({
|
|
@@ -144,12 +127,12 @@ async function selectLanguage(): Promise<"typescript" | "javascript"> {
|
|
|
144
127
|
name: "JavaScript",
|
|
145
128
|
value: "javascript",
|
|
146
129
|
description: "Vanilla JavaScript for simpler projects",
|
|
147
|
-
}
|
|
148
|
-
]
|
|
130
|
+
}
|
|
131
|
+
]
|
|
149
132
|
});
|
|
150
133
|
|
|
151
134
|
return language as "typescript" | "javascript";
|
|
152
|
-
}
|
|
135
|
+
};
|
|
153
136
|
|
|
154
137
|
async function selectTelemetry(): Promise<"none" | "sentry" | "glitchtip" | "discord"> {
|
|
155
138
|
const telemetry = await select({
|
|
@@ -174,12 +157,12 @@ async function selectTelemetry(): Promise<"none" | "sentry" | "glitchtip" | "dis
|
|
|
174
157
|
name: "Discord Webhook",
|
|
175
158
|
value: "discord",
|
|
176
159
|
description: "Send error notifications to Discord channel",
|
|
177
|
-
}
|
|
178
|
-
]
|
|
160
|
+
}
|
|
161
|
+
]
|
|
179
162
|
});
|
|
180
163
|
|
|
181
164
|
return telemetry as "none" | "sentry" | "glitchtip" | "discord";
|
|
182
|
-
}
|
|
165
|
+
};
|
|
183
166
|
|
|
184
167
|
async function createProject(
|
|
185
168
|
projectName: string,
|
|
@@ -195,14 +178,10 @@ async function createProject(
|
|
|
195
178
|
process.exit(1);
|
|
196
179
|
}
|
|
197
180
|
|
|
198
|
-
if (!isCurrentDir) {
|
|
199
|
-
await mkdir(targetDir, { recursive: true });
|
|
200
|
-
}
|
|
181
|
+
if (!isCurrentDir) await mkdir(targetDir, { recursive: true });
|
|
201
182
|
|
|
202
183
|
let telemetry = telemetryArg || "none";
|
|
203
|
-
if (!telemetryArg)
|
|
204
|
-
telemetry = await selectTelemetry();
|
|
205
|
-
}
|
|
184
|
+
if (!telemetryArg) telemetry = await selectTelemetry();
|
|
206
185
|
|
|
207
186
|
let useDocker = useDockerArg || false;
|
|
208
187
|
if (!useDockerArg) {
|
|
@@ -213,22 +192,17 @@ async function createProject(
|
|
|
213
192
|
}
|
|
214
193
|
|
|
215
194
|
let pkgJson;
|
|
216
|
-
if (language === "typescript")
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
pkgJson = getJavaScriptPackageJson(projectName, telemetry);
|
|
220
|
-
}
|
|
221
|
-
|
|
195
|
+
if (language === "typescript") pkgJson = getTypeScriptPackageJson(projectName, telemetry);
|
|
196
|
+
else pkgJson = getJavaScriptPackageJson(projectName, telemetry);
|
|
197
|
+
|
|
222
198
|
await writeFile(join(targetDir, "package.json"), JSON.stringify(pkgJson, null, 2));
|
|
223
199
|
|
|
224
200
|
if (language === "typescript") {
|
|
225
201
|
await writeFile(join(targetDir, "tsconfig.json"), getTsConfig());
|
|
226
202
|
await writeFile(join(targetDir, "vite.config.ts"), getViteConfig());
|
|
227
203
|
await writeFile(join(targetDir, "sprint.config.ts"), getSprintConfigFile(language, telemetry));
|
|
228
|
-
} else
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
|
|
204
|
+
} else await writeFile(join(targetDir, "sprint.config.js"), getSprintConfigFile(language, telemetry));
|
|
205
|
+
|
|
232
206
|
const srcDir = join(targetDir, "src");
|
|
233
207
|
await mkdir(srcDir, { recursive: true });
|
|
234
208
|
|
|
@@ -236,6 +210,7 @@ async function createProject(
|
|
|
236
210
|
await mkdir(join(srcDir, "routes"), { recursive: true });
|
|
237
211
|
await mkdir(join(srcDir, "controllers"), { recursive: true });
|
|
238
212
|
await mkdir(join(srcDir, "schemas"), { recursive: true });
|
|
213
|
+
await mkdir(join(srcDir, "cronjobs"), { recursive: true });
|
|
239
214
|
|
|
240
215
|
await writeFile(join(srcDir, "middlewares", ".gitkeep"), "");
|
|
241
216
|
|
|
@@ -252,6 +227,8 @@ async function createProject(
|
|
|
252
227
|
await writeFile(join(srcDir, "schemas", "home." + (language === "typescript" ? "ts" : "js")), getHomeSchema(language));
|
|
253
228
|
await writeFile(join(srcDir, "schemas", "admin." + (language === "typescript" ? "ts" : "js")), getAdminSchema(language));
|
|
254
229
|
|
|
230
|
+
await writeFile(join(srcDir, "cronjobs", "example." + (language === "typescript" ? "ts" : "js")), getExampleCronJob(language));
|
|
231
|
+
|
|
255
232
|
await writeFile(join(targetDir, ".env.development.example"), getEnvDevelopment(telemetry));
|
|
256
233
|
await writeFile(join(targetDir, ".env.production.example"), getEnvProduction(telemetry));
|
|
257
234
|
|
|
@@ -265,4 +242,4 @@ async function createProject(
|
|
|
265
242
|
await writeFile(join(targetDir, "docker-compose.yml"), getDockerCompose(language));
|
|
266
243
|
await writeFile(join(targetDir, ".dockerignore"), getDockerIgnore());
|
|
267
244
|
}
|
|
268
|
-
}
|
|
245
|
+
};
|
package/src/validators.ts
CHANGED
|
@@ -3,30 +3,19 @@ export function validateProjectName(name: string): string | null {
|
|
|
3
3
|
|
|
4
4
|
const n = name.trim();
|
|
5
5
|
|
|
6
|
-
if (n !== n.toLowerCase())
|
|
7
|
-
return "Project name must be lowercase";
|
|
8
|
-
}
|
|
6
|
+
if (n !== n.toLowerCase()) return "Project name must be lowercase";
|
|
9
7
|
|
|
10
|
-
if (n.length > 214)
|
|
11
|
-
return "Project name must be less than 214 characters";
|
|
12
|
-
}
|
|
8
|
+
if (n.length > 214) return "Project name must be less than 214 characters";
|
|
13
9
|
|
|
14
|
-
if (n.startsWith("-") || n.startsWith("."))
|
|
15
|
-
return "Project name cannot start with - or .";
|
|
16
|
-
}
|
|
10
|
+
if (n.startsWith("-") || n.startsWith(".")) return "Project name cannot start with - or .";
|
|
17
11
|
|
|
18
|
-
if (/[~!@#$%^&*(){}[\]<>?:]/.test(n))
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (n !== encodeURIComponent(n)) {
|
|
23
|
-
return "Project name must be URL-safe";
|
|
24
|
-
}
|
|
12
|
+
if (/[~!@#$%^&*(){}[\]<>?:]/.test(n)) return "Project name cannot contain special characters (only letters, numbers, - and _)";
|
|
13
|
+
|
|
14
|
+
if (n !== encodeURIComponent(n)) return "Project name must be URL-safe";
|
|
15
|
+
|
|
25
16
|
|
|
26
17
|
const reserved = ["node_modules", "favicon.ico"];
|
|
27
|
-
if (reserved.includes(n.toLowerCase())) {
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
18
|
+
if (reserved.includes(n.toLowerCase())) return `Cannot use "${n}" as project name`;
|
|
19
|
+
|
|
31
20
|
return null;
|
|
32
|
-
}
|
|
21
|
+
};
|