create-sprint 0.0.1 ā 0.0.3
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/bin/cli.js +650 -0
- package/bin/cli.ts +639 -221
- package/package.json +35 -32
package/bin/cli.js
ADDED
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { select, input, confirm } from "@inquirer/prompts";
|
|
3
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
4
|
+
import { existsSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
import { execSync } from "child_process";
|
|
7
|
+
const args = process.argv.slice(2);
|
|
8
|
+
const hasHelp = args.includes("--help") || args.includes("-h");
|
|
9
|
+
const hasTs = args.includes("--ts") || args.includes("--typescript");
|
|
10
|
+
const hasJs = args.includes("--js") || args.includes("--javascript");
|
|
11
|
+
const hasName = args.indexOf("--name");
|
|
12
|
+
const projectNameArg = hasName !== -1 ? args[hasName + 1] : null;
|
|
13
|
+
const useCurrentDirArg = args.includes("--current");
|
|
14
|
+
const skipInstallArg = args.includes("--no-install");
|
|
15
|
+
const telemetryArg = args.includes("--telemetry") ? args[args.indexOf("--telemetry") + 1] : null;
|
|
16
|
+
const useDockerArg = args.includes("--docker");
|
|
17
|
+
if (hasHelp) {
|
|
18
|
+
console.log("\nš Sprint - Quickly API Framework\n");
|
|
19
|
+
console.log("Usage: sprint [options]");
|
|
20
|
+
console.log("\nOptions:");
|
|
21
|
+
console.log(" --ts, --typescript Create TypeScript project");
|
|
22
|
+
console.log(" --js, --javascript Create JavaScript project");
|
|
23
|
+
console.log(" --name <name> Project name (use '.' for current directory)");
|
|
24
|
+
console.log(" --no-install Skip automatic dependency installation");
|
|
25
|
+
console.log(" --telemetry <type> Telemetry: none, sentry, glitchtip, discord");
|
|
26
|
+
console.log(" --docker Add Docker support");
|
|
27
|
+
console.log(" --help, -h Show this help message");
|
|
28
|
+
console.log("\nExamples:");
|
|
29
|
+
console.log(" sprint Interactive mode");
|
|
30
|
+
console.log(" sprint --ts Create TypeScript project");
|
|
31
|
+
console.log(" sprint --ts --name my-api");
|
|
32
|
+
console.log(" sprint --js --name . --telemetry sentry --docker\n");
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
async function main() {
|
|
36
|
+
console.log("\nš Welcome to Sprint - Quickly API Framework\n");
|
|
37
|
+
let projectName;
|
|
38
|
+
let language;
|
|
39
|
+
if (projectNameArg) {
|
|
40
|
+
projectName = projectNameArg;
|
|
41
|
+
}
|
|
42
|
+
else if (useCurrentDirArg) {
|
|
43
|
+
projectName = ".";
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
projectName = await getProjectName();
|
|
47
|
+
}
|
|
48
|
+
if (hasTs) {
|
|
49
|
+
language = "typescript";
|
|
50
|
+
}
|
|
51
|
+
else if (hasJs) {
|
|
52
|
+
language = "javascript";
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
language = await selectLanguage();
|
|
56
|
+
}
|
|
57
|
+
console.log(`\nā
Creating Sprint project: ${projectName === "." ? "current directory" : projectName} with ${language === "typescript" ? "TypeScript" : "JavaScript"}\n`);
|
|
58
|
+
await createProject(projectName, language);
|
|
59
|
+
console.log("\nā
Project created successfully!");
|
|
60
|
+
let installDeps = true;
|
|
61
|
+
if (!skipInstallArg) {
|
|
62
|
+
installDeps = await confirm({
|
|
63
|
+
message: "Do you want to install dependencies now?",
|
|
64
|
+
default: true,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (installDeps) {
|
|
68
|
+
console.log("\nš¦ Installing dependencies...\n");
|
|
69
|
+
const targetDir = projectName === "." ? process.cwd() : join(process.cwd(), projectName);
|
|
70
|
+
try {
|
|
71
|
+
execSync("npm install", { cwd: targetDir, stdio: "inherit" });
|
|
72
|
+
console.log("\nā
Dependencies installed successfully!");
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
console.error("\nā Error installing dependencies. Please run 'npm install' manually.");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
console.log("\nš¦ Next steps:");
|
|
79
|
+
const cdCmd = projectName === "." ? "" : `cd ${projectName} && `;
|
|
80
|
+
if (!installDeps) {
|
|
81
|
+
console.log(` ${cdCmd}npm install`);
|
|
82
|
+
}
|
|
83
|
+
console.log(` ${cdCmd}npm run dev`);
|
|
84
|
+
console.log("\n");
|
|
85
|
+
}
|
|
86
|
+
async function getProjectName() {
|
|
87
|
+
const name = await input({
|
|
88
|
+
message: "Enter project name:",
|
|
89
|
+
validate: (value) => {
|
|
90
|
+
if (!value.trim())
|
|
91
|
+
return "Please enter a project name";
|
|
92
|
+
return true;
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
return name;
|
|
96
|
+
}
|
|
97
|
+
async function selectLanguage() {
|
|
98
|
+
const language = await select({
|
|
99
|
+
message: "Select your preferred language:",
|
|
100
|
+
choices: [
|
|
101
|
+
{
|
|
102
|
+
name: "TypeScript",
|
|
103
|
+
value: "typescript",
|
|
104
|
+
description: "Recommended - Type safety and better developer experience",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "JavaScript",
|
|
108
|
+
value: "javascript",
|
|
109
|
+
description: "Vanilla JavaScript for simpler projects",
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
return language;
|
|
114
|
+
}
|
|
115
|
+
async function selectTelemetry() {
|
|
116
|
+
const telemetry = await select({
|
|
117
|
+
message: "Select error tracking/telemetry solution:",
|
|
118
|
+
choices: [
|
|
119
|
+
{
|
|
120
|
+
name: "None",
|
|
121
|
+
value: "none",
|
|
122
|
+
description: "No error tracking integration",
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "Sentry",
|
|
126
|
+
value: "sentry",
|
|
127
|
+
description: "Full-featured error tracking (free tier available)",
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: "GlitchTip",
|
|
131
|
+
value: "glitchtip",
|
|
132
|
+
description: "Simple error tracking, can be self-hosted",
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: "Discord Webhook",
|
|
136
|
+
value: "discord",
|
|
137
|
+
description: "Send error notifications to Discord channel",
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
});
|
|
141
|
+
return telemetry;
|
|
142
|
+
}
|
|
143
|
+
async function createProject(projectName, language) {
|
|
144
|
+
const isCurrentDir = projectName === ".";
|
|
145
|
+
const targetDir = isCurrentDir ? process.cwd() : join(process.cwd(), projectName);
|
|
146
|
+
if (!isCurrentDir && existsSync(targetDir)) {
|
|
147
|
+
console.error(`Error: Directory ${projectName} already exists`);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
if (!isCurrentDir) {
|
|
151
|
+
await mkdir(targetDir, { recursive: true });
|
|
152
|
+
}
|
|
153
|
+
let telemetry = "none";
|
|
154
|
+
if (telemetryArg && ["sentry", "glitchtip", "discord", "none"].includes(telemetryArg)) {
|
|
155
|
+
telemetry = telemetryArg;
|
|
156
|
+
}
|
|
157
|
+
else if (!hasTs && !hasJs) {
|
|
158
|
+
telemetry = await selectTelemetry();
|
|
159
|
+
}
|
|
160
|
+
let useDocker = useDockerArg;
|
|
161
|
+
if (!useDocker && !hasTs && !hasJs) {
|
|
162
|
+
useDocker = await confirm({
|
|
163
|
+
message: "Do you want to add Docker support?",
|
|
164
|
+
default: false,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
let pkgJson;
|
|
168
|
+
if (language === "typescript") {
|
|
169
|
+
pkgJson = getTypeScriptPackageJson(projectName, telemetry);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
pkgJson = getJavaScriptPackageJson(projectName, telemetry);
|
|
173
|
+
}
|
|
174
|
+
await writeFile(join(targetDir, "package.json"), JSON.stringify(pkgJson, null, 2));
|
|
175
|
+
if (language === "typescript") {
|
|
176
|
+
await writeFile(join(targetDir, "tsconfig.json"), getTsConfig());
|
|
177
|
+
await writeFile(join(targetDir, "vite.config.ts"), getViteConfig());
|
|
178
|
+
}
|
|
179
|
+
const srcDir = join(targetDir, "src");
|
|
180
|
+
await mkdir(srcDir, { recursive: true });
|
|
181
|
+
await mkdir(join(srcDir, "middlewares"), { recursive: true });
|
|
182
|
+
await mkdir(join(srcDir, "routes"), { recursive: true });
|
|
183
|
+
await mkdir(join(srcDir, "controllers"), { recursive: true });
|
|
184
|
+
await writeFile(join(srcDir, "middlewares", ".gitkeep"), "");
|
|
185
|
+
await writeFile(join(srcDir, "controllers", ".gitkeep"), "");
|
|
186
|
+
await writeFile(join(srcDir, "index." + (language === "typescript" ? "ts" : "js")), getMainFile(language, telemetry));
|
|
187
|
+
await writeFile(join(srcDir, "routes", "home." + (language === "typescript" ? "ts" : "js")), getHomeRoute(language));
|
|
188
|
+
if (language === "typescript") {
|
|
189
|
+
await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getAppFile(language, telemetry));
|
|
190
|
+
}
|
|
191
|
+
await writeFile(join(targetDir, ".env.example"), getEnvExample(telemetry));
|
|
192
|
+
await writeFile(join(targetDir, ".env"), "");
|
|
193
|
+
if (telemetry !== "none") {
|
|
194
|
+
await writeFile(join(targetDir, "sprint.config.js"), getSprintConfig(telemetry));
|
|
195
|
+
}
|
|
196
|
+
await writeFile(join(targetDir, ".gitignore"), getGitignore(language));
|
|
197
|
+
if (useDocker) {
|
|
198
|
+
await writeFile(join(targetDir, "Dockerfile"), getDockerfile(language));
|
|
199
|
+
await writeFile(join(targetDir, "docker-compose.yml"), getDockerCompose(language));
|
|
200
|
+
await writeFile(join(targetDir, ".dockerignore"), getDockerIgnore());
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function getTypeScriptPackageJson(name, telemetry) {
|
|
204
|
+
const deps = {
|
|
205
|
+
"sprint-es": "^0.0.24",
|
|
206
|
+
dotenv: "^17.0.0",
|
|
207
|
+
};
|
|
208
|
+
const devDeps = {
|
|
209
|
+
"@types/node": "^22.0.0",
|
|
210
|
+
"tsx": "^4.19.0",
|
|
211
|
+
typescript: "^5.6.0",
|
|
212
|
+
vite: "^6.0.0",
|
|
213
|
+
};
|
|
214
|
+
if (telemetry === "sentry") {
|
|
215
|
+
deps["@sentry/node"] = "^8.0.0";
|
|
216
|
+
}
|
|
217
|
+
else if (telemetry === "glitchtip") {
|
|
218
|
+
deps["@sentry/node"] = "^8.0.0";
|
|
219
|
+
}
|
|
220
|
+
else if (telemetry === "discord") {
|
|
221
|
+
deps["axios"] = "^1.6.0";
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
name: name === "." ? "sprint-app" : name,
|
|
225
|
+
version: "0.0.1",
|
|
226
|
+
description: "Sprint API",
|
|
227
|
+
main: "dist/index.js",
|
|
228
|
+
scripts: {
|
|
229
|
+
build: "vite build",
|
|
230
|
+
start: "node dist/index.js --prod",
|
|
231
|
+
dev: "vite --dev",
|
|
232
|
+
},
|
|
233
|
+
dependencies: deps,
|
|
234
|
+
devDependencies: devDeps,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function getJavaScriptPackageJson(name, telemetry) {
|
|
238
|
+
const deps = {
|
|
239
|
+
"sprint-es": "^0.0.24",
|
|
240
|
+
dotenv: "^17.0.0",
|
|
241
|
+
};
|
|
242
|
+
if (telemetry === "sentry") {
|
|
243
|
+
deps["@sentry/node"] = "^8.0.0";
|
|
244
|
+
}
|
|
245
|
+
else if (telemetry === "glitchtip") {
|
|
246
|
+
deps["@sentry/node"] = "^8.0.0";
|
|
247
|
+
}
|
|
248
|
+
else if (telemetry === "discord") {
|
|
249
|
+
deps["axios"] = "^1.6.0";
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
name: name === "." ? "sprint-app" : name,
|
|
253
|
+
version: "0.0.1",
|
|
254
|
+
description: "Sprint API",
|
|
255
|
+
main: "src/index.js",
|
|
256
|
+
type: "module",
|
|
257
|
+
scripts: {
|
|
258
|
+
start: "node src/index.js --prod",
|
|
259
|
+
dev: "node --watch src/index.js --dev",
|
|
260
|
+
},
|
|
261
|
+
dependencies: deps,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function getTsConfig() {
|
|
265
|
+
return JSON.stringify({
|
|
266
|
+
compilerOptions: {
|
|
267
|
+
target: "ES2020",
|
|
268
|
+
module: "ESNext",
|
|
269
|
+
moduleResolution: "bundler",
|
|
270
|
+
lib: ["ES2020"],
|
|
271
|
+
outDir: "./dist",
|
|
272
|
+
rootDir: "./src",
|
|
273
|
+
strict: true,
|
|
274
|
+
esModuleInterop: true,
|
|
275
|
+
skipLibCheck: true,
|
|
276
|
+
forceConsistentCasingInFileNames: true,
|
|
277
|
+
resolveJsonModule: true,
|
|
278
|
+
declaration: true,
|
|
279
|
+
declarationMap: true,
|
|
280
|
+
sourceMap: true,
|
|
281
|
+
tabWidth: 4,
|
|
282
|
+
},
|
|
283
|
+
include: ["src/**/*"],
|
|
284
|
+
exclude: ["node_modules", "dist"],
|
|
285
|
+
}, null, 2);
|
|
286
|
+
}
|
|
287
|
+
function getViteConfig() {
|
|
288
|
+
return `import { defineConfig } from "vite";
|
|
289
|
+
import { resolve } from "path";
|
|
290
|
+
|
|
291
|
+
export default defineConfig({
|
|
292
|
+
build: {
|
|
293
|
+
lib: {
|
|
294
|
+
entry: resolve(__dirname, "src/index.ts"),
|
|
295
|
+
formats: ["es"],
|
|
296
|
+
fileName: "index",
|
|
297
|
+
},
|
|
298
|
+
outDir: "dist",
|
|
299
|
+
rollupOptions: {
|
|
300
|
+
external: ["sprint-es", "express", "cors", "morgan", "serve-favicon", "dotenv"],
|
|
301
|
+
},
|
|
302
|
+
target: "ES2020",
|
|
303
|
+
},
|
|
304
|
+
resolve: {
|
|
305
|
+
alias: {
|
|
306
|
+
"@": resolve(__dirname, "src"),
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
`;
|
|
311
|
+
}
|
|
312
|
+
function getMainFile(language, telemetry) {
|
|
313
|
+
const hasTelemetry = telemetry !== "none";
|
|
314
|
+
if (language === "typescript") {
|
|
315
|
+
let code = `import Sprint from "sprint-es";
|
|
316
|
+
import dotenv from "dotenv";
|
|
317
|
+
import homeRouter from "./routes/home";
|
|
318
|
+
|
|
319
|
+
dotenv.config();
|
|
320
|
+
|
|
321
|
+
`;
|
|
322
|
+
if (hasTelemetry) {
|
|
323
|
+
code += getTelemetryImport(language, telemetry);
|
|
324
|
+
}
|
|
325
|
+
code += `const app = new Sprint({
|
|
326
|
+
port: process.env.PORT ? parseInt(process.env.PORT) : 3000,
|
|
327
|
+
favicon: process.env.FAVICON || undefined,
|
|
328
|
+
bodyParser: {
|
|
329
|
+
limit: "10mb"
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
app.use(homeRouter);
|
|
334
|
+
|
|
335
|
+
app.listen();
|
|
336
|
+
`;
|
|
337
|
+
return code;
|
|
338
|
+
}
|
|
339
|
+
let code = `import Sprint from "sprint-es";
|
|
340
|
+
import dotenv from "dotenv";
|
|
341
|
+
import homeRouter from "./routes/home";
|
|
342
|
+
|
|
343
|
+
dotenv.config();
|
|
344
|
+
|
|
345
|
+
`;
|
|
346
|
+
if (hasTelemetry) {
|
|
347
|
+
code += getTelemetryImport(language, telemetry);
|
|
348
|
+
}
|
|
349
|
+
code += `const app = new Sprint({
|
|
350
|
+
port: process.env.PORT ? parseInt(process.env.PORT) : 3000,
|
|
351
|
+
favicon: process.env.FAVICON || undefined,
|
|
352
|
+
bodyParser: {
|
|
353
|
+
limit: "10mb"
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
app.use(homeRouter);
|
|
358
|
+
|
|
359
|
+
app.listen();
|
|
360
|
+
`;
|
|
361
|
+
return code;
|
|
362
|
+
}
|
|
363
|
+
function getTelemetryImport(language, telemetry) {
|
|
364
|
+
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
365
|
+
return `import * as Sentry from "@sentry/node";
|
|
366
|
+
|
|
367
|
+
Sentry.init({
|
|
368
|
+
dsn: process.env.SENTRY_DSN,
|
|
369
|
+
integrations: [
|
|
370
|
+
Sentry.httpIntegration(),
|
|
371
|
+
],
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
`;
|
|
375
|
+
}
|
|
376
|
+
else if (telemetry === "discord") {
|
|
377
|
+
return `import axios from "axios";
|
|
378
|
+
|
|
379
|
+
const discordWebhook = process.env.DISCORD_WEBHOOK_URL;
|
|
380
|
+
|
|
381
|
+
async function sendDiscordError(error, req) {
|
|
382
|
+
if (!discordWebhook) return;
|
|
383
|
+
|
|
384
|
+
const embed = {
|
|
385
|
+
title: "šØ Error in Sprint API",
|
|
386
|
+
description: \`\${error.message}\`,
|
|
387
|
+
color: 16711680,
|
|
388
|
+
fields: [
|
|
389
|
+
{
|
|
390
|
+
name: "Method",
|
|
391
|
+
value: req.method,
|
|
392
|
+
inline: true,
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
name: "URL",
|
|
396
|
+
value: req.url,
|
|
397
|
+
inline: true,
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
name: "Stack",
|
|
401
|
+
value: error.stack?.split("\\n").slice(0, 5).join("\\n") || "No stack trace",
|
|
402
|
+
},
|
|
403
|
+
],
|
|
404
|
+
timestamp: new Date().toISOString(),
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
try {
|
|
408
|
+
await axios.post(discordWebhook, {
|
|
409
|
+
embeds: [embed],
|
|
410
|
+
});
|
|
411
|
+
} catch (e) {
|
|
412
|
+
console.error("Failed to send Discord webhook:", e.message);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
`;
|
|
417
|
+
}
|
|
418
|
+
return "";
|
|
419
|
+
}
|
|
420
|
+
function getAppFile(language, telemetry) {
|
|
421
|
+
if (language === "typescript") {
|
|
422
|
+
return `import type { SprintOptions } from "sprint-es";
|
|
423
|
+
|
|
424
|
+
export const options: SprintOptions = {
|
|
425
|
+
port: 3000,
|
|
426
|
+
bodyParser: {
|
|
427
|
+
limit: "10mb"
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
`;
|
|
431
|
+
}
|
|
432
|
+
return "";
|
|
433
|
+
}
|
|
434
|
+
function getEnvExample(telemetry) {
|
|
435
|
+
let env = `PORT=3000
|
|
436
|
+
FAVICON=./public/favicon.ico
|
|
437
|
+
NODE_ENV=development
|
|
438
|
+
`;
|
|
439
|
+
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
440
|
+
env += `
|
|
441
|
+
# Sentry / GlitchTip (use GlitchTip DSN for self-hosted)
|
|
442
|
+
SENTRY_DSN=
|
|
443
|
+
`;
|
|
444
|
+
}
|
|
445
|
+
else if (telemetry === "discord") {
|
|
446
|
+
env += `
|
|
447
|
+
# Discord Webhook URL for error notifications
|
|
448
|
+
DISCORD_WEBHOOK_URL=
|
|
449
|
+
`;
|
|
450
|
+
}
|
|
451
|
+
return env;
|
|
452
|
+
}
|
|
453
|
+
function getSprintConfig(telemetry) {
|
|
454
|
+
if (telemetry === "discord") {
|
|
455
|
+
return `export default {
|
|
456
|
+
errorHandler: async (error, req, res) => {
|
|
457
|
+
console.error(error);
|
|
458
|
+
|
|
459
|
+
if (process.env.DISCORD_WEBHOOK_URL && res.socket.server) {
|
|
460
|
+
const axios = await import("axios");
|
|
461
|
+
const embed = {
|
|
462
|
+
title: "šØ Error in Sprint API",
|
|
463
|
+
description: error.message,
|
|
464
|
+
color: 16711680,
|
|
465
|
+
fields: [
|
|
466
|
+
{
|
|
467
|
+
name: "Method",
|
|
468
|
+
value: req.method,
|
|
469
|
+
inline: true,
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
name: "URL",
|
|
473
|
+
value: req.url,
|
|
474
|
+
inline: true,
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
name: "Stack",
|
|
478
|
+
value: error.stack?.split("\\n").slice(0, 5).join("\\n") || "No stack",
|
|
479
|
+
},
|
|
480
|
+
],
|
|
481
|
+
timestamp: new Date().toISOString(),
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
try {
|
|
485
|
+
await axios.default.post(process.env.DISCORD_WEBHOOK_URL, {
|
|
486
|
+
embeds: [embed],
|
|
487
|
+
});
|
|
488
|
+
} catch (e) {
|
|
489
|
+
console.error("Discord webhook error:", e.message);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
res.status(500).json({ error: "Internal server error" });
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
`;
|
|
497
|
+
}
|
|
498
|
+
return "";
|
|
499
|
+
}
|
|
500
|
+
function getHomeRoute(language) {
|
|
501
|
+
if (language === "typescript") {
|
|
502
|
+
return `import { Router } from "sprint-es";
|
|
503
|
+
|
|
504
|
+
const router = Router();
|
|
505
|
+
|
|
506
|
+
router.get("/", (req, res) => {
|
|
507
|
+
res.json({
|
|
508
|
+
message: "Hello World",
|
|
509
|
+
status: "ok"
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
export default router;
|
|
514
|
+
`;
|
|
515
|
+
}
|
|
516
|
+
return `import { Router } from "sprint-es";
|
|
517
|
+
|
|
518
|
+
const router = Router();
|
|
519
|
+
|
|
520
|
+
router.get("/", (req, res) => {
|
|
521
|
+
res.json({
|
|
522
|
+
message: "Hello World",
|
|
523
|
+
status: "ok"
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
export default router;
|
|
528
|
+
`;
|
|
529
|
+
}
|
|
530
|
+
function getDockerfile(language) {
|
|
531
|
+
if (language === "typescript") {
|
|
532
|
+
return `FROM node:20-alpine
|
|
533
|
+
|
|
534
|
+
WORKDIR /app
|
|
535
|
+
|
|
536
|
+
COPY package*.json ./
|
|
537
|
+
|
|
538
|
+
RUN npm install
|
|
539
|
+
|
|
540
|
+
COPY . .
|
|
541
|
+
|
|
542
|
+
RUN npm run build
|
|
543
|
+
|
|
544
|
+
EXPOSE 3000
|
|
545
|
+
|
|
546
|
+
CMD ["npm", "start"]
|
|
547
|
+
`;
|
|
548
|
+
}
|
|
549
|
+
return `FROM node:20-alpine
|
|
550
|
+
|
|
551
|
+
WORKDIR /app
|
|
552
|
+
|
|
553
|
+
COPY package*.json ./
|
|
554
|
+
|
|
555
|
+
RUN npm install
|
|
556
|
+
|
|
557
|
+
COPY . .
|
|
558
|
+
|
|
559
|
+
EXPOSE 3000
|
|
560
|
+
|
|
561
|
+
CMD ["npm", "start"]
|
|
562
|
+
`;
|
|
563
|
+
}
|
|
564
|
+
function getDockerCompose(language) {
|
|
565
|
+
if (language === "typescript") {
|
|
566
|
+
return `version: "3.8"
|
|
567
|
+
|
|
568
|
+
services:
|
|
569
|
+
app:
|
|
570
|
+
build: .
|
|
571
|
+
ports:
|
|
572
|
+
- "3000:3000"
|
|
573
|
+
environment:
|
|
574
|
+
- NODE_ENV=production
|
|
575
|
+
- PORT=3000
|
|
576
|
+
restart: unless-stopped
|
|
577
|
+
`;
|
|
578
|
+
}
|
|
579
|
+
return `version: "3.8"
|
|
580
|
+
|
|
581
|
+
services:
|
|
582
|
+
app:
|
|
583
|
+
build: .
|
|
584
|
+
ports:
|
|
585
|
+
- "3000:3000"
|
|
586
|
+
environment:
|
|
587
|
+
- NODE_ENV=production
|
|
588
|
+
- PORT=3000
|
|
589
|
+
restart: unless-stopped
|
|
590
|
+
`;
|
|
591
|
+
}
|
|
592
|
+
function getGitignore(language) {
|
|
593
|
+
return `# Dependencies
|
|
594
|
+
node_modules/
|
|
595
|
+
npm-debug.log*
|
|
596
|
+
yarn-debug.log*
|
|
597
|
+
yarn-error.log*
|
|
598
|
+
|
|
599
|
+
# Build
|
|
600
|
+
dist/
|
|
601
|
+
build/
|
|
602
|
+
*.tsbuildinfo
|
|
603
|
+
|
|
604
|
+
# Environment
|
|
605
|
+
.env
|
|
606
|
+
.env.local
|
|
607
|
+
.env.*.local
|
|
608
|
+
|
|
609
|
+
# IDE
|
|
610
|
+
.vscode/
|
|
611
|
+
.idea/
|
|
612
|
+
*.swp
|
|
613
|
+
*.swo
|
|
614
|
+
*~
|
|
615
|
+
|
|
616
|
+
# OS
|
|
617
|
+
.DS_Store
|
|
618
|
+
Thumbs.db
|
|
619
|
+
|
|
620
|
+
# Logs
|
|
621
|
+
logs/
|
|
622
|
+
*.log
|
|
623
|
+
|
|
624
|
+
# Test
|
|
625
|
+
coverage/
|
|
626
|
+
|
|
627
|
+
# Temporary
|
|
628
|
+
tmp/
|
|
629
|
+
temp/
|
|
630
|
+
`;
|
|
631
|
+
}
|
|
632
|
+
function getDockerIgnore() {
|
|
633
|
+
return `node_modules
|
|
634
|
+
npm-debug.log
|
|
635
|
+
.env
|
|
636
|
+
.env.local
|
|
637
|
+
.git
|
|
638
|
+
.gitignore
|
|
639
|
+
README.md
|
|
640
|
+
dist
|
|
641
|
+
build
|
|
642
|
+
coverage
|
|
643
|
+
.vscode
|
|
644
|
+
.idea
|
|
645
|
+
*.log
|
|
646
|
+
tmp
|
|
647
|
+
temp
|
|
648
|
+
`;
|
|
649
|
+
}
|
|
650
|
+
main().catch(console.error);
|